[lldb-dev] DWARFASTParserClang and DW_TAG_typedef for anonymous structs

Greg Clayton via lldb-dev lldb-dev at lists.llvm.org
Wed Mar 9 16:18:57 PST 2016


So we ran into a problem where we had anonymous structs in modules. They have no name, so we had no way to say "module A, please give me a struct named... nothing in the namespace 'foo'". Obviously this doesn't work, so we always try to make sure a typedef doesn't come from a module first, by asking us to get the typedef from the DWO file:

type_sp = ParseTypeFromDWO(die, log);

If this fails, it just means we have the typedef in hand. If I compile your example I end up with:

0x0000000b: TAG_compile_unit [1] *
             AT_producer( "Apple LLVM version 8.0.0 (clang-800.0.5.3)" )
             AT_language( DW_LANG_C99 )
             AT_name( "main.c" )
             AT_stmt_list( 0x00000000 )
             AT_comp_dir( "/tmp" )
             AT_low_pc( 0x0000000100000f60 )
             AT_high_pc( 0x0000000100000fb0 )

0x0000002e:     TAG_subprogram [2] *
                 AT_low_pc( 0x0000000100000f60 )
                 AT_high_pc( 0x0000000100000f85 )
                 AT_frame_base( rbp )
                 AT_name( "myfunc" )
                 AT_decl_file( "/private/tmp/main.c" )
                 AT_decl_line( 6 )
                 AT_prototyped( 0x01 )
                 AT_external( 0x01 )

0x00000049:         TAG_formal_parameter [3]  
                     AT_location( fbreg -8 )
                     AT_name( "s" )
                     AT_decl_file( "/private/tmp/main.c" )
                     AT_decl_line( 6 )
                     AT_type( {0x0000008c} ( my_untagged_struct* ) )

0x00000057:         NULL

0x00000058:     TAG_subprogram [4] *
                 AT_low_pc( 0x0000000100000f90 )
                 AT_high_pc( 0x0000000100000fb0 )
                 AT_frame_base( rbp )
                 AT_name( "main" )
                 AT_decl_file( "/private/tmp/main.c" )
                 AT_decl_line( 12 )
                 AT_type( {0x00000085} ( int ) )
                 AT_external( 0x01 )

0x00000076:         TAG_variable [5]  
                     AT_location( fbreg -16 )
                     AT_name( "s" )
                     AT_decl_file( "/private/tmp/main.c" )
                     AT_decl_line( 14 )
                     AT_type( {0x00000091} ( my_untagged_struct ) )

0x00000084:         NULL

0x00000085:     TAG_base_type [6]  
                 AT_name( "int" )
                 AT_encoding( DW_ATE_signed )
                 AT_byte_size( 0x04 )

0x0000008c:     TAG_pointer_type [7]  
                 AT_type( {0x00000091} ( my_untagged_struct ) )

0x00000091:     TAG_typedef [8]  
                 AT_type( {0x0000009c} ( struct  ) )
                 AT_name( "my_untagged_struct" )
                 AT_decl_file( "/private/tmp/main.c" )
                 AT_decl_line( 4 )

0x0000009c:     TAG_structure_type [9] *
                 AT_byte_size( 0x08 )
                 AT_decl_file( "/private/tmp/main.c" )
                 AT_decl_line( 1 )

0x000000a0:         TAG_member [10]  
                     AT_name( "i" )
                     AT_type( {0x00000085} ( int ) )
                     AT_decl_file( "/private/tmp/main.c" )
                     AT_decl_line( 2 )
                     AT_data_member_location( +0 )

0x000000ae:         TAG_member [10]  
                     AT_name( "f" )
                     AT_type( {0x000000bd} ( float ) )
                     AT_decl_file( "/private/tmp/main.c" )
                     AT_decl_line( 3 )
                     AT_data_member_location( +4 )

0x000000bc:         NULL

0x000000bd:     TAG_base_type [6]  
                 AT_name( "float" )
                 AT_encoding( DW_ATE_float )
                 AT_byte_size( 0x04 )

0x000000c4:     NULL


Note that the typedef is at 0x00000091, and it is a typedef to 0x0000009c.  Also note that the DWARF DIE at 0x0000009c is a complete definition as it has children describing its members and 0x0000009c doesn't have a DW_AT_declaration(1) attribute. Is this how your DWARF looks for your stuff? The DWARF you had looked like:

0x0000005c:   DW_TAG_typedef [6]  
               DW_AT_name( "my_untagged_struct" ) 
               DW_AT_decl_file("/home/luke/main.cpp") 
               DW_AT_decl_line(4)
               DW_AT_type({0x0000002d})


What did the type at 0x0000002d look like? Similar to 0x0000009c in my DWARF I presume?

The DWARFASTParserClang class is responsible for making up a clang type in the clang::ASTContext for this typedef. What will happen in the code where the flow falls through is the we will make a lldb_private::Type that says "I am a typedef to type whose user ID is 0x0000002d (in your example)". A NULL pointer should not be returned from the DWARFASTParserClang::ParseTypeFromDWARF() function. If it is, please step through and figure out why. I compiled your example and did the following:


% lldb a.out 
(lldb) b main
(lldb) r
Process 89808 launched: '/private/tmp/a.out' (x86_64)
Process 89808 stopped
* thread #1: tid = 0xf7473, 0x0000000100000fa3 a.out main + 19, stop reason = breakpoint 1.1, queue = com.apple.main-thread
    frame #0: 0x0000000100000fa3 a.out main + 19 at main.c:15
   12  	int main()
   13  	{
   14  	   my_untagged_struct s;
-> 15  	   myfunc(&s);
   16  	   return 0;
   17  	}
(lldb) p myfunc(&s)
(lldb) 

So I was able to call this function. Are you not able to call it?

Likewise if I step into this function I can see the variable:

(lldb) s
(lldb) fr var s
(my_untagged_struct *) s = 0x00007fff5fbff8d0
(lldb) fr var *s
(my_untagged_struct) *s = (i = 0, f = 3.1400001)

So to sum up: when we parse the DW_TAG_typedef in DWARFASTParserClang::ParseTypeFromDWARF(), we should return a valid TypeSP that contains a valid pointer. If that isn't happening, that is a bug. Feel free to send me the example binary and I can figure things out if you have any trouble. I wrote all of this code so I am quite familiar with it.

Greg Clayton


> On Mar 9, 2016, at 3:54 PM, luke Drummond via lldb-dev <lldb-dev at lists.llvm.org> wrote:
> 
> Hi All
> 
> I'm hoping that someone might be able to give me some direction
> regarding `Type` resolution from DWARF informationfor functions taking
> anonymous structs hidden behind a typedef
> 
> e.g.
> 
> ```
> typedef struct {
>    int i;
>    float f;
> } my_untagged_struct;
> 
> void __attribute__((noinline)) myfunc(my_untagged_struct *s)
> {
>    s->i = 0;
>    s->f = 3.14f;
> }
> 
> int main()
> {
>    my_untagged_struct s;
>    myfunc(&s);
>    return 0;
> }
> 
> ```
> 
> I [recently reported a
> bug](https://llvm.org/bugs/show_bug.cgi?id=26790) relating to the
> clang expression evaluator no longer being able to resolve calls to
> functions with arguments to typedefed anonymous structs, after a cleanup
> to the expression parsing code.
> I was perfectly wrong in my assumptions about the cause of the bug, and
> after some more digging, I think I've tracked it down to a section of
> code in `DWARFASTParserClang::ParseTypeFromDWARF`.
> 
> 
> (DWARFASTParserClang::ParseTypeFromDwarf:254)
> ```
> switch (tag)
> {
>    case DW_TAG_typedef:
>        // Try to parse a typedef from the DWO file first as modules
>        // can contain typedef'ed structures that have no names like:
>        //
>        //  typedef struct { int a; } Foo;
>        //
>        // In this case we will have a structure with no name and a
>        // typedef named "Foo" that points to this unnamed structure.
>        // The name in the typedef is the only identifier for the
> struct, // so always try to get typedefs from DWO files if possible.
>        //
>        // The type_sp returned will be empty if the typedef doesn't
> exist // in a DWO file, so it is cheap to call this function just to
> check. //
>        // If we don't do this we end up creating a TypeSP that says
> this // is a typedef to type 0x123 (the DW_AT_type value would be 0x123
>        // in the DW_TAG_typedef), and this is the unnamed structure
> type. // We will have a hard time tracking down an unnammed structure
>        // type in the module DWO file, so we make sure we don't get
> into // this situation by always resolving typedefs from the DWO file.
>        type_sp = ParseTypeFromDWO(die, log);
>        if (type_sp)
>            return type_sp;
>    LLVM_FALLTHROUGH
> ```
> 
> In my case, the type information for the typedef is included within the
> main executable's DWARF rather than an external .dwo file (snippet from
> the DWARF included the end of this message), and therefore the `case`
> for `DW_TAG_typedef` falls through as `ParseTypeFromDWO` returns a NULL
> value.
> 
> 
> As this is code I'm not familiar with, I'd appreciate if any one on the
> list was able to give some guidance as to the best way to resolve this
> issue, so that `ClangExpressionDeclMap::FindExternalVisibleDecls` can
> correctly resolve calls to functions taking typedef names to anonymous
> structs. I'm happy to take a whack at implementing this feature, but
> I'm a bit stuck as to how to resolve this type given the current DIE
> object.
> 
> Any help or guidance on where to start with this would be really
> helpful.
> 
> All the best
> 
> Luke
> 
> 
> 
> 
> --------
> This is a snippet from the output of llvm-dwarfdump on the above code
> example.
> 
> `g++ -g main.cpp && llvm-dwarfdump a.out | grep DW_TAG_typedef -A 35`
> --------
> 
> 0x0000005c:   DW_TAG_typedef [6]  
>                DW_AT_name [DW_FORM_strp]
> ( .debug_str[0x00000069] = "my_untagged_struct") DW_AT_decl_file
> [DW_FORM_data1]	("/home/luke/main.cpp") DW_AT_decl_line
> [DW_FORM_data1]	(4) DW_AT_type [DW_FORM_ref4]	(cu +
> 0x002d => {0x0000002d})
> 
> 0x00000067:   DW_TAG_subprogram [7] *
>                DW_AT_external [DW_FORM_flag_present]	(true)
>                DW_AT_name [DW_FORM_strp]
> ( .debug_str[0x00000006] = "myfunc") DW_AT_decl_file
> [DW_FORM_data1]	("/home/luke/main.cpp") DW_AT_decl_line
> [DW_FORM_data1]	(6) DW_AT_linkage_name [DW_FORM_strp]
> ( .debug_str[0x0000005d] = "_Z6myfuncP18my_untagged_struct")
> DW_AT_low_pc [DW_FORM_addr]	(0x0000000000400566) DW_AT_high_pc
> [DW_FORM_data8]	(0x0000000000000026) DW_AT_frame_base
> [DW_FORM_exprloc]	(<0x1> 9c ) DW_AT_Unknown_2117
> [DW_FORM_flag_present]	(true) DW_AT_sibling
> [DW_FORM_ref4]	(cu + 0x0095 => {0x00000095})
> 
> 0x00000088:     DW_TAG_formal_parameter [8]  
>                  DW_AT_name [DW_FORM_string]	("s")
>                  DW_AT_decl_file [DW_FORM_data1]
> ("/home/luke/main.cpp") DW_AT_decl_line [DW_FORM_data1]	(6)
>                  DW_AT_type [DW_FORM_ref4]	(cu + 0x0095 =>
> {0x00000095}) DW_AT_location [DW_FORM_exprloc]	(<0x2> 91 68 )
> 
> 0x00000094:     NULL
> 
> 0x00000095:   DW_TAG_pointer_type [9]  
>                DW_AT_byte_size [DW_FORM_data1]	(0x08)
>                DW_AT_type [DW_FORM_ref4]	(cu + 0x005c =>
> {0x0000005c})
> 
> _______________________________________________
> lldb-dev mailing list
> lldb-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev



More information about the lldb-dev mailing list