2012-05-24 11:20 AM
Very occasionally, my code takes an unexpected exception and ends up in a default handler :)
I'd like to write such a handler so that GDB can successfully unwind the stack. For example,default_handler (void) { asm(''ldr lr, [sp, #28]''); while(1); }loads the link register from the value stored when the exception was taken (actually, it should be 24, but this is a quick hack because gcc does an extra push). With that I can at least see the call chain, but of course the register values aren't right and I don't see the frame that caused the exception. I'm thinking there's a magic incantation that would set things up so that gdb could properly unwind the stack (e.g. make it look a call to a signal handler ??)Any thoughts ?Geoffrey2012-05-24 11:38 AM
There is some example code for such an exception handler around in the internet, written by Joseph Yiu.
However, seemingly random crashes are often caused by insufficient stack size. Crossworks, for instance, is a little stinted in this regard. The default setting for the stack size is just 128 bytes, crashing every nontrivial code sooner or later.2012-05-24 12:00 PM
2012-05-24 01:42 PM
''...thinking more of the needs of my students''
Sounds like an ideal opportunity for them to learn how to unwind the stack for themselves...2012-05-25 02:00 PM
''Sounds like an ideal opportunity for them to learn how to unwind the stack for themselves...''
Perhaps, but there's a limit to the number of ratholes I can afford to send them down in one semesters. Their plates will be overflowing as it is.I think the way to do this is to push a sigcontext on the stack and fake a call from the trampoline code that gdb expects to find. Now I have to track down what gdb understands about signals in the arm part of its code.I have done this before, but then I was porting GDB to a new architecture. Plus it's been a dozen years, so the synapses are a bit rusted. I was hoping somebody had already done the heavy lifting.2012-06-05 01:50 PM
Here's a partial solution (no luck on getting gdb to do the unwinding).
#include <stm32f10x.h>#include <core_cm3.h>struct fault_saved{ unsigned int arm_r4; unsigned int arm_r5; unsigned int arm_r6; unsigned int arm_r7; unsigned int arm_r8; unsigned int arm_r9; unsigned int arm_r10; unsigned int arm_fp; // saved by hardware unsigned int arm_r0; unsigned int arm_r1; unsigned int arm_r2; unsigned int arm_r3; unsigned int arm_ip; unsigned int arm_lr; unsigned int arm_pc; unsigned int arm_cpsr;};void default_handler (void){ asm('' add r1, sp, #32\n'' // old stack pointer '' sub sp, sp, #32\n'' // allocate additional storage '' stmia sp, {r4-r11}\n'' // save registers '' mov r0, sp\n'' '' b default_handler_c\n'');}void default_handler_c(struct fault_saved *saved, unsigned int sp){ if (CoreDebug->DHCSR & 1) { // check C_DEBUGEN == 1 -> Debugger Connected asm(''bkpt 0\n''); } while (1); // enter endless loop otherwise}