diff options
author | Tom Tromey <tromey@redhat.com> | 2013-10-08 19:56:15 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2013-10-08 19:56:15 +0000 |
commit | dc294be54c96414035eed7d53dafdea0a6f31a72 (patch) | |
tree | e2ec6dd2f5754858a562b4b7105ab16fd5b302af /gdb/testsuite | |
parent | 5bb7df2edfeb80282ce424bc0d32f07713e24220 (diff) | |
download | gdb-dc294be54c96414035eed7d53dafdea0a6f31a72.zip gdb-dc294be54c96414035eed7d53dafdea0a6f31a72.tar.gz gdb-dc294be54c96414035eed7d53dafdea0a6f31a72.tar.bz2 |
fix PR symtab/15597
This patch fixes gdb PR symtab/15597.
The bug is that the .gnu_debugaltlink section includes the build-id of
the alt file, but gdb does not use it.
This patch fixes the problem by changing gdb to do what it ought to
always have done: verify the build id of the file found using the
filename in .gnu_debugaltlink; and if that does not match, try to find
the correct debug file using the build-id and debug-file-directory.
This patch touches BFD. Previously, gdb had its own code for parsing
.gnu_debugaltlink; I changed it to use the BFD functions after those
were introduced. However, the BFD functions are incorrect -- they
assume that .gnu_debugaltlink is formatted like .gnu_debuglink.
However, it it is not. Instead, it consists of a file name followed
by the build-id -- no alignment, and the build-id is not a CRC.
Fixing this properly is a bit of a pain. But, because
separate_alt_debug_file_exists just has a FIXME for the build-id case,
I did not fix it properly. Instead I introduced a hack. This leaves
BFD working just as well as it did before my patch.
I'm willing to do something better here but I could use some guidance
as to what. It seems that the build-id code in BFD is largely punted
on.
FWIW gdb is the only user of bfd_get_alt_debug_link_info outside of
BFD itself.
I moved the build-id logic out of elfread.c and into a new file.
This seemed cleanest to me.
Writing a test case was a bit of a pain. I added a couple new
features to the DWARF assembler to handle this.
Built and regtested on x86-64 Fedora 18.
* bfd-in2.h: Rebuild.
* opncls.c (bfd_get_alt_debug_link_info): Add buildid_len
parameter. Change type of buildid_out. Update.
(get_alt_debug_link_info_shim): New function.
(bfd_follow_gnu_debuglink): Use it.
* Makefile.in (SFILES): Add build-id.c.
(HFILES_NO_SRCDIR): Add build-id.h.
* build-id.c: New file, largely from elfread.c. Modified
most functions.
* build-id.h: New file.
* dwarf2read.c (dwarf2_get_dwz_file): Update for change to
bfd_get_alt_debug_link_info. Verify dwz file's build-id.
Search for dwz file using build-id.
* elfread.c (build_id_bfd_get, build_id_verify)
(build_id_to_debug_filename, find_separate_debug_file): Remove.
* gdb.dwarf2/dwzbuildid.exp: New file.
* lib/dwarf.exp (Dwarf::_section): Add "flags" and "type"
parameters.
(Dwarf::_defer_output): Change "section" parameter to
"section_spec"; update.
(Dwarf::gnu_debugaltlink, Dwarf::_note, Dwarf::build_id): New
procs.
Diffstat (limited to 'gdb/testsuite')
-rw-r--r-- | gdb/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dwzbuildid.exp | 170 | ||||
-rw-r--r-- | gdb/testsuite/lib/dwarf.exp | 62 |
3 files changed, 237 insertions, 5 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 4c15ae8..3e5e970 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2013-10-08 Tom Tromey <tromey@redhat.com> + + * gdb.dwarf2/dwzbuildid.exp: New file. + * lib/dwarf.exp (Dwarf::_section): Add "flags" and "type" + parameters. + (Dwarf::_defer_output): Change "section" parameter to + "section_spec"; update. + (Dwarf::gnu_debugaltlink, Dwarf::_note, Dwarf::build_id): New + procs. + 2013-10-08 Joel Brobecker <brobecker@adacore.com> * gdb.ada/mi_catch_ex.exp: Make "mi_execute_to" test names unique. diff --git a/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp new file mode 100644 index 0000000..e6ae881 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp @@ -0,0 +1,170 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# No remote host testing either. +if {[is_remote host]} { + return 0 +} + + +# Lots of source files since we test a few cases and make new files +# for each. +# The tests are: +# ok - the main file refers to a dwz and the buildids match +# mismatch - the buildids do not match +# fallback - the buildids do not match but a match is found via buildid +standard_testfile main.c \ + dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \ + dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \ + dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \ + dwzbuildid-fallback-ok.S + +# Write some assembly that just has a .gnu_debugaltlink section. +proc write_just_debugaltlink {filename dwzname buildid} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + upvar dwzname dwzname + upvar buildid buildid + + gnu_debugaltlink $dwzname $buildid + + # Only the DWARF reader checks .gnu_debugaltlink, so make sure + # there is a bit of DWARF in here. + cu {} { + compile_unit {{language @DW_LANG_C}} { + } + } + } +} + +# Write some DWARF that also sets the buildid. +proc write_dwarf_file {filename buildid {value 99}} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + declare_labels partial_label double_label int_label int_label2 + + upvar buildid buildid + upvar value value + + build_id $buildid + + cu {} { + compile_unit {{language @DW_LANG_C}} { + int_label2: base_type { + {name int} + {byte_size 4 sdata} + {encoding @DW_ATE_signed} + } + + constant { + {name the_int} + {type :$int_label2} + {const_value $value data1} + } + } + } + } +} + +if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != "" } { + return -1 +} + +# The values don't really matter, just whether they are equal. +set ok_prefix 01 +set ok_suffix 0203040506 +set ok_suffix2 02030405ff +set ok_buildid ${ok_prefix}${ok_suffix} +set ok_buildid2 ${ok_prefix}${ok_suffix2} +set bad_buildid ffffffffffff + +set outdir [standard_output_file {}] +set basedir $outdir/.build-id +file mkdir $basedir $basedir/$ok_prefix + +# Test where the separate debuginfo's buildid matches. +write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid +write_dwarf_file $srcfile3 $ok_buildid + +# Test where the separate debuginfo's buildid does not match. +write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid +write_dwarf_file $srcfile5 $bad_buildid + +# Test where the separate debuginfo's buildid does not match, but then +# we find a match in the .build-id directory. +write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2 +# Use 77 as the value so that if we load the bad debuginfo, we will +# see the wrong result. +write_dwarf_file $srcfile7 $bad_buildid 77 +write_dwarf_file $srcfile8 $ok_buildid2 + +# Compile everything. +for {set i 2} {$i <= 8} {incr i} { + if {[gdb_compile [standard_output_file [set srcfile$i]] \ + ${binfile}$i.o object nodebug] != ""} { + return -1 + } +} + +# Copy a file into the .build-id place for the "fallback" test. +file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug + +# Link the executables. +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] ${binfile}-ok \ + executable {}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}4.o] ${binfile}-mismatch \ + executable {}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}6.o] ${binfile}-fallback \ + executable {}] != ""} { + return -1 +} + + +foreach testname {ok mismatch fallback} { + with_test_prefix $testname { + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + + gdb_test_no_output "set debug-file-directory $outdir" + + gdb_load ${binfile}-${testname} + + if {[runto_main]} { + if {$testname == "mismatch"} { + gdb_test "print the_int" \ + "No symbol table is loaded.*" + } else { + gdb_test "print the_int" " = 99" + } + } + } +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5264def..c28b986 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -523,20 +523,27 @@ namespace eval Dwarf { } } - proc _section {name} { - _emit " .section $name" + proc _section {name {flags ""} {type ""}} { + if {$flags == "" && $type == ""} { + _emit " .section $name" + } elseif {$type == ""} { + _emit " .section $name, \"$flags\"" + } else { + _emit " .section $name, \"$flags\", %$type" + } } - proc _defer_output {section body} { + # SECTION_SPEC is a list of arguments to _section. + proc _defer_output {section_spec body} { variable _defer variable _deferred_output set old_defer $_defer - set _defer $section + set _defer [lindex $section_spec 0] if {![info exists _deferred_output($_defer)]} { set _deferred_output($_defer) "" - _section $section + eval _section $section_spec } uplevel $body @@ -948,6 +955,51 @@ namespace eval Dwarf { unset the_array(_) } + # Emit a .gnu_debugaltlink section with the given file name and + # build-id. The buildid should be represented as a hexadecimal + # string, like "ffeeddcc". + proc gnu_debugaltlink {filename buildid} { + _defer_output .gnu_debugaltlink { + _op .ascii [_quote $filename] + foreach {a b} [split $buildid {}] { + _op .byte 0x$a$b + } + } + } + + proc _note {type name hexdata} { + set namelen [expr [string length $name] + 1] + + # Name size. + _op .4byte $namelen + # Data size. + _op .4byte [expr [string length $hexdata] / 2] + # Type. + _op .4byte $type + # The name. + _op .ascii [_quote $name] + # Alignment. + set align 2 + set total [expr {($namelen + (1 << $align) - 1) & (-1 << $align)}] + for {set i $namelen} {$i < $total} {incr i} { + _op .byte 0 + } + # The data. + foreach {a b} [split $hexdata {}] { + _op .byte 0x$a$b + } + } + + # Emit a note section holding the given build-id. + proc build_id {buildid} { + _defer_output {.note.gnu.build-id a note} { + # From elf/common.h. + set NT_GNU_BUILD_ID 3 + + _note $NT_GNU_BUILD_ID GNU $buildid + } + } + # The top-level interface to the DWARF assembler. # FILENAME is the name of the file where the generated assembly # code is written. |