Menu

QXK back-trace programmatically issue

2019-11-07
2019-11-11
  • Ayman Hendawy

    Ayman Hendawy - 2019-11-07

    Hi,
    I'm trying to add backtrace functionallity to the exceptional handler as an offline debugging method where it's not possible to connct a debugger at a customer enviromnet, so it would print in a file the calling stack untill it reachs the exceptional handler.
    I followed this thread but I didn't get how to do so through the QSPY or the build flag -mapcs-frame, so I tried this thread by adding a call to the below code from the exception handler and trying these flags to the build flags of the Makefile
    -mapcs-frame -funwind-tables or -fasynchronous-unwind-tables

    #include <unwind.h> // GCC's internal unwinder, part of libgcc
    _Unwind_Reason_Code trace_fcn(_Unwind_Context *ctx, void *d)
    {
        int *depth = (int*)d;
        printf("\t#%d: program counter at %08x\n", *depth, _Unwind_GetIP(ctx));
        (*depth)++;
        return _URC_NO_REASON;
    }
    
    void print_backtrace_here()
    {
        int depth = 0;
        _Unwind_Backtrace(&trace_fcn, &depth);
    }
    

    When I tried to build, it throwed the follwoing error

    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(unwind-arm.o): In function `__aeabi_unwind_cpp_pr0':
    /home_local/msokolov/tc-build/gcc-build/arm-eabi/libgcc/../../../gcc-4.7.3/libgcc/config/arm/unwind-arm.c:510: multiple definition of `__aeabi_unwind_cpp_pr0'
    /media/sec_hdd/ahendawy/sedona_workspace/MACSW/qxkinit/aeabi_stubs.o:/media/sec_hdd/ahendawy/sedona_workspace/MACSW/qxkinit/aeabi_stubs.c:8: first defined here
    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(unwind-arm.o): In function `get_eit_entry':
    unwind-arm.c:(.text+0x28c): undefined reference to `__exidx_start'
    unwind-arm.c:(.text+0x290): undefined reference to `__exidx_end'
    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(unwind-arm.o): In function `unwind_phase2':
    unwind-arm.c:(.text+0x458): undefined reference to `abort'
    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(unwind-arm.o): In function `__gnu_Unwind_Resume':
    unwind-arm.c:(.text+0x568): undefined reference to `abort'
    unwind-arm.c:(.text+0x590): undefined reference to `abort'
    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(pr-support.o): In function `_Unwind_GetDataRelBase':
    /home_local/msokolov/tc-build/gcc-build/arm-eabi/libgcc/../../../gcc-4.7.3/libgcc/config/arm/pr-support.c:394: undefined reference to `abort'
    /media/sec_hdd/ahendawy/sedona_workspace/SM-Tools-OS/bin/../lib/gcc/arm-eabi/4.7.3/libgcc.a(pr-support.o): In function `_Unwind_GetTextRelBase':
    /home_local/msokolov/tc-build/gcc-build/arm-eabi/libgcc/../../../gcc-4.7.3/libgcc/config/arm/pr-support.c:400: undefined reference to `abort'
    

    So kindly, any clues how to fix such error, or in general how to add a backtrace for QXK exceptional handler.

    Thanks

     
  • Quantum Leaps

    Quantum Leaps - 2019-11-07

    As you notice, GCC's internal unwinder is part of libgcc, while your build errors are comming from the linker that is unable to find exactly parts of libgcc. This is most likely due to the fact that the program is built without the standard library (see linker options -specs=nosys.specs -specs=nano.specs). The ommision of the standard library in the QP examples for GCC is intentional, because it saves you several KB of code space and allows you to use your own startup code and exception handlers.

    But I'm not sure what you're getting from "unwind.h". I mean, there are easier ways to just dump several words from the current stack. I would just take an address of an automatic variable and take this as a good approximation of the current top of stack. From there, you can keep incrementing the pointer. (On ARM the stack grows towards lower addresses, so going from the top of stack down corresponds to incrementing a pointer). A pseudocode for this could look something like this:

    void dumpStack(uint32_t depth) {
        uint32_t stack; // <-- automatic variable on the stack
        uint32_t const *sp = &stack;
        for (; depth != 0; --depth, ++sp) {
            printf("\t#%d: %08x\n", (int)sp, *sp);
        }
    }
    

    Also, I would probably use QP/Spy to dump the stack instead of printf().

    --MMS

     

    Last edit: Quantum Leaps 2019-11-07
  • Ayman Hendawy

    Ayman Hendawy - 2019-11-11

    I added these flags for the compiler -Wl,-specs=nosys.specs,-specs=nano.specs,-funwind-tables,-fno-exceptions, but it didn't solve the above problems, the flag -fno-exceptions just fix __exidx_start __exidx_end errors.

    I see we have here two different errors,
    1- multiple definition of __aeabi_unwind_cpp_pr0 which seems conflict with qxk stub at this file qxkinit/aeabi_stubs.c
    2- undefined reference to abort function I don't have any idea what's the missing library here, I tried differet options but get nothing.

    I'm not close to "unwind.h", but my point behind unwind.h is to print the call stack or the stack trace till the exception handler, the purpose is to print the function addresses ,calling sequence, that leads to that exception handler, I don't know how I could doing so by dumping the current stack in the way you have mentioned above, it may print the return function address 'LR register', but could it print the list of calling functions?

    I understand -corect me if I'm wrong- that QP/SPY has the utility to print the call stack or the stack trace but I don't know it could do so?

    Thanks

     
  • Quantum Leaps

    Quantum Leaps - 2019-11-11

    As I wrote in my previous post, the Makefiles for the QP/C++ examples have been carefully optimized to avoid as much C++ overhead as possible. But to achieve this, the Makefiles don't use the standard library, because that's where the most "fat" could be cut down.

    In your case, you apparently use some parts of the GCC library, so you would need to experiment and figure out compiler options and libraries are needed. This might include the "abort()" function and other facilities.

    But I would perhaps step back and look at the bigger picture of what you are trying to achieve here. If your application crashes by calling an exception handler, then I would highly recommend that you focus on designing the exception handler to provide some additional information. For example, the return address from the exception is located at the specified offset from the top of stack (the exact offset depends on the use of FPU etc.). Also, if you are using the startup code provided with the QP examples, your exception handler should end up calling the assertion handler (Q_onAssert()). Therefore, you could also think of instrumenting the assertion handler to provide some information.

    But stepping back even further, the fact that your application ends up crashing means that you very likely might be using too few assertions in your code. With the right assertion density all errors end up tripping an assertion, which is much better than "crash and burn". You could read more about assertions in the code here:

    https://embeddedgurus.com/state-space/2009/11/a-nail-for-a-fuse/
    https://www.state-machine.com/doc/Samek0308.pdf
    https://jaxenter.com/power-ten-nasas-coding-commandments-114124.html

    --MMS

     

Log in to post a comment.