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

Reply via email to