From 39f0547e554df96608dd041d2a7b3c72882fd515 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 25 Feb 2019 12:15:41 +0000 Subject: [PATCH] Extend objdump's --dwarf=follow-links option so that separate debug info files will also be affected by other dump function, and symbol tables from separate debug info files will be used when disassembling the main file. * objdump.c (sym_ok): New function. (find_symbol_for_address): Use new function. (disassemble_section): Compare sections by name, not pointer. (dump_dwarf): Move code to initialise byte_get pointer and iterate over separate debug files from here to ... (dump_bfd): ... here. Add parameter indicating that a separate debug info file is being dumped. For main file, pull in the symbol tables from all separate debug info files. (display_object): Update call to dump_bfd. * doc/binutils.texi: Document extened behaviour of the --dwarf=follow-links option. * NEWS: Mention this new feature. * testsuite/binutils-all/objdump.WK2: Update expected output. * testsuite/binutils-all/objdump.exp (test_follow_debuglink): Add options and dump file parameters. Add extra test. * testsuite/binutils-all/objdump.WK3: New file. * testsuite/binutils-all/readelf.exp: Change expected output for readelf -wKis test. * testsuite/binutils-all/readelf.wKis: New file. --- binutils/ChangeLog | 23 +++ binutils/NEWS | 7 + binutils/doc/binutils.texi | 8 + binutils/dwarf.c | 9 ++ binutils/dwarf.h | 1 + binutils/objdump.c | 149 ++++++++++++++----- binutils/testsuite/binutils-all/debuglink.s | 1 - binutils/testsuite/binutils-all/linkdebug.s | 1 - binutils/testsuite/binutils-all/objdump.WK2 | 13 +- binutils/testsuite/binutils-all/objdump.WK3 | 17 +++ binutils/testsuite/binutils-all/objdump.exp | 11 +- binutils/testsuite/binutils-all/readelf.exp | 2 +- binutils/testsuite/binutils-all/readelf.wKis | 25 ++++ 13 files changed, 212 insertions(+), 55 deletions(-) create mode 100644 binutils/testsuite/binutils-all/objdump.WK3 create mode 100644 binutils/testsuite/binutils-all/readelf.wKis diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 65316ee9ded..f3d8fa2a5cc 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,26 @@ +2019-02-25 Nick Clifton + + * objdump.c (sym_ok): New function. + (find_symbol_for_address): Use new function. + (disassemble_section): Compare sections by name, not pointer. + (dump_dwarf): Move code to initialise byte_get pointer and iterate + over separate debug files from here to ... + (dump_bfd): ... here. Add parameter indicating that a separate + debug info file is being dumped. For main file, pull in the + symbol tables from all separate debug info files. + (display_object): Update call to dump_bfd. + * doc/binutils.texi: Document extened behaviour of the + --dwarf=follow-links option. + * NEWS: Mention this new feature. + * testsuite/binutils-all/objdump.WK2: Update expected output. + * testsuite/binutils-all/objdump.exp (test_follow_debuglink): Add + options and dump file parameters. + Add extra test. + * testsuite/binutils-all/objdump.WK3: New file. + * testsuite/binutils-all/readelf.exp: Change expected output for + readelf -wKis test. + * testsuite/binutils-all/readelf.wKis: New file. + 2019-02-22 Nick Clifton PR 23843 diff --git a/binutils/NEWS b/binutils/NEWS index 5413321b4ba..7c9d7bef30b 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -6,6 +6,13 @@ more than one are present in a file. (This usually happens when gcc's -gsplit-dwarf option is used). + In addition objdump's --dwarf=follow-links now also affects its other + display options, so that for example, when combined with --syms it will + cause the symbol tables in any linked debug info files to also be + displayed. In addition when combined with --disassemble the --dwarf= + follow-links option will ensure that any symbol tables in the linked + files are read and used when disassembling code in the main file. + Changes in 2.32: * The addr2line, c++filt, nm and objdump tools now have a limit on the diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 01f1e5f56db..eb5c3e87a3c 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -2236,6 +2236,10 @@ will stop at the end of the function, otherwise it will stop when the next symbol is encountered. If there are no matches for @var{symbol} then nothing will be displayed. +Note if the @option{--dwarf=follow-links} option has also been enabled +then any symbol tables in linked debug info files will be read in and +used when disassembling. + @item -D @itemx --disassemble-all Like @option{-d}, but disassemble the contents of all sections, not just @@ -2254,6 +2258,10 @@ If the target is an ARM architecture this switch also has the effect of forcing the disassembler to decode pieces of data found in code sections as if they were instructions. +Note if the @option{--dwarf=follow-links} option has also been enabled +then any symbol tables in linked debug info files will be read in and +used when disassembling. + @item --prefix-addresses When disassembling, print the complete address on each line. This is the older disassembly format. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 07142af747e..9f17af9ff82 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -9826,6 +9826,7 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data) The CRC value is stored after the filename, aligned up to 4 bytes. */ name = (const char *) section->start; + crc_offset = strnlen (name, section->size) + 1; crc_offset = (crc_offset + 3) & ~3; if (crc_offset + 4 > section->size) @@ -9981,6 +9982,11 @@ load_separate_debug_info (const char * main_filename, sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); if (check_func (debug_filename, func_data)) goto found; + + /* Try the first extra debug file root. */ + sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename); + if (check_func (debug_filename, func_data)) + goto found; #endif #ifdef EXTRA_DEBUG_ROOT2 @@ -10010,6 +10016,9 @@ load_separate_debug_info (const char * main_filename, #endif #ifdef EXTRA_DEBUG_ROOT1 + sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename); + warn (_("tried: %s\n"), debug_filename); + sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename); warn (_("tried: %s\n"), debug_filename); #endif diff --git a/binutils/dwarf.h b/binutils/dwarf.h index a0287fc0bc5..ca2f062efb7 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -218,6 +218,7 @@ extern int do_debug_addr; extern int do_debug_cu_index; extern int do_wide; extern int do_debug_links; +extern int do_follow_links; extern int dwarf_cutoff_level; extern unsigned long dwarf_start_die; diff --git a/binutils/objdump.c b/binutils/objdump.c index 19365b67a01..ab091c10d4b 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -987,6 +987,30 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf, free (alloc); } +static inline bfd_boolean +sym_ok (bfd_boolean want_section, + bfd * abfd ATTRIBUTE_UNUSED, + long place, + asection * sec, + struct disassemble_info * inf) +{ + if (want_section) + { + /* Note - we cannot just compare section pointers because they could + be different, but the same... Ie the symbol that we are trying to + find could have come from a separate debug info file. Under such + circumstances the symbol will be associated with a section in the + debug info file, whilst the section we want is in a normal file. + So the section pointers will be different, but the section names + will be the same. */ + if (strcmp (bfd_section_name (abfd, sorted_syms[place]->section), + bfd_section_name (abfd, sec)) != 0) + return FALSE; + } + + return inf->symbol_is_valid (sorted_syms[place], inf); +} + /* Locate a symbol given a bfd and a section (from INFO->application_data), and a VMA. If INFO->application_data->require_sec is TRUE, then always require the symbol to be in the section. Returns NULL if there is no @@ -1062,8 +1086,7 @@ find_symbol_for_address (bfd_vma vma, && (bfd_asymbol_value (sorted_syms[min]) == bfd_asymbol_value (sorted_syms[thisplace]))) { - if (sorted_syms[min]->section == sec - && inf->symbol_is_valid (sorted_syms[min], inf)) + if (sym_ok (TRUE, abfd, min, sec, inf)) { thisplace = min; @@ -1090,16 +1113,15 @@ find_symbol_for_address (bfd_vma vma, && vma >= bfd_get_section_vma (abfd, sec) && vma < (bfd_get_section_vma (abfd, sec) + bfd_section_size (abfd, sec) / opb))); - if ((sorted_syms[thisplace]->section != sec && want_section) - || ! inf->symbol_is_valid (sorted_syms[thisplace], inf)) + + if (! sym_ok (want_section, abfd, thisplace, sec, inf)) { long i; long newplace = sorted_symcount; for (i = min - 1; i >= 0; i--) { - if ((sorted_syms[i]->section == sec || !want_section) - && inf->symbol_is_valid (sorted_syms[i], inf)) + if (sym_ok (want_section, abfd, i, sec, inf)) { if (newplace == sorted_symcount) newplace = i; @@ -1122,8 +1144,7 @@ find_symbol_for_address (bfd_vma vma, Look for one with a larger value. */ for (i = thisplace + 1; i < sorted_symcount; i++) { - if ((sorted_syms[i]->section == sec || !want_section) - && inf->symbol_is_valid (sorted_syms[i], inf)) + if (sym_ok (want_section, abfd, i, sec, inf)) { thisplace = i; break; @@ -1131,8 +1152,7 @@ find_symbol_for_address (bfd_vma vma, } } - if ((sorted_syms[thisplace]->section != sec && want_section) - || ! inf->symbol_is_valid (sorted_syms[thisplace], inf)) + if (! sym_ok (want_section, abfd, thisplace, sec, inf)) /* There is no suitable symbol. */ return NULL; } @@ -2460,7 +2480,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf) else { #define is_valid_next_sym(SYM) \ - ((SYM)->section == section \ + (strcmp (bfd_section_name (abfd, (SYM)->section), bfd_section_name (abfd, section)) == 0 \ && (bfd_asymbol_value (SYM) > bfd_asymbol_value (sym)) \ && pinfo->symbol_is_valid (SYM, pinfo)) @@ -2882,24 +2902,18 @@ dump_dwarf_section (bfd *abfd, asection *section, static void dump_dwarf (bfd *abfd) { - bfd_boolean have_separates; - - is_relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; - - eh_addr_size = bfd_arch_bits_per_address (abfd) / 8; - - if (bfd_big_endian (abfd)) - byte_get = byte_get_big_endian; - else if (bfd_little_endian (abfd)) - byte_get = byte_get_little_endian; - else - /* PR 17512: file: objdump-s-endless-loop.tekhex. */ + /* The byte_get pointer should have been set at the start of dump_bfd(). */ + if (byte_get == NULL) { warn (_("File %s does not contain any dwarf debug information\n"), bfd_get_filename (abfd)); return; } + is_relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; + + eh_addr_size = bfd_arch_bits_per_address (abfd) / 8; + switch (bfd_get_arch (abfd)) { case bfd_arch_i386: @@ -2946,21 +2960,7 @@ dump_dwarf (bfd *abfd) break; } - have_separates = load_separate_debug_files (abfd, bfd_get_filename (abfd)); - bfd_map_over_sections (abfd, dump_dwarf_section, NULL); - - if (have_separates) - { - separate_info * i; - - for (i = first_separate_info; i != NULL; i = i->next) - bfd_map_over_sections (i->handle, dump_dwarf_section, NULL); - - /* The file handles are closed by the call to free_debug_memory() below. */ - } - - free_debug_memory (); } /* Read ABFD's stabs section STABSECT_NAME, and return a pointer to @@ -3768,8 +3768,38 @@ adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, /* Dump selected contents of ABFD. */ static void -dump_bfd (bfd *abfd) +dump_bfd (bfd *abfd, bfd_boolean is_mainfile) { + if (bfd_big_endian (abfd)) + byte_get = byte_get_big_endian; + else if (bfd_little_endian (abfd)) + byte_get = byte_get_little_endian; + else + byte_get = NULL; + + /* Load any separate debug information files. + We do this now and without checking do_follow_links because separate + debug info files may contain symbol tables that we will need when + displaying information about the main file. Any memory allocated by + load_separate_debug_files will be released when we call + free_debug_memory below. + + The test on is_mainfile is there because the chain of separate debug + info files is a global variable shared by all invocations of dump_bfd. */ + if (is_mainfile) + { + load_separate_debug_files (abfd, bfd_get_filename (abfd)); + + /* If asked to do so, recursively dump the separate files. */ + if (do_follow_links) + { + separate_info * i; + + for (i = first_separate_info; i != NULL; i = i->next) + dump_bfd (i->handle, FALSE); + } + } + /* If we are adjusting section VMA's, change them all now. Changing the BFD information is a hack. However, we must do it, or bfd_find_nearest_line will not do the right thing. */ @@ -3799,7 +3829,40 @@ dump_bfd (bfd *abfd) || disassemble || dump_debugging || dump_dwarf_section_info) - syms = slurp_symtab (abfd); + { + syms = slurp_symtab (abfd); + + /* If following links, load any symbol tables from the linked files as well. */ + if (do_follow_links && is_mainfile) + { + separate_info * i; + + for (i = first_separate_info; i != NULL; i = i->next) + { + asymbol ** extra_syms; + long old_symcount = symcount; + + extra_syms = slurp_symtab (i->handle); + + if (extra_syms) + { + if (old_symcount == 0) + { + syms = extra_syms; + } + else + { + syms = xrealloc (syms, (symcount + old_symcount) * sizeof (asymbol *)); + memcpy (syms + old_symcount, + extra_syms, + symcount * sizeof (asymbol *)); + } + } + + symcount += old_symcount; + } + } + } if (dump_section_headers) dump_headers (abfd); @@ -3807,6 +3870,7 @@ dump_bfd (bfd *abfd) if (dump_dynamic_symtab || dump_dynamic_reloc_info || (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0)) dynsyms = slurp_dynamic_symtab (abfd); + if (disassemble) { synthcount = bfd_get_synthetic_symtab (abfd, symcount, syms, @@ -3880,6 +3944,9 @@ dump_bfd (bfd *abfd) symcount = 0; dynsymcount = 0; synthcount = 0; + + if (is_mainfile) + free_debug_memory (); } static void @@ -3889,7 +3956,7 @@ display_object_bfd (bfd *abfd) if (bfd_check_format_matches (abfd, bfd_object, &matching)) { - dump_bfd (abfd); + dump_bfd (abfd, TRUE); return; } @@ -3909,7 +3976,7 @@ display_object_bfd (bfd *abfd) if (bfd_check_format_matches (abfd, bfd_core, &matching)) { - dump_bfd (abfd); + dump_bfd (abfd, TRUE); return; } diff --git a/binutils/testsuite/binutils-all/debuglink.s b/binutils/testsuite/binutils-all/debuglink.s index 9cadc67da24..b51500ddd27 100644 --- a/binutils/testsuite/binutils-all/debuglink.s +++ b/binutils/testsuite/binutils-all/debuglink.s @@ -64,4 +64,3 @@ debugS: ;# will be started. .balign 2, 0 debugE: - diff --git a/binutils/testsuite/binutils-all/linkdebug.s b/binutils/testsuite/binutils-all/linkdebug.s index 6b43bbe38aa..7d8db73592f 100644 --- a/binutils/testsuite/binutils-all/linkdebug.s +++ b/binutils/testsuite/binutils-all/linkdebug.s @@ -51,4 +51,3 @@ string3: .asciz "string-4" .balign 2 string_end: - diff --git a/binutils/testsuite/binutils-all/objdump.WK2 b/binutils/testsuite/binutils-all/objdump.WK2 index c98fdc15b58..539a0875cfe 100644 --- a/binutils/testsuite/binutils-all/objdump.WK2 +++ b/binutils/testsuite/binutils-all/objdump.WK2 @@ -1,5 +1,11 @@ #... .*debuglink.o: Found separate debug info file:.*linkdebug.debug +#... +Contents of the .debug_str section \(loaded from .*linkdebug.debug\): + + 0x00000000 73747269 6e672d33 00737472 696e672d string-3.string- + 0x00000010 3400 4. + #... Contents of the .debug_str section \(loaded from .*debuglink.o\): @@ -17,9 +23,4 @@ Contents of the .debug_info section \(loaded from .*debuglink.o\): DW_AT_name : \(indirect string, offset: 0x0\): string-1 <0><10>: Abbrev Number: 2 \(DW_TAG_subprogram\) <11> DW_AT_name : \(alt indirect string, offset: 0x0\) string-3 - -Contents of the .debug_str section \(loaded from .*linkdebug.debug\): - - 0x00000000 73747269 6e672d33 00737472 696e672d string-3.string- - 0x00000010 3400 4. - +#pass diff --git a/binutils/testsuite/binutils-all/objdump.WK3 b/binutils/testsuite/binutils-all/objdump.WK3 new file mode 100644 index 00000000000..399cf5264e4 --- /dev/null +++ b/binutils/testsuite/binutils-all/objdump.WK3 @@ -0,0 +1,17 @@ +#... +.*debuglink.o: Found separate debug info file:.*linkdebug.debug +#... +.*linkdebug.debug:.* +#... + .* .debug_abbrev .* + .* .debug_str .* +#... +.*debuglink.o:.* +#... + .* .gnu_debuglink .* + .* .gnu_debugaltlink .* + .* .debug_str .* + .* .debug_info .* +#... + .* .debug_line .* +#pass diff --git a/binutils/testsuite/binutils-all/objdump.exp b/binutils/testsuite/binutils-all/objdump.exp index dd2e9bb02d0..81a061f70c1 100644 --- a/binutils/testsuite/binutils-all/objdump.exp +++ b/binutils/testsuite/binutils-all/objdump.exp @@ -623,12 +623,12 @@ if { [is_elf_format] } then { # Very similar to proc test_build_id_debuglink except this time we # display some of the contents of the separate debug info file. -proc test_follow_debuglink {} { +proc test_follow_debuglink { options dumpfile } { global srcdir global subdir global OBJDUMP - set test "follow-debuglink" + set test "follow-debuglink ($options)" if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then { fail "$test (reason: assemble first source file)" @@ -647,13 +647,13 @@ proc test_follow_debuglink {} { set tempfile [remote_download host tmpdir/debuglink.o] } - set got [remote_exec host "$OBJDUMP --dwarf=follow-links --dwarf=info --dwarf=str $tempfile" "" "/dev/null" "tmpdir/objdump.out"] + set got [remote_exec host "$OBJDUMP $options $tempfile" "" "/dev/null" "tmpdir/objdump.out"] if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then { fail "$test (reason: unexpected error output from objdump)" return } - if { [regexp_diff tmpdir/objdump.out $srcdir/$subdir/objdump.WK2] } then { + if { [regexp_diff tmpdir/objdump.out $srcdir/$subdir/$dumpfile] } then { fail $test verbose "output is \n[file_contents objdump.out]" 2 return @@ -668,7 +668,8 @@ proc test_follow_debuglink {} { } if {[is_elf_format]} then { - test_follow_debuglink + test_follow_debuglink "--dwarf=follow-links --dwarf=info --dwarf=str" objdump.WK2 + test_follow_debuglink "--dwarf=follow-links --headers --wide" objdump.WK3 } # Options which are not tested: -a -D -R -T -x -l --stabs diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp index e41e22bf26d..0d9a42fba83 100644 --- a/binutils/testsuite/binutils-all/readelf.exp +++ b/binutils/testsuite/binutils-all/readelf.exp @@ -489,7 +489,7 @@ if {![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o]} then { set tempfile2 [remote_download host tmpdir/linkdebug.debug] } - readelf_test {-wKis} $tempfile objdump.WK2 {} + readelf_test {-wKis} $tempfile readelf.wKis {} } } diff --git a/binutils/testsuite/binutils-all/readelf.wKis b/binutils/testsuite/binutils-all/readelf.wKis new file mode 100644 index 00000000000..5c7c0b25a5e --- /dev/null +++ b/binutils/testsuite/binutils-all/readelf.wKis @@ -0,0 +1,25 @@ +#... +.*debuglink.o: Found separate debug info file:.*linkdebug.debug +#... +Contents of the .debug_str section \(loaded from .*debuglink.o\): + + 0x00000000 73747269 6e672d31 00737472 696e672d string-1.string- + 0x00000010 3200 2. +#... +Contents of the .debug_info section \(loaded from .*debuglink.o\): + + Compilation Unit @ offset 0x0: + Length: 0x12 \(32-bit\) + Version: 4 + Abbrev Offset: 0x0 + Pointer Size: 4 + <0>: Abbrev Number: 1 \(DW_TAG_compile_unit\) + DW_AT_name : \(indirect string, offset: 0x0\): string-1 + <0><10>: Abbrev Number: 2 \(DW_TAG_subprogram\) + <11> DW_AT_name : \(alt indirect string, offset: 0x0\) string-3 +#... +Contents of the .debug_str section \(loaded from .*linkdebug.debug\): + + 0x00000000 73747269 6e672d33 00737472 696e672d string-3.string- + 0x00000010 3400 4. +#pass -- 2.30.2