Open japaric opened 4 years ago
GDB doesn't seem to require this info (
.debug_frame
) to print stack backtraces but GDB also contains a full blown disassembler so I guess it can figure out the missing info on its own
Having interacted with that code I would strongly suggest you not rely on it but rather use the CFI directives. There's nothing more unpleasant than debugging your debugger when it becomes confused by an especially strange stack frame and either gets lost or crashes. (Though I guess the problem might be less acute on ARMv7 than on OR1K.)
Other crates with external assembly:
@japaric Regarding the psp_w and msp_w functions:
I'm not sure if it is possible to properly unwind after overwriting the stack pointer, I don't see a way how the debugger could recover the previous call frame address, it's not stored anywhere.
The functions that overwrite the stack pointer should probably use .cfi_undefined
directives after the instruction
This interacts with https://github.com/rust-embedded/cortex-m/pull/259 – I've removed all the directives there, since rustc should generate them automatically for all Rust functions. But I don't know if that can see through inline assembly and emit unwind info for individual instructions in there.
virtual unwinders (*), for example based on
gimli::{DebugFrame,UnwindSection}
, are not able to unwind through external assembly subroutines like__nop
because these subroutines lack CFI (Call Frame Information), which -- when present -- gets encoded in the.debug_frame
(**) section of the ELF.For subroutines that do not touch the stack pointer or link register adding CFI with no register rules is sufficient to make virtual unwinding work. Adding that CFI looks like this:
And yeah
bx lr
does not count as "touching LR" because it does not modify LR.What needs to be done:
assemble.sh
. Some instructions that do modify SP / LR arepush
,pop
,stmia
,ldmia
,mov
/msr
where SP/LR is the destination (first argument) -- do not modify subroutines that contain those instructions (see "hard part" below)To test this part run the following command on the archives (
bin/*.a*
):You should see one "FDE" for each subroutine that now has CFI.
cortex_m_rt::HardFaultTrampoline
(*) GDB doesn't seem to require this info (
.debug_frame
) to print stack backtraces but GDB also contains a full blown disassembler so I guess it can figure out the missing info on its own(**) AFAIK, for proper stack unwinding, where stack frames are popped and destructors are called as the stack is unwound, one needs
.eh_frame
instead of.debug_frame
. But we are dealing withpanic=abort
targets (which also lack the other unwinding ingredient: "landing pads" big question mark) here so we don't need the "full" version (.eh_frame
).P.S.
cortex-m
is not the only crate that's missing this info.cortex-m-rt
,cortex-m-semihosting
, etc. also need these changes.