[Dwarf-Discuss] How to differentiate between multiple inlined segments of same function from line table?

Cary Coutant ccoutant@gmail.com
Thu May 2 01:45:47 GMT 2019


> I am trying to understand how a profiler can get the following
> information from a DWARF line table. Let us look at a specific
> example:
> ...
> When foo() is inlined at all the 3 instances, the line number
> from the line table will reference the line numbers of the
> original foo() function body, i.e. something like lines 7-11, at
> all the 3 inlined segments.
>
> When a profiler looks at this, how can the profiler know which
> inlined instance it is looking at?

With current DWARF, you need to look at the debug info to get inline
information. In the debug info, first look for a declaration of your
inline function that looks something like this DIE:

 <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram)
    <2e>   DW_AT_external    : 1
    <2e>   DW_AT_name        : foo
    <32>   DW_AT_decl_file   : 1
    <33>   DW_AT_decl_line   : 1
    <34>   DW_AT_prototyped  : 1
    <34>   DW_AT_type        : <0x50>
    <38>   DW_AT_inline      : 3 (declared as inline and inlined)

The distinguishing features here are the DW_AT_inline attribute and
the lack of a DW_AT_low_pc/high_pc. This is the abstract definition of
your inline function.

Next, if an out-of-line copy of the function was generated, you'll
find a concrete instance of it that may look something like this DIE:

 <1><57>: Abbrev Number: 6 (DW_TAG_subprogram)
    <58>   DW_AT_abstract_origin: <0x2d>
    <5c>   DW_AT_low_pc      : 0x0
    <64>   DW_AT_high_pc     : 0x17
    <6c>   DW_AT_frame_base  : 1 byte block: 9c (DW_OP_call_frame_cfa)

Here, the DW_AT_abstract_origin tells you that it's a concrete
instance of the abstract definition declared above, and gives you the
PC range for the out-of-line code.

Now, for each location where your function has been inlined, you'll
find a DW_TAG_inlined_subroutine DIE nested inside the
DW_TAG_subprogram DIE where it was called.

 <1><85>: Abbrev Number: 9 (DW_TAG_subprogram)
    <86>   DW_AT_external    : 1
    <86>   DW_AT_name        : bar
    <8a>   DW_AT_decl_file   : 1
    <8b>   DW_AT_decl_line   : 10
    <8c>   DW_AT_prototyped  : 1
    <8c>   DW_AT_type        : <0x50>
    <90>   DW_AT_low_pc      : 0x17
    <98>   DW_AT_high_pc     : 0x55
    <a0>   DW_AT_frame_base  : 1 byte block: 9c (DW_OP_call_frame_cfa)
 ...
 <2><b3>: Abbrev Number: 11 (DW_TAG_inlined_subroutine)
    <b4>   DW_AT_abstract_origin: <0x2d>
    <b8>   DW_AT_low_pc      : 0x1f
    <c0>   DW_AT_high_pc     : 0xe
    <c8>   DW_AT_call_file   : 1
    <c9>   DW_AT_call_line   : 11
    <ca>   DW_AT_sibling     : <0xf3>
 ...
 <2><f3>: Abbrev Number: 11 (DW_TAG_inlined_subroutine)
    <f4>   DW_AT_abstract_origin: <0x2d>
    <f8>   DW_AT_low_pc      : 0x39
    <100>   DW_AT_high_pc     : 0xe
    <108>   DW_AT_call_file   : 1
    <109>   DW_AT_call_line   : 13
 ...
 <2><133>: Abbrev Number: 11 (DW_TAG_inlined_subroutine)
    <134>   DW_AT_abstract_origin: <0x2d>
    <138>   DW_AT_low_pc      : 0x53
    <140>   DW_AT_high_pc     : 0xe
    <148>   DW_AT_call_file   : 1
    <149>   DW_AT_call_line   : 15

The low_pc and high_pc attributes in each inlined_subroutine DIE will
identify, for a given PC, which inlined instance you're looking at,
and the call_file and call_line attributes will give you the source
file information for the caller. If there are nested inlines, you'll
find nested inlined_subroutine DIEs, so you can follow the call stack
all the way up to the outermost non-inlined function.

> It appeared to me initially the line table discriminator field
> (http://wiki.dwarfstd.org/index.php?title=Path_Discriminators)
> could be used for this. But after further study, I think I need
> something more general.

No, discriminators are for something else entirely.

> It appears I need something like the "context" column at
> http://wiki.dwarfstd.org/index.php?title=TwoLevelLineTables.
> However this does not appear to be in any DWARF spec.

Yes, this proposal would do what you're looking for. It modifies the
line table so that inline information can be represented entirely in
the line table without having to process the DIE structures. See also
DWARF issue #140906.1 [1].

The proposal was deferred to the next revision of DWARF (it was
proposed before DWARF 5 was finalized, but too late to make it into
that revision). There's a prototype implementation on the GCC
google/gcc-4_9 branch and the binutils
users/ccoutant/two-level-line-tables branch. Although that prototype
doesn't quite match the proposal as written, it was close enough to
demonstrate the effectiveness of the idea.

-cary


[1] http://dwarfstd.org/ShowIssue.php?issue=140906.1



More information about the Dwarf-discuss mailing list