cancel
Showing results for 
Search instead for 
Did you mean: 

gdb backtrace/ exception handlers

geoffreymbrown
Associate II
Posted on May 24, 2012 at 20:20

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 ?

Geoffrey

5 REPLIES 5
frankmeyer9
Associate II
Posted on May 24, 2012 at 20:38

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.

geoffreymbrown
Associate II
Posted on May 24, 2012 at 21:00

I tracked down that code, which really just extracts the saved state from the stack.  I'm thinking something more like faking a signal trampoline so that gdb will do the unwinding.  I did this in a past life for a processor we built at HP and it was very effective.  But that's so long ago, that I forget the key bits.

I understand your warning about stack size. I was being a bit facetious with the ''very occasionally''.  Actually it's not an uncommon event when learning the ins and outs of programming the stm32 and I was thinking more of the needs of my students.

Geoffrey
Posted on May 24, 2012 at 22:42

''...thinking more of the needs of my students''

Sounds like an ideal opportunity for them to learn how to unwind the stack for themselves...
geoffreymbrown
Associate II
Posted on May 25, 2012 at 23:00

''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.
geoffreymbrown
Associate II
Posted on June 05, 2012 at 22:50

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

}