[DWARF] Tracking uninitialized variables

Michael Eager eager@eagerm.com
Fri Jul 17 17:31:00 GMT 2015


On 07/17/2015 03:43 AM, Nikolai Bozhenov wrote:
> Hello!
>
> It is certainly true that debugging an optimized code is an inherently
> difficult task. Though, I wonder if the compiler could make such
> debugging experience slightly less surprising.
>
> 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.

>
> That is, actual values for variables are supposed to reside in fixed
> stack slots throughout the whole function. But in fact, by the time
> the breakpoint is hit none of the values is stored on the stack (the
> last line of the function, evaluation of the first argument for the
> call):
>
>     Dump of assembler code for function foo:
>        0x00000000004004c0 <+0>:     mov    %esi,%ecx
>        0x00000000004004c2 <+2>:     add    %edi,%esi
>        0x00000000004004c4 <+4>:     sub    $0x18,%rsp
>        0x00000000004004c8 <+8>:     imul   %edi,%esi
>        0x00000000004004cb <+11>:    mov    %edi,%eax
>     => 0x00000000004004cd <+13>:    lea    0xc(%rsp),%rdx
>        0x00000000004004d2 <+18>:    shl    %cl,%eax
>        0x00000000004004d4 <+20>:    mov    %eax,0x4(%rsp)
>        0x00000000004004d8 <+24>:    mov    %esi,0x8(%rsp)
>        0x00000000004004dc <+28>:    add    %edi,%esi
>        0x00000000004004de <+30>:    lea    0x4(%rsp),%rdi
>        0x00000000004004e3 <+35>:    mov    %esi,0xc(%rsp)
>        0x00000000004004e7 <+39>:    lea    0x8(%rsp),%rsi
>        0x00000000004004ec <+44>:    callq  0x4004f6 <bar>
>        0x00000000004004f1 <+49>:    add    $0x18,%rsp
>        0x00000000004004f5 <+53>:    retq
>     End of assembler dump.
>
> By contrast, If I didn't take addresses of these variables, they would
> be <optimized out> until we can determine their correct values. I
> believe that such behavior is much better than displaying wrong values
> for variables. Also, GCC seems to be able to produce DW_OP_GNU_uninit
> operations to mark uninitialized variables (when -fvar-tracking-uninit
> is used) but I've never seen it in generated debug info.
>
> At first glance the problem seems to have something to do with the
> fact that there's no gimple_debug/BIND and debug_insn/var_location
> instructions for such stack variables in internal representation.
> There are only statements like this:
>
>     gimple_assign <lshift_expr, a.0_3, i1_1(D), i2_2(D), NULL>
>     # .MEM_5 = VDEF <.MEM_4(D)>
>     gimple_assign <ssa_name, a, a.0_3, NULL, NULL>
>
> and *no* BIND statement like gimple_debug BIND <a, a.0_3>
>
> Furthermore, in dwarf2out.c there are a lot of calls to
> mem_loc_descriptor where var_init_status is unconditionally set to
> VAR_INIT_STATUS_INITIALIZED. And it looks like currently all values
> in memory are considered to be initialized by default. And only in
> few places NOTE_VAR_LOCATION_STATUS is taken into account (anyway,
> there's no such notes for variables a, b, c in this case).
>
> So, here are my questions:
> 1) Wouldn't it be nice if GCC marked such stack variables either as
>     uninitialized (with DW_OP_GNU_uninit) or as <optimized out>?
> 2) Is it feasible to implement such tracking for variables?
> 3) What exactly is GCC supposed to track with -fvar-tracking-uninit
>     option?
>
>
> Thanks,
> Nikolai
>


-- 
Michael Eager	 eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306  650-325-8077



More information about the Gcc mailing list