arm64: Add gdb stack unwind support

Signed-off-by: Tao Liu <ltao@redhat.com>
This commit is contained in:
Tao Liu 2024-09-04 19:49:40 +12:00 committed by Lianbo Jiang
parent 89ff1e4573
commit 968debd0d5
2 changed files with 148 additions and 8 deletions

120
arm64.c
View File

@ -121,6 +121,11 @@ static void arm64_get_struct_page_size(struct machine_specific *ms);
#define mte_tag_reset(addr) (((ulong)addr & ~mte_tag_shifted(KASAN_TAG_KERNEL)) | \
mte_tag_shifted(KASAN_TAG_KERNEL))
struct user_regs_bitmap_struct {
struct arm64_pt_regs ur;
ulong bitmap[32];
};
static inline bool is_mte_kvaddr(ulong addr)
{
/* check for ARM64_MTE enabled */
@ -197,6 +202,94 @@ out:
machdep->is_page_ptr = arm64_vmemmap_is_page_ptr;
}
static int
arm64_get_current_task_reg(int regno, const char *name,
int size, void *value)
{
struct bt_info bt_info, bt_setup;
struct task_context *tc;
struct user_regs_bitmap_struct *ur_bitmap;
ulong ip, sp;
bool ret = FALSE;
switch (regno) {
case X0_REGNUM ... PC_REGNUM:
break;
default:
return FALSE;
}
tc = CURRENT_CONTEXT();
if (!tc)
return FALSE;
BZERO(&bt_setup, sizeof(struct bt_info));
clone_bt_info(&bt_setup, &bt_info, tc);
fill_stackbuf(&bt_info);
get_dumpfile_regs(&bt_info, &sp, &ip);
if (bt_info.stackbuf)
FREEBUF(bt_info.stackbuf);
ur_bitmap = (struct user_regs_bitmap_struct *)bt_info.machdep;
if (!ur_bitmap)
return FALSE;
if (!bt_info.need_free) {
goto get_all;
}
switch (regno) {
case X0_REGNUM ... X30_REGNUM:
if (!NUM_IN_BITMAP(ur_bitmap->bitmap,
REG_SEQ(arm64_pt_regs, regs[0]) + regno - X0_REGNUM)) {
FREEBUF(ur_bitmap);
return FALSE;
}
break;
case SP_REGNUM:
if (!NUM_IN_BITMAP(ur_bitmap->bitmap,
REG_SEQ(arm64_pt_regs, sp))) {
FREEBUF(ur_bitmap);
return FALSE;
}
break;
case PC_REGNUM:
if (!NUM_IN_BITMAP(ur_bitmap->bitmap,
REG_SEQ(arm64_pt_regs, pc))) {
FREEBUF(ur_bitmap);
return FALSE;
}
break;
}
get_all:
switch (regno) {
case X0_REGNUM ... X30_REGNUM:
if (size != sizeof(ur_bitmap->ur.regs[regno]))
break;
memcpy(value, &ur_bitmap->ur.regs[regno], size);
ret = TRUE;
break;
case SP_REGNUM:
if (size != sizeof(ur_bitmap->ur.sp))
break;
memcpy(value, &ur_bitmap->ur.sp, size);
ret = TRUE;
break;
case PC_REGNUM:
if (size != sizeof(ur_bitmap->ur.pc))
break;
memcpy(value, &ur_bitmap->ur.pc, size);
ret = TRUE;
break;
}
if (bt_info.need_free) {
FREEBUF(ur_bitmap);
bt_info.need_free = FALSE;
}
return ret;
}
/*
* Do all necessary machine-specific setup here. This is called several times
* during initialization.
@ -549,6 +642,7 @@ arm64_init(int when)
machdep->dumpfile_init = NULL;
machdep->verify_line_number = NULL;
machdep->init_kernel_pgd = arm64_init_kernel_pgd;
machdep->get_current_task_reg = arm64_get_current_task_reg;
/* use machdep parameters */
arm64_calc_phys_offset();
@ -683,6 +777,7 @@ arm64_init(int when)
*/
if (!LIVE())
arm64_get_crash_notes();
gdb_change_thread_context();
break;
case LOG_ONLY:
@ -4134,6 +4229,7 @@ arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame
try_kernel:
frame->sp = ptregs->sp;
frame->fp = ptregs->regs[29];
bt->machdep = ptregs;
}
if (arm64_in_kdump_text(bt, frame) ||
@ -4162,22 +4258,30 @@ arm64_get_stackframe(struct bt_info *bt, struct arm64_stackframe *frame)
static void
arm64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
{
int ret;
struct user_regs_bitmap_struct *ur_bitmap;
struct arm64_stackframe stackframe = { 0 };
if (DUMPFILE() && is_task_active(bt->task)) {
ret = arm64_get_dumpfile_stackframe(bt, &stackframe);
arm64_get_dumpfile_stackframe(bt, &stackframe);
bt->need_free = FALSE;
} else {
if (bt->flags & BT_SKIP_IDLE)
bt->flags &= ~BT_SKIP_IDLE;
ret = arm64_get_stackframe(bt, &stackframe);
}
arm64_get_stackframe(bt, &stackframe);
if (!ret)
error(WARNING,
"cannot determine starting stack frame for task %lx\n",
bt->task);
ur_bitmap = (struct user_regs_bitmap_struct *)GETBUF(sizeof(*ur_bitmap));
memset(ur_bitmap, 0, sizeof(*ur_bitmap));
ur_bitmap->ur.pc = stackframe.pc;
ur_bitmap->ur.sp = stackframe.sp;
ur_bitmap->ur.regs[29] = stackframe.fp;
SET_BIT(ur_bitmap->bitmap, REG_SEQ(arm64_pt_regs, pc));
SET_BIT(ur_bitmap->bitmap, REG_SEQ(arm64_pt_regs, sp));
SET_BIT(ur_bitmap->bitmap, REG_SEQ(arm64_pt_regs, regs[0])
+ X29_REGNUM - X0_REGNUM);
bt->machdep = ur_bitmap;
bt->need_free = TRUE;
}
bt->frameptr = stackframe.fp;
if (pcp)

36
defs.h
View File

@ -8143,6 +8143,42 @@ enum x86_64_regnum {
LAST_REGNUM
};
enum arm64_regnum {
X0_REGNUM,
X1_REGNUM,
X2_REGNUM,
X3_REGNUM,
X4_REGNUM,
X5_REGNUM,
X6_REGNUM,
X7_REGNUM,
X8_REGNUM,
X9_REGNUM,
X10_REGNUM,
X11_REGNUM,
X12_REGNUM,
X13_REGNUM,
X14_REGNUM,
X15_REGNUM,
X16_REGNUM,
X17_REGNUM,
X18_REGNUM,
X19_REGNUM,
X20_REGNUM,
X21_REGNUM,
X22_REGNUM,
X23_REGNUM,
X24_REGNUM,
X25_REGNUM,
X26_REGNUM,
X27_REGNUM,
X28_REGNUM,
X29_REGNUM,
X30_REGNUM,
SP_REGNUM,
PC_REGNUM,
};
/*
* Register numbers to make crash_target->fetch_registers()
* ---> machdep->get_current_task_reg() work properly.