0
点赞
收藏
分享

微信扫一扫

Xtensa架构的callstack实现方式

MaxWen 2022-12-04 阅读 71


首先参考轮子库Linux的实现,Linux实现的主干逻辑如下:

Xtensa架构的callstack实现方式_#endif

Xtensa架构有其特殊性,最核心的一点是所谓的window ABI,通过window ABI减少了函数调用过程中压栈出栈的操作,获取了性能上的提升。不知道是不是由于 Window ABI引入的代价,他的的堆栈布局非常规整,有板有眼。这对stack hacking带了了很多便利,从上图中可以看出,Linux中针对xtensa架构的dump_stack实现还是非常的简洁的。

移植结果:

#include <stddef.h>
#include <stdio.h>

#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define THREAD_SIZE (8*1024)
#define SPILL_SLOT(sp, reg) (*(((unsigned long *)(sp)) - 4 + (reg)))
#define MAKE_PC_FROM_RA(ra,sp) (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
#define __always_inline inline __attribute__((__always_inline__))

struct stackframe {
unsigned long pc;
unsigned long sp;
};

static __always_inline unsigned long *stack_pointer(void)
{
unsigned long *sp;

__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));

return sp;
}

static inline void spill_registers(void)
{
#if XCHAL_NUM_AREGS > 16
__asm__ __volatile__ (
"call8 1f\n"
"_j 2f\n"
"retw\n"
".align 4\n"
"1:\n"
#if XCHAL_NUM_AREGS == 32
"_entry a1, 32\n"
"addi a8, a0, 3\n"
"_entry a1, 16\n"
"mov a12, a12\n"
"retw\n"
#else
"_entry a1, 48\n"
"call12 1f\n"
"retw\n"
".align 4\n"
"1:\n"
".rept (" __stringify(XCHAL_NUM_AREGS) " - 16) / 12\n"
"_entry a1, 48\n"
"mov a12, a0\n"
".endr\n"
"_entry a1, 16\n"
#if XCHAL_NUM_AREGS % 12 == 0
"mov a12, a12\n"
#elif XCHAL_NUM_AREGS % 12 == 4
"mov a4, a4\n"
#elif XCHAL_NUM_AREGS % 12 == 8
"mov a8, a8\n"
#endif
"retw\n"
#endif
"2:\n"
: : : "a8", "a9", "memory");
#else
__asm__ __volatile__ (
"mov a12, a12\n"
: : : "memory");
#endif
}

static int recursive_counter = 0;
void walk_stackframe(unsigned long *sp, int (*fn)(struct stackframe *frame, void *data), void *data)
{
recursive_counter ++;

// check nest call scenarios for printf would get lock, which would call dump_stack again.
if(recursive_counter > 20)
{
return;
}

unsigned long a0, a1;
unsigned long sp_end;

a1 = (unsigned long)sp;
sp_end = ALIGN(a1, THREAD_SIZE);

spill_registers();

while (a1 < sp_end)
{
struct stackframe frame;

sp = (unsigned long *)a1;
a0 = SPILL_SLOT(a1, 0);
a1 = SPILL_SLOT(a1, 1);

if (a1 <= (unsigned long)sp)
{
break;
}

frame.pc = MAKE_PC_FROM_RA(a0, a1);
frame.sp = a1;

if (fn(&frame, data))
{
return;
}
}

return;
}

static int show_trace_cb(struct stackframe *frame, void *data)
{
printf("%s line %d, pc 0x%lx, sp 0x%lx, data=%p.\n", __func__, __LINE__, frame->pc, frame->sp, data);

return 0;
}

void show_trace(unsigned long pc, unsigned long *sp)
{
walk_stackframe(sp, show_trace_cb, NULL);
}

void show_stack(unsigned long pc, unsigned long *sp)
{
unsigned long *stack;

stack = sp;
show_trace(pc, stack);
}

static void __dump_stack(void)
{
unsigned long *sp = stack_pointer();

show_stack(0, sp);
}

void dump_stack(void)
{
__dump_stack();
}

结束!

举报

相关推荐

0 条评论