crash-stack: Fix a misuse of register (workaround) 96/318296/3 accepted/tizen/unified/20250116.113515 accepted/tizen/unified/x/20250116.213650
authorSung-hun Kim <sfoon.kim@samsung.com>
Wed, 15 Jan 2025 07:00:36 +0000 (16:00 +0900)
committerSung-hun Kim <sfoon.kim@samsung.com>
Wed, 15 Jan 2025 07:23:20 +0000 (16:23 +0900)
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 <sfoon.kim@samsung.com>
Reported-by: Seung-Woo Kim <sw0312.kim@samsung.com>
src/crash-stack/crash-stack-riscv64.c

index 084fee9b4e547eaa810d69a175401ec2e0b3990a..15d2b95e2e9b0d66aabe3b904441580a63caaad8 100644 (file)
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <asm/ptrace.h>
+#include <assert.h>
 
 #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];
 }