[gdb/symtab] Handle PU without import in "save gdb-index"

Consider the test-case added in this patch, with resulting dwarf:
...
  Compilation Unit @ offset 0xc7:
   Length:        0x2c (32-bit)
   Version:       4
   Abbrev Offset: 0x64
   Pointer Size:  8
 <0><d2>: Abbrev Number: 2 (DW_TAG_partial_unit)
    <d3>   DW_AT_language    : 2        (non-ANSI C)
    <d4>   DW_AT_name        : imported_unit.c
 <1><e4>: Abbrev Number: 3 (DW_TAG_base_type)
    <e5>   DW_AT_byte_size   : 4
    <e6>   DW_AT_encoding    : 5        (signed)
    <e7>   DW_AT_name        : int
 <1><eb>: Abbrev Number: 4 (DW_TAG_subprogram)
    <ec>   DW_AT_name        : main
    <f1>   DW_AT_type        : <0xe4>
    <f5>   DW_AT_external    : 1
 <1><f6>: Abbrev Number: 0
  Compilation Unit @ offset 0xf7:
   Length:        0x2c (32-bit)
   Version:       4
   Abbrev Offset: 0x85
   Pointer Size:  8
 <0><102>: Abbrev Number: 2 (DW_TAG_compile_unit)
    <103>   DW_AT_language    : 2       (non-ANSI C)
    <104>   DW_AT_name        : <artificial>
 <1><111>: Abbrev Number: 3 (DW_TAG_subprogram)
    <112>   DW_AT_abstract_origin: <0xeb>
    <116>   DW_AT_low_pc      : 0x4004a7
    <11e>   DW_AT_high_pc     : 0x4004b2
 <1><126>: Abbrev Number: 0
...

When run with target board cc-with-gdb-index, we run into:
...
(gdb) break main
warning: (Internal error: pc 0x4004a7 in read in CU, but not in symtab.)
<repeat>
warning: (Internal error: pc 0x4004ab in read in CU, but not in symtab.)
<repeat>
Breakpoint 1 at 0x4004ab
(gdb) PASS: gdb.dwarf2/imported-unit-runto-main.exp: setting breakpoint at main
run
Starting program: /data/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.dwarf2/imported-unit-runto-main/imported-unit-runto-main
warning: (Internal error: pc 0x4004a7 in read in CU, but not in symtab.)
<repeat>
warning: (Internal error: pc 0x4004ab in read in CU, but not in symtab.)
<repeat>

Breakpoint 1, warning: (Internal error: pc 0x4004ab in read in CU, but not in symtab.)
warning: (Internal error: pc 0x4004ab in read in CU, but not in symtab.)
<repeat>
0x00000000004004ab in main ()
warning: (Internal error: pc 0x4004ab in read in CU, but not in symtab.)
<repeat>
(gdb) FAIL: gdb.dwarf2/imported-unit-runto-main.exp: running to main in runto
...

Looking at the .gdb_index section contents using objdump --dwarf=gdb_index, we
have:
...
CU table:
[  0] 0x0 - 0x2d
[  1] 0x2e - 0xa4
[  2] 0xa5 - 0xc6
[  3] 0xf7 - 0x126
[  4] 0x127 - 0x2de
[  5] 0x2df - 0x300

Address table:
00000000004004a7 00000000004004b2 4

Symbol table:
[489] main: 4 [global, function]
...
We see that both the main symbol, and main address range map to CU 4, which has
offset range 0x127 - 0x2de, while main actually is contained in CU 3 at offset
range 0xf7 - 0x126.

This is caused by this continue in write_gdbindex, which triggers for the PU:
...
      /* CU of a shared file from 'dwz -m' may be unused by this main file.
        It may be referenced from a local scope but in such case it does not
        need to be present in .gdb_index.  */
      if (psymtab == NULL)
       continue;
...
The continue causes the PU to be skipped in the CU table (we can see that the
PU offset range 0xc7-0xf6 is missing) but the references are not taking that
into account.

I've tried fixing this in the optimal way, by updating the references, but ran
into trouble when follow_die_offset tries to find the CU for the inter-CU
ref.  Because the PU is missing from the CU table,
dwarf2_find_containing_comp_unit bisects to the wrong CU.

Fix this by not skipping the PU in the CU table.

Build and reg-tested on x86_64-linux, with native and target boards
cc-with-gdb-index, cc-with-dwz and cc-with-dwz-m.

gdb/ChangeLog:

2020-04-16  Tom de Vries  <tdevries@suse.de>

	PR symtab/25791
	* dwarf2/index-write.c (write_gdbindex): Generate CU table entries for
	CUs without psymtab.

gdb/testsuite/ChangeLog:

2020-04-16  Tom de Vries  <tdevries@suse.de>

	PR symtab/25791
	* gdb.dwarf2/gdb-add-index.exp (add_gdb_index): Move ...
	(ensure_gdb_index): and factor out and move ...
	* lib/gdb.exp (add_gdb_index, ensure_gdb_index): ... here.
	* gdb.dwarf2/imported-unit-runto-main.exp: New file.
This commit is contained in:
Tom de Vries 2020-04-16 14:56:32 +02:00
parent 97ed802d15
commit efba5c2319
6 changed files with 160 additions and 48 deletions

View file

@ -1,3 +1,9 @@
2020-04-16 Tom de Vries <tdevries@suse.de>
PR symtab/25791
* dwarf2/index-write.c (write_gdbindex): Generate CU table entries for
CUs without psymtab.
2020-04-16 Kevin Buettner <kevinb@redhat.com> 2020-04-16 Kevin Buettner <kevinb@redhat.com>
* python/python.c (do_start_initialization): Don't call * python/python.c (do_start_initialization): Don't call

View file

@ -1426,18 +1426,15 @@ write_gdbindex (struct dwarf2_per_objfile *dwarf2_per_objfile, FILE *out_file,
= dwarf2_per_objfile->all_comp_units[i]; = dwarf2_per_objfile->all_comp_units[i];
partial_symtab *psymtab = per_cu->v.psymtab; partial_symtab *psymtab = per_cu->v.psymtab;
/* CU of a shared file from 'dwz -m' may be unused by this main file. if (psymtab != NULL)
It may be referenced from a local scope but in such case it does not {
need to be present in .gdb_index. */ if (psymtab->user == NULL)
if (psymtab == NULL) recursively_write_psymbols (objfile, psymtab, &symtab,
continue; psyms_seen, i);
if (psymtab->user == NULL) const auto insertpair = cu_index_htab.emplace (psymtab, i);
recursively_write_psymbols (objfile, psymtab, &symtab, gdb_assert (insertpair.second);
psyms_seen, i); }
const auto insertpair = cu_index_htab.emplace (psymtab, i);
gdb_assert (insertpair.second);
/* The all_comp_units list contains CUs read from the objfile as well as /* The all_comp_units list contains CUs read from the objfile as well as
from the eventual dwz file. We need to place the entry in the from the eventual dwz file. We need to place the entry in the

View file

@ -1,3 +1,11 @@
2020-04-16 Tom de Vries <tdevries@suse.de>
PR symtab/25791
* gdb.dwarf2/gdb-add-index.exp (add_gdb_index): Move ...
(ensure_gdb_index): and factor out and move ...
* lib/gdb.exp (add_gdb_index, ensure_gdb_index): ... here.
* gdb.dwarf2/imported-unit-runto-main.exp: New file.
2020-04-16 Tom de Vries <tdevries@suse.de> 2020-04-16 Tom de Vries <tdevries@suse.de>
* gdb.base/maint-expand-symbols-header-file.exp: Set language before * gdb.base/maint-expand-symbols-header-file.exp: Set language before

View file

@ -27,48 +27,14 @@ if { [prepare_for_testing "failed to prepare" "${testfile}" \
return -1 return -1
} }
# Add a .gdb_index section to PROGRAM. if { [ensure_gdb_index $binfile] == -1 } {
# PROGRAM is assumed to be the output of standard_output_file. return -1
# Returns the 0 if there is a failure, otherwise 1.
proc add_gdb_index { program } {
global srcdir GDB env BUILD_DATA_DIRECTORY
set contrib_dir "$srcdir/../contrib"
set env(GDB) "$GDB --data-directory=$BUILD_DATA_DIRECTORY"
set result [catch "exec $contrib_dir/gdb-add-index.sh $program" output]
if { $result != 0 } {
verbose -log "result is $result"
verbose -log "output is $output"
return 0
}
return 1
}
# Build a copy of the program with an index (.gdb_index/.debug_names).
# But only if the toolchain didn't already create one: gdb doesn't support
# building an index from a program already using one.
set test "check if index present"
gdb_test_multiple "mt print objfiles ${testfile}" $test {
-re "gdb_index.*${gdb_prompt} $" {
set binfile_with_index $binfile
}
-re "debug_names.*${gdb_prompt} $" {
set binfile_with_index $binfile
}
-re "Psymtabs.*${gdb_prompt} $" {
if { [add_gdb_index $binfile] != "1" } {
return -1
}
set binfile_with_index $binfile
}
} }
# Ok, we have a copy of $binfile with an index. # Ok, we have a copy of $binfile with an index.
# Restart gdb and verify the index was used. # Restart gdb and verify the index was used.
clean_restart ${binfile_with_index} clean_restart ${binfile}
gdb_test "mt print objfiles ${testfile}" \ gdb_test "mt print objfiles ${testfile}" \
"(gdb_index|debug_names).*" \ "(gdb_index|debug_names).*" \
"index used" "index used"

View file

@ -0,0 +1,92 @@
# Copyright 2020 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
};
standard_testfile main.c .S
set executable ${testfile}
set asm_file [standard_output_file ${srcfile2}]
# We need to know the size of integer types in order to write some of the
# debugging info we'd like to generate.
if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] {
return -1
}
# Create the DWARF.
Dwarf::assemble $asm_file {
declare_labels cu_label main_label int_label
declare_labels aaa_label
set int_size [get_sizeof "int" 4]
global srcdir subdir srcfile
extern main
set main_range [function_range main ${srcdir}/${subdir}/${srcfile}]
set main_start [lindex $main_range 0]
set main_length [lindex $main_range 1]
cu {} {
cu_label: partial_unit {
{language @DW_LANG_C}
{name "imported_unit.c"}
} {
int_label: base_type {
{byte_size $int_size sdata}
{encoding @DW_ATE_signed}
{name int}
}
main_label: subprogram {
{name main}
{type :$int_label}
{external 1 flag}
}
}
}
cu {} {
compile_unit {
{language @DW_LANG_C}
{name "<artificial>"}
} {
subprogram {
{abstract_origin %$main_label}
{low_pc $main_start addr}
{high_pc "$main_start + $main_length" addr}
}
}
}
}
if { [prepare_for_testing "failed to prepare" ${testfile} \
[list $srcfile $asm_file] {nodebug}] } {
return -1
}
if { [ensure_gdb_index $binfile] == -1 } {
return -1
}
clean_restart ${binfile}
runto main message

View file

@ -7038,5 +7038,48 @@ proc verify_psymtab_expanded { filename readin } {
} }
} }
# Add a .gdb_index section to PROGRAM.
# PROGRAM is assumed to be the output of standard_output_file.
# Returns the 0 if there is a failure, otherwise 1.
proc add_gdb_index { program } {
global srcdir GDB env BUILD_DATA_DIRECTORY
set contrib_dir "$srcdir/../contrib"
set env(GDB) "$GDB --data-directory=$BUILD_DATA_DIRECTORY"
set result [catch "exec $contrib_dir/gdb-add-index.sh $program" output]
if { $result != 0 } {
verbose -log "result is $result"
verbose -log "output is $output"
return 0
}
return 1
}
# Add a .gdb_index section to PROGRAM, unless it alread has an index
# (.gdb_index/.debug_names). Gdb doesn't support building an index from a
# program already using one. Return 1 if a .gdb_index was added, return 0
# if it already contained an index, and -1 if an error occurred.
proc ensure_gdb_index { binfile } {
set testfile [file tail $binfile]
set test "check if index present"
gdb_test_multiple "mt print objfiles ${testfile}" $test {
-re -wrap "gdb_index.*" {
return 0
}
-re -wrap "debug_names.*" {
return 0
}
-re -wrap "Psymtabs.*" {
if { [add_gdb_index $binfile] != "1" } {
return -1
}
return 1
}
}
return -1
}
# Always load compatibility stuff. # Always load compatibility stuff.
load_lib future.exp load_lib future.exp