From 18bd398bc4f10077209229e52f1e603139f5c6a7 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 3 Nov 2004 10:44:45 +0000 Subject: Add support to readelf to decode and display the contents of .debug_ranges sections. --- binutils/readelf.c | 761 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 533 insertions(+), 228 deletions(-) (limited to 'binutils/readelf.c') diff --git a/binutils/readelf.c b/binutils/readelf.c index 69b8051..4cbbf88 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -159,6 +159,7 @@ int do_debug_abbrevs; int do_debug_lines; int do_debug_pubnames; int do_debug_aranges; +int do_debug_ranges; int do_debug_frames; int do_debug_frames_interp; int do_debug_macinfo; @@ -185,7 +186,16 @@ size_t group_count = 0; struct group **section_headers_groups; -/* A dynamic array of flags indicating which sections require dumping. */ +/* A dynamic array of flags indicating for which sections a hex dump + has been requested (via the -x switch) and/or a disassembly dump + (via the -i switch). */ +char *cmdline_dump_sects = NULL; +unsigned num_cmdline_dump_sects = 0; + +/* A dynamic array of flags indicating for which sections a dump of + some kind has been requested. It is reset on a per-object file + basis and then initialised from the cmdline_dump_sects array and + the results of interpreting the -w switch. */ char *dump_sects = NULL; unsigned int num_dump_sects = 0; @@ -212,8 +222,8 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); #define UNKNOWN -1 #define SECTION_NAME(X) ((X) == NULL ? "" : \ - ((X)->sh_name >= string_table_length \ - ? "" : string_table + (X)->sh_name)) + ((X)->sh_name >= string_table_length \ + ? "" : string_table + (X)->sh_name)) /* Given st_shndx I, map to section_headers index. */ #define SECTION_HEADER_INDEX(I) \ @@ -259,6 +269,10 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); /* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has already been called and verified that the string exists. */ #define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset) + +/* This is just a bit of syntatic sugar. */ +#define streq(a,b) (strcmp ((a), (b)) == 0) +#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) static void error (const char *message, ...) @@ -566,8 +580,8 @@ byte_get_big_endian (unsigned char *field, int size) #ifndef BFD64 case 8: - /* Although we are extracing data from an 8 byte wide field, we - are returning only 4 bytes of data. */ + /* Although we are extracing data from an 8 byte wide field, + we are returning only 4 bytes of data. */ return ((unsigned long) (field[7])) | (((unsigned long) (field[6])) << 8) | (((unsigned long) (field[5])) << 16) @@ -743,7 +757,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { - error(_("out of memory parsing relocs")); + error (_("out of memory parsing relocs")); return 0; } @@ -770,7 +784,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { - error(_("out of memory parsing relocs")); + error (_("out of memory parsing relocs")); return 0; } @@ -813,7 +827,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { - error(_("out of memory parsing relocs")); + error (_("out of memory parsing relocs")); return 0; } @@ -840,7 +854,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { - error(_("out of memory parsing relocs")); + error (_("out of memory parsing relocs")); return 0; } @@ -1268,12 +1282,13 @@ dump_relocations (FILE *file, } else if (is_rela) { - printf ("%*c", is_32bit_elf ? (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' '); + printf ("%*c", is_32bit_elf ? + (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' '); print_vma (rels[i].r_addend, LONG_HEX); } if (elf_header.e_machine == EM_SPARCV9 - && !strcmp (rtype, "R_SPARC_OLO10")) + && streq (rtype, "R_SPARC_OLO10")) printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info)); putchar ('\n'); @@ -1291,7 +1306,7 @@ dump_relocations (FILE *file, else printf ("%-17.17s", rtype2); - printf("\n Type3: "); + printf ("\n Type3: "); if (rtype3 == NULL) #ifdef _bfd_int64_low @@ -2401,7 +2416,7 @@ get_parisc_section_type_name (unsigned int sh_type) static const char * get_ia64_section_type_name (unsigned int sh_type) { - /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */ + /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */ if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG) return get_osabi_name ((sh_type & 0x00FF0000) >> 16); @@ -2576,8 +2591,8 @@ usage (void) -A --arch-specific Display architecture specific information (if any).\n\ -D --use-dynamic Use the dynamic section info when displaying symbols\n\ -x --hex-dump= Dump the contents of section \n\ - -w[liaprmfFso] or\n\ - --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]\n\ + -w[liaprmfFsoR] or\n\ + --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\ Display the contents of DWARF2 debug sections\n")); #ifdef SUPPORT_DISASSEMBLY fprintf (stdout, _("\ @@ -2594,6 +2609,11 @@ usage (void) exit (0); } +/* Record the fact that the user wants the contents of section number + SECTION to be displayed using the method(s) encoded as flags bits + in TYPE. Note, TYPE can be zero if we are creating the array for + the first time. */ + static void request_dump (unsigned int section, int type) { @@ -2744,10 +2764,13 @@ parse_args (int argc, char **argv) break; case 'r': - case 'R': do_debug_aranges = 1; break; + case 'R': + do_debug_ranges = 1; + break; + case 'F': do_debug_frames_interp = 1; case 'f': @@ -2781,10 +2804,33 @@ parse_args (int argc, char **argv) do_debugging = 1; else { - static const char *debug_dump_opt[] - = { "line", "info", "abbrev", "pubnames", "ranges", - "macro", "frames", "frames-interp", "str", "loc", NULL }; - unsigned int index; + typedef struct + { + const char * option; + int * variable; + } + debug_dump_long_opts; + + debug_dump_long_opts opts_table [] = + { + /* Please keep this table alpha- sorted. */ + { "Ranges", & do_debug_ranges }, + { "abbrev", & do_debug_abbrevs }, + { "aranges", & do_debug_aranges }, + { "frames", & do_debug_frames }, + { "frames-interp", & do_debug_frames_interp }, + { "info", & do_debug_info }, + { "line", & do_debug_lines }, + { "loc", & do_debug_loc }, + { "macro", & do_debug_macinfo }, + { "pubnames", & do_debug_pubnames }, + /* This entry is for compatability + with earlier versions of readelf. */ + { "ranges", & do_debug_aranges }, + { "str", & do_debug_str }, + { NULL, NULL } + }; + const char *p; do_debugging = 0; @@ -2792,59 +2838,28 @@ parse_args (int argc, char **argv) p = optarg; while (*p) { - for (index = 0; debug_dump_opt[index]; index++) + debug_dump_long_opts * entry; + + for (entry = opts_table; entry->option; entry++) { - size_t len = strlen (debug_dump_opt[index]); + size_t len = strlen (entry->option); - if (strncmp (p, debug_dump_opt[index], len) == 0 + if (strneq (p, entry->option, len) && (p[len] == ',' || p[len] == '\0')) { - switch (p[0]) - { - case 'i': - do_debug_info = 1; - break; - - case 'a': - do_debug_abbrevs = 1; - break; - - case 'l': - if (p[1] == 'i') - do_debug_lines = 1; - else - do_debug_loc = 1; - break; - - case 'p': - do_debug_pubnames = 1; - break; - - case 'r': - do_debug_aranges = 1; - break; - - case 'f': - if (len > 6) - do_debug_frames_interp = 1; - do_debug_frames = 1; - break; - - case 'm': - do_debug_macinfo = 1; - break; - - case 's': - do_debug_str = 1; - break; - } + * entry->variable = 1; + + /* The --debug-dump=frames-interp option also + enables the --debug-dump=frames option. */ + if (do_debug_frames_interp) + do_debug_frames = 1; p += len; break; } } - if (debug_dump_opt[index] == NULL) + if (entry->option == NULL) { warn (_("Unrecognized debug option '%s'\n"), p); p = strchr (p, ','); @@ -2895,7 +2910,7 @@ parse_args (int argc, char **argv) else if (argc < 3) { warn (_("Nothing to do.\n")); - usage(); + usage (); } } @@ -3271,7 +3286,7 @@ process_program_headers (FILE *file) for (j = 0, sec = section_headers; j < elf_header.e_shnum; j++, sec++) - if (strcmp (SECTION_NAME (sec), ".dynamic") == 0) + if (streq (SECTION_NAME (sec), ".dynamic")) break; if (j == elf_header.e_shnum || sec->sh_size == 0) @@ -3716,7 +3731,7 @@ process_section_headers (FILE *file) dynamic_symbols = GET_ELF_SYMBOLS (file, section); } else if (section->sh_type == SHT_STRTAB - && strcmp (name, ".dynstr") == 0) + && streq (name, ".dynstr")) { if (dynamic_strings != NULL) { @@ -3740,29 +3755,30 @@ process_section_headers (FILE *file) else if ((do_debugging || do_debug_info || do_debug_abbrevs || do_debug_lines || do_debug_pubnames || do_debug_aranges || do_debug_frames || do_debug_macinfo || do_debug_str - || do_debug_loc) - && strncmp (name, ".debug_", 7) == 0) + || do_debug_loc || do_debug_ranges) + && strneq (name, ".debug_", 7)) { name += 7; if (do_debugging - || (do_debug_info && (strcmp (name, "info") == 0)) - || (do_debug_abbrevs && (strcmp (name, "abbrev") == 0)) - || (do_debug_lines && (strcmp (name, "line") == 0)) - || (do_debug_pubnames && (strcmp (name, "pubnames") == 0)) - || (do_debug_aranges && (strcmp (name, "aranges") == 0)) - || (do_debug_frames && (strcmp (name, "frame") == 0)) - || (do_debug_macinfo && (strcmp (name, "macinfo") == 0)) - || (do_debug_str && (strcmp (name, "str") == 0)) - || (do_debug_loc && (strcmp (name, "loc") == 0)) + || (do_debug_info && streq (name, "info")) + || (do_debug_abbrevs && streq (name, "abbrev")) + || (do_debug_lines && streq (name, "line")) + || (do_debug_pubnames && streq (name, "pubnames")) + || (do_debug_aranges && streq (name, "aranges")) + || (do_debug_ranges && streq (name, "ranges")) + || (do_debug_frames && streq (name, "frame")) + || (do_debug_macinfo && streq (name, "macinfo")) + || (do_debug_str && streq (name, "str")) + || (do_debug_loc && streq (name, "loc")) ) request_dump (i, DEBUG_DUMP); } /* linkonce section to be combined with .debug_info at link time. */ else if ((do_debugging || do_debug_info) - && strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + && strneq (name, ".gnu.linkonce.wi.", 17)) request_dump (i, DEBUG_DUMP); - else if (do_debug_frames && strcmp (name, ".eh_frame") == 0) + else if (do_debug_frames && streq (name, ".eh_frame")) request_dump (i, DEBUG_DUMP); } @@ -4071,6 +4087,7 @@ struct }; /* Process the reloc section. */ + static int process_relocs (FILE *file) { @@ -4434,7 +4451,7 @@ slurp_ia64_unwind_table (FILE *file, sym = aux->symtab + ELF64_R_SYM (rp->r_info); } - if (strncmp (relname, "R_IA64_SEGREL", 13) != 0) + if (! strneq (relname, "R_IA64_SEGREL", 13)) { warn (_("Skipping unexpected relocation type %s\n"), relname); continue; @@ -4522,42 +4539,38 @@ ia64_process_unwind (FILE *file) for (; g != NULL; g = g->next) { sec = SECTION_HEADER (g->section_index); - if (strcmp (SECTION_NAME (sec), - ELF_STRING_ia64_unwind_info) == 0) + + if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)) break; } if (g == NULL) i = elf_header.e_shnum; } - else if (strncmp (SECTION_NAME (unwsec), - ELF_STRING_ia64_unwind_once, len) == 0) + else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len)) { - /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO */ + /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO. */ len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1; suffix = SECTION_NAME (unwsec) + len; for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) - if (strncmp (SECTION_NAME (sec), - ELF_STRING_ia64_unwind_info_once, len2) == 0 - && strcmp (SECTION_NAME (sec) + len2, suffix) == 0) + if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info_once, len2) + && streq (SECTION_NAME (sec) + len2, suffix)) break; } else { /* .IA_64.unwindFOO -> .IA_64.unwind_infoFOO - .IA_64.unwind or BAR -> .IA_64.unwind_info */ + .IA_64.unwind or BAR -> .IA_64.unwind_info. */ len = sizeof (ELF_STRING_ia64_unwind) - 1; len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1; suffix = ""; - if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, - len) == 0) + if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, len)) suffix = SECTION_NAME (unwsec) + len; for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) - if (strncmp (SECTION_NAME (sec), - ELF_STRING_ia64_unwind_info, len2) == 0 - && strcmp (SECTION_NAME (sec) + len2, suffix) == 0) + if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info, len2) + && streq (SECTION_NAME (sec) + len2, suffix)) break; } @@ -4689,12 +4702,12 @@ dump_hppa_unwind (struct hppa_unw_aux_info *aux) print_vma (tp->end.offset, PREFIX_HEX); printf ("]\n\t"); -#define PF(_m) if (tp->_m) printf(#_m " "); -#define PV(_m) if (tp->_m) printf(#_m "=%d ", tp->_m); +#define PF(_m) if (tp->_m) printf (#_m " "); +#define PV(_m) if (tp->_m) printf (#_m "=%d ", tp->_m); PF(Cannot_unwind); PF(Millicode); PF(Millicode_save_sr0); - /* PV(Region_description); */ + /* PV(Region_description); */ PF(Entry_SR); PV(Entry_FR); PV(Entry_GR); @@ -4722,7 +4735,7 @@ dump_hppa_unwind (struct hppa_unw_aux_info *aux) #undef PV } - printf("\n"); + printf ("\n"); } static int @@ -4897,9 +4910,12 @@ slurp_hppa_unwind_table (FILE *file, static int hppa_process_unwind (FILE *file) { - Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec; - unsigned long i, addr_size; struct hppa_unw_aux_info aux; + Elf_Internal_Shdr *unwsec = NULL; + Elf_Internal_Shdr *strsec; + Elf_Internal_Shdr *sec; + unsigned long addr_size; + unsigned long i; memset (& aux, 0, sizeof (aux)); @@ -4918,7 +4934,7 @@ hppa_process_unwind (FILE *file) aux.strtab = get_data (NULL, file, strsec->sh_offset, aux.strtab_size, _("string table")); } - else if (strcmp (SECTION_NAME(sec), ".PARISC.unwind") == 0) + else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) unwsec = sec; } @@ -4927,9 +4943,8 @@ hppa_process_unwind (FILE *file) for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) { - if (strcmp (SECTION_NAME(sec), ".PARISC.unwind") == 0) + if (streq (SECTION_NAME (sec), ".PARISC.unwind")) { - printf (_("\nUnwind section ")); printf (_("'%s'"), SECTION_NAME (sec)); @@ -4973,7 +4988,7 @@ process_unwind (FILE *file) for (i = 0; handlers[i].handler != NULL; i++) if (elf_header.e_machine == handlers[i].machtype) - return handlers[i].handler(file); + return handlers[i].handler (file); printf (_("\nThere are no unwind sections in this file.\n")); return 1; @@ -5669,7 +5684,7 @@ process_dynamic_section (FILE *file) case DT_NEEDED: printf (_("Shared library: [%s]"), name); - if (strcmp (name, program_interpreter) == 0) + if (streq (name, program_interpreter)) printf (_(" program interpreter")); break; @@ -6811,7 +6826,7 @@ process_syminfo (FILE *file ATTRIBUTE_UNUSED) } #ifdef SUPPORT_DISASSEMBLY -static void +static int disassemble_section (Elf_Internal_Shdr *section, FILE *file) { printf (_("\nAssembly dump of section %s\n"), @@ -6972,6 +6987,7 @@ reset_state_machine (int is_stmt) /* Handled an extend line op. Returns true if this is the end of sequence. */ + static int process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size) { @@ -7042,7 +7058,7 @@ find_section (const char * name) for (i = elf_header.e_shnum, sec = section_headers + i - 1; i; --i, --sec) - if (strcmp (SECTION_NAME (sec), name) == 0) + if (streq (SECTION_NAME (sec), name)) break; if (i && sec && sec->sh_size != 0) @@ -7051,11 +7067,27 @@ find_section (const char * name) return NULL; } -/* Size of pointers in the .debug_line section. This information is not - really present in that section. It's obtained before dumping the debug - sections by doing some pre-scan of the .debug_info section. */ -static unsigned int * debug_line_pointer_sizes = NULL; -static unsigned int num_debug_line_pointer_sizes = 0; +/* This could just be an array of unsigned integers, but I expect + that we will want to extend the structure to contain other + information. */ +typedef struct +{ + unsigned int pointer_size; +} +debug_info; + +static debug_info * debug_information = NULL; +static unsigned int num_debug_info_entries = 0; + +static unsigned int +get_pointer_size_of_comp_unit (unsigned int comp_unit) +{ + if (num_debug_info_entries == 0 + || comp_unit >= num_debug_info_entries) + return 0; + + return debug_information [comp_unit].pointer_size; +} /* Locate and scan the .debug_info section in the file and record the pointer sizes for the compilation units in it. Usually an executable will have @@ -7064,7 +7096,7 @@ static unsigned int num_debug_line_pointer_sizes = 0; compilation units upon success. */ static unsigned int -get_debug_line_pointer_sizes (FILE * file) +get_debug_info (FILE * file) { Elf_Internal_Shdr * section; unsigned char * start; @@ -7074,13 +7106,17 @@ get_debug_line_pointer_sizes (FILE * file) unsigned int num_units; unsigned int unit; + /* If we already have the information there is nothing else to do. */ + if (num_debug_info_entries > 0) + return num_debug_info_entries; + section = find_section (".debug_info"); if (section == NULL) return 0; length = section->sh_size; start = get_data (NULL, file, section->sh_offset, section->sh_size, - _("extracting pointer sizes from .debug_info section")); + _("extracting information from .debug_info section")); if (start == NULL) return 0; @@ -7109,11 +7145,11 @@ get_debug_line_pointer_sizes (FILE * file) return 0; } - /* Then allocate an array to hold the pointer sizes. */ - debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes); - if (debug_line_pointer_sizes == NULL) + /* Then allocate an array to hold the information. */ + debug_information = malloc (num_units * sizeof * debug_information); + if (debug_information == NULL) { - error (_("Not enough memory for a pointer size array of %u entries"), + error (_("Not enough memory for a debug info array of %u entries"), num_units); free (start); return 0; @@ -7134,7 +7170,7 @@ get_debug_line_pointer_sizes (FILE * file) ----------------------------- Total: 22 bytes */ - debug_line_pointer_sizes [unit] = byte_get (begin + 22, 1); + debug_information [unit].pointer_size = byte_get (begin + 22, 1); length = byte_get (begin + 4, 8); begin += length + 12; } @@ -7149,40 +7185,39 @@ get_debug_line_pointer_sizes (FILE * file) ----------------------------- Total: 10 bytes */ - debug_line_pointer_sizes [unit] = byte_get (begin + 10, 1); + debug_information [unit].pointer_size = byte_get (begin + 10, 1); begin += length + 4; } } free (start); - num_debug_line_pointer_sizes = num_units; - return num_units; + + return num_debug_info_entries = num_units; } static int display_debug_lines (Elf_Internal_Shdr *section, unsigned char *start, FILE *file) { - unsigned char *hdrptr; - DWARF2_Internal_LineInfo info; - unsigned char *standard_opcodes; unsigned char *data = start; unsigned char *end = start + section->sh_size; - unsigned char *end_of_sequence; - int i; - int offset_size; - int initial_length_size; unsigned int comp_unit = 0; printf (_("\nDump of debug contents of section %s:\n\n"), SECTION_NAME (section)); - if (num_debug_line_pointer_sizes == 0) - get_debug_line_pointer_sizes (file); + get_debug_info (file); while (data < end) { + DWARF2_Internal_LineInfo info; + unsigned char *standard_opcodes; + unsigned char *end_of_sequence; + unsigned char *hdrptr; unsigned int pointer_size; + int initial_length_size; + int offset_size; + int i; hdrptr = data; @@ -7239,16 +7274,13 @@ display_debug_lines (Elf_Internal_Shdr *section, /* Get the pointer size from the comp unit associated with this block of line number information. */ - if (comp_unit >= num_debug_line_pointer_sizes) + pointer_size = get_pointer_size_of_comp_unit (comp_unit); + if (pointer_size == 0) { error (_("Not enough comp units for .debug_line section\n")); return 0; } - else - { - pointer_size = debug_line_pointer_sizes [comp_unit]; - comp_unit ++; - } + comp_unit ++; printf (_(" Length: %ld\n"), info.li_length); printf (_(" DWARF Version: %d\n"), info.li_version); @@ -7326,7 +7358,6 @@ display_debug_lines (Elf_Internal_Shdr *section, /* Now display the statements. */ printf (_("\n Line Number Statements:\n")); - while (data < end_of_sequence) { unsigned char op_code; @@ -7433,16 +7464,14 @@ display_debug_lines (Elf_Internal_Shdr *section, default: printf (_(" Unknown opcode %d with operands: "), op_code); - { - int i; - for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) - { - printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0), - i == 1 ? "" : ", "); - data += bytes_read; - } - putchar ('\n'); - } + + for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + { + printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); break; } } @@ -7952,7 +7981,8 @@ display_debug_macinfo (Elf_Internal_Shdr *section, filenum = read_leb128 (curr, & bytes_read, 0); curr += bytes_read; - printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), lineno, filenum); + printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), + lineno, filenum); } break; @@ -7965,7 +7995,8 @@ display_debug_macinfo (Elf_Internal_Shdr *section, curr += bytes_read; string = curr; curr += strlen (string) + 1; - printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), lineno, string); + printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), + lineno, string); break; case DW_MACINFO_undef: @@ -7973,7 +8004,8 @@ display_debug_macinfo (Elf_Internal_Shdr *section, curr += bytes_read; string = curr; curr += strlen (string) + 1; - printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), lineno, string); + printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), + lineno, string); break; case DW_MACINFO_vendor_ext: @@ -7984,7 +8016,8 @@ display_debug_macinfo (Elf_Internal_Shdr *section, curr += bytes_read; string = curr; curr += strlen (string) + 1; - printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), constant, string); + printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), + constant, string); } break; } @@ -8023,11 +8056,9 @@ display_debug_abbrev (Elf_Internal_Shdr *section, entry->children ? _("has children") : _("no children")); for (attr = entry->first_attr; attr; attr = attr->next) - { - printf (_(" %-18s %s\n"), - get_AT_name (attr->attribute), - get_FORM_name (attr->form)); - } + printf (_(" %-18s %s\n"), + get_AT_name (attr->attribute), + get_FORM_name (attr->form)); } free_abbrevs (); @@ -8438,8 +8469,7 @@ display_debug_loc (Elf_Internal_Shdr *section, return 0; } - if (num_debug_line_pointer_sizes == 0) - get_debug_line_pointer_sizes (file); + get_debug_info (file); printf (_("Contents of the .debug_loc section:\n\n")); printf (_("\n Offset Begin End Expression\n")); @@ -8456,16 +8486,13 @@ display_debug_loc (Elf_Internal_Shdr *section, /* Get the pointer size from the comp unit associated with this block of location information. */ - if (comp_unit >= num_debug_line_pointer_sizes) + pointer_size = get_pointer_size_of_comp_unit (comp_unit); + if (pointer_size == 0) { error (_("Not enough comp units for .debug_loc section\n")); return 0; } - else - { - pointer_size = debug_line_pointer_sizes [comp_unit]; - comp_unit ++; - } + comp_unit ++; while (1) { @@ -8603,6 +8630,156 @@ display_debug_str (Elf_Internal_Shdr *section, return 1; } +static const char * debug_range_contents; +static unsigned long debug_range_size; + +static void +load_debug_range (FILE *file) +{ + Elf_Internal_Shdr *sec; + + /* If it is already loaded, do nothing. */ + if (debug_range_contents != NULL) + return; + + /* Locate the .debug_str section. */ + sec = find_section (".debug_ranges"); + if (sec == NULL) + return; + + debug_range_size = sec->sh_size; + + debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_range section data")); +} + +static void +free_debug_range (void) +{ + if (debug_range_contents == NULL) + return; + + free ((char *) debug_range_contents); + debug_range_contents = NULL; + debug_range_size = 0; +} + + +/* Decode a DW_AT_ranges attribute for 64bit DWARF3 . */ + +static void +decode_64bit_range (unsigned long offset, bfd_vma base_address) +{ + const char * start = debug_range_contents + offset; + const char * end = debug_range_contents + debug_range_size; + + do + { + bfd_vma a; + bfd_vma b; + + a = byte_get ((unsigned char *) start, 8); + b = byte_get ((unsigned char *) start + 8, 8); + + if (a == 0xffffffff) + { + base_address = b; + } + else if (a == 0 && b == 0) + break; + else if (a > b) + printf (_(" [corrupt: start > end]")); + else + { + printf (" "); + print_vma (base_address + a, PREFIX_HEX); + printf (" - "); + print_vma (base_address + b, PREFIX_HEX); + printf (", "); + } + + start += 16; + } + while (start < end); +} + +/* Decode a DW_AT_ranges attribute. */ + +static void +decode_range (unsigned long offset, bfd_vma base_address) +{ + const char * start; + const char * end; + + if (offset >= (debug_range_size - 8)) + { + printf (_("[corrupt: offset is outside the .debug_ranges section]")); + return; + } + + /* Since all entries in the .debug_ranges section are pairs of either + 4-byte integers (32-bit DWARF3) or 8-byte integers (64-bit DWARF3) + the offset should always be a multiple of 8 bytes. */ + if (offset % 8) + { + printf (_("[corrupt: offset is not a multiple of 8]")); + return; + } + + start = debug_range_contents + offset; + + if (offset > 0 + /* Be paranoid - check to see if the previous + two words were and end-of-range marker. */ + && (byte_get ((unsigned char *) start - 4, 4) != 0 + || byte_get ((unsigned char *) start - 8, 4) != 0)) + { + printf (_("[corrupt: offset is not at the start of a range]")); + return; + } + + end = debug_range_contents + debug_range_size; + + printf ("("); + do + { + unsigned long a; + unsigned long b; + + a = byte_get ((unsigned char *) start, 4); + b = byte_get ((unsigned char *) start + 4, 4); + + if (a == 0xffffffff) + { + if (b == 0xffffffff) + { + decode_64bit_range (offset, base_address); + return; + } + + base_address = b; + } + else if (a == 0 && b == 0) + break; + else if (a > b) + printf (_("[corrupt: start > end]")); + else + { + if (start > debug_range_contents + offset) + printf (", "); + + printf (_("0x%lx - 0x%lx"), + (unsigned long) base_address + a, + (unsigned long) base_address + b); + } + + start += 8; + } + while (start < end); + printf (")"); +} + + static unsigned char * read_and_display_attr_value (unsigned long attribute, unsigned long form, @@ -8612,6 +8789,7 @@ read_and_display_attr_value (unsigned long attribute, unsigned long offset_size, int dwarf_version) { + static unsigned long saved_DW_AT_low_pc = 0; unsigned long uvalue = 0; unsigned char *block_start = NULL; int bytes_read; @@ -8925,11 +9103,20 @@ read_and_display_attr_value (unsigned long attribute, printf (")"); } else if (form == DW_FORM_data4 || form == DW_FORM_data8) - { - printf ("("); - printf ("location list"); - printf (")"); - } + printf (_("(location list)")); + + break; + + case DW_AT_low_pc: + /* This is a hack. We keep track of the DW_AT_low_pc attributes + and use them when decoding DW_AT_ranges attributes. The + assumption here is that we are decoding the attributes in order + and so the correct base address for the range is the low_pc. */ + saved_DW_AT_low_pc = uvalue; + break; + + case DW_AT_ranges: + decode_range (uvalue, saved_DW_AT_low_pc); break; default: @@ -9007,10 +9194,15 @@ debug_apply_rela_addends (FILE *file, sym = symtab + ELF32_R_SYM (rp->r_info); if (ELF32_R_SYM (rp->r_info) != 0 - && ELF32_ST_TYPE (sym->st_info) != STT_SECTION) + && ELF32_ST_TYPE (sym->st_info) != STT_SECTION + /* Relocations against object symbols can happen, + eg when referencing a global array. For an + example of this see the _clz.o binary in libgcc.a. */ + && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT) { - warn (_("Skipping unexpected symbol type %u\n"), - ELF32_ST_TYPE (sym->st_info)); + warn (_("%s: skipping unexpected symbol type %s in relocation in section .rela%s\n"), + get_symbol_type (ELF32_ST_TYPE (sym->st_info)), + SECTION_NAME (section)); continue; } } @@ -9019,10 +9211,12 @@ debug_apply_rela_addends (FILE *file, sym = symtab + ELF64_R_SYM (rp->r_info); if (ELF64_R_SYM (rp->r_info) != 0 - && ELF64_ST_TYPE (sym->st_info) != STT_SECTION) + && ELF64_ST_TYPE (sym->st_info) != STT_SECTION + && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT) { - warn (_("Skipping unexpected symbol type %u\n"), - ELF64_ST_TYPE (sym->st_info)); + warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"), + get_symbol_type (ELF64_ST_TYPE (sym->st_info)), + SECTION_NAME (section)); continue; } } @@ -9049,6 +9243,7 @@ display_debug_info (Elf_Internal_Shdr *section, load_debug_str (file); load_debug_loc (file); + load_debug_range (file); while (start < end) { @@ -9188,6 +9383,7 @@ display_debug_info (Elf_Internal_Shdr *section, } } + free_debug_range (); free_debug_str (); free_debug_loc (); @@ -9292,6 +9488,95 @@ display_debug_aranges (Elf_Internal_Shdr *section, return 1; } +static int +display_64bit_debug_ranges (unsigned char * start, unsigned char * end) +{ + bfd_vma base_address = 0; + + while (start < end) + { + bfd_vma a, b; + + a = byte_get (start, 8); + b = byte_get (start + 8, 8); + + if (a == 0xffffffffffffffffLL) + { + printf (_(" set base address to ")); + print_vma (b, PREFIX_HEX); + base_address = b; + } + else if (a == 0 && b == 0) + printf ( _("end of range")); + else if (a > b) + printf (_(" ")); + else if (base_address == 0) + { + printf ("range from base address + "); + print_vma (a, PREFIX_HEX); + printf (" to base address + "); + print_vma (b, PREFIX_HEX); + } + else + { + printf ("range from "); + print_vma (base_address + a, PREFIX_HEX); + printf (" to "); + print_vma (base_address + b, PREFIX_HEX); + } + + start += 16; + printf ("\n"); + } + + return 1; +} + +static int +display_debug_ranges (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) +{ + unsigned long base_address = 0; + unsigned char *end = start + section->sh_size; + + printf (_("The section %s contains:\n\n"), SECTION_NAME (section)); + + while (start < end) + { + unsigned long a; + unsigned long b; + + a = byte_get (start, 4); + b = byte_get (start + 4, 4); + + if (a == 0xffffffff) + { + /* Attempt to handle 64-bit DWARF3 format. This assumes + that in a 32-bit DWARF3 file the base address will + never be 0xffffffff, and that the .debug_ranges section + will never contain a mixture of 32-bit and 64-bit entries. */ + if (b == 0xffffffff) + return display_64bit_debug_ranges (start, end); + + printf (_(" set base address to 0x%lx\n"), b); + base_address = b; + } + else if (a == 0 && b == 0) + printf (_(" end of range\n")); + else if (a > b) + printf (_(" \n")); + else if (base_address == 0) + printf (_(" range from base address + 0x%lx to base address + 0x%lx\n"), a, b); + else + printf (_(" range from 0x%lx to 0x%lx\n"), base_address + a, base_address + b); + + start += 8; + } + + return 1; +} + typedef struct Frame_Chunk { struct Frame_Chunk *next; @@ -9439,7 +9724,7 @@ display_debug_frames (Elf_Internal_Shdr *section, Frame_Chunk *chunks = 0; Frame_Chunk *remembered_state = 0; Frame_Chunk *rs; - int is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0); + int is_eh = streq (SECTION_NAME (section), ".eh_frame"); int length_return; int max_regs = 0; int addr_size = is_32bit_elf ? 4 : 8; @@ -9528,7 +9813,7 @@ display_debug_frames (Elf_Internal_Shdr *section, augmentation_data = start; start += augmentation_data_len; } - else if (strcmp (fc->augmentation, "eh") == 0) + else if (streq (fc->augmentation, "eh")) { start += addr_size; fc->code_factor = LEB (); @@ -9687,8 +9972,8 @@ display_debug_frames (Elf_Internal_Shdr *section, } } - /* At this point, fc is the current chunk, cie (if any) is set, and we're - about to interpret instructions for the chunk. */ + /* At this point, fc is the current chunk, cie (if any) is set, and + we're about to interpret instructions for the chunk. */ /* ??? At present we need to do this always, since this sizes the fc->col_type and fc->col_offset arrays, which we write into always. We should probably split the interpreted and non-interpreted bits @@ -10089,7 +10374,7 @@ display_debug_frames (Elf_Internal_Shdr *section, break; default: - fprintf (stderr, "unsupported or unknown DW_CFA_%d\n", op); + warn (_("unsupported or unknown DW_CFA_%d\n"), op); start = block_end; } } @@ -10140,7 +10425,7 @@ debug_displays[] = { ".debug_str", display_debug_str }, { ".debug_loc", display_debug_loc }, { ".debug_pubtypes", display_debug_pubnames }, - { ".debug_ranges", display_debug_not_supported }, + { ".debug_ranges", display_debug_ranges }, { ".debug_static_func", display_debug_not_supported }, { ".debug_static_vars", display_debug_not_supported }, { ".debug_types", display_debug_not_supported }, @@ -10152,7 +10437,7 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file) { char *name = SECTION_NAME (section); bfd_size_type length; - unsigned char *start; + int result = 1; int i; length = section->sh_size; @@ -10162,42 +10447,50 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file) return 0; } - start = get_data (NULL, file, section->sh_offset, length, - _("debug section data")); - if (!start) - return 0; - - /* See if we know how to display the contents of this section. */ - if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + if (strneq (name, ".gnu.linkonce.wi.", 17)) name = ".debug_info"; + /* See if we know how to display the contents of this section. */ for (i = NUM_ELEM (debug_displays); i--;) - if (strcmp (debug_displays[i].name, name) == 0) + if (streq (debug_displays[i].name, name)) { - debug_displays[i].display (section, start, file); + unsigned char *start; + + start = get_data (NULL, file, section->sh_offset, length, + _("debug section data")); + if (start == NULL) + { + result = 0; + break; + } + + result &= debug_displays[i].display (section, start, file); + free (start); + + /* If we loaded in the abbrev section + at some point, we must release it here. */ + free_abbrevs (); + break; } if (i == -1) - printf (_("Unrecognized debug section: %s\n"), name); - - free (start); - - /* If we loaded in the abbrev section at some point, - we must release it here. */ - free_abbrevs (); + { + printf (_("Unrecognized debug section: %s\n"), name); + result = 0; + } - return 1; + return result; } -static int +static void process_section_contents (FILE *file) { Elf_Internal_Shdr *section; unsigned int i; if (! do_dump) - return 1; + return; for (i = 0, section = section_headers; i < elf_header.e_shnum && i < num_dump_sects; @@ -10214,10 +10507,11 @@ process_section_contents (FILE *file) display_debug_section (section, file); } - if (i < num_dump_sects) - warn (_("Some sections were not dumped because they do not exist!\n")); - - return 1; + /* Check to see if the user requested a + dump of a section that does not exist. */ + while (i++ < num_dump_sects) + if (dump_sects[i]) + warn (_("Section %d was not dumped because it does not exist!\n"), i); } static void @@ -10835,7 +11129,7 @@ process_note (Elf_Internal_Note *pnote) note type strings. */ nt = get_note_type (pnote->type); - else if (strncmp (pnote->namedata, "NetBSD-CORE", 11) == 0) + else if (strneq (pnote->namedata, "NetBSD-CORE", 11)) /* NetBSD-specific core file notes. */ nt = get_netbsd_elfcore_note_type (pnote->type); @@ -11129,6 +11423,23 @@ process_object (char *file_name, FILE *file) if (show_name) printf (_("\nFile: %s\n"), file_name); + /* Initialise the dump_sects array from the cmdline_dump_sects array. + Note we do this even if cmdline_dump_sects is empty because we + must make sure that the dump_sets array is zeroed out before each + object file is processed. */ + if (num_dump_sects > num_cmdline_dump_sects) + memset (dump_sects, 0, num_dump_sects); + + if (num_cmdline_dump_sects > 0) + { + if (num_dump_sects == 0) + /* A sneaky way of allocating the dump_sects array. */ + request_dump (num_cmdline_dump_sects, 0); + + assert (num_dump_sects >= num_cmdline_dump_sects); + memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + } + if (! process_file_header ()) return 1; @@ -11226,6 +11537,13 @@ process_object (char *file_name, FILE *file) section_groups = NULL; } + if (debug_information) + { + free (debug_information); + debug_information = NULL; + num_debug_info_entries = 0; + } + return 0; } @@ -11294,7 +11612,7 @@ process_archive (char *file_name, FILE *file) if (fread (longnames, longnames_size, 1, file) != 1) { free (longnames); - error(_("%s: failed to read string table\n"), file_name); + error (_("%s: failed to read string table\n"), file_name); return 1; } @@ -11367,7 +11685,7 @@ process_archive (char *file_name, FILE *file) archive_file_offset = ftell (file); archive_file_size = strtoul (arhdr.ar_size, NULL, 10); - + ret |= process_object (namealc, file); free (namealc); @@ -11476,8 +11794,6 @@ int main (int argc, char **argv) { int err; - char *cmdline_dump_sects = NULL; - unsigned num_cmdline_dump_sects = 0; #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) setlocale (LC_MESSAGES, ""); @@ -11490,13 +11806,9 @@ main (int argc, char **argv) parse_args (argc, argv); - if (optind < (argc - 1)) - show_name = 1; - - /* When processing more than one file remember the dump requests - issued on command line to reset them after each file. */ - if (optind + 1 < argc && dump_sects != NULL) + if (num_dump_sects > 0) { + /* Make a copy of the dump_sects array. */ cmdline_dump_sects = malloc (num_dump_sects); if (cmdline_dump_sects == NULL) error (_("Out of memory allocating dump request table.")); @@ -11507,19 +11819,12 @@ main (int argc, char **argv) } } + if (optind < (argc - 1)) + show_name = 1; + err = 0; while (optind < argc) - { - err |= process_file (argv[optind++]); - - /* Reset dump requests. */ - if (optind < argc && dump_sects != NULL) - { - num_dump_sects = num_cmdline_dump_sects; - if (num_cmdline_dump_sects > 0) - memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); - } - } + err |= process_file (argv[optind++]); if (dump_sects != NULL) free (dump_sects); -- cgit v1.1