rvbacktrace
https://github.com/Yaochenger/RvBacktrace
// 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);
#if __riscv_xlen == 32
#define BACKTRACE_LEN 8
#endif
#if __riscv_xlen == 64
#define BACKTRACE_LEN 16
#endif
主要函数rvbacktrace_fno
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();
}
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;
}
}
关键函数
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
}
__builtin_frame_address是GCC和Clang编译器提供的一个内置函数,用于获取当前函数调用堆栈中某个帧的地址。以下是其详细用法:
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
https://club.rt-thread.org/ask/article/64bfe06feb7b3e29.html
-fno-omit-frame-pointer 不优化帧指针
默认情况下,编译器可能会优化掉帧指针(-fomit-frame-pointer),以节省寄存器资源并提高性能。但这样会导致帧指针链表不完整,无法正确回溯栈帧。
FP是S0
s0会保存帧指针的地址(调用者)
long的字节长度有可能是4个字节,有可能是8个字节。
由于进函数的时候,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
ra, so 相对于原来的SP的地址是不变的,默认是8
-fno-omit-frame-pointer 是一个编译器选项,其中 omit 是英语单词,意思是“省略”或“忽略”。这个选项的作用是告诉编译器不要省略帧指针。
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
}
TODO: Kconfig添加: 1.3个宏 - 开fno-omit - 开线程保护protect 2.rt_kprintf 3.TEXT 段的开始的宏和结束的宏
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