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! |