<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 - Unwind augmentation on x86 is off by one instruction"
   href="https://bugs.llvm.org/show_bug.cgi?id=43561">43561</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Unwind augmentation on x86 is off by one instruction
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>lldb
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>9.0
          </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>normal
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>All Bugs
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>lldb-dev@lists.llvm.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>jarin@google.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>jdevlieghere@apple.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>I believe the x86 augmentation of eh_frame info from assembly is broken: it
computes the unwinding info for offset x from instruction at offset x, but
instead it should be computed from the previous instruction (here is the loop
in question:
<a href="https://github.com/llvm/llvm-project/blob/c118a03e6945805edc88732a33ff51cc4d96db09/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp#L1381">https://github.com/llvm/llvm-project/blob/c118a03e6945805edc88732a33ff51cc4d96db09/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp#L1381</a>).
Looking back at the history of the file, this was likely introduced by the very
first revision of the file
(<a href="https://github.com/llvm/llvm-project/commit/1c9858b298d79ce82c45a2954096718b39550109#diff-375a2be066db6f34bb9a71442c9b71fcL913">https://github.com/llvm/llvm-project/commit/1c9858b298d79ce82c45a2954096718b39550109#diff-375a2be066db6f34bb9a71442c9b71fcL913</a>);
the original version handled this properly by copying the previous instruction
out before advancing the instruction pointer.

It is quite nicely visible in the glibc’s raise function, which has the
following unwinding plan (according to “image show-unwind -a $pc”):

This UnwindPlan originally sourced from eh_frame CFI plus augmentation from
assembly parsing
This UnwindPlan is sourced from the compiler: no.
This UnwindPlan is valid at all instruction locations: yes.
Address range of this UnwindPlan: [libc.so.6..text + 79344-0x00000000000136de)
row[0]:    0: CFA=rsp +8 => rip=[CFA-8]
row[1]:    1: CFA=rsp+16 => rbx=[CFA-16] rip=[CFA-8]
row[2]:   28: CFA=rsp+152 => rbx=[CFA-16] rip=[CFA-8]  << Comes from
augmentation
row[3]:   35: CFA=rsp+152 => rbx=[CFA-16] rip=[CFA-8]
row[4]:  207: CFA=rsp+16 => rbx=[CFA-16] rip=[CFA-8]  << Comes from
augmentation
row[5]:  214: CFA=rsp+16 => rbx=[CFA-16] rip=[CFA-8]
row[6]:  217: CFA=rsp +8 => rbx=[CFA-16] rip=[CFA-8]
row[7]:  218: CFA=rsp +8 => rbx=[CFA-16] rip=[CFA-8]
row[8]:  224: CFA=rsp+152 => rbx=[CFA-16] rip=[CFA-8]

This is already suspicious because of the duplicate lines. Disassembling
confirms the suspicion: offsets 28 and 207 should be still on their original
unwinding rows.

0x7ffff5e94f44:  movl   $0x8, %r10d
0x7ffff5e94f4a:  xorl   %edi, %edi
0x7ffff5e94f4c:  subq   $0x88, %rsp       ;; offset 28
0x7ffff5e94f53:  leaq   -0x78(%rsp), %r9  ;; offset 35
0x7ffff5e94f58:  movq   %rax, 0x8(%rsp)
...
0x7ffff5e94ff8:  movl   $0xe, %eax
0x7ffff5e94ffd:  syscall
0x7ffff5e94fff:  addq   $0x88, %rsp       ;; offset 207
0x7ffff5e95006:  movl   %r8d, %eax        ;; offset 214

It is worth noting the the eh_frame unwinding info is actually correct:

This UnwindPlan originally sourced from eh_frame CFI
This UnwindPlan is sourced from the compiler: yes.
This UnwindPlan is valid at all instruction locations: no.
Address range of this UnwindPlan: [libc.so.6..text + 79344-0x00000000000136de)
row[0]:    0: CFA=rsp +8 => rip=[CFA-8]
row[1]:    1: CFA=rsp+16 => rbx=[CFA-16] rip=[CFA-8]
row[2]:   35: CFA=rsp+152 => rbx=[CFA-16] rip=[CFA-8]
row[3]:  214: CFA=rsp+16 => rbx=[CFA-16] rip=[CFA-8]
row[4]:  218: CFA=rsp +8 => rbx=[CFA-16] rip=[CFA-8]
row[5]:  224: CFA=rsp+152 => rbx=[CFA-16] rip=[CFA-8]


Here is my program and the lldb session that shows the missing stack entry for
the SHOULD_BE_ON_STACK function.

--- main.cpp ---
#include <stdlib.h>

void SHOULD_BE_ON_STACK() {
        abort();
}

int main(int argc, char** argv) {
        SHOULD_BE_ON_STACK();
}

$ lldb MissingStack
(lldb) target create "MissingStack"
Current executable set to 'MissingStack' (x86_64).
(lldb) r
Process 8262 launched: '/srv/game/assets/MissingStack' (x86_64)
Process 8262 stopped
* thread #1, name = 'MissingStack', stop reason = signal SIGABRT
    frame #0: 0x00007ffff5e94fff libc.so.6`__GI_raise(sig=6) at raise.c:51
(lldb) bt
* thread #1, name = 'MissingStack', stop reason = signal SIGABRT
  * frame #0: 0x00007ffff5e94fff libc.so.6`__GI_raise(sig=6) at raise.c:51
    frame #1: 0xfffffffe7fffffff
    frame #2: 0x0000000000201174 MissingStack`main(argc=1,
argv=0x00007fffffffe5e8) at main.cpp:8
    frame #3: 0x00007ffff5e822e1
libc.so.6`__libc_start_main(main=(MissingStack`main at main.cpp:7), argc=1,
argv=0x00007fffffffe5e8, init=<unavailable>, fini=<unavailable>,
rtld_fini=<unavailable>, stack_end=0x00007fffffffe5d8) at libc-start.c:291
    frame #4: 0x000000000020102a MissingStack`_start + 42</pre>
        </div>
      </p>


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

      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>