[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