bluetoothlover_doc icon indicating copy to clipboard operation
bluetoothlover_doc copied to clipboard

rvbacktrace

Open supperthomas opened this issue 9 months ago • 22 comments

supperthomas avatar Apr 08 '25 07:04 supperthomas

https://github.com/Yaochenger/RvBacktrace

supperthomas avatar Apr 08 '25 07:04 supperthomas

//  backtrace function
void rvbacktrace_fno(int (*print_func)(const char *fmt, ...))
{
    print_func("\r\n---- RV_Backtrace Call Frame Start: ----\r\n");
    print_func("###Please consider the value of ra as accurate and the value of sp as only for reference###\n");
    print_func("------------------------------Thread: %s backtrace------------------------------\r\n", ((rt_thread_t)rt_thread_self())->parent.name);
    walk_stackframe(print_func);
    rvbacktrace_addr2line((rt_uint32_t *)&rvstack_frame[0], print_func); // addr2line function
#if defined (BACKTRACE_ALL_THREAD)
    print_func("\r\n");
    walk_stackframe_all(print_func);
#endif /* BACKTRACE_ALL_THREAD */
    print_func("---- RV_Backtrace Call Frame End:----\r\n");
    print_func("\r\n");
}

void rv_backtrace_func(void)
{
    rvbacktrace_fno(BACKTRACE_PRINTF);
}
MSH_CMD_EXPORT_ALIAS(rv_backtrace_func, rv_backtrace_all, backtrace all threads);

supperthomas avatar Apr 08 '25 07:04 supperthomas

#if __riscv_xlen == 32
#define BACKTRACE_LEN 8
#endif

#if __riscv_xlen == 64
#define BACKTRACE_LEN 16
#endif

supperthomas avatar Apr 08 '25 07:04 supperthomas

主要函数rvbacktrace_fno

supperthomas avatar Apr 10 '25 01:04 supperthomas

void rt_cm_backtrace_exception_hook(void *context)
{
    uint8_t lr_offset = 0;
    uint32_t lr;

#define CMB_LR_WORD_OFFSET_START       6
#define CMB_LR_WORD_OFFSET_END         20
#define CMB_SP_WORD_OFFSET             (lr_offset + 1)

#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M0) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M3)
#define EXC_RETURN_MASK                0x0000000F // Bits[31:4]
#else
#define EXC_RETURN_MASK                0x0000000F // Bits[31:5]
#endif

    rt_interrupt_enter();

#ifdef RT_USING_FINSH
    extern long list_thread(void);
    list_thread();
#endif

    /* the PSP is changed by RT-Thread HardFault_Handler, so restore it to HardFault context */
#if (defined (__VFP_FP__) && !defined(__SOFTFP__)) || (defined (__ARMVFP__)) || (defined(__ARM_PCS_VFP) || defined(__TARGET_FPU_VFP))
    cmb_set_psp(cmb_get_psp() + 4 * 10);
#else
    cmb_set_psp(cmb_get_psp() + 4 * 9);
#endif

    /* auto calculate the LR offset */
    for (lr_offset = CMB_LR_WORD_OFFSET_START; lr_offset <= CMB_LR_WORD_OFFSET_END; lr_offset ++)
    {
        lr = *((uint32_t *)(cmb_get_sp() + sizeof(uint32_t) * lr_offset));
        /*
         * Cortex-M0: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Babefdjc.html
         * Cortex-M3: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html
         * Cortex-M4: http://infocenter.arm.com/help/topic/com.arm.doc.dui0553b/DUI0553.pdf P41
         * Cortex-M7: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0646c/Babefdjc.html
         */
        if ((lr == 0xFFFFFFF1) || (lr == 0xFFFFFFF9) || (lr == 0xFFFFFFFD) || (lr == 0xFFFFFFE1) || (lr == 0xFFFFFFE9) || (lr == 0xFFFFFFED))
        {
            break;
        }
    }

    cm_backtrace_fault(lr, cmb_get_sp() + sizeof(uint32_t) * CMB_SP_WORD_OFFSET);

    cmb_println("Current system tick: %ld", rt_tick_get());
    rt_interrupt_leave();
}

supperthomas avatar Apr 10 '25 02:04 supperthomas

    for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t)) {
        /* the *sp value may be LR, so need decrease a word to PC */
        pc = *((uint32_t *) sp) - sizeof(size_t);
        /* the Cortex-M using thumb instruction, so the pc must be an odd number */
        if (pc % 2 == 0) {
            continue;
        }
        /* fix the PC address in thumb mode */
        pc = *((uint32_t *) sp) - 1;
        if ((pc >= code_start_addr + sizeof(size_t)) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
                /* check the the instruction before PC address is 'BL' or 'BLX' */
                && disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < size)) {
            /* the second depth function may be already saved, so need ignore repeat */
            if ((depth == 2) && regs_saved_lr_is_valid && (pc == buffer[1])) {
                continue;
            }
            buffer[depth++] = pc;
        }
    }

关键函数

supperthomas avatar Apr 10 '25 03:04 supperthomas


extern char *__etext;
extern char *__stext;

__attribute__((always_inline)) static inline void *backtrace_get_sp(void)
{
    void *sp;
    __asm__ volatile("mv %0, sp\n" : "=r"(sp));
    return sp;
}
__attribute__((always_inline)) static inline void *backtrace_get_pc(void)
{
    void *pc;
    __asm__ volatile("auipc %0, 0\n" : "=r"(pc));
    return pc;
}
#define BT_FUNC_LIMIT   0x2000
#define BT_LVL_LIMIT    64
unsigned int rvstack_frame_len; // stack frame len

#define BT_CHK_PC_AVAIL(pc)   ((uintptr_t)(pc) < (uintptr_t)(&__etext) \
                              && (uintptr_t)(pc) > (uintptr_t)(&__stext))

#define BT_PC2ADDR(pc)        ((char *)(((uintptr_t)(pc))))
#define STACK_FRAME_LEN (10)
#define STACK_BUFFER_LEN (100)
unsigned int rvstack_frame[STACK_FRAME_LEN]; // stack frame
/* get the offset between the jump instruction and the return address */
static int backtraceFindLROffset(char *LR)
{
    int offset = 0;
    char *LR_indeed;
    unsigned int ins32;

    LR_indeed = BT_PC2ADDR(LR);

    /* Usually jump using the JAL instruction */
   // ins32 = *(unsigned int *)(LR_indeed - 4);
    vmemcpy(&ins32, (LR_indeed - 4), sizeof(ins32));
    if ((ins32 & 0x3) == 0x3) {
        offset = 4;
    } else {
        offset = 2;
    }

    return offset;
}
/* get framesize from c ins32 */
static int riscv_backtrace_framesize_get1(unsigned int inst)
{
    unsigned int imm = 0;
    /* addi sp, sp, -im 
     * d1010113          	addi	sp,sp,-752
     * bit[31:20] = imm[11:0]
     * bit[19:15] = 00010
     * bit[14:12] = 000
     * bit[11:7]  = 00010
     * bit[6:0]  = 0010011
     */
    if ((inst & 0x800FFFFF) == 0x80010113) {
        imm = (inst >> 20) & 0x7FF;
        imm = (~imm & 0x7FF) + 1;
        return imm >> 2;
    }

    return -1;
}
/* get framesize from c ins */
static int riscv_backtrace_framesize_get(unsigned short inst)
{
    unsigned int imm = 0;
    /* addi sp, sp, -im
     * 1141:addi    sp,sp,-16
     * bit[13-15] = 000
     * bit[1:0]  = 01
     * imm[5] = bit[12]   默认负数
     * imm[4:0] = bit[6:2]
     * bit[11:7] = 00010
     * default:0x1101:  000 1 00010 00000 01
     * */
    if ((inst & 0xFF83) == 0x1101) {
        imm = (inst >> 2) & 0x1F;
        imm = (~imm & 0x1F) + 1;
        return imm >> 2;
    }

    /* c.addi16sp sp, nzuimm6<<4 
       * 7101:addi	sp,sp,-512
       * 7119:addi  sp,sp,-128
       * bit[12] = imm[9]  默认负数
       * bit[11:7] = 00010   //x2 (ra)
       * bit[6]  = imm[4]
       * bit[5]  = imm[6]
       * bit[4]  = imm[8]
       * bit[3]  = imm[7]
       * bit[2]  = imm[5]
       * bit[15:13] = 011
       * default: 0x7101: 011 1 00010 00000 01
    */
    if ((inst & 0xFF83) == 0x7101) {
        imm = (inst >> 3) & 0x3;  //imm[8,7]
        imm = (imm << 1) | ((inst >> 5) & 0x1);//imm[6]
        imm = (imm << 1) | ((inst >> 2) & 0x1);//imm[5]
        imm = (imm << 1) | ((inst >> 6) & 0x1);//imm[4]
        imm = ((~imm & 0x1f) + 1) << 4;   // 扩大16倍
        return imm >> 2;
    }

    return -1;
}

static int riscv_backtrace_ra_offset_get1(unsigned int inst)
{
    unsigned int imm = 0;
    /*  
     * 2e112623          	sw	ra,748(sp)
     * BIT[31:25] = imm[11:5]
     * BIT[11:7] = imm[4:0]
     * 
    */
    if ((inst & 0x81FFF07F) == 0x112023) {
        imm = (inst >> 7) & 0x1F;
        imm |= ((inst >> 25) & 0x7F) << 5;
        /* The unit is size_t, So we don't have to move 3 bits to the left */
        return imm >> 2;
    }
    return -1;
}

/* get ra position in the stack */
static int riscv_backtrace_ra_offset_get(unsigned short inst)
{
    unsigned int imm = 0;
    /* sw  ra, imm(sp)
     * c606: sw  ra,12(sp)
     * ce06: sw  ra,28(sp)
     * c206: sw  ra,4(sp)
     * c006: sw  ra,0(sp)
     * bit[15:13] = 110
     * bit[12:9] = imm[5:2]
     * bit[8:7]  = imm[7:6]
     * bit[6:2]  = 00001
     * bit[1:0]  = 01
     * default: 0xc006 : 110 000000 00001 10
     *  */
    if ((inst & 0xE07F) == 0xC006) {
        imm = (inst >> 9) & 0x0F; //imm[5:2] 已经偏移最低两位
        imm = imm | (((inst >> 7) & 0x3)<<4); //imm[7:6]
        /* The unit is size_t, So we don't have to move 3 bits to the left */
        return imm;
    }

    return -1;
}
static int lvl;
static int backtraceFromStack(uint32_t **pSP, char **pPC)
{
    char *CodeAddr = NULL;
    uint32_t  *SP      = *pSP;
    char *PC       = *pPC;
    char *LR;
    int   i;
    int   framesize;
    int   offset = 0;
    unsigned int ins32;
    unsigned short ins16;

    /* 1. scan code, find lr pushed */
    for (i = 0; i < BT_FUNC_LIMIT;) {
        /* FIXME: not accurate from bottom to up. how to judge 2 or 4byte inst */
        //CodeAddr = (char *)(((long)PC & (~0x3)) - i);
        CodeAddr = (char *)(PC - i);
        //ins32 = *(unsigned int *)(CodeAddr);
        //非对齐访问
        vmemcpy(&ins32, CodeAddr, sizeof(ins32));
        if ((ins32 & 0x3) == 0x3) {
            ins16 = *(unsigned short *)(CodeAddr - 2);
            if ((ins16 & 0x3) != 0x3) {
                i += 4;
                framesize = riscv_backtrace_framesize_get1(ins32);
                if (framesize >= 0) {
                    CodeAddr += 4;
                    break;
                }
                continue;
            }
        }
        i += 2;
        ins16 = (ins32 >> 16) & 0xffff;
        framesize = riscv_backtrace_framesize_get(ins16);
        if (framesize >= 0) {
            CodeAddr += 2;
            break;
        }
    }

    if (i == BT_FUNC_LIMIT) {
        /* error branch */
        NOTICE_PRINTF("[rvbacktrace]paras fail=SP:0x%x==PC:0x%x=",SP,PC);
        return -1;
    }
    /* 2. scan code, find ins: sd ra,24(sp) or sd ra,552(sp) */
    for (i = 0; CodeAddr + i < PC;) {
      //  ins32 = *(unsigned int *)(CodeAddr + i);
        vmemcpy(&ins32, (CodeAddr+i), sizeof(ins32));
        if ((ins32 & 0x3) == 0x3) {
            i += 4;
            offset = riscv_backtrace_ra_offset_get1(ins32);
            if (offset >= 0) {
                break;
            }
        } else {
            i += 2;
            ins16 = ins32 & 0xffff;
            offset = riscv_backtrace_ra_offset_get(ins16);
            if (offset >= 0) {
                break;
            }
        }
    }
    /* 3. output */
    //去除LR的值
    LR     = (char *) * (SP + offset);

    if (BT_CHK_PC_AVAIL(LR) == 0) {
        NOTICE_PRINTF("End of stack backtracking\r\n");
        return -1;
    }
    //重新给SP 赋值,找上一个函数
    *pSP   = SP + framesize;
    //回退到字节数,比如退2个字节,还是4个字节
    offset = backtraceFindLROffset(LR);
    rvstack_frame[lvl] = (unsigned int)(LR - offset);

    NOTICE_PRINTF("\n[%d]Stack interval :[0x%x - 0x%x]  ra 0x%x pc 0x%x", lvl, SP, SP + framesize, LR, LR - offset);
    *pPC   = LR - offset;

    return offset == 0 ? 1 : 0;
}
void backtrace_check()
{
    char *PC;
    uint32_t  *SP;
    int   ret;

    SP = backtrace_get_sp();
    PC = backtrace_get_pc();

    for (lvl = 1; lvl < BT_LVL_LIMIT; lvl++) {
        ret = backtraceFromStack(&SP, &PC);
        if (ret != 0) {
            rvstack_frame_len = lvl;
            break;
        }
    }
}
void rvbacktrace_addr2line(uint32_t *frame)
{
    char buffer[STACK_BUFFER_LEN];
    int offset = 0;

    for (int i = 0; i < rvstack_frame_len; i++)
    {
        offset += snprintf(buffer + offset, STACK_BUFFER_LEN - offset, "%lx ", frame[i]);
        if (offset >= STACK_BUFFER_LEN)
            break;
    }
    NOTICE_PRINTF("\n addr2line -e va9658_corebt_debug.elf -a -f %s\n", buffer);
}
void rvbacktrace_info(uint32_t *uSP, uint32_t *uPC)
{
    char *PC;
    uint32_t  *SP;
    SP = uSP;
    PC = (char *)uPC;
    int   ret;    //先保存PC的值,方便addr2line使用
    rvstack_frame[0] = (unsigned int)(PC);
    for (lvl = 1; lvl < BT_LVL_LIMIT; lvl++) {
        ret = backtraceFromStack(&SP, &PC);
        if (ret != 0) {
            rvstack_frame_len = lvl;
            break;
        }
    }
    rvbacktrace_addr2line((uint32_t *)&rvstack_frame[0]); // addr2line function
}

void rvbacktrace_fno()
{
    NOTICE_PRINTF("\n---- RV_Backtrace Call Frame Start: -SP-0x%p-PC:0x%p-",backtrace_get_sp(),backtrace_get_pc());
    backtrace_check();
    rvbacktrace_addr2line((uint32_t *)&rvstack_frame[0]); // addr2line function
}

supperthomas avatar Apr 12 '25 12:04 supperthomas

__builtin_frame_address是GCC和Clang编译器提供的一个内置函数,用于获取当前函数调用堆栈中某个帧的地址。以下是其详细用法:

supperthomas avatar Apr 12 '25 13:04 supperthomas

C:/RT-ThreadStudio/repo/Extract/ToolChain_Support_Packages/RISC-V/RISC-V-GCC-RV32/2022-04-12/bin/riscv32-unknown-elf-objdump -d rtthread.elf > rtthread.asm

supperthomas avatar Apr 12 '25 13:04 supperthomas

https://club.rt-thread.org/ask/article/64bfe06feb7b3e29.html

supperthomas avatar Apr 12 '25 13:04 supperthomas

-fno-omit-frame-pointer 不优化帧指针

supperthomas avatar Apr 12 '25 13:04 supperthomas

默认情况下,编译器可能会优化掉帧指针(-fomit-frame-pointer),以节省寄存器资源并提高性能。但这样会导致帧指针链表不完整,无法正确回溯栈帧。

supperthomas avatar Apr 12 '25 13:04 supperthomas

FP是S0

supperthomas avatar Apr 12 '25 13:04 supperthomas

Image

supperthomas avatar Apr 12 '25 13:04 supperthomas

s0会保存帧指针的地址(调用者)

supperthomas avatar Apr 12 '25 14:04 supperthomas

long的字节长度有可能是4个字节,有可能是8个字节。

supperthomas avatar Apr 12 '25 14:04 supperthomas

由于进函数的时候,sp会变化,同时,SP会保存固定长度的帧,例如是8个word,8个寄存器,则fp就是保存sp变化前的数值;

8000b0c2 <hpm_rtt_exception_handler>:
8000b0c2:	1101                	addi	sp,sp,-32
8000b0c4:	ce06                	sw	ra,28(sp)
8000b0c6:	cc22                	sw	s0,24(sp)
8000b0c8:	ca26                	sw	s1,20(sp)
8000b0ca:	c84a                	sw	s2,16(sp)
8000b0cc:	c64e                	sw	s3,12(sp)
8000b0ce:	c452                	sw	s4,8(sp)
8000b0d0:	c256                	sw	s5,4(sp)
8000b0d2:	1000                	addi	s0,sp,32

supperthomas avatar Apr 12 '25 14:04 supperthomas

ra, so 相对于原来的SP的地址是不变的,默认是8

supperthomas avatar Apr 12 '25 14:04 supperthomas

-fno-omit-frame-pointer 是一个编译器选项,其中 omit 是英语单词,意思是“省略”或“忽略”。这个选项的作用是告诉编译器不要省略帧指针。

supperthomas avatar Apr 12 '25 14:04 supperthomas


extern char *__text_start__;
extern char *__text_end__;

__attribute__((always_inline)) static inline void *backtrace_get_sp(void)
{
    void *sp;
    __asm__ volatile("mv %0, sp\n" : "=r"(sp));
    return sp;
}
__attribute__((always_inline)) static inline void *backtrace_get_pc(void)
{
    void *pc;
    __asm__ volatile("auipc %0, 0\n" : "=r"(pc));
    return pc;
}
#define BT_FUNC_LIMIT   0x2000
#define BT_LVL_LIMIT    64
unsigned int rvstack_frame_len; // stack frame len

#define BT_CHK_PC_AVAIL(pc)   ((uintptr_t)(pc) < (uintptr_t)(&__text_end__) \
                              && (uintptr_t)(pc) > (uintptr_t)(&__text_start__))

#define BT_PC2ADDR(pc)        ((char *)(((uintptr_t)(pc))))
#define STACK_FRAME_LEN (10)
#define STACK_BUFFER_LEN (100)
unsigned int rvstack_frame[STACK_FRAME_LEN]; // stack frame
/* get the offset between the jump instruction and the return address */
static int backtraceFindLROffset(char *LR)
{
    int offset = 0;
    char *LR_indeed;
    unsigned int ins32;

    LR_indeed = BT_PC2ADDR(LR);

    /* Usually jump using the JAL instruction */
   // ins32 = *(unsigned int *)(LR_indeed - 4);
    vmemcpy(&ins32, (LR_indeed - 4), sizeof(ins32));
    if ((ins32 & 0x3) == 0x3) {
        offset = 4;
    } else {
        offset = 2;
    }

    return offset;
}
/* get framesize from c ins32 */
static int riscv_backtrace_framesize_get1(unsigned int inst)
{
    unsigned int imm = 0;
    /* addi sp, sp, -im 
     * d1010113          	addi	sp,sp,-752
     * bit[31:20] = imm[11:0]
     * bit[19:15] = 00010
     * bit[14:12] = 000
     * bit[11:7]  = 00010
     * bit[6:0]  = 0010011
     */
    if ((inst & 0x800FFFFF) == 0x80010113) {
        imm = (inst >> 20) & 0x7FF;
        imm = (~imm & 0x7FF) + 1;
        return imm >> 2;
    }

    return -1;
}
/* get framesize from c ins */
static int riscv_backtrace_framesize_get(unsigned short inst)
{
    unsigned int imm = 0;
    /* addi sp, sp, -im
     * 1141:addi    sp,sp,-16
     * bit[13-15] = 000
     * bit[1:0]  = 01
     * imm[5] = bit[12]   默认负数
     * imm[4:0] = bit[6:2]
     * bit[11:7] = 00010
     * default:0x1101:  000 1 00010 00000 01
     * */
    if ((inst & 0xFF83) == 0x1101) {
        imm = (inst >> 2) & 0x1F;
        imm = (~imm & 0x1F) + 1;
        return imm >> 2;
    }

    /* c.addi16sp sp, nzuimm6<<4 
       * 7101:addi	sp,sp,-512
       * 7119:addi  sp,sp,-128
       * bit[12] = imm[9]  默认负数
       * bit[11:7] = 00010   //x2 (ra)
       * bit[6]  = imm[4]
       * bit[5]  = imm[6]
       * bit[4]  = imm[8]
       * bit[3]  = imm[7]
       * bit[2]  = imm[5]
       * bit[15:13] = 011
       * default: 0x7101: 011 1 00010 00000 01
    */
    if ((inst & 0xFF83) == 0x7101) {
        imm = (inst >> 3) & 0x3;  //imm[8,7]
        imm = (imm << 1) | ((inst >> 5) & 0x1);//imm[6]
        imm = (imm << 1) | ((inst >> 2) & 0x1);//imm[5]
        imm = (imm << 1) | ((inst >> 6) & 0x1);//imm[4]
        imm = ((~imm & 0x1f) + 1) << 4;   // 扩大16倍
        return imm >> 2;
    }

    return -1;
}

static int riscv_backtrace_ra_offset_get1(unsigned int inst)
{
    unsigned int imm = 0;
    /*  
     * 2e112623          	sw	ra,748(sp)
     * 14112623          	sw	ra,332(sp)
     * 
     * BIT[31:25] = imm[11:5]
     * BIT[11:7] = imm[4:0]
     * BIT[6:0] - 0100011
     * BIT[14:12] = 010
     * 
     * default: 0x1122023: 0000000 00001 00010 010 00000 0100011
    */
    if ((inst & 0x81FFF07F) == 0x112023) {
        imm = (inst >> 7) & 0x1F;
        imm |= ((inst >> 25) & 0x7F) << 5;
        /* The unit is size_t, So we don't have to move 3 bits to the left */
        return imm >> 2;
    }
    return -1;
}

/* get ra position in the stack */
static int riscv_backtrace_ra_offset_get(unsigned short inst)
{
    unsigned int imm = 0;
    /* sw  ra, imm(sp)
     * c606: sw  ra,12(sp)
     * ce06: sw  ra,28(sp)
     * c206: sw  ra,4(sp)
     * c006: sw  ra,0(sp)
     * bit[15:13] = 110
     * bit[12:9] = imm[5:2]
     * bit[8:7]  = imm[7:6]
     * bit[6:2]  = 00001
     * bit[1:0]  = 01
     * default: 0xc006 : 110 000000 00001 10
     *  */
    if ((inst & 0xE07F) == 0xC006) {
        imm = (inst >> 9) & 0x0F; //imm[5:2] 已经偏移最低两位
        imm = imm | (((inst >> 7) & 0x3)<<4); //imm[7:6]
        /* The unit is size_t, So we don't have to move 3 bits to the left */
        return imm;
    }

    return -1;
}
static int lvl;
static int backtraceFromStack(uint32_t **pSP, char **pPC)
{
    char *CodeAddr = NULL;
    uint32_t  *SP      = *pSP;
    char *PC       = *pPC;
    char *LR;
    int   i;
    int   framesize;
    int   offset = 0;
    unsigned int ins32;
    unsigned short ins16;

    /* 1. scan code, find lr pushed */
    for (i = 0; i < BT_FUNC_LIMIT;) {
        /* FIXME: not accurate from bottom to up. how to judge 2 or 4byte inst */
        //CodeAddr = (char *)(((long)PC & (~0x3)) - i);
        CodeAddr = (char *)(PC - i);
        //ins32 = *(unsigned int *)(CodeAddr);
        //非对齐访问
        vmemcpy(&ins32, CodeAddr, sizeof(ins32));
        if ((ins32 & 0x3) == 0x3) {
            ins16 = *(unsigned short *)(CodeAddr - 2);
            if ((ins16 & 0x3) != 0x3) {
                i += 4;
                framesize = riscv_backtrace_framesize_get1(ins32);
                if (framesize >= 0) {
                    CodeAddr += 4;
                    break;
                }
                continue;
            }
        }
        i += 2;
        ins16 = (ins32 >> 16) & 0xffff;
        framesize = riscv_backtrace_framesize_get(ins16);
        if (framesize >= 0) {
            CodeAddr += 2;
            break;
        }
    }

    if (i == BT_FUNC_LIMIT) {
        /* error branch */
        NOTICE_PRINTF("[rvbacktrace]paras fail=SP:0x%x==PC:0x%x=",SP,PC);
        return -1;
    }
    /* 2. scan code, find ins: sd ra,24(sp) or sd ra,552(sp) */
    for (i = 0; CodeAddr + i < PC;) {
      //  ins32 = *(unsigned int *)(CodeAddr + i);
        vmemcpy(&ins32, (CodeAddr+i), sizeof(ins32));
        if ((ins32 & 0x3) == 0x3) {
            i += 4;
            offset = riscv_backtrace_ra_offset_get1(ins32);
            if (offset >= 0) {
                break;
            }
        } else {
            i += 2;
            ins16 = ins32 & 0xffff;
            offset = riscv_backtrace_ra_offset_get(ins16);
            if (offset >= 0) {
                break;
            }
        }
    }
    /* 3. output */
    //去除LR的值
    LR     = (char *) * (SP + offset);

    if (BT_CHK_PC_AVAIL(LR) == 0) {
        NOTICE_PRINTF("End of stack backtracking\r\n");
        return -1;
    }
    //重新给SP 赋值,找上一个函数
    *pSP   = SP + framesize;
    //回退到字节数,比如退2个字节,还是4个字节
    offset = backtraceFindLROffset(LR);
    rvstack_frame[lvl] = (unsigned int)(LR - offset);

    NOTICE_PRINTF("\n[%d]Stack interval :[0x%x - 0x%x]  ra 0x%x pc 0x%x", lvl, SP, SP + framesize, LR, LR - offset);
    *pPC   = LR - offset;

    return offset == 0 ? 1 : 0;
}
void backtrace_check()
{
    char *PC;
    uint32_t  *SP;
    int   ret;

    SP = backtrace_get_sp();
    PC = backtrace_get_pc();

    for (lvl = 1; lvl < BT_LVL_LIMIT; lvl++) {
        ret = backtraceFromStack(&SP, &PC);
        if (ret != 0) {
            rvstack_frame_len = lvl;
            break;
        }
    }
}
void rvbacktrace_addr2line(uint32_t *frame)
{
    char buffer[STACK_BUFFER_LEN];
    int offset = 0;

    for (int i = 0; i < rvstack_frame_len; i++)
    {
        offset += snprintf(buffer + offset, STACK_BUFFER_LEN - offset, "%lx ", frame[i]);
        if (offset >= STACK_BUFFER_LEN)
            break;
    }
    NOTICE_PRINTF("\n addr2line -e va9658_corebt_debug.elf -a -f %s\n", buffer);
}
void rvbacktrace_info(uint32_t *uSP, uint32_t *uPC)
{
    char *PC;
    uint32_t  *SP;
    SP = uSP;
    PC = (char *)uPC;
    int   ret;    //先保存PC的值,方便addr2line使用
    rvstack_frame[0] = (unsigned int)(PC);
    for (lvl = 1; lvl < BT_LVL_LIMIT; lvl++) {
        ret = backtraceFromStack(&SP, &PC);
        if (ret != 0) {
            rvstack_frame_len = lvl;
            break;
        }
    }
    rvbacktrace_addr2line((uint32_t *)&rvstack_frame[0]); // addr2line function
}

void rvbacktrace_fno()
{
    NOTICE_PRINTF("\n---- RV_Backtrace Call Frame Start: -SP-0x%p-PC:0x%p-",backtrace_get_sp(),backtrace_get_pc());
    backtrace_check();
    rvbacktrace_addr2line((uint32_t *)&rvstack_frame[0]); // addr2line function
}

supperthomas avatar Apr 13 '25 09:04 supperthomas

TODO: Kconfig添加: 1.3个宏 - 开fno-omit - 开线程保护protect 2.rt_kprintf 3.TEXT 段的开始的宏和结束的宏

supperthomas avatar Apr 14 '25 01:04 supperthomas

rt-studio 的汇编 C:/RT-ThreadStudio/repo/Extract/ToolChain_Support_Packages/RISC-V/RISC-V-GCC-RV32/2022-04-12/bin/riscv32-unknown-elf-objdump -d rtthread.elf > rtthread.asm

supperthomas avatar Apr 15 '25 12:04 supperthomas