mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
arm: use CFI directives for stack usage
Call Frame Information is stored in the .debug_frame section and is used
by debuggers for unwinding. For assembly, this information is not known.
Debuggers will normally use heuristics to figure out the parent function
in the absence of call frame information.
This usually works fine, but is not enough for determining stack sizes.
Instead, I hardcoded the stack size information in
stacksize/stacksize.go, which is somewhat fragile. This change uses CFI
assembly directives to store this information instead of hardcoding it.
This change also fixes the following error message that would appear in
GDB:
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
More information on CFI:
* https://sourceware.org/binutils/docs/as/CFI-directives.html
* https://www.imperialviolet.org/2017/01/18/cfi.html
This commit is contained in:
committed by
Ron Evans
parent
6ad6f14a04
commit
50a677e9b7
+11
-2
@@ -207,6 +207,15 @@ func (fi *frameInfo) exec(bytecode []byte) ([]frameInfoLine, error) {
|
||||
switch lowBits {
|
||||
case 0: // DW_CFA_nop
|
||||
// no operation
|
||||
case 0x07: // DW_CFA_undefined
|
||||
// Marks a single register as undefined. This is used to stop
|
||||
// unwinding in tinygo_startTask using:
|
||||
// .cfi_undefined lr
|
||||
// Ignore this directive.
|
||||
_, err := readULEB128(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 0x0c: // DW_CFA_def_cfa
|
||||
register, err := readULEB128(r)
|
||||
if err != nil {
|
||||
@@ -225,10 +234,10 @@ func (fi *frameInfo) exec(bytecode []byte) ([]frameInfoLine, error) {
|
||||
}
|
||||
fi.cfaOffset = offset
|
||||
default:
|
||||
return nil, fmt.Errorf("could not decode .debug_frame bytecode op 0x%x", op)
|
||||
return nil, fmt.Errorf("could not decode .debug_frame bytecode op 0x%x (for address 0x%x)", op, fi.loc)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("could not decode .debug_frame bytecode op 0x%x", op)
|
||||
return nil, fmt.Errorf("could not decode .debug_frame bytecode op 0x%x (for address 0x%x)", op, fi.loc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,14 +181,6 @@ func CallGraph(f *elf.File, callsIndirectFunction []string) (map[string][]*CallN
|
||||
switch f.Machine {
|
||||
case elf.EM_ARM:
|
||||
knownFrameSizes := map[string]uint64{
|
||||
// implemented in assembly in TinyGo
|
||||
"tinygo_startTask": 0, // thunk
|
||||
"tinygo_getSystemStackPointer": 0, // getter
|
||||
"tinygo_switchToScheduler": 0, // calls tinygo_swapTask
|
||||
"tinygo_switchToTask": 0, // calls tinygo_swapTask
|
||||
"tinygo_swapTask": 9 * 4, // 9 registers saved
|
||||
"tinygo_scanCurrentStack": 9 * 4, // 9 registers saved
|
||||
|
||||
// implemented with assembly in compiler-rt
|
||||
"__aeabi_uidivmod": 3 * 4, // 3 registers on thumb1 but 1 register on thumb2
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user