Stack unwinding fails on x86/x86_64

Hi,

i’m running into stack unwinding issues when trying to get a backtrace for a currently selected thread. You can see the output of diagnose-unwind here: https://gist.github.com/badlogic/99736e5c37f54ea08481

The simple stack walking algorithm in diagnose-unwind succeeds in reconstructing the correct frames.

Any idea what I could be doing wrong or how i could fix this issue?

Thanks,
Mario

Hi Mario, sorry I missed this one over the holidays.

The problem here is the '[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V' function. It has a mid-function epilogue which lldb can't handle today on x86_64. This is a common idiom on armv7/arm64 - I have experience with how to solve the problem there but I had never seen a compiler generate code like this on x86_64 so it wasn't handled there.

In your example session, when you're stopped at 0x000000010014bb5f, lldb is no longer able to backtrace. Looking at the disassembly, we see that 0x10014bb5f is just past a mid-function epilogue. We'll need to update the x86_64 assembly unwinder to recognize the epilogue sequence and re-install the previous unwind state before the epilogue unwound it.

0x10014bb38 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V>: pushq %rbp
0x10014bb39 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+1>: movq %rsp, %rbp
0x10014bb3c <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+4>: subq $0x20, %rsp
0x10014bb40 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+8>: movq %rdi, -0x8(%rbp)
0x10014bb44 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+12>: movq -0x10000(%rsp), %rax
0x10014bb4c <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+20>: movl %esi, -0xc(%rbp)
0x10014bb4f <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+23>: cmpl $0x64, -0xc(%rbp)
0x10014bb53 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+27>: movq %rdi, -0x18(%rbp)
0x10014bb57 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+31>: jle 0x10014bb5f ; [J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V + 39 at InvalidFrame.java:13
0x10014bb59 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+33>: addq $0x20, %rsp
0x10014bb5d <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+37>: popq %rbp
0x10014bb5e <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+38>: retq
0x10014bb5f <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+39>: movl -0xc(%rbp), %eax
0x10014bb62 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+42>: addl $0x1, %eax
0x10014bb65 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+45>: movl %eax, -0x10(%rbp)
0x10014bb68 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+48>: movl -0x10(%rbp), %esi
0x10014bb6b <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+51>: movq -0x18(%rbp), %rdi
0x10014bb6f <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+55>: callq 0x10014bb38 ; [J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V at InvalidFrame.java:10
0x10014bb74 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+60>: addq $0x20, %rsp
0x10014bb78 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+64>: popq %rbp
0x10014bb79 <[J]com.robovm.debug.server.apps.InvalidFrame.testRecursion(I)V+65>: retq

Forgot to respond to all. Sorry Jason!

Hi,

sorry for taking so long. You can find a binary at
http://libgdx.badlogicgames.com/downloads/InvalidFrameTest.zip

This is a debug build for Mac OS X 64-bit. You should be able to run
it, the README.md file has a few notes about that in it. Let me know
if i can help any other way.

Thanks,
Mario

Give top of tree a try if you're still doing codegen like this. Let me know if it doesn't look correct.

Sending source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
Transmitting file data .
Committed revision 225773.

NB I do know about one remaining small problem with this on your example program. The eh_frame augmentation is doing the correct thing, e.g. image show-unwind says that the original eh_frame instructions were

row[0]: 0: CFA=rsp +8 => rip=[rsp]
row[1]: 1: CFA=rsp+16 => rbp=[rsp] rip=[rsp+8]
row[2]: 4: CFA=rbp+16 => rbp=[rbp] rip=[rbp+8]

& the augmented instructions identify the mid-function epilogue at offset 41, re-instate the unwind rules on offset 42, and then get the unwind rules correct for the final epilogue instruction at offset 68:

row[0]: 0: CFA=rsp +8 => rip=[rsp]
row[1]: 1: CFA=rsp+16 => rbp=[rsp] rip=[rsp+8]
row[2]: 4: CFA=rbp+16 => rbp=[rbp] rip=[rbp+8]
row[3]: 41: CFA=rsp +8 => rbp=[rsp-8] rip=[rsp]
row[4]: 42: CFA=rbp+16 => rbp=[rbp] rip=[rbp+8]
row[5]: 68: CFA=rsp +8 => rbp=[rsp-8] rip=[rsp]

But the assembly language unwinder, which you wouldn't use here, is missing the final epilogue. It gets

row[0]: 0: CFA=rsp +8 => rsp=rsp+8 rip=[rsp]
row[1]: 1: CFA=rsp+16 => rbp=[rsp] rsp=rsp+16 rip=[rsp+8]
row[2]: 4: CFA=rbp+16 => rbp=[rbp] rsp=rbp+16 rip=[rbp+8]
row[3]: 41: CFA=rsp +8 => rsp=rsp+8 rip=[rsp]
row[4]: 42: CFA=rbp+16 => rbp=[rbp] rsp=rbp+16 rip=[rbp+8]

I need to track that down still but it's time to go home. For simple test programs I tried, it's doing the correct thing. But there's an off-by-one error with this particular function that I need to track down before this is complete.

J

Sounds great! We are currently in a hot phase regarding our product. May take a bit until i get some time to test with the changes in trunk.

Thanks!
Mario