DWARF: cannot break on out-of-line function nested inside inlined function.
Consider the following code, which defines a function, Child2,
which is itself nested inside Child1:
procedure Foo_O224_021 is
O1 : constant Object_Type := Get_Str ("Foo");
procedure Child1 is
O2 : constant Object_Type := Get_Str ("Foo");
function Child2 (S : String) return Boolean is -- STOP
begin
for C of S loop
Do_Nothing (C);
if C = 'o' then
return True;
end if;
end loop;
return False;
end Child2;
R : Boolean;
begin
R := Child2 ("Foo");
R := Child2 ("Bar");
R := Child2 ("Foobar");
end Child1;
begin
Child1;
end Foo_O224_021;
On x86_64-linux, when compiled at -O2, GDB is unable to insert
a breakpoint on Child2:
% gnatmake -g -O2 foo_o224_021
% gdb foo_o224_021
(gdb) b child2
Function "child2" not defined.
(gdb) b foo_o224_021.child1.child2
Function "foo_o224_021.child1.child2" not defined.
The problem is caused by the fact that GDB did not create a symbol
for Child2, and this, in turn, is caused by the fact that the compiler
decided to inline Child1, but not Child2. The DWARF debugging info
first provides an abstract instance tree for Child1...
<3><1b7b>: Abbrev Number: 29 (DW_TAG_subprogram)
<1b7c> DW_AT_name : (indirect string, offset: 0x23f8): foo_o224_021__child1
<1b82> DW_AT_inline : 1 (inlined)
<1b83> DW_AT_sibling : <0x1c01>
... where that subprogram is given the DW_AT_inline attribute.
Inside that function there is a lexical block which has no PC
range (corresponding to the fact that this is the abstract tree):
<4><1b87>: Abbrev Number: 30 (DW_TAG_lexical_block)
... inside which our subprogram Child2 is described:
<5><1b92>: Abbrev Number: 32 (DW_TAG_subprogram)
<1b93> DW_AT_name : (indirect string, offset: 0x2452): foo_o224_021__child1__child2
<1b99> DW_AT_type : <0x1ab1>
<1b9d> DW_AT_low_pc : 0x402300
<1ba5> DW_AT_high_pc : 0x57
[...]
Then, later on, we get the concrete instance tree, starting at:
<3><1c5e>: Abbrev Number: 41 (DW_TAG_inlined_subroutine)
<1c5f> DW_AT_abstract_origin: <0x1b7b>
<1c63> DW_AT_entry_pc : 0x4025fd
<1c6b> DW_AT_ranges : 0x150
... which refers to Child1. One of that inlined subroutine children
is the concrete instance of the empty lexical block we saw above
(in the abstract instance tree), which gives the actual address
range for this inlined instance:
<5><1c7a>: Abbrev Number: 43 (DW_TAG_lexical_block)
<1c7b> DW_AT_abstract_origin: <0x1b87>
<1c7f> DW_AT_ranges : 0x180
This is the DIE which provides the context inside which we can
record Child2. But unfortunately, GDB does not take the abstract
origin into account when handling lexical blocks, causing it
to miss the fact that this block contains some symbols described
in the abstract instance tree. This is the first half of this patch:
modifying GDB to follow DW_AT_abstract_origin attributes for
lexical blocks.
But this not enough to fix the issue, as we're still unable to
break on Child2 with just that change. The second issue can be
traced to the way inherit_abstract_dies determines the list of
DIEs to inherit from. For that, it iterates over all the DIEs in
the concrete instance tree, and finds the list of DIEs from the
abstract instance tree that are not referenced from the concrete
instance tree. As it happens, there is one type of DIE in the
concrete instance tree which does reference Child2's DIE, but
in fact does otherwise define a concrete instance of the reference
DIE; that's (where <0x1b92> is Child2's DIE):
<6><1d3c>: Abbrev Number: 35 (DW_TAG_GNU_call_site)
<1d3d> DW_AT_low_pc : 0x4026a4
<1d45> DW_AT_abstract_origin: <0x1b92>
So, the second part of the patch is to modify inherit_abstract_dies
to ignore DW_TAG_GNU_call_site DIEs when iterating over the concrete
instance tree.
This patch also includes a testcase which can be used to reproduce
the issue. Unfortunately, for it to actually pass, a smal patch in
GCC is also necessary to make sure that GCC provides lexical blocks'
DW_AT_abstract_origin attributes from the concrete tree back to
the abstract tree. We hope to be able to submit and integrate that
patch in the GCC tree soon. Meanwhile, a setup_xfail has been added.
gdb/ChangeLog:
2014-05-05 Pierre-Marie de Rodat <derodat@adacore.com>
* dwarf2read.c (inherit_abstract_dies): Skip
DW_TAG_GNU_call_site dies while inheriting children of an
abstract DIE into a scope.
(read_lexical_block_scope): Inherit abstract DIE's for
lexical scopes.
gdb/testsuite/ChangeLog:
* gdb.ada/out_of_line_in_inlined: New testcase.
2015-04-20 15:53:00 +00:00
|
|
|
# Copyright 2015 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 "ada.exp"
|
|
|
|
|
|
|
|
standard_ada_testfile foo_o224_021
|
|
|
|
|
|
|
|
if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug optimize=-O2}] != ""} {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
clean_restart ${testfile}
|
|
|
|
|
|
|
|
# GCC currently is missing a DW_AT_origin attribute in one of the
|
|
|
|
# lexical blocks, preventing GDB from creating a symbol for the
|
|
|
|
# subprogram we want to break on.
|
|
|
|
setup_xfail "*-*-*"
|
|
|
|
gdb_test "break foo_o224_021.child1.child2" \
|
|
|
|
"Breakpoint \[0-9\]+ at.*: file .*foo_o224_021.adb, line \[0-9\]+."
|
out of line functions nested inside inline functions.
This patch improves the handling of out-of-line functions nested
inside functions that have been inlined.
Consider for instance a situation where function Foo_O224_021
has a function Child1 declared in it, which itself has a function
Child2 nested inside Child1. After compiling the program with
optimization on, Child1 gets inlined, but not Child2.
After inserting a breakpoint on Child2, and running the program
until reaching that breakpoint, we get the following backtrace:
% gdb foo_o224_021
(gdb) break foo_o224_021.child1.child2
(gdb) run
[...]
Breakpoint 1, foo_o224_021 () at foo_o224_021.adb:28
28 Child1;
(gdb) bt
#0 0x0000000000402400 in foo_o224_021 () at foo_o224_021.adb:28
#1 0x00000000004027a4 in foo_o224_021.child1 () at foo_o224_021.adb:23
#2 0x00000000004027a4 in foo_o224_021 () at foo_o224_021.adb:28
GDB reports the wrong function name for frame #0. We also get the same
kind of error in the "Breakpoint 1, foo_o224_021 () [...]" message.
In both cases, the function name should be foo_o224_021.child1.child2,
and the parameters should be "s=...".
What happens is that the inlined frame handling does not handle well
the case where an inlined function is calling an out-of-line function
which was declared inside the inlined function's scope.
In particular, looking first at the inlined-frame sniffer when applying
to frame #0:
/* Calculate DEPTH, the number of inlined functions at this
location. */
depth = 0;
cur_block = frame_block;
while (BLOCK_SUPERBLOCK (cur_block))
{
if (block_inlined_p (cur_block))
depth++;
cur_block = BLOCK_SUPERBLOCK (cur_block);
}
What happens is that cur_block starts as the block associated
to child2, which is not inlined. We shoud be stopping here, but
instead, we keep walking the superblock chain, which takes us
all the way to Foo_O224_021's block, via Child2's block. And
since Child1 was inlined, we end up with a depth count of 1,
wrongly making GDB think that frame #0 is an inlined frame.
Same kind of issue inside skip_inline_frames.
The fix is to stop checking for inlined frames as soon as we see
a block corresponding to a function which is not inlined. This is
the behavior we now obtain:
(gdb) run
[...]
Breakpoint 1, foo_o224_021.child1.child2 (s=...) at foo_o224_021.adb:9
9 function Child2 (S : String) return Boolean is
(gdb) bt
#0 0x0000000000402400 in foo_o224_021.child1.child2 (s=...)
at foo_o224_021.adb:9
#1 0x00000000004027a4 in foo_o224_021.child1 () at foo_o224_021.adb:23
#2 0x00000000004027a4 in foo_o224_021 () at foo_o224_021.adb:28
gdb/ChangeLog:
* inline-frame.c (inline_frame_sniffer, skip_inline_frames):
Stop counting inlined frames as soon as an out-of-line function
is found.
gdb/testsuite/ChangeLog:
* gdb.ada/out_of_line_in_inlined.exp: Add run and "bt" tests.
2015-04-21 17:34:04 +00:00
|
|
|
|
|
|
|
gdb_run_cmd
|
|
|
|
setup_xfail "*-*-*"
|
|
|
|
gdb_test "" \
|
|
|
|
"Breakpoint $decimal, foo_o224_021\\.child1\\.child2 \\(s=\\.\\.\\.\\).*"
|
|
|
|
|
|
|
|
set opt_addr_in "($hex in)?"
|
|
|
|
setup_xfail "*-*-*"
|
|
|
|
gdb_test "bt" \
|
|
|
|
[multi_line "#0 +$opt_addr_in +foo_o224_021\\.child1\\.child2 \\(s=\\.\\.\\.\\).*" \
|
|
|
|
"#1 +$opt_addr_in +foo_o224_021\\.child1 \\(\\).*" \
|
|
|
|
"#2 +$opt_addr_in +foo_o224_021 \\(\\).*" ]
|