mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
0a87846bd8
This function is called when a hard fault occurs. Hard faults happen
when something really bad happens - like writing to unwritable memory or
an unaligned memory access on Cortex-M0. It is not generally possible to
recover from these.
This commit optimizes the code size overhead of hard fault handling:
* It removes the stack overflow checking code.
This may seem like a bad thing, but the only thing this could check
were stack overflows outside goroutines. In practice, this could
only really happen on a stack overflow in the scheduler (unlikely),
or in interrupt code (possible, but interrupts are small so still
unlikely). Most stack overflows happen in regular goroutines, and
weren't caught in the HardFault.
* It makes the panic message similar to a regular panic. This has two
advantages:
* It reduces code size, because the string can be reused between
the HardFault handler and the runtime panic function.
* Using the same pattern automatically makes `-monitor` print the
source address for the hard fault. Not a big benefit as we could
trivially add any other pattern but a nice benefit nonetheless.
Result:
$ tinygo flash -target=microbit -size=short -programmer=openocd -monitor examples/serial
code data bss | flash ram
3036 8 2256 | 3044 2264
[...snip]
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
panic: runtime error at 0x00000344: HardFault with sp=0x200007d0
[tinygo: panic at /home/ayke/src/tinygo/tinygo/src/internal/task/task_stack_cortexm.go:48:4]
(This is with https://github.com/tinygo-org/tinygo/pull/3680 not yet
fixed and some local changes to configure the UART so I can actually see
the panic).
For atsamd21/nrf51 chips this results in a binary size reduction of
around 100 bytes. For other Cortex-M chips it's around 24 bytes but I
hope to change this in the future because a lot of the fault decoding in
runtime_cortexm_hardfault_debug.go should IMHO be done by the TinyGo
monitor instead (I estimate that this would save around 800 bytes on
these chips).
27 lines
1.0 KiB
Go
27 lines
1.0 KiB
Go
//go:build atsamd21 || nrf51
|
|
|
|
package runtime
|
|
|
|
// This function is called at HardFault.
|
|
//
|
|
// For details, see:
|
|
// https://community.arm.com/developer/ip-products/system/f/embedded-forum/3257/debugging-a-cortex-m0-hard-fault
|
|
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
|
//
|
|
//export HardFault_Handler
|
|
func HardFault_Handler() {
|
|
// Obtain the stack pointer as it was on entry to the HardFault. It contains
|
|
// the registers that were pushed by the NVIC and that we can now read back
|
|
// to print the PC value at the time of the hard fault, for example.
|
|
sp := (*interruptStack)(llvm_sponentry())
|
|
|
|
// Note: by reusing the string "panic: runtime error at " we save a little
|
|
// bit in terms of code size as the string can be deduplicated.
|
|
print("panic: runtime error at ", sp.PC, ": HardFault with sp=", sp)
|
|
// TODO: try to find the cause of the hard fault. Especially on Cortex-M3
|
|
// and higher it is possible to find more detailed information in special
|
|
// status registers.
|
|
println()
|
|
abort()
|
|
}
|