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 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? [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.]

Thanks,
Siva Chandra


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