u-boot 没有 backtrace() 函数, 调试时想跟踪调用关系, 没 jtag 就比较困难了.
这里通过获取 sp 指针的地址, 分析地址指令打印了栈中的调用地址. 这些地址可以在 u-boot 编译生成的 System.map 中查找, 就可以获得对应函数地址.
extern char __image_copy_start[]; extern char __image_copy_end[]; #define MAX_CALL_STACK_LEVEL 16 // 转换成 System.map 中的地址 static unsigned long convert_address(unsigned long address) { return CONFIG_SYS_TEXT_BASE + (address - (unsigned long)__image_copy_start); } static void print_stack_trace(unsigned long *sp) { int count = 0; while((unsigned long)sp < CONFIG_SYS_INIT_SP_ADDR) { unsigned long address = *sp; if ((0 == ((address) & 0x0003)) && (address >= (unsigned long)__image_copy_start && address <= (unsigned long)__image_copy_end) ) { ulong prev = address - 4; ulong opcode = *(ulong*)prev; // BL or BLX if (((opcode & 0x0f000000) == 0x0b000000) || ((opcode & 0x0ffffff0) == 0x012FFFF10)) { printf("%08lx\n", convert_address(address)); if (++count > MAX_CALL_STACK_LEVEL) { break; } } } sp++; } printf("----------------------------\n"); } void dprint_stack_trace(void) { unsigned long *sp; asm volatile("mov %0, sp":"=r"(sp)); printf("stack trace, sp = %08lx: \n", (unsigned long)sp); printf("----------------------------\n"); print_stack_trace(sp); } |
#include <stdio.h> #include <malloc.h> #include <string.h> #define MAX_NAME_LEN 128 typedef struct _addr_pair_t { unsigned long addr; char name[MAX_NAME_LEN]; }addr_pair_t; static addr_pair_t *pair_buf = NULL; static int pair_count = 0, pair_buf_len = 0; static void inc_pair_buf(void) { pair_buf_len += 128; pair_buf = realloc(pair_buf, pair_buf_len * sizeof(addr_pair_t)); } static int load_system_map(void) { FILE *fp = fopen("System.map", "rb"); if (fp != NULL) { char *line = NULL; size_t s = 0; ssize_t c; char fmt[128]; sprintf(fmt,"%%lx %%c %%%ds", MAX_NAME_LEN - 1); inc_pair_buf(); while (!feof(fp)) { unsigned long addr; char flag; char name[MAX_NAME_LEN]; c = getline(&line,&s,fp); if (c > 0) { if (3 == sscanf(line,fmt,&addr,&flag,name)) { if (flag == 'T' || flag == 't') { name[MAX_NAME_LEN - 1] = 0; if (pair_count >= pair_buf_len) { inc_pair_buf(); } pair_buf[pair_count].addr = addr; strcpy(pair_buf[pair_count].name,name); pair_count ++; } } } } if ( line != NULL) { free(line); } fclose(fp); } else { fprintf(stderr, "System.map not exist!\n"); } } static void print_addr(unsigned long addr) { if ((addr >= pair_buf[0].addr) && (addr <= pair_buf[pair_count - 1].addr)) { int c = 0; int top = pair_count; int bottom = 0; while (1) { int index = bottom + (top - bottom) / 2; if ((index == (pair_count - 1)) || (pair_buf[index].addr <= addr && pair_buf[index + 1].addr >= addr)) { printf("%08lx: %s + 0x%lx\n",addr, pair_buf[index].name ,addr - pair_buf[index].addr); break; } if (addr < pair_buf[index].addr) { top = index; } else if(addr > pair_buf[index].addr) { bottom = index; } } } } #define MAX_ADDR_COUNT 128 void main(int argc, const char ** argv) { load_system_map(); if (pair_count > 0) { unsigned long addr_buf[MAX_ADDR_COUNT]; int addr_count = 0; unsigned long addr; char str[128]; int i; while (1 == scanf("%lx",&addr)) { addr_buf[addr_count ++] = addr; if (addr_count >= MAX_ADDR_COUNT) { break; } } for (i = 0; i < addr_count; ++i) { print_addr(addr_buf[i]); } printf("end!\n"); } free(pair_buf); } |
u-boot$ ./taddr 60012194 60012b28 60010e00 600178f0 60006510 60000d34 600049d8 6000048c 60049120 60049120 60049120 60024148 60024148 600262ec 600262d8 600262c4 ---------------------------- 60012194: sys_boot + 0x344 60012b28: myboot + 0x110 60010e00: board_late_init + 0x8 600178f0: do_go + 0x54 60006510: clbss_l + 0x18 60000d34: invalidate_dcache_range + 0x24 600049d8: rk_pl330_rq + 0xa4 6000048c: irq + 0x2c 60049120: __udivdi3 + 0x18b38 60049120: __udivdi3 + 0x18b38 60049120: __udivdi3 + 0x18b38 60024148: rk_lcdc_load_screen + 0x1cc 60024148: rk_lcdc_load_screen + 0x1cc 600262ec: rk_mipi_dsi_init + 0x36c 600262d8: rk_mipi_dsi_init + 0x358 600262c4: rk_mipi_dsi_init + 0x344 end! |