diff options
author | Roland McGrath <roland@redhat.com> | 2010-08-30 19:22:41 -0700 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2010-08-30 19:22:41 -0700 |
commit | fa1449555dd648a3a22f2dc59a3c856b126e3940 (patch) | |
tree | 82a68a616c8cd833077c74356ae8741d738ac443 | |
parent | a159915a87d83951acb9e504b9cefc08ba98b8bd (diff) | |
download | elfutils-fa1449555dd648a3a22f2dc59a3c856b126e3940.tar.gz |
readelf: Print .debug_loc/.debug_ranges with cognizance of actual DIE pointers into them.
-rw-r--r-- | src/ChangeLog | 17 | ||||
-rw-r--r-- | src/readelf.c | 364 |
2 files changed, 304 insertions, 77 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 3010ce58..060e9df7 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,22 @@ 2010-08-30 Roland McGrath <roland@redhat.com> + Print .debug_loc/.debug_ranges with cognizance of actual DIE uses. + * readelf.c (parse_opt): Add section_info to implicit_debug_sections + for ranges, loc. + (struct listptr, struct listptr_table): New types. + (compare_listptr, reset_listptr, sort_listptr): New functions. + (notice_listptr, skip_listptr_hole): New functions. + (struct attrcb_args): Add silent member. + (attr_callback): Call notice_listptr for loclistptr and rangelistptr. + Suppress output if silent, but still call notice_listptr. + (print_debug_units): Suppress output if section_info not requested. + (print_debug_loc_section): Call sort_listptr, skip_listptr_hole. + (print_debug_ranges_section): Likewise. + (print_debug): Call reset_listptr on both tables. + + * readelf.c (print_debug_ranges_section): Print empty list. + (print_debug_loc_section): Likewise. + * readelf.c (print_debug_loc_section): Check for bogus length before calling print_ops. (print_ops): Check harder for bogus data that would read off end. diff --git a/src/readelf.c b/src/readelf.c index fd9f9a5d..2b7f9f2f 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -380,13 +380,19 @@ parse_opt (int key, char *arg, else if (strcmp (arg, "aranges") == 0) print_debug_sections |= section_aranges; else if (strcmp (arg, "ranges") == 0) - print_debug_sections |= section_ranges; + { + print_debug_sections |= section_ranges; + implicit_debug_sections |= section_info; + } else if (strcmp (arg, "frame") == 0 || strcmp (arg, "frames") == 0) print_debug_sections |= section_frame; else if (strcmp (arg, "info") == 0) print_debug_sections |= section_info; else if (strcmp (arg, "loc") == 0) - print_debug_sections |= section_loc; + { + print_debug_sections |= section_loc; + implicit_debug_sections |= section_info; + } else if (strcmp (arg, "line") == 0) print_debug_sections |= section_line; else if (strcmp (arg, "pubnames") == 0) @@ -4234,6 +4240,143 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, } +struct listptr +{ + Dwarf_Off offset:(64 - 3); + bool addr64:1; + bool dwarf64:1; + bool warned:1; +}; + +#define listptr_offset_size(p) ((p)->dwarf64 ? 8 : 4) +#define listptr_address_size(p) ((p)->addr64 ? 8 : 4) + +static int +compare_listptr (const void *a, const void *b, void *arg) +{ + const char *name = arg; + struct listptr *p1 = (void *) a; + struct listptr *p2 = (void *) b; + + if (p1->offset < p2->offset) + return -1; + if (p1->offset > p2->offset) + return 1; + + if (!p1->warned && !p2->warned) + { + if (p1->addr64 != p2->addr64) + { + p1->warned = p2->warned = true; + error (0, 0, + gettext ("%s %#" PRIx64 " used with different address sizes"), + name, (uint64_t) p1->offset); + } + if (p1->dwarf64 != p2->dwarf64) + { + p1->warned = p2->warned = true; + error (0, 0, + gettext ("%s %#" PRIx64 " used with different offset sizes"), + name, (uint64_t) p1->offset); + } + } + + return 0; +} + +struct listptr_table +{ + size_t n; + size_t alloc; + struct listptr *table; +}; + +static struct listptr_table known_loclistptr; +static struct listptr_table known_rangelistptr; + +static void +reset_listptr (struct listptr_table *table) +{ + free (table->table); + table->n = table->alloc = 0; +} + +static void +notice_listptr (enum section_e section, struct listptr_table *table, + uint_fast8_t address_size, uint_fast8_t offset_size, + Dwarf_Off offset) +{ + if (print_debug_sections & section) + { + if (table->n == table->alloc) + { + if (table->alloc == 0) + table->alloc = 128; + else + table->alloc *= 2; + table->table = xrealloc (table->table, + table->alloc * sizeof table->table[0]); + } + + struct listptr *p = &table->table[table->n++]; + + *p = (struct listptr) + { + .addr64 = address_size == 8, + .dwarf64 = offset_size == 8, + .offset = offset + }; + assert (p->offset == offset); + } +} + +static void +sort_listptr (struct listptr_table *table, const char *name) +{ + if (table->n > 0) + qsort_r (table->table, table->n, sizeof table->table[0], + &compare_listptr, (void *) name); +} + +static bool +skip_listptr_hole (struct listptr_table *table, size_t *idxp, + uint_fast8_t *address_sizep, uint_fast8_t *offset_sizep, + ptrdiff_t offset, unsigned char **readp, unsigned char *endp) +{ + if (table->n == 0) + return false; + + while (*idxp < table->n && table->table[*idxp].offset < (Dwarf_Off) offset) + ++*idxp; + + struct listptr *p = &table->table[*idxp]; + + if (*idxp == table->n + || p->offset >= (Dwarf_Off) (endp - *readp + offset)) + { + *readp = endp; + printf (gettext (" [%6tx] <UNUSED GARBAGE IN REST OF SECTION>\n"), + offset); + return true; + } + + if (p->offset != (Dwarf_Off) offset) + { + *readp += p->offset - offset; + printf (gettext (" [%6tx] <UNUSED GARBAGE> ... %" PRIu64 " bytes ...\n"), + offset, (Dwarf_Off) p->offset - offset); + return true; + } + + if (address_sizep != NULL) + *address_sizep = listptr_address_size (p); + if (offset_sizep != NULL) + *offset_sizep = listptr_offset_size (p); + + return false; +} + + static void print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)), Ebl *ebl __attribute__ ((unused)), @@ -4380,14 +4523,23 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), ".debug_ranges", (uint64_t) shdr->sh_offset); - size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + sort_listptr (&known_rangelistptr, "rangelistptr"); + size_t listptr_idx = 0; + + uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; bool first = true; + unsigned char *const endp = (unsigned char *) data->d_buf + data->d_size; unsigned char *readp = data->d_buf; - while (readp < (unsigned char *) data->d_buf + data->d_size) + while (readp < endp) { ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + if (first && skip_listptr_hole (&known_rangelistptr, &listptr_idx, + &address_size, NULL, + offset, &readp, endp)) + continue; + if (unlikely (data->d_size - offset < address_size * 2)) { printf (gettext (" [%6tx] <INVALID DATA>\n"), offset); @@ -4416,7 +4568,11 @@ print_debug_ranges_section (Dwfl_Module *dwflmod, free (b); } else if (begin == 0 && end == 0) /* End of list entry. */ - first = true; + { + if (first) + printf (gettext (" [%6tx] empty list\n"), offset); + first = true; + } else { char *b = format_dwarf_addr (dwflmod, address_size, begin); @@ -5177,6 +5333,7 @@ struct attrcb_args Dwfl_Module *dwflmod; Dwarf *dbg; int level; + bool silent; unsigned int version; unsigned int addrsize; unsigned int offset_size; @@ -5193,42 +5350,48 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) unsigned int attr = dwarf_whatattr (attrp); if (unlikely (attr == 0)) { - error (0, 0, gettext ("cannot get attribute code: %s"), - dwarf_errmsg (-1)); + if (!cbargs->silent) + error (0, 0, gettext ("cannot get attribute code: %s"), + dwarf_errmsg (-1)); return DWARF_CB_ABORT; } unsigned int form = dwarf_whatform (attrp); if (unlikely (form == 0)) { - error (0, 0, gettext ("cannot get attribute form: %s"), - dwarf_errmsg (-1)); + if (!cbargs->silent) + error (0, 0, gettext ("cannot get attribute form: %s"), + dwarf_errmsg (-1)); return DWARF_CB_ABORT; } switch (form) { case DW_FORM_addr: - { - Dwarf_Addr addr; - if (unlikely (dwarf_formaddr (attrp, &addr) != 0)) - { - attrval_out: - error (0, 0, gettext ("cannot get attribute value: %s"), - dwarf_errmsg (-1)); - return DWARF_CB_ABORT; - } - char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr); - printf (" %*s%-20s (%s) %s\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_form_string (form), a); - free (a); - } + if (!cbargs->silent) + { + Dwarf_Addr addr; + if (unlikely (dwarf_formaddr (attrp, &addr) != 0)) + { + attrval_out: + if (!cbargs->silent) + error (0, 0, gettext ("cannot get attribute value: %s"), + dwarf_errmsg (-1)); + return DWARF_CB_ABORT; + } + char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr); + printf (" %*s%-20s (%s) %s\n", + (int) (level * 2), "", dwarf_attr_string (attr), + dwarf_form_string (form), a); + free (a); + } break; case DW_FORM_indirect: case DW_FORM_strp: - case DW_FORM_string:; + case DW_FORM_string: + if (cbargs->silent) + break; const char *str = dwarf_formstring (attrp); if (unlikely (str == NULL)) goto attrval_out; @@ -5243,6 +5406,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) case DW_FORM_ref4: case DW_FORM_ref2: case DW_FORM_ref1:; + if (cbargs->silent) + break; Dwarf_Die ref; if (unlikely (dwarf_formref_die (attrp, &ref) == NULL)) goto attrval_out; @@ -5253,6 +5418,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) break; case DW_FORM_ref_sig8: + if (cbargs->silent) + break; printf (" %*s%-20s (%s) {%6" PRIx64 "}\n", (int) (level * 2), "", dwarf_attr_string (attr), dwarf_form_string (form), @@ -5276,14 +5443,16 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) const char *valuestr = NULL; switch (attr) { - /* This case can take either a constant or a loclistptr. */ + /* This case can take either a constant or a loclistptr. */ case DW_AT_data_member_location: - if (form != DW_FORM_data4 && form != DW_FORM_data8 - && form != DW_FORM_sec_offset) /* XXX not data[48] if CU v4! */ + if (form != DW_FORM_sec_offset + && (cbargs->version >= 4 + || (form != DW_FORM_data4 && form != DW_FORM_data8))) { - printf (" %*s%-20s (%s) %" PRIxMAX "\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_form_string (form), (uintmax_t) num); + if (!cbargs->silent) + printf (" %*s%-20s (%s) %" PRIxMAX "\n", + (int) (level * 2), "", dwarf_attr_string (attr), + dwarf_form_string (form), (uintmax_t) num); return DWARF_CB_OK; } /* else fallthrough */ @@ -5297,15 +5466,21 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) case DW_AT_frame_base: case DW_AT_return_addr: case DW_AT_static_link: - printf (" %*s%-20s (%s) location list [%6" PRIxMAX "]\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_form_string (form), (uintmax_t) num); + notice_listptr (section_loc, &known_loclistptr, + cbargs->addrsize, cbargs->offset_size, num); + if (!cbargs->silent) + printf (" %*s%-20s (%s) location list [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + dwarf_form_string (form), (uintmax_t) num); return DWARF_CB_OK; case DW_AT_ranges: - printf (" %*s%-20s (%s) range list [%6" PRIxMAX "]\n", - (int) (level * 2), "", dwarf_attr_string (attr), - dwarf_form_string (form), (uintmax_t) num); + notice_listptr (section_ranges, &known_rangelistptr, + cbargs->addrsize, cbargs->offset_size, num); + if (!cbargs->silent) + printf (" %*s%-20s (%s) range list [%6" PRIxMAX "]\n", + (int) (level * 2), "", dwarf_attr_string (attr), + dwarf_form_string (form), (uintmax_t) num); return DWARF_CB_OK; case DW_AT_language: @@ -5343,6 +5518,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) break; } + if (cbargs->silent) + break; + if (valuestr == NULL) printf (" %*s%-20s (%s) %" PRIuMAX "\n", (int) (level * 2), "", dwarf_attr_string (attr), @@ -5353,7 +5531,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) dwarf_form_string (form), valuestr, (uintmax_t) num); break; - case DW_FORM_flag:; + case DW_FORM_flag: + if (cbargs->silent) + break; bool flag; if (unlikely (dwarf_formflag (attrp, &flag) != 0)) goto attrval_out; @@ -5364,6 +5544,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) break; case DW_FORM_flag_present: + if (cbargs->silent) + break; printf (" %*s%-20s (%s) %s\n", (int) (level * 2), "", dwarf_attr_string (attr), dwarf_form_string (form), nl_langinfo (YESSTR)); @@ -5373,7 +5555,9 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) case DW_FORM_block4: case DW_FORM_block2: case DW_FORM_block1: - case DW_FORM_block:; + case DW_FORM_block: + if (cbargs->silent) + break; Dwarf_Block block; if (unlikely (dwarf_formblock (attrp, &block) != 0)) goto attrval_out; @@ -5420,6 +5604,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) break; default: + if (cbargs->silent) + break; printf (" %*s%-20s (form: %#x) ???\n", (int) (level * 2), "", dwarf_attr_string (attr), (int) form); @@ -5437,14 +5623,16 @@ print_debug_units (Dwfl_Module *dwflmod, GElf_Shdr *shdr, Dwarf *dbg, bool debug_types) { + const bool silent = !(print_debug_sections & section_info); const char *secname = debug_types ? ".debug_types" : ".debug_info"; - printf (gettext ("\ + if (!silent) + printf (gettext ("\ \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n [Offset]\n"), - elf_ndxscn (scn), secname, (uint64_t) shdr->sh_offset); + elf_ndxscn (scn), secname, (uint64_t) shdr->sh_offset); /* If the section is empty we don't have to do anything. */ - if (shdr->sh_size == 0) + if (!silent && shdr->sh_size == 0) return; int maxdies = 20; @@ -5468,26 +5656,30 @@ print_debug_units (Dwfl_Module *dwflmod, debug_types ? &typeoff : NULL) != 0) goto do_return; - if (debug_types) - printf (gettext (" Type unit at offset %" PRIu64 ":\n" - " Version: %" PRIu16 ", Abbreviation section offset: %" - PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 - "\n Type signature: %#" PRIx64 - ", Type offset: %#" PRIx64 "\n"), - (uint64_t) offset, version, abbroffset, addrsize, offsize, - typesig, (uint64_t) typeoff); - else - printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" - " Version: %" PRIu16 ", Abbreviation section offset: %" - PRIu64 ", Address size: %" PRIu8 ", Offset size: %" PRIu8 - "\n"), - (uint64_t) offset, version, abbroffset, addrsize, offsize); - + if (!silent) + { + if (debug_types) + printf (gettext (" Type unit at offset %" PRIu64 ":\n" + " Version: %" PRIu16 ", Abbreviation section offset: %" + PRIu64 ", Address size: %" PRIu8 + ", Offset size: %" PRIu8 + "\n Type signature: %#" PRIx64 + ", Type offset: %#" PRIx64 "\n"), + (uint64_t) offset, version, abbroffset, addrsize, offsize, + typesig, (uint64_t) typeoff); + else + printf (gettext (" Compilation unit at offset %" PRIu64 ":\n" + " Version: %" PRIu16 ", Abbreviation section offset: %" + PRIu64 ", Address size: %" PRIu8 + ", Offset size: %" PRIu8 "\n"), + (uint64_t) offset, version, abbroffset, addrsize, offsize); + } struct attrcb_args args = { .dwflmod = dwflmod, .dbg = dbg, + .silent = silent, .version = version, .addrsize = addrsize, .offset_size = offsize, @@ -5501,9 +5693,10 @@ print_debug_units (Dwfl_Module *dwflmod, if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie) (dbg, offset, &dies[level]) == NULL)) { - error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, secname, dwarf_errmsg (-1)); + if (!silent) + error (0, 0, gettext ("cannot get DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, secname, dwarf_errmsg (-1)); goto do_return; } @@ -5512,23 +5705,26 @@ print_debug_units (Dwfl_Module *dwflmod, offset = dwarf_dieoffset (&dies[level]); if (unlikely (offset == ~0ul)) { - error (0, 0, gettext ("cannot get DIE offset: %s"), - dwarf_errmsg (-1)); + if (!silent) + error (0, 0, gettext ("cannot get DIE offset: %s"), + dwarf_errmsg (-1)); goto do_return; } int tag = dwarf_tag (&dies[level]); if (unlikely (tag == DW_TAG_invalid)) { - error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 - " in section '%s': %s"), - (uint64_t) offset, secname, dwarf_errmsg (-1)); + if (!silent) + error (0, 0, gettext ("cannot get tag of DIE at offset %" PRIu64 + " in section '%s': %s"), + (uint64_t) offset, secname, dwarf_errmsg (-1)); goto do_return; } - printf (" [%6" PRIx64 "] %*s%s\n", - (uint64_t) offset, (int) (level * 2), "", - dwarf_tag_string (tag)); + if (!silent) + printf (" [%6" PRIx64 "] %*s%s\n", + (uint64_t) offset, (int) (level * 2), "", + dwarf_tag_string (tag)); /* Print the attribute values. */ args.level = level; @@ -5549,15 +5745,17 @@ print_debug_units (Dwfl_Module *dwflmod, if (unlikely (res == -1)) { - error (0, 0, gettext ("cannot get next DIE: %s\n"), - dwarf_errmsg (-1)); + if (!silent) + error (0, 0, gettext ("cannot get next DIE: %s\n"), + dwarf_errmsg (-1)); goto do_return; } } else if (unlikely (res < 0)) { - error (0, 0, gettext ("cannot get next DIE: %s"), - dwarf_errmsg (-1)); + if (!silent) + error (0, 0, gettext ("cannot get next DIE: %s"), + dwarf_errmsg (-1)); goto do_return; } else @@ -6095,11 +6293,11 @@ print_debug_loc_section (Dwfl_Module *dwflmod, \nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"), elf_ndxscn (scn), ".debug_loc", (uint64_t) shdr->sh_offset); - size_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + sort_listptr (&known_loclistptr, "loclistptr"); + size_t listptr_idx = 0; - /* XXX This is wrong! We can only know the right size given the CU that - points to this location list. */ - size_t offset_size = 4; + uint_fast8_t address_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + uint_fast8_t offset_size = 4; bool first = true; unsigned char *readp = data->d_buf; @@ -6108,6 +6306,11 @@ print_debug_loc_section (Dwfl_Module *dwflmod, { ptrdiff_t offset = readp - (unsigned char *) data->d_buf; + if (first && skip_listptr_hole (&known_loclistptr, &listptr_idx, + &address_size, &offset_size, + offset, &readp, endp)) + continue; + if (unlikely (data->d_size - offset < address_size * 2)) { printf (gettext (" [%6tx] <INVALID DATA>\n"), offset); @@ -6136,7 +6339,11 @@ print_debug_loc_section (Dwfl_Module *dwflmod, free (b); } else if (begin == 0 && end == 0) /* End of list entry. */ - first = true; + { + if (first) + printf (gettext (" [%6tx] empty list\n"), offset); + first = true; + } else { /* We have a location expression entry. */ @@ -6756,6 +6963,9 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr) } } } + + reset_listptr (&known_loclistptr); + reset_listptr (&known_rangelistptr); } |