From 4b49f35fb0efcb04774173cba516d59e4150fb18 Mon Sep 17 00:00:00 2001 From: Sung-hun Kim Date: Wed, 15 Jan 2025 16:00:36 +0900 Subject: [PATCH] crash-stack: Fix a misuse of register (workaround) Regsiter values in struct user_regs_struct has a different layout against its real register layout in the RISCV architecture. Especially, x0 in RISCV means hard-wired zero register, but user_regs_struct has PC value as the first member of it. Since, crash-stack follows the layout of user_regs_struct, it should have maps from original register numbers to its array indexes. The previous code defines these maps, but there is a mistake. It does not properly map UNW_RISCV_PC (64) to the index zero in its register value array. Because of that, a try to get UNW_RISCV_PC causes a buffer-overflow problem. This patch fixes this issue. But, I think that the use of register names should be revised due to the their semantics. Change-Id: I420da22f37e693e0bdf29debb03997d7cdd8bf29 Signed-off-by: Sung-hun Kim Reported-by: Seung-Woo Kim --- src/crash-stack/crash-stack-riscv64.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/crash-stack/crash-stack-riscv64.c b/src/crash-stack/crash-stack-riscv64.c index 084fee9b..15d2b95e 100644 --- a/src/crash-stack/crash-stack-riscv64.c +++ b/src/crash-stack/crash-stack-riscv64.c @@ -30,6 +30,7 @@ #include #include #include +#include #define REG_RISCV_S0 8 #define REG_RISCV_RA 1 @@ -81,7 +82,6 @@ void *_get_place_for_register_value(const char *regname, int regnum) unsigned long _get_register_value(int n) { - // return g_registers.regs[n]; const static int reg_map[] = { [UNW_RISCV_X0] = offsetof(struct user_regs_struct, pc) / sizeof(long), [UNW_RISCV_X1] = offsetof(struct user_regs_struct, ra) / sizeof(long), @@ -116,6 +116,13 @@ unsigned long _get_register_value(int n) [UNW_RISCV_X30] = offsetof(struct user_regs_struct, t5) / sizeof(long), [UNW_RISCV_X31] = offsetof(struct user_regs_struct, t6) / sizeof(long), }; + // XXX: To match with libunwind, UNW_RISCV_PC should be handled as UNW_RISCV_X0. + // This is because user_regs_struct holds PC value as the first member of it. + // But it is not a proper use of register name. Originally, UNW_RISCV_X0 is used + // to get zero value. + if (n == UNW_RISCV_PC) + n = UNW_RISCV_X0; + assert(n >= UNW_RISCV_X0 && n <= UNW_RISCV_X31); n = reg_map[n]; return ((elf_greg_t*)&g_registers)[n]; } -- 2.34.1