[SOLVED] GDBServer: Call Stack reconstruction in fault condition

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • Hi,

    in the link you provided is to be read "works in conjunction with a tiny hard fault exception handler". I'm sure most of the work for getting the call stack
    built up correctly is done in this handler, as the call stack is completely generated by the GDB client using the GDB Server only for reading memory.

    We already have Tools, which can build up the call stack even from within an exception handler.

    Maybe you want to give Ozone - The J-Link Debugger a try?

    Our IDE Embedded Studio is also able to do this and is available free of charge for evaluation and non-profit educational purposes.

    Best regards,

  • I tried to use the stacked lr

    C Source Code

    1. __asm volatile(" tst lr, #4 \n" );
    2. __asm volatile(" ite eq \n" );
    3. __asm volatile(" mrseq r0, msp \n" );
    4. __asm volatile(" mrsne r0, psp \n" );
    5. __asm volatile(" ldr lr, [r0,#20] \n" ); //use the stacked lr

    but this did not produce good results.

    for now, I'm getting the best results when I write the actual msp/psp to the sp.

    what is your impression?

    The post was edited 1 time, last by pruesch ().

  • ooookayy...

    it seems like I used the wrong offset to get the stacked lr from the stack frame.

    I was confused because the this hardfault handler uses offset 5 as lr...

    if I take the lr pc with an offset of 24 bytes, and write it to the lr, the call stack is even more beautiful once the breakpoint instruction is hit.
    see the attached screenshot.

    how can I make the debug view focused on that lr address? like manipulating the pc and trigger another breakpoint after one instruction, is that possible?

    maybe setting up some breakpoint register and making a branch to lr?

    I think we got a bit confused here about the lr offsets. the stacked lr is indeed at offset 20(!). but in the current scenario, we are more interested to restore the stacked pc!
    and this is at offset 24.
    • call_stack_hardfault_2.png

      108.87 kB, 800×604, viewed 492 times

    The post was edited 5 times, last by pruesch ().

  • Hi,

    this might not be possible, you cannot access the debug/breakpoint registers from within your application.

    We maybe could implement in the GDB Server to do two single steps after a software BP. If your hardfault handler immediately does a branch to LR after the software BP, the PC should be exactly at the exception's cause. As a side effect you would no more need to do anything else, since the exception return is executed by the CPU and every register is restored to the state before the exception. Additionally we could pass the software BP's immediate value as signal number to the GDB client.

    I will discuss that later internally.

    Best regards,
  • Hi,

    I have created a beta version with this feature: download.segger.com/Arne/JLinkGDBServer
    The GDB server must be started with the command line parameter "-excdbg".
    The hardfault handler must have a "bx lr" directly behind the "bkpt" and it must be declared with the naked attribute.

    The simplest implementation of a working hardfault handler:

    Source Code

    1. __attribute__((naked)) void HardFaultHandler(void)
    2. {
    3. __asm volatile (
    4. " bkpt #10 \n"
    5. " bx lr \n"
    6. );
    7. }

    The immediate value of the bkpt instruction is directly passed as signal number to the GDB client.
    The above sample (signal number 10 is "SIGBUS") should look like this when triggered:

    Best regards and
  • Hi Arne,

    thank you very much for your effort! I'm very impressed how fast our conversation lead to this :)
    and you even built a linux binary! great!

    I will try it soon.

    would it be possible to have the gdb server evaluate the core's fault register the determine which kind of fault occurred and set the immediate value dynamically to display it in the debug view?

    best regards

    unfortunately, I'm having some trouble getting the GDBServer running:


    1. [developer@localhost JLink_Linux_V541g_x86_64]$ sudo strace ./JLinkGDBServer_beta
    2. execve("./JLinkGDBServer_beta", ["./JLinkGDBServer_beta"], [/* 22 vars */]) = 0
    3. brk(0) = 0x1007000
    4. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70cbbe5000
    5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
    6. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70cbbe4000
    7. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f70cbbe3000
    8. arch_prctl(ARCH_SET_FS, 0x7f70cbbe4680) = 0
    9. --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x8} ---
    10. +++ killed by SIGSEGV (core dumped) +++
    11. [developer@localhost JLink_Linux_V541g_x86_64]$
    Display All

    I tried to LD_PRELOAD=libjlinkarm.so.5 but still the same.

    maybe this causes my error:

    Source Code

    1. [developer@localhost JLink_Linux_V541g_x86_64]$ file JLinkGDBServer
    2. JLinkGDBServer: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
    3. [developer@localhost JLink_Linux_V541g_x86_64]$ file JLinkGDBServer_beta
    4. JLinkGDBServer_beta: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), stripped

    I'm trying this on CentOS 6.7

    The post was edited 4 times, last by pruesch ().

  • Hi Peter,

    you can do any evaluations by yourself in the hardfault handler, if you branch to different "bkpt n & bx lr" instruction blocks dependent on the fault register.
    The only requirement for the fault handler is to have the "bx lr" directly after the "bkpt n", everything else is up to you.

    Best regards,
  • Hi Arne,

    I tested the binary you supplied. It's perfect!

    For a test, I hardcoded the SIGFPE (#8 ) Signal which is shown in the debugger view in eclipse. perfect!
    after the excpetion, the pc points at the exact instruction which caused it. perfect!

    it is do be discussed what amount of exception identification can be done on the target / gdb server.
    I find your suggestion with different "bkpt #X && bx lr" combinations great.

    during the last weeks, you winded up the quality of embedded debugging by a huge leap, congratulations for that! I really like the results of it!
    your interaction with this forum is remarkable and very welcome at our side :)

    hope this Proof of Example can find its way into one of the next stable versions.

    Best Regards
    • arm_exception_debug.png

      279.33 kB, 1,399×970, viewed 509 times

    The post was edited 3 times, last by pruesch ().

  • Hi Peter,

    thank you very much for your positive feedback.

    Of course this feature will find its way into one of the the next stable versions, at least it will be in the official beta builds from now on.
    Future builds will accept a parameter after -excdbg, specifying the number of steps to do after the breakpoint. Some IDEs with automatic code generation
    might have their default handlers that only call custom code as a subroutine. This would require additional steps to get out of the exception handler.

    Best regards,
  • would it make sense to use this kind of stack unwinding also for normal interrupts?

    I would like to see in the unwound call stack where I will resume execution when I return from the ISR.

    did you think about that before?

    to clarify my thoughts, take a look at the attached picture. it shows the callstack before and after stepping out of the ISR.

    best regards
    • isr_stack.png

      101.54 kB, 1,622×546, viewed 573 times

    The post was edited 1 time, last by pruesch ().