PR open:
https://bitbucket.org/hudson/magic-lantern/pull-requests/849/stack-trace-aka-backtrace-in-crash-logs/diffHow does it work?
It attempts to figure out where return addresses are on the stack (some sort of stack unwinding). On ARM, when a function call is made, the return address is saved in the LR register; with nested calls, LR is pushed on the stack (and restored on return). However, the stack contains a bunch of other stuff, so it's not straightforward to tell what positions on the stack were used for LR.
To find the return address of a function, this code attempts to "emulate" the ARM program from the current position (e.g. where the exception happened) until it gets out of the function. The interesting things to emulate are:
- instructions that modify SP
- direct jumps (they should be followed)
- instructions that restore LR (POP)
- function calls are skipped (they shouldn't modify SP according to the ABI)
Sometimes the "emulation" may get stuck in a loop, without being able to find the end of the function. To find a solution, I've tried to take conditional branches randomly, hoping one of them would be lucky. It helps in some cases, but not much. It's not enabled by default.
After writing all this code, I've found out I might have been reinventing the wheel:
- g3gg0 has an interesting heuristic in
gdb.c: check each item and see whether it looks like a valid LR (whether there's a call instruction at that LR); that's worth trying as a backup strategy (edit: DONE).
-
this public domain code appears to do something similar.
Didn't try it yet. edit: tried it; if anyone would like to see a comparison, just ask.
-
stack unwinding for Thumb using the same idea.
However,
all the solutions I've found before writing this code required some sort of debugging info (dwarf) or frame pointer (not present in Canon code). Maybe I didn't know what keywords to use.