Skip to content

Further debugging on faults #5

@pingbird

Description

@pingbird

A really nice feature would be the ability to actually locate what code caused a fault not just that one occurred, it was actually easier to achieve than i thought

First we have to get the pc at the point of the fault
Here is some working code:

static const char * const hex = "0123456789ABCDEF";
static void _fault_dumpInt(uint32_t num) {
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = '0';
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = 'x';
    unsigned char i = 32;
    while (i) {
        i -= 4;
        while (!(USART1->SR & USART_SR_TXE));
        USART1->DR = hex[(num >> i) % 16];
    }
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = '\r';
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = '\n';
}

// this function is basically the default error handler but prints out the instruction pointer
uint32_t _fault_dumpPC(uint32_t *faultStack) {
    //we dont need these for now
    //volatile uint32_t r0;
    //volatile uint32_t r1;
    //volatile uint32_t r2;
    //volatile uint32_t r3;
    //volatile uint32_t r12;
    //volatile uint32_t lr;
    volatile uint32_t pc;
    //volatile uint32_t psr;

    //r0 = faultStack[0];
    //r1 = faultStack[1];
    //r2 = faultStack[2];
    //r3 = faultStack[3];
    //r12 = faultStack[4];
    //lr = faultStack[5];
    pc = faultStack[6];
    //psr = faultStack[7];

    __disable_irq();
    USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;

    _fault_dumpInt(pc);

    while (!(USART1->SR & USART_SR_TXE));

    __reset();
}

// some ASM that calls our _fault_dumpPC function with a pointer to the stack that caused the fault
static void _fault_test( void ) __attribute__( ( naked ) );
static void _fault_test(void) {
    __asm volatile (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word _fault_dumpPC               \n"
    );
}

and then just call it at the top of the current fault handler because im lazy

void __attribute__((noreturn)) _exit(int status) {
    _fault_test();

compile kernel, put it in a project with some faulty code:
code

compile project and open up the debug terminal:
terminal

woo! we have our instruction pointer "0x08000192"

in order to convert this into the actual location of the fault, (obviously) first we need to compile the project with debugging information by adding -g to $CFLAGS in common.mk

CFLAGS:=$(CCFLAGS) -std=gnu99 -Werror=implicit-function-declaration -g

make sure you have arm-none-eabi-addr2line
finally

pixel@pixel-PC:~/pros_test$ arm-none-eabi-addr2line 0x08000192 --exe=bin/output.elf
/home/pixel/pros_test/src/opcontrol.c:36

Now ill work on getting a full backtrace and automating the process

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureA brand new featurep: lowLow priority

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions