This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] While processing a struct die, store the method's address in its fn_field


On Tue, Nov 25, 2014 at 7:00 AM, Siva Chandra <sivachandra@google.com> wrote:
> On Mon, Nov 24, 2014 at 12:22 PM, Doug Evans <dje@google.com> wrote:
>> Adding new fields to types or symbols is a big deal.
>> I'd like to understand why things are failing better.
>> For normal functions gdb gets the start address
>> from BLOCK_START (SYMBOL_BLOCK_VALUE (sym)).
>
> I will try, but tl;dr.
>
> Consider a simple class definition like this which has a method which
> is not inlined:
>
> class A
> {
> public:
>   int method (int a);
> };
>
> int
> A::method (int a)
> {
>   return a * a;
> }
>
> The DWARF for the class comes out like this:
>
> < 1><0x0000002d>    DW_TAG_class_type
>                       DW_AT_name                  "A"
>                       DW_AT_byte_size             0x00000001
>                       DW_AT_decl_file             0x00000001 /tmp
>                       DW_AT_decl_line             0x00000001
>                       DW_AT_sibling               <0x00000057>
> < 2><0x00000037>      DW_TAG_subprogram
>                         DW_AT_external              yes(1)
>                         DW_AT_name                  "method"
>                         DW_AT_decl_file             0x00000001 /tmp
>                         DW_AT_decl_line             0x00000004
>                         DW_AT_linkage_name          "_ZN1A6methodEi"
>                         DW_AT_type                  <0x00000057>
>                         DW_AT_accessibility         DW_ACCESS_public
>                         DW_AT_declaration           yes(1)
>                         DW_AT_object_pointer        <0x0000004b>
> < 3><0x0000004b>        DW_TAG_formal_parameter
>                           DW_AT_type                  <0x0000005e>
>                           DW_AT_artificial            yes(1)
> < 3><0x00000050>        DW_TAG_formal_parameter
>                           DW_AT_type                  <0x00000057>
>
> Notice that there is a linkage name for the method named "method". So,
> one can demangle the linkage name and get to the symbol. If this
> fails, one can use the linkage name to get to the minsym. The issue
> with lambdas is that their operator() methods do not have a linkage
> name. Not exactly true: they have a linkage name but the DWARF doesn't
> specify it. Consider this example:
>
> $> cat lambda.cc
>
> int
> main ()
> {
>   auto lambda = [] (int j) { return j + 113; };
>   return lambda (-113);
> }
>
> $> g++ -g -std=c++11 lambda.cc -o lambda
>
> The DWARF for the lambda struct come out like this:
>
> < 3><0x00000070>        DW_TAG_structure_type
>                           DW_AT_name                  "<lambda(int)>"
>                           DW_AT_byte_size             0x00000001
>                           DW_AT_decl_file             0x00000001 /tmp
>                           DW_AT_decl_line             0x00000004
> < 4><0x00000078>          DW_TAG_subprogram
>                             DW_AT_name                  "<lambda>"
>                             DW_AT_artificial            yes(1)
>                             DW_AT_declaration           yes(1)
>                             DW_AT_object_pointer        <0x00000085>
>                             DW_AT_sibling               <0x0000009c>
> < 5><0x00000085>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x0000008a>
>                               DW_AT_artificial            yes(1)
> < 5><0x0000008a>            DW_TAG_pointer_type
>                               DW_AT_byte_size             0x00000008
>                               DW_AT_type                  <0x00000070>
> < 5><0x00000090>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x00000095>
> < 5><0x00000095>            DW_TAG_rvalue_reference_type
>                               DW_AT_byte_size             0x00000008
>                               DW_AT_type                  <0x00000070>
> < 4><0x0000009c>          DW_TAG_subprogram
>                             DW_AT_name                  "<lambda>"
>                             DW_AT_artificial            yes(1)
>                             DW_AT_declaration           yes(1)
>                             DW_AT_object_pointer        <0x000000a9>
>                             DW_AT_sibling               <0x000000bf>
> < 5><0x000000a9>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x0000008a>
>                               DW_AT_artificial            yes(1)
> < 5><0x000000ae>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x000000b3>
> < 5><0x000000b3>            DW_TAG_reference_type
>                               DW_AT_byte_size             0x00000008
>                               DW_AT_type                  <0x000000b9>
> < 5><0x000000b9>            DW_TAG_const_type
>                               DW_AT_type                  <0x00000070>
> < 4><0x000000bf>          DW_TAG_subprogram
>                             DW_AT_name                  "<lambda>"
>                             DW_AT_artificial            yes(1)
>                             DW_AT_declaration           yes(1)
>                             <Unknown AT value 0x211a>   yes(1)
>                             DW_AT_object_pointer        <0x000000cc>
>                             DW_AT_sibling               <0x000000d2>
> < 5><0x000000cc>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x0000008a>
>                               DW_AT_artificial            yes(1)
> < 4><0x000000d2>          DW_TAG_subprogram
>                             DW_AT_name                  "~<lambda>"
>                             DW_AT_artificial            yes(1)
>                             DW_AT_declaration           yes(1)
>                             DW_AT_object_pointer        <0x000000df>
>                             DW_AT_sibling               <0x000000ea>
> < 5><0x000000df>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x0000008a>
>                               DW_AT_artificial            yes(1)
> < 5><0x000000e4>            DW_TAG_formal_parameter
>                               DW_AT_type                  <0x0000002d>
>                               DW_AT_artificial            yes(1)
> < 4><0x000000ea>          DW_TAG_subprogram
>                             DW_AT_name                  "operator()"
>                             DW_AT_type                  <0x0000002d>
>                             DW_AT_artificial            yes(1)
>                             DW_AT_low_pc                0x00400566
>                             DW_AT_high_pc               <offset-from-lowpc>19
>                             DW_AT_frame_base            len 0x0001:
> 9c: DW_OP_call_frame_cfa
>                             DW_AT_object_pointer        <0x0000010f>
>                             DW_AT_GNU_all_call_sites    yes(1)
> < 5><0x00000109>            DW_TAG_pointer_type
>                               DW_AT_byte_size             0x00000008
>                               DW_AT_type                  <0x000000b9>
> < 5><0x0000010f>            DW_TAG_formal_parameter
>                               DW_AT_name                  "__closure"
>                               DW_AT_type                  <0x0000011b>
>                               DW_AT_artificial            yes(1)
>                               DW_AT_location              len 0x0002:
> 9168: DW_OP_fbreg -24
> < 5><0x0000011b>            DW_TAG_const_type
>                               DW_AT_type                  <0x00000109>
> < 5><0x00000120>            DW_TAG_formal_parameter
>                               DW_AT_name                  "j"
>                               DW_AT_decl_file             0x00000001 /tmp
>                               DW_AT_decl_line             0x00000004
>                               DW_AT_type                  <0x0000002d>
>                               DW_AT_location              len 0x0002:
> 9164: DW_OP_fbreg -28
>
> Notice that the operator() method has no linkage name specified in the
> DWARF. But, it has a DW_AT_low_pc. Lets grep the binary for this low
> pc value:
>
> $> readelf -a lambda | grep 400566
>     41: 0000000000400566    19 FUNC    LOCAL  DEFAULT   12 _ZZ4mainENKUliE_clEi
>
> So then, there is an ELF symbol for the operator() method! Lets
> demangle the name:
>
> (gdb) maintenance demangle _ZZ4mainENKUliE_clEi
> main::{lambda(int)#1}::operator()(int) const
>
> This name is not the same as the name of the lambda structure given by
> DWARF! If I use clang to compile, the demangled ELF symbol for the
> operator() turns out to be "main::$_0::operator()(int) const", which
> seems to indicate that gcc and clang have their own way of
> differentiating the different lambdas that can occur in a CU. Hence,
> GDB should probably not even attempt to generate a name, mangle it and
> lookup for a symbol with that name. However, low_pc is immediately
> available in the DWARF generated by GCC, so why not use it?

For functions/methods gdb already uses lowpc as the start address.
[IOW it doesn't use the linkage name, though even recently
I'd forgotten this and thought otherwise.
Also, GDB doesn't take a demangled name, mangle it,
and then try to look that up in the ELF symbol table.]

If I do "mt print symbols foo.sym", then I see this:

Symtab for file lambda.cc
Compilation directory is /home/dje/src/play
Read from object file /home/dje/ruffies-copy/src/play/lambda.x64 (0x288bf00)
Language: c++

Line table:

 line 6 at 0x4006a6
 line 6 at 0x4006b1
 line 5 at 0x4006b9
 line 7 at 0x4006c1
 line 8 at 0x4006d3
 line 0 at 0x4006d5

Blockvector:

block #000, object at 0x277ee90, 1 syms/buckets in 0x4006a6..0x4006d5
 int main(); block object 0x277edc0, 0x4006b9..0x4006d5 section .text
  block #001, object at 0x277ee20 under 0x277ee90, 1 syms/buckets in
0x4006a6..0x4006d5
   typedef int int;
        block #002, object at 0x277ec80 under 0x277ed50, 3
syms/buckets in 0x4006a6..0x4006b9, function
<lambda(int)>::operator()(int) const
         int <lambda(int)>::operator()(int) const; block object
0x277ec80, 0x4006a6..0x4006b9
         const struct <lambda(int)> {
         } * const __closure; computed at runtime
         int j; computed at runtime
    block #003, object at 0x277edc0 under 0x277ee20, 0 syms/buckets in
0x4006b9..0x4006d5, function main()
      block #004, object at 0x277ed50 under 0x277edc0, 1 syms/buckets
in 0x4006c1..0x4006d3
       struct <lambda(int)> {
       } lambda; computed at runtime
       struct <lambda(int)> {
       };

Note that there is a block for "function
<<lambda(int)>::operator()(int) const>" with a start address of
0x4006a6.

(gdb) ! nm lambda.x64 | grep ZZ4
00000000004006a6 t _ZZ4mainENKUliE_clEi

So I think(!) the existing mechanism of using
BLOCK_START (SYMBOL_BLOCK_VALUE (sym))
should work here, we just need to make sure
the various pieces are glued together.
But we don't AFAICT need a new field to record low_pc,
it is already recorded.

>  [Clang
> actually does not put out the low pc value for the subprogram die
> under a structure die, but it puts out a separate (not under a
> structure die) subprogram die for the operator() method with the low
> pc value.]

DWARF can be hard to read at times.
Note that GCC can do this too.  E.g.,
It will output a declaration in the proper context
(e.g., inside a class definition for a method) without DW_AT_low_pc
and then it will output another DIE at the top level with DW_AT_low_pc
and with a DW_AT_specification referring back to previous DIE in its context.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]