<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [DebugInfo] Location list entries expressed in caller-saved registers are incompatible for unwinding with GDB"
   href="https://bugs.llvm.org/show_bug.cgi?id=39752">39752</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[DebugInfo] Location list entries expressed in caller-saved registers are incompatible for unwinding with GDB
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>DebugInfo
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>david.stenberg@ericsson.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>jdevlieghere@apple.com, keith.walker@arm.com, llvm-bugs@lists.llvm.org, paul_robinson@playstation.sony.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>(This might be a known issue.)

Consider the following example:

    int global;

    __attribute__((noinline)) void fn3(int p3) {
      global = p3;
      /* Thrash parameter register. */
      __asm volatile ("movl $999, %%edi" : : : "%edi");
    }

    __attribute__((noinline)) int fn2(int p2) {
      global = p2;
      fn3(p2);
      return 0;
    }

    __attribute__((noinline)) int fn1(int p1) {
      global = p1;
      fn2(p1);
      return 0;
    }

    int main() {
      return fn1(111);
    }

compiled using:

    clang -target x86_64 -O3 -g test.c -o test.out

For fn2 we emit the following assembly:

    (gdb) disas fn2
    Dump of assembler code for function fn2:
       0x0000000000400500 <+0>:     push   %rbp
       0x0000000000400501 <+1>:     mov    %rsp,%rbp
       0x0000000000400504 <+4>:     mov    %edi,0x200b2a(%rip)        #
0x601034 <global>
       0x000000000040050a <+10>:    callq  0x4004e0 <fn3>
       0x000000000040050f <+15>:    xor    %eax,%eax
       0x0000000000400511 <+17>:    pop    %rbp
       0x0000000000400512 <+18>:    retq
    End of assembler dump.

and the following location list for p2:

    (gdb) info addr p2
    Symbol "p2" is multi-location:
      Range 0x400500-0x40050f: a variable in $rdi

As seen, we say that p2 is valid during the call. The same situation holds for
fn1 and p1.

When unwinding with GDB, which (at least for x86-64) relies on the DWARF
information to tell if a register is caller-saved, we will print invalid values
for the unwound p1 and p2 variables after we have thrashed $edi in fn3:

    (gdb) disas
    Dump of assembler code for function fn3:
       0x00000000004004e0 <+0>:     push   %rbp
       0x00000000004004e1 <+1>:     mov    %rsp,%rbp
       0x00000000004004e4 <+4>:     mov    %edi,0x200b4a(%rip)        #
0x601034 <global>
       0x00000000004004ea <+10>:    mov    $0x3e7,%edi
    => 0x00000000004004ef <+15>:    pop    %rbp
       0x00000000004004f0 <+16>:    retq
    End of assembler dump.
    (gdb) bt
    #0  fn3 (p3=<optimized out>) at test.c:11
    #1  0x000000000040050f in fn2 (p2=999) at test.c:15
    #2  0x000000000040052f in fn1 (p1=999) at test.c:21
    #3  0x000000000040054e in main () at test.c:26

This is not an issue with LLDB, as it is ABI-aware, and does not print out any
caller-saved registers in outer frames.

When unwinding, GDB and LLDB assume that the address is (return_address - 1)
when printing variables, etc. GCC seems to utilize this fact to get the
location expression correct for the caller-saved described variable, by ending
the location list entry right before that:

GCC 5.4.0 output:

    (gdb) disas fn2
    Dump of assembler code for function fn2:
       0x0000000000400500 <+0>:     mov    %edi,0x200b2e(%rip)        #
0x601034 <global>
       0x0000000000400506 <+6>:     callq  0x4004f0 <fn3>
       0x000000000040050b <+11>:    xor    %eax,%eax
       0x000000000040050d <+13>:    retq
    End of assembler dump.

    (gdb) info addr p2
    Symbol "p2" is multi-location:
      Range 0x400500-0x40050a: a variable in $rdi
      Range 0x40050a-0x40050e: a complex DWARF expression:
         0: DW_OP_GNU_entry_value
           2: DW_OP_reg5 [$rdi]
         3: DW_OP_stack_value

As seen, the first address after the call is 0x40050b, but the (exclusive)
ending address for p2 in the location list entry is 0x40050a.

Would it make sense to adapt LLVM to this behavior to be GDB compatible? Or is
it an acceptable incompatibility?

If we instead want to go the CFI route, maybe the compiler could emit
DW_CFA_undefined for caller-saved registers when they are clobbered?</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>