runtime: libunwind is unable to unwind CGo to Go's stack #40044
Comments
This is different from #39524 . We switch stacks at Go/C boundaries. Go code runs on goroutine stacks (typically small), whereas C code runs on system stacks (typically large). Since they are not on the same stack, I would not expect any stack unwinding tool to work. Not sure if there is anything we could do. Maybe we could use the frame pointer to "fake" it? Not sure this is a good idea... |
Indeed. Thinking about it however, it doesn't feel that hard to do. Either by locally modifying asmcgocall, or, in a more ambitious way, via |
Also, weirdly enough, lldb is able to do it, without dwarf. |
I am also realizing this is very different from #39524 indeed. But in some way, since |
If you want to unwind from C++ back into Go you may want to try github.com/ianlancetaylor/cgosymbolizer. Although that will only help from the Go side, not the C++ side. In principle we could hand write unwind information for |
@ianlancetaylor thank you. The issue, on the iOS side, is that unwinding is done locally, on the device (presumably with libunwind), without DWARF. DWARF is only added later to symbolicate the crashes. That said, it could be useful for Android (which uses breakpad with minidumps) @cherrymui I tried that forsaken piece of code to, in order to call the backtrace method without cgo, and alas, the unwinding still stops before it somehow. This is based on the rustgo article: TEXT ·backtracetrampoline(SB),0,$2048
MOVQ SP, BX // Save SP in a callee-saved registry
ADDQ $2048, SP // Rollback SP to reuse this function's frame
ANDQ $~15, SP // Align the stack to 16-bytes
CALL backtrace(SB)
MOVQ BX, SP // Restore SP
RET |
@steeve Sorry, I'm not sure exactly what you're planning to do, and why Also, on what architecture? You mentioned iOS (presumably ARM64), but also AMD64 in your That said, does CL https://go-review.googlesource.com/c/go/+/241080 makes any difference (on ARM64)? Thanks. |
@cherrymui Thank you for the CL, I wasn't hoping as much. Will definitely try and let you know. My ultimate target is indeed iOS (and Android, to an extent). |
Change https://golang.org/cl/241158 mentions this issue: |
@steeve libunwind unwinds the stack using the unwind information, which is not DWARF but is approximately the same format as a subset of DWARF. That's what I was referring to when I suggested that we could write unwind information for |
I just tried your CL @cherrymui on a real device, and unfortunately, when I pause inside XCode's, I only see the stack up to In my case I did put a
Note that on amd64, |
What version of Go are you using (
go version
)?master
as of the buildDoes this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Following @cherrymui's comment on #39524, I figured I tried to check why lots of our backtraces on iOS stop at
runtime.asmcgocall
.Since I wanted to reproduce it on my computer and
lldb
manges to properly backtrace, I figured I'd givelibunwind
a try, since this is was iOS uses when a program crashes.Unfortunately
libunwind
didn't manage to walk the stack past CGo generated_Cfunc_
functions.Given this program:
It prints:
I tried doing Go(1) -> C(1) -> Go(2) -> C(2) and backtrace, and it only unwinds C(2).
Also, I tried to make set
asmcgocall
to have a 16 bytes stack, hoping that the generated frame pointer would help, but it didn't.What did you expect to see?
The complete backtrace.
What did you see instead?
A backtrace for C functions only.
The text was updated successfully, but these errors were encountered: