This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Back trace from hard fault handler with s110 flashed?

I'm using Nordic NRF51822 and the Segger JLink with the s110 Bluetooth stack active (correction: flashed on the chip, see below). When my code hard faults (say due to a dereferencing an invalid pointer), I see only the following stack trace:

(gdb) bt
#0  HardFault_HandlerC (hardfault_args=<optimized out> ) at main_display.cpp:440
#1  0x00011290 in ?? ()

I have a hard fault handler installed (see attached file) and it can give me the lr and pc:

(gdb) p/x stacked_pc
$1 = 0x18ea6
(gdb) p/x stacked_lr
$2 = 0x18b35

And I know I can use addr-to-line to translate these to source code lines:

> arm-none-eabi-addr2line -e main_display.elf 0x18ea6
/Users/cmason/code/nrf/src/../libs/epaper/EPD_Display.cpp:33
> arm-none-eabi-addr2line -e main_display.elf 0x18b35
/Users/cmason/code/nrf/src/../libs/epaper/EPD.cpp:414

Can I get the rest of the backtrace somehow? If I stop at a normal breakpoint I can get a backtrace, so I know GDB can do the (somewhat complex) algorithm to unwind the stack on ARM. I understand that, in the general case, the stack may be screwed up by my code to the point where it's unreadable, but I don't think that's what's happening in this case.

I think this may be complicated by the s110 memory protection scheme. I'd guess that the Nordic Hard Fault handler is at 0x00011290 and that it is executing on an alternate stack from my code. Nordic's Hard Fault handler is calling mine.

Can I somehow get GDB to display the stack trace of my (user mode) stack instead of this special protected mode stack?

Thanks!

-c

hard_fault_handler.c

  • Does anyone have an ideas here? Can I modify the fault handler somehow to give me access to the frame pointer? See also the same question at Stack Overflow: http://stackoverflow.com/questions/18640673/gdb-backtrace-from-hard-fault-handler-on-arm-cortex-m0-nrf51822

  • I'm sorry for the delay, but I've been digging around a little today, experimenting with different handlers and inspecting the stack manually, and as far as I can see, this isn't really possible. However, to be a little more certain, it would have been useful to have a look at your HardFault handlers. Could you upload a code file with them here?

  • I've attached the code, which comes directly from the link in my original post. Would it be possible to post the code from s110's hard fault handler? Does it have attribute((naked))? Does it just directly forward to the handler in my interrupt vector? I'm confused, based on reading docs [1], why both the Nordic and my fault handlers are not simply pushed onto the existing stack...

    [1] http://infocenter.arm.com/help/topic/com.arm.doc.dui0497a/Babefdjc.html#BABDBGGA

  • Unfortunately, as far as I can see, there is something about a HardFault occuring that causes the GDB backtracing to be confused, no matter if the softdevice is currently on the chip or not.

    When testing this, I've been using the following code to cause a hardfault in a simple program:

    
    void cause_hardfault(void)
    {
    	uint32_t * cause_hardfault = (uint32_t *) 0x1;
    	
    	uint32_t value = *cause_hardfault;
    	(void) value;
    }
    
    

    When running this, even with no softdevice on the chip, I'm not able to get any reasonable backtrace from any hardfault handlers. When inspecting memory manually, it does however seem that the stack isn't corrupted, but no matter what I try to set the current frame to, GDB won't give me any useful backtrace.

    I have to admit that I'm on thin ice regarding my own knowledge here, so there could very well be some (potentially easy) trick that can be done to "explain" GDB how to read the stack. It would have been very interesting if either someone here, or someone on Stack Overflow could come up with something!

  • Ole, I really appreciate you investigating, but I'm afraid I'm not seeing the same thing you are.

    I just reconfirmed that I am indeed able to see backtraces in gdb from HardFault handlers when the soft device is not flashed on the NRF51822.

    If I run this program:

    
    #include <stdint.h>
    
    void cause_hardfault(void)
    {
        uint32_t * cause_hardfault = (uint32_t *) 0x1;
    
        uint32_t value = *cause_hardfault;
        (void) value;
    }
    
    int do_something(int unused) {
        cause_hardfault();
        return 1;
    }
    
    int main() {
        do_something(0);
        return 0;
    }
    
    
    

    And I compile, using gcc-arm-none-eabi-4_7-2013q2 like such:

    
    arm-none-eabi-gcc -Wall -g3 -O0 -mcpu=cortex-m0 -mthumb -c main_crash.c
    arm-none-eabi-gcc -Wall -g3 -O0 -mcpu=cortex-m0 -mthumb -c nRF51822.c
    arm-none-eabi-gcc -Wall -g3 -O0 -mcpu=cortex-m0 -mthumb -c error.c
    arm-none-eabi-gcc -O0  -g3 -mcpu=cortex-m0 -mthumb -TnRF51822-bare.ld -o main_crash.elf main_crash.o  nRF51822.o error.o -lg_s -lc_s -lrdimon
    
    

    I then flash this on the chip with no soft device present.

    I get this stack trace:

    
    Breakpoint 1, main () at main_crash.c:17
    17	    do_something(0);
    (gdb) c
    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    HardFault_HandlerC (hardfault_args=0x20003fa8) at error.c:58
    58	    __asm("BKPT #0"  ) ; // Break into the debugger
    (gdb) bt
    #0  HardFault_HandlerC (hardfault_args=0x20003fa8) at error.c:58
    #1  <signal handler called>
    #2  0x000004e0 in cause_hardfault () at main_crash.c:7
    #3  0x000004f8 in do_something (unused=0) at main_crash.c:12
    #4  0x0000050e in main () at main_crash.c:17
    
    

    I've also tried with -O2 and -Os. All of these work when I do not have the s110 stack flashed on the chip.

    However, if I use the soft device ld file:

    
    arm-none-eabi-gcc -O0  -g3 -mcpu=cortex-m0 -mthumb -TnRF51822-softdevice.ld -o main_crash.elf main_crash.o  nRF51822.o error.o -lg_s -lc_s -lrdimon
    
    

    And flash it onto a chip where the soft device has also been loaded, I get this stack trace:

    Breakpoint 1, main () at main_crash.c:17 17 do_something(0); (gdb) c

    
    Program received signal SIGTRAP, Trace/breakpoint trap.
    HardFault_HandlerC (hardfault_args=0x20003fa8) at error.c:58
    58	    __asm("BKPT #0"  ) ; // Break into the debugger
    (gdb) bt
    #0  HardFault_HandlerC (hardfault_args=0x20003fa8) at error.c:58
    #1  0x00011290 in ?? ()
    #2  0x00011290 in ?? ()
    Backtrace stopped: previous frame identical to this frame (corrupt stack?)
    

    It's not necessary for the s110 to be active, but if it is flashed on the chip, then I get ?? backtraces like the ones shown in the above.

    I've attached a zip of a project with Makefile that demonstrates this. Use:

    
    make NRF51_USE_SOFTDEVICE=0 all
    make clean
    make NRF51_USE_SOFTDEVICE=1 all
    
    

    to test. I use the JLink to clear the flash between runs so none of the soft device is left in flash.

    I have to conclude that something about the presence of the s110 soft device causes gdb to not be able to report stack traces from hard faults.

    Again, would it be possible for you to share the contents of the s110 HardFault handler function?

    Thank you so much for your kind attention!

    -c

Related