[RFA/DWARF v2] Fix breakpoint add on inlined function using function name.
Simon Marchi
simon.marchi@polymtl.ca
Thu Dec 21 22:52:00 GMT 2017
On 2017-12-21 06:03, Joel Brobecker wrote:
> Hi Simon,
>
> On Wed, Dec 20, 2017 at 09:35:34PM -0500, Simon Marchi wrote:
>> On 2017-12-20 08:21, Xavier Roirand wrote:
>> > So far only approved by Joel B.
>> >
>> > Using this Ada example:
>> >
>> > package B is
>> > procedure Read_Small with Inline_Always;
>> > end B;
>> >
>> > package body B is
>> > Total : Natural := 0;
>> > procedure Read_Small is
>> > begin
>> > Total := Total + 1;
>> > end Read_Small;
>> > end B;
>> >
>> > and
>> >
>> > with B;
>> >
>> > procedure M is
>> > begin
>> > B.Read_Small;
>> > end M;
>> >
>> > % gnatmake -g -O0 -m m.adb -cargs -gnatn
>> > % gdb m
>> >
>> > Inserting a breakpoint on Read_Small inlined function does not work:
>> >
>> > (gdb) b read_small
>> > Breakpoint 1 at 0x40250e: file b.adb, line 5.
>> > (gdb) info b
>> > Num Type Disp Enb Address What
>> > 1 breakpoint keep y 0x000000000040250e in b.doit at b.adb:5
>> > (gdb)
>> >
>> > In this exemple we should have two breakpoints set, one in package B and
>>
>> "example"
>>
>> > the other one in the inlined instance inside procedure M), like below:
>> >
>> > (gdb) b read_small
>> > Breakpoint 1 at 0x40250e: b.adb:5. (2 locations)
>> > (gdb) info b
>> > Num Type Disp Enb Address What
>> > 1 breakpoint keep y <MULTIPLE>
>> > 1.1 y 0x000000000040250e in b.doit at
>> > b.adb:5
>> > 1.2 y 0x0000000000402540 in m at b.adb:5
>> > (gdb)
>> >
>> > Looking at the DWARF info for inlined instance of Read_Small:
>> >
>> > <1><1526>: Abbrev Number: 2 (DW_TAG_subprogram)
>> > <1527> DW_AT_name : ([...], offset: 0x1e82): b__read_small
>> > <152b> DW_AT_decl_file : 2
>> > <152c> DW_AT_decl_line : 3
>> > <152d> DW_AT_inline : 3 (declared as inline and inlined)
>> > [...]
>> > <2><1547>: Abbrev Number: 4 (DW_TAG_inlined_subroutine)
>> > <1548> DW_AT_abstract_origin: <0x1526>
>> > <154c> DW_AT_low_pc : 0x402552
>> > <1554> DW_AT_high_pc : 0x2b
>> > <155c> DW_AT_call_file : 1
>> > <155d> DW_AT_call_line : 5
>> > <2><155e>: Abbrev Number: 0
>> >
>> > During the parsing of DWARF info in order to produce partial DIE linked
>> > list, the DW_TAG_inlined_subroutine were skipped thus not present in the
>> > final partial dies.
>> > Taking DW_TAG_inlined_subroutine in account during the parsing process
>> > fixes the problem.
>>
>> Do you have some insights as to why we don't see the same problem in
>> other
>> languages such as C? I tried to make a test case in C similar to
>> yours. I
>> made a shared library that contained a function, with both the
>> standalone
>> instance and an inlined instance. In the beginning, we have only
>> loaded
>> partial symbols for the library. I tried placing a breakpoint on the
>> function, and got the expected two locations. What seems to happen is
>> that
>> placing the breakpoint triggers the read of the full symbols, which
>> eventually finds the inline instance. Do you have any idea what's
>> different
>> about Ada?
>
> I think we'll need to look more deeply at your example to figure out
> what is going on.
>
> First, just to make sure we understand the lookup process:
> When trying to search for a symbol, we first search through all
> the partial symtabs to see if they contain partial symbols that
> match our search. From there, we expand those partial symtabs into
> full symtabs, and only then do we search the full symtabs for
> symbols that match, and that's the list we return.
>
> In our case, here is the reasoning: Imagine we have the following
> C pseudo-code:
>
> /* inc.h */
> inline int increment (int i);
>
> /* inc.c */
> int
> increment (int i)
> {
> return i + 1;
> }
>
> /* foo.c */
> #include "inc.h"
>
> int
> main (void)
> {
> return increment (0);
> }
>
> For function increment, we would assume that the compiler would first
> generate a DW_TAG_subprogram DIE, and that this DIE would be a child
> of inc.c's compilation unit.
>
> Looking at the debugging information for foo.c's unit, we would see
> the DW_TAG_subprogram DIE for the function "main". And if the compiler
> were to elect to inline increment, we would see one of the children of
> main's DW_TAG_subprogram be a DW_TAG_inline_subroutine DIE.
>
> Now, let's take a look at what happens when the dwarf2read module
> processes the DWARF, and transforms a DW_TAG_subprogram DIE into
> a partial symbol: First, it processes the DIE's attributes. So far
> so good, but then you see that it processes the DIE's children
> only in the case of Ada. See dwarf2read.c::add_partial_subprogram:
>
> if (cu->language == language_ada)
> {
> pdi = pdi->die_child;
> while (pdi != NULL)
> {
> fixup_partial_die (pdi, cu);
> if (pdi->tag == DW_TAG_subprogram
> || pdi->tag == DW_TAG_lexical_block)
> add_partial_subprogram (pdi, lowpc, highpc, set_addrmap,
> cu);
> pdi = pdi->die_sibling;
> }
> }
>
> The reason why we do it for Ada is that nested subprograms are
> common-place in Ada, and users expect to be able to be able to
> break on those subprograms without having to be inside the function
> itself to do so. In other words, we don't treat the symbol as
> being local to the enclosing subprogram.
>
> With that in mind, what happens in the C case while dwarf2read
> processes the main's DW_TAG_subprogram: It adds "main"'s partial
> symbol, but stops there instead of looking at its children.
> The net result is that the inline instance of our "increment"
> function never makes it to the partial symtabs/symbols. This
> impacts our partial symtab scan, as we now only have one partial
> symbol for increment in inc.c's partial symtab which matches.
> So, that's the only partial symtab selected for expansion.
> This then potentially affects the next step, which is the full
> symtab scan, and if "foo.c"'s partial symtab hasn't be expanded
> for some reasons unrelated to our lookup, we'll end up only
> finding one match, the non-inlined one.
Why doesn't the same happen in the Ada case? The debug info in the Ada
program looks similar, so a partial symbol should be created for this
DIE:
<1><77b>: Abbrev Number: 2 (DW_TAG_subprogram)
<77c> DW_AT_external : 1
<77c> DW_AT_name : (indirect string, offset: 0xae3):
b__read_small
<780> DW_AT_decl_file : 2
<781> DW_AT_decl_line : 3
<782> DW_AT_inline : 3 (declared as inline and inlined)
Then, when we set the breakpoint, I would expect GDB to find the partial
symbol for read_small in this objfile, expand it to full symbols, and
then find the inlined instance, just as it does for C. That's the
difference I don't get.
Simon
More information about the Gdb-patches
mailing list