[DWARF] Tracking uninitialized variables

Nikolai Bozhenov n.bozhenov@samsung.com
Mon Jul 20 16:55:00 GMT 2015


On 07/17/2015 08:31 PM, Michael Eager wrote:
> On 07/17/2015 03:43 AM, Nikolai Bozhenov wrote:
>> Consider the following example:
>>
>>      1 extern void bar(int *i1, int *i2, int *i3);
>>      2
>>      3 int __attribute__((noinline)) foo(int i1, int i2) {
>>      4   int a, b, c;
>>      5   a = i1 << i2;
>>      6   b = (i1 + i2) * i1;
>>      7   c = (b + i1);
>>      8   bar(&a, &b, &c);
>>      9 }
>>     10
>>     11 int main() {
>>     12   foo(42, 12);
>>     13 }
>>
>> Let's compile it:
>>
>>     $ gcc-trunk tst.c -g -fvar-tracking-uninit -O2
>>
>> After hitting a breakpoint at line 8 (the last line of the function
>> foo) I have some random (and very confusing) values displayed in gdb
>> for all three variables a, b and c. This is because GCC allocates
>> these three variables on the stack (their addresses are taken) and
>> creates for them DWARF entries like this:
>>
>>     <2><a8>: Abbrev Number: 8 (DW_TAG_variable)
>>        <a9>   DW_AT_name        : a
>>        <ab>   DW_AT_decl_file   : 1
>>        <ac>   DW_AT_decl_line   : 4
>>        <ad>   DW_AT_type        : <0x64>
>>        <b1>   DW_AT_location    : 2 byte block: 91 64 (DW_OP_fbreg: -28)
>
> This (incorrectly) says that the variable is at the specified location
> for the entire scope of the function.  This should be a location list,
> which specifies the live range for the variable.  At the breakpoint,
> this location list would/should have no location for the variable.
>
> A related issue is where the breakpoint is taken.  GCC sets breakpoints
> at the first instruction generated for a statement, which in this case,
> appears to be before any of the arguments to bar are evaluated.  A
> possibly better location would be after arguments are evaluated, before
> the call is executed.
>

Not sure that this is a GCC issue. I annotated instructions with line
numbers taken from debug info that GCC generated for the function and
these numbers look perfectly correct:

    0000000000000000 <foo>:
       0:   89 f1                   mov    %esi,%ecx       // 5
       2:   01 fe                   add    %edi,%esi       // 6
       4:   48 83 ec 18             sub    $0x18,%rsp      // 3
       8:   0f af f7                imul   %edi,%esi       // 6
       b:   89 f8                   mov    %edi,%eax       // 5
       d:   48 8d 54 24 0c          lea    0xc(%rsp),%rdx  // 8
      12:   d3 e0                   shl    %cl,%eax        // 5
      14:   89 44 24 04             mov    %eax,0x4(%rsp)  // 5
      18:   89 74 24 08             mov    %esi,0x8(%rsp)  // 6
      1c:   01 fe                   add    %edi,%esi       // 7
      1e:   48 8d 7c 24 04          lea    0x4(%rsp),%rdi  // 8
      23:   89 74 24 0c             mov    %esi,0xc(%rsp)  // 7
      27:   48 8d 74 24 08          lea    0x8(%rsp),%rsi  // 8
      2c:   e8 00 00 00 00          callq  31 <foo+0x31>   // 8
      31:   48 83 c4 18             add    $0x18,%rsp      // 9
      35:   c3                      retq                   // 9

In this case GDB set the breakpoint at the instruction at 0x0d where
evaluation of the first argument for the call is performed. I'm not
sure that there is a less confusing way to choose an address to set a
breakpoint. For example I don't think it is a good idea to ignore
evaluation of function arguments and set a breakpoint right at the
call instruction. But even if there is a better way, such new feature
is likely to be implemented in GDB rather than in GCC.

Nikolai



More information about the Gcc mailing list