[Lldb-commits] [PATCH] D27394: Fix expression evaluation inside lambda functions for gcc

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 6 08:43:37 PST 2016


> On Dec 6, 2016, at 1:42 AM, Tamas Berghammer via Phabricator <reviews at reviews.llvm.org> wrote:
> 
> tberghammer added a reviewer: aprantl.
> tberghammer added a comment.
> 
> +Adrian
> 
> Thank you for all the comment. I agree that teaching the AST Importer to be able to handle types inside a DeclBlock would be the best long term solution but I am not sure about its complexity and feasibility (will take a look).
> 
> For the test Jim pasted clang ~ToT generates the following (IMO fairly bad) debug info:
> 
>   Compilation Unit @ offset 0x0:
>    Length:        0xe5 (32-bit)
>    Version:       4
>    Abbrev Offset: 0x0
>    Pointer Size:  8
>  <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
>     <c>   DW_AT_producer    : (indirect string, offset: 0x0): clang version 4.0.0 (http://llvm.org/git/clang.git 12dcbf43701c142e8313d322c14b53a6c2957826) (http://llvm.org/git/llvm.git 8ab193a8a5383b6a2ddca138c76cfd43bcff6a09)	
>     <10>   DW_AT_language    : 4	(C++)
>     <12>   DW_AT_name        : (indirect string, offset: 0xa5): foo.cpp	
>     <16>   DW_AT_stmt_list   : 0x0	
>     <1a>   DW_AT_comp_dir    : (indirect string, offset: 0xad): /home/tberghammer/tmp	
>     <1e>   DW_AT_low_pc      : 0x400510	
>     <26>   DW_AT_high_pc     : 0x75	
>  <1><2a>: Abbrev Number: 2 (DW_TAG_subprogram)
>     <2b>   DW_AT_low_pc      : 0x400510	
>     <33>   DW_AT_high_pc     : 0x75	
>     <37>   DW_AT_frame_base  : 1 byte block: 56 	(DW_OP_reg6 (rbp))
>     <39>   DW_AT_name        : (indirect string, offset: 0xc3): main	
>     <3d>   DW_AT_decl_file   : 1	
>     <3e>   DW_AT_decl_line   : 3	
>     <3f>   DW_AT_type        : <0xc2>	
>     <43>   DW_AT_external    : 1	
>  <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter)
>     <44>   DW_AT_location    : 2 byte block: 91 78 	(DW_OP_fbreg: -8)
>     <47>   DW_AT_name        : (indirect string, offset: 0xc8): argc	
>     <4b>   DW_AT_decl_file   : 1	
>     <4c>   DW_AT_decl_line   : 3	
>     <4d>   DW_AT_type        : <0xc2>	
>  <2><51>: Abbrev Number: 3 (DW_TAG_formal_parameter)
>     <52>   DW_AT_location    : 2 byte block: 91 70 	(DW_OP_fbreg: -16)
>     <55>   DW_AT_name        : (indirect string, offset: 0xcd): argv	
>     <59>   DW_AT_decl_file   : 1	
>     <5a>   DW_AT_decl_line   : 3	
>     <5b>   DW_AT_type        : <0xc9>	
>  <2><5f>: Abbrev Number: 4 (DW_TAG_lexical_block)
>     <60>   DW_AT_low_pc      : 0x40053a	
>     <68>   DW_AT_high_pc     : 0x1f	
>  <3><6c>: Abbrev Number: 5 (DW_TAG_variable)
>     <6d>   DW_AT_location    : 2 byte block: 91 68 	(DW_OP_fbreg: -24)
>     <70>   DW_AT_name        : (indirect string, offset: 0xd7): my_foo	
>     <74>   DW_AT_decl_file   : 1	
>     <75>   DW_AT_decl_line   : 11	
>     <76>   DW_AT_type        : <0x97>	
>  <3><7a>: Abbrev Number: 0
>  <2><7b>: Abbrev Number: 4 (DW_TAG_lexical_block)
>     <7c>   DW_AT_low_pc      : 0x400563	
>     <84>   DW_AT_high_pc     : 0x1a	
>  <3><88>: Abbrev Number: 5 (DW_TAG_variable)
>     <89>   DW_AT_location    : 2 byte block: 91 60 	(DW_OP_fbreg: -32)
>     <8c>   DW_AT_name        : (indirect string, offset: 0xd7): my_foo	
>     <90>   DW_AT_decl_file   : 1	
>     <91>   DW_AT_decl_line   : 20	
>     <92>   DW_AT_type        : <0xac>	
>  <3><96>: Abbrev Number: 0
>  <2><97>: Abbrev Number: 6 (DW_TAG_structure_type)
>     <98>   DW_AT_name        : (indirect string, offset: 0xda): foo	
>     <9c>   DW_AT_byte_size   : 8	
>     <9d>   DW_AT_decl_file   : 1	
>     <9e>   DW_AT_decl_line   : 7	
>  <3><9f>: Abbrev Number: 7 (DW_TAG_member)
>     <a0>   DW_AT_name        : (indirect string, offset: 0xde): value	
>     <a4>   DW_AT_type        : <0xda>	
>     <a8>   DW_AT_decl_file   : 1	
>     <a9>   DW_AT_decl_line   : 9	
>     <aa>   DW_AT_data_member_location: 0	
>  <3><ab>: Abbrev Number: 0
>  <2><ac>: Abbrev Number: 6 (DW_TAG_structure_type)
>     <ad>   DW_AT_name        : (indirect string, offset: 0xda): foo	
>     <b1>   DW_AT_byte_size   : 2	
>     <b2>   DW_AT_decl_file   : 1	
>     <b3>   DW_AT_decl_line   : 16	
>  <3><b4>: Abbrev Number: 7 (DW_TAG_member)
>     <b5>   DW_AT_name        : (indirect string, offset: 0xde): value	
>     <b9>   DW_AT_type        : <0xe1>	
>     <bd>   DW_AT_decl_file   : 1	
>     <be>   DW_AT_decl_line   : 18	
>     <bf>   DW_AT_data_member_location: 0	
>  <3><c0>: Abbrev Number: 0
>  <2><c1>: Abbrev Number: 0
>  <1><c2>: Abbrev Number: 8 (DW_TAG_base_type)
>     <c3>   DW_AT_name        : (indirect string, offset: 0xe9): int	
>     <c7>   DW_AT_encoding    : 5	(signed)
>     <c8>   DW_AT_byte_size   : 4	
>  <1><c9>: Abbrev Number: 9 (DW_TAG_pointer_type)
>     <ca>   DW_AT_type        : <0xce>	
>  <1><ce>: Abbrev Number: 9 (DW_TAG_pointer_type)
>     <cf>   DW_AT_type        : <0xd3>	
>  <1><d3>: Abbrev Number: 8 (DW_TAG_base_type)
>     <d4>   DW_AT_name        : (indirect string, offset: 0xd2): char	
>     <d8>   DW_AT_encoding    : 6	(signed char)
>     <d9>   DW_AT_byte_size   : 1	
>  <1><da>: Abbrev Number: 8 (DW_TAG_base_type)
>     <db>   DW_AT_name        : (indirect string, offset: 0xe4): long int	
>     <df>   DW_AT_encoding    : 5	(signed)
>     <e0>   DW_AT_byte_size   : 8	
>  <1><e1>: Abbrev Number: 8 (DW_TAG_base_type)
>     <e2>   DW_AT_name        : (indirect string, offset: 0xed): short	
>     <e6>   DW_AT_encoding    : 5	(signed)
>     <e7>   DW_AT_byte_size   : 2	
>  <1><e8>: Abbrev Number: 0
> 
> Clang emits the type information for both foo type into the DW_TAG_subprogram without giving any (explicit) clue about the actual scope for these types. The reason LLDB can still debug this code is that it will import the local variable and then look up the type for that specific variable. My change won't effect this behaviour in any way.

> 
> If we compile the same code with gcc 4.9 then it will emit the debug info for the types inside a DW_TAG_lexical_block (as expected) and that will cause the problem I am trying to fix here. The goal of my fix is to take the debug info emitted by gcc and make it look like the one emitted by clang.
> 

A cast would fail, however, so the behavior is testable:

 > cat tryme.cpp
#include <stdio.h>

int
main(int argc, char **argv)
{
  if (argc < 2)
    {
      struct foo {
        short int var;
      };
      foo my_foo = {10};
      printf ("It is: %d.\n", my_foo.var);
    }
  else
    {
      struct foo {
        long int var;
      };
      foo my_foo = {10};
      void *my_foo_ptr = (void *) &my_foo;
      printf ("It is: %ld %p.\n", my_foo.var, my_foo_ptr);
    }
  return 0;
}
> lldb tryme
(lldb) br s -l 21
Breakpoint 1: where = tryme`main + 95 at tryme.cpp:21, address = 0x0000000100000f3f
(lldb) run a b c d
Process 22305 launched: '/private/tmp/tryme' (x86_64)
Process 22305 stopped
* thread #1: tid = 0x58b4d, function: main , stop reason = breakpoint 1.1
    frame #0: 0x0000000100000f3f tryme`main at tryme.cpp:21
   18  	      };
   19  	      foo my_foo = {10};
   20  	      void *my_foo_ptr = (void *) &my_foo;
-> 21  	      printf ("It is: %ld %p.\n", my_foo.var, my_foo_ptr);
   22  	    }
   23  	  return 0;
   24  	}
(lldb) expr -T -- *(foo *) my_foo_ptr
(foo) $2 = {
  (short) var = 10
}

which is wrong.  It seems a shame to punish producers of correct debug info for the failings of others...

> For the example Sean posted (after adding some white space) I get the following debug info when compiling with ~ToT clang:
> 
>   Compilation Unit @ offset 0x0:
>    Length:        0x12a (32-bit)
>    Version:       4
>    Abbrev Offset: 0x0
>    Pointer Size:  8
>  <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
>     <c>   DW_AT_producer    : (indirect string, offset: 0x0): clang version 4.0.0 (http://llvm.org/git/clang.git 12dcbf43701c142e8313d322c14b53a6c2957826) (http://llvm.org/git/llvm.git 8ab193a8a5383b6a2ddca138c76cfd43bcff6a09)	
>     <10>   DW_AT_language    : 4	(C++)
>     <12>   DW_AT_name        : (indirect string, offset: 0xa5): a.cpp	
>     <16>   DW_AT_stmt_list   : 0x0	
>     <1a>   DW_AT_comp_dir    : (indirect string, offset: 0xab): /home/tberghammer/tmp	
>     <1e>   DW_AT_low_pc      : 0x4004d0	
>     <26>   DW_AT_high_pc     : 0x74	
>  <1><2a>: Abbrev Number: 2 (DW_TAG_subprogram)
>     <2b>   DW_AT_low_pc      : 0x4004d0	
>     <33>   DW_AT_high_pc     : 0x31	
>     <37>   DW_AT_frame_base  : 1 byte block: 56 	(DW_OP_reg6 (rbp))
>     <39>   DW_AT_name        : (indirect string, offset: 0xd0): main	
>     <3d>   DW_AT_decl_file   : 1	
>     <3e>   DW_AT_decl_line   : 1	
>     <3f>   DW_AT_type        : <0x72>	
>     <43>   DW_AT_external    : 1	
>  <2><43>: Abbrev Number: 3 (DW_TAG_class_type)
>     <44>   DW_AT_byte_size   : 1	
>     <45>   DW_AT_decl_file   : 1	
>     <46>   DW_AT_decl_line   : 2	
>  <3><47>: Abbrev Number: 4 (DW_TAG_subprogram)
>     <48>   DW_AT_name        : (indirect string, offset: 0xc1): operator()	
>     <4c>   DW_AT_decl_file   : 1	
>     <4d>   DW_AT_decl_line   : 2	
>     <4e>   DW_AT_type        : <0x72>	
>     <52>   DW_AT_declaration : 1	
>     <52>   DW_AT_external    : 1	
>     <52>   DW_AT_accessibility: 1	(public)
>  <4><53>: Abbrev Number: 5 (DW_TAG_formal_parameter)
>     <54>   DW_AT_type        : <0x79>	
>     <58>   DW_AT_artificial  : 1	
>  <4><58>: Abbrev Number: 0
>  <3><59>: Abbrev Number: 0
>  <2><5a>: Abbrev Number: 3 (DW_TAG_class_type)
>     <5b>   DW_AT_byte_size   : 1	
>     <5c>   DW_AT_decl_file   : 1	
>     <5d>   DW_AT_decl_line   : 9	
>  <3><5e>: Abbrev Number: 4 (DW_TAG_subprogram)
>     <5f>   DW_AT_name        : (indirect string, offset: 0xc1): operator()	
>     <63>   DW_AT_decl_file   : 1	
>     <64>   DW_AT_decl_line   : 9	
>     <65>   DW_AT_type        : <0x72>	
>     <69>   DW_AT_declaration : 1	
>     <69>   DW_AT_external    : 1	
>     <69>   DW_AT_accessibility: 1	(public)
>  <4><6a>: Abbrev Number: 5 (DW_TAG_formal_parameter)
>     <6b>   DW_AT_type        : <0xce>	
>     <6f>   DW_AT_artificial  : 1	
>  <4><6f>: Abbrev Number: 0
>  <3><70>: Abbrev Number: 0
>  <2><71>: Abbrev Number: 0
>  <1><72>: Abbrev Number: 6 (DW_TAG_base_type)
>     <73>   DW_AT_name        : (indirect string, offset: 0xcc): int	
>     <77>   DW_AT_encoding    : 5	(signed)
>     <78>   DW_AT_byte_size   : 4	
>  <1><79>: Abbrev Number: 7 (DW_TAG_pointer_type)
>     <7a>   DW_AT_type        : <0x7e>	
>  <1><7e>: Abbrev Number: 8 (DW_TAG_const_type)
>     <7f>   DW_AT_type        : <0x43>	
>  <1><83>: Abbrev Number: 9 (DW_TAG_subprogram)
>     <84>   DW_AT_low_pc      : 0x400510	
>     <8c>   DW_AT_high_pc     : 0x14	
>     <90>   DW_AT_frame_base  : 1 byte block: 56 	(DW_OP_reg6 (rbp))
>     <92>   DW_AT_object_pointer: <0x9e>	
>     <96>   DW_AT_linkage_name: (indirect string, offset: 0xd5): _ZZ4mainENK3$_0clEv	
>     <9a>   DW_AT_specification: <0x47>	
>  <2><9e>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>     <9f>   DW_AT_location    : 2 byte block: 91 78 	(DW_OP_fbreg: -8)
>     <a2>   DW_AT_name        : (indirect string, offset: 0xfd): this	
>     <a6>   DW_AT_type        : <0x123>	
>     <aa>   DW_AT_artificial  : 1	
>  <2><aa>: Abbrev Number: 11 (DW_TAG_variable)
>     <ab>   DW_AT_location    : 2 byte block: 91 70 	(DW_OP_fbreg: -16)
>     <ae>   DW_AT_name        : (indirect string, offset: 0x102): a1	
>     <b2>   DW_AT_decl_file   : 1	
>     <b3>   DW_AT_decl_line   : 5	
>     <b4>   DW_AT_type        : <0xb8>	
>  <2><b8>: Abbrev Number: 12 (DW_TAG_structure_type)
>     <b9>   DW_AT_name        : (indirect string, offset: 0x107): A	
>     <bd>   DW_AT_byte_size   : 4	
>     <be>   DW_AT_decl_file   : 1	
>     <bf>   DW_AT_decl_line   : 3	
>  <3><c0>: Abbrev Number: 13 (DW_TAG_member)
>     <c1>   DW_AT_name        : (indirect string, offset: 0x105): a	
>     <c5>   DW_AT_type        : <0x72>	
>     <c9>   DW_AT_decl_file   : 1	
>     <ca>   DW_AT_decl_line   : 4	
>     <cb>   DW_AT_data_member_location: 0	
>  <3><cc>: Abbrev Number: 0
>  <2><cd>: Abbrev Number: 0
>  <1><ce>: Abbrev Number: 7 (DW_TAG_pointer_type)
>     <cf>   DW_AT_type        : <0xd3>	
>  <1><d3>: Abbrev Number: 8 (DW_TAG_const_type)
>     <d4>   DW_AT_type        : <0x5a>	
>  <1><d8>: Abbrev Number: 9 (DW_TAG_subprogram)
>     <d9>   DW_AT_low_pc      : 0x400530	
>     <e1>   DW_AT_high_pc     : 0x14	
>     <e5>   DW_AT_frame_base  : 1 byte block: 56 	(DW_OP_reg6 (rbp))
>     <e7>   DW_AT_object_pointer: <0xf3>	
>     <eb>   DW_AT_linkage_name: (indirect string, offset: 0xe9): _ZZ4mainENK3$_1clEv	
>     <ef>   DW_AT_specification: <0x5e>	
>  <2><f3>: Abbrev Number: 10 (DW_TAG_formal_parameter)
>     <f4>   DW_AT_location    : 2 byte block: 91 78 	(DW_OP_fbreg: -8)
>     <f7>   DW_AT_name        : (indirect string, offset: 0xfd): this	
>     <fb>   DW_AT_type        : <0x128>	
>     <ff>   DW_AT_artificial  : 1	
>  <2><ff>: Abbrev Number: 11 (DW_TAG_variable)
>     <100>   DW_AT_location    : 2 byte block: 91 70 	(DW_OP_fbreg: -16)
>     <103>   DW_AT_name        : (indirect string, offset: 0x109): a2	
>     <107>   DW_AT_decl_file   : 1	
>     <108>   DW_AT_decl_line   : 12	
>     <109>   DW_AT_type        : <0x10d>	
>  <2><10d>: Abbrev Number: 12 (DW_TAG_structure_type)
>     <10e>   DW_AT_name        : (indirect string, offset: 0x107): A	
>     <112>   DW_AT_byte_size   : 4	
>     <113>   DW_AT_decl_file   : 1	
>     <114>   DW_AT_decl_line   : 10	
>  <3><115>: Abbrev Number: 13 (DW_TAG_member)
>     <116>   DW_AT_name        : (indirect string, offset: 0x10c): b	
>     <11a>   DW_AT_type        : <0x72>	
>     <11e>   DW_AT_decl_file   : 1	
>     <11f>   DW_AT_decl_line   : 11	
>     <120>   DW_AT_data_member_location: 0	
>  <3><121>: Abbrev Number: 0
>  <2><122>: Abbrev Number: 0
>  <1><123>: Abbrev Number: 7 (DW_TAG_pointer_type)
>     <124>   DW_AT_type        : <0x7e>	
>  <1><128>: Abbrev Number: 7 (DW_TAG_pointer_type)
>     <129>   DW_AT_type        : <0xd3>	
>  <1><12d>: Abbrev Number: 0
> 
> It doesn't contain any DW_TAG_lexical_block so this change won't have any effect on the behaviour. I tested it with LLDB both before this change and after this change and it seems to work as expected for me (seeing the frame variables and can evaluate expressions).
> 
> For the test I opted to try to run an expression while we are stopped inside a lambda expression because that is the original problem I am trying to solve and I think having a test like this is a good idea anyway. It effects the code modified by this CL because both gcc and clang generated an artificial for every lambda created to hold the function call operator and the captured variables. If people think that we should have a test for the case Jim posted I can write a separate test for that.

I am still not in favor of this way of doing the fix.  We're doing something that is certainly formally incorrect, and which you can tell is wrong with a fairly common expression.  We'll forget we did this because it comes up in so few cases, but some poor person out there is going to waste hours of their day trying to figure out why their cast didn't work, and maybe they won't even be the person who wrote the code that questionable way, so it was in no way their fault...

Jim


> 
> 
> https://reviews.llvm.org/D27394
> 
> 
> 



More information about the lldb-commits mailing list