[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