2167108126
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
335 lines
11 KiB
Diff
335 lines
11 KiB
Diff
From d86dc6901ce76a0fc29022ed448a4baa83a47dd7 Mon Sep 17 00:00:00 2001
|
|
From: Song Shuai <songshuaishuai@tinylab.org>
|
|
Date: Wed, 13 Dec 2023 17:45:06 +0800
|
|
Subject: [PATCH 2/6] RISCV64: Add support for 'bt -e' option
|
|
|
|
With this patch we can search the stack for possible kernel and user
|
|
mode exception frames via 'bt -e' command.
|
|
|
|
TEST: a lkdtm DIRECT EXCEPTION vmcore
|
|
|
|
crash> bt -e
|
|
PID: 1 TASK: ff600000000e0000 CPU: 1 COMMAND: "sh"
|
|
|
|
KERNEL-MODE EXCEPTION FRAME AT: ff200000000138d8
|
|
PC: ffffffff805303c0 [lkdtm_EXCEPTION+6]
|
|
RA: ffffffff8052fe36 [lkdtm_do_action+16]
|
|
SP: ff20000000013cf0 CAUSE: 000000000000000f
|
|
epc : ffffffff805303c0 ra : ffffffff8052fe36 sp : ff20000000013cf0
|
|
gp : ffffffff814ef848 tp : ff600000000e0000 t0 : 6500000000000000
|
|
t1 : 000000000000006c t2 : 6550203a6d74646b s0 : ff20000000013d00
|
|
s1 : 000000000000000a a0 : ffffffff814aef40 a1 : c0000000ffffefff
|
|
a2 : 0000000000000010 a3 : 0000000000000001 a4 : 5d53ea10ca096e00
|
|
a5 : ffffffff805303ba a6 : 0000000000000008 a7 : 0000000000000038
|
|
s2 : ff60000001324000 s3 : ffffffff814aef40 s4 : ff20000000013e30
|
|
s5 : 000000000000000a s6 : ff20000000013e30 s7 : ff600000000ce000
|
|
s8 : 0000555560f0f8a8 s9 : 00007ffff497f6b4 s10: 00007ffff497f6b0
|
|
s11: 0000555560fa30e0 t3 : ffffffff81502197 t4 : ffffffff81502197
|
|
t5 : ffffffff81502198 t6 : ff20000000013b28
|
|
status: 0000000200000120 badaddr: 0000000000000000
|
|
cause: 000000000000000f orig_a0: 0000000000000000
|
|
|
|
USER-MODE EXCEPTION FRAME AT: ff20000000013ee0
|
|
PC: 007fff8780431aff RA: 007fff877b168400 SP: 007ffff497f5b000
|
|
ORIG_A0: 0000000000000100 SYSCALLNO: 0000000000004000
|
|
epc : 007fff8780431aff ra : 007fff877b168400 sp : 007ffff497f5b000
|
|
gp : 00555560f5134800 tp : 007fff8774378000 t0 : 0000000000100000
|
|
t1 : 00555560e427bc00 t2 : 0000000000271000 s0 : 007ffff497f5e000
|
|
s1 : 0000000000000a00 a0 : 0000000000000100 a1 : 00555560faa68000
|
|
a2 : 0000000000000a00 a3 : 4000000000000000 a4 : 20000000000000a8
|
|
a5 : 0000000000000054 a6 : 0000000000000400 a7 : 0000000000004000
|
|
s2 : 00555560faa68000 s3 : 007fff878b33f800 s4 : 0000000000000a00
|
|
s5 : 00555560faa68000 s6 : 0000000000000a00 s7 : 00555560f5131400
|
|
s8 : 00555560f0f8a800 s9 : 007ffff497f6b400 s10: 007ffff497f6b000
|
|
s11: 00555560fa30e000 t3 : 007fff877af1fe00 t4 : 00555560fa6f2000
|
|
t5 : 0000000000000100 t6 : 9e1fea5bf8683300
|
|
status: 00000200004020b9 badaddr: 0000000000000000
|
|
cause: 0000000000000800 orig_a0: 0000000000000100
|
|
crash>
|
|
|
|
Signed-off-by: Song Shuai <songshuaishuai@tinylab.org>
|
|
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
|
|
---
|
|
defs.h | 15 +++--
|
|
riscv64.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++-----
|
|
2 files changed, 181 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/defs.h b/defs.h
|
|
index aa8eba83b7f4..9cf9501348ed 100644
|
|
--- a/defs.h
|
|
+++ b/defs.h
|
|
@@ -7011,17 +7011,16 @@ int riscv64_IS_VMALLOC_ADDR(ulong);
|
|
#define display_idt_table() \
|
|
error(FATAL, "-d option is not applicable to RISCV64 architecture\n")
|
|
|
|
-/* from arch/riscv/include/asm/ptrace.h */
|
|
+/*
|
|
+ * regs[0,31] : struct user_regs_struct
|
|
+ * from arch/riscv/include/uapi/asm/ptrace.h
|
|
+ * regs[0,35] : struct pt_regs
|
|
+ * from arch/riscv/include/asm/ptrace.h
|
|
+ */
|
|
struct riscv64_register {
|
|
ulong regs[36];
|
|
};
|
|
|
|
-struct riscv64_pt_regs {
|
|
- ulong badvaddr;
|
|
- ulong cause;
|
|
- ulong epc;
|
|
-};
|
|
-
|
|
struct riscv64_unwind_frame {
|
|
ulong fp;
|
|
ulong sp;
|
|
@@ -7085,6 +7084,8 @@ struct machine_specific {
|
|
#define RISCV64_REGS_RA 1
|
|
#define RISCV64_REGS_SP 2
|
|
#define RISCV64_REGS_FP 8
|
|
+#define RISCV64_REGS_STATUS 32
|
|
+#define RISCV64_REGS_CAUSE 34
|
|
|
|
#endif /* RISCV64 */
|
|
|
|
diff --git a/riscv64.c b/riscv64.c
|
|
index 872be594d72b..6097c0029ccc 100644
|
|
--- a/riscv64.c
|
|
+++ b/riscv64.c
|
|
@@ -35,6 +35,7 @@ static int riscv64_kvtop(struct task_context *tc, ulong kvaddr,
|
|
static void riscv64_cmd_mach(void);
|
|
static void riscv64_stackframe_init(void);
|
|
static void riscv64_back_trace_cmd(struct bt_info *bt);
|
|
+static int riscv64_eframe_search(struct bt_info *bt);
|
|
static int riscv64_get_dumpfile_stack_frame(struct bt_info *bt,
|
|
ulong *nip, ulong *ksp);
|
|
static void riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp,
|
|
@@ -51,6 +52,8 @@ static int riscv64_get_elf_notes(void);
|
|
static void riscv64_get_va_range(struct machine_specific *ms);
|
|
static void riscv64_get_va_bits(struct machine_specific *ms);
|
|
static void riscv64_get_struct_page_size(struct machine_specific *ms);
|
|
+static void riscv64_print_exception_frame(struct bt_info *, ulong , int );
|
|
+static int riscv64_is_kernel_exception_frame(struct bt_info *, ulong );
|
|
|
|
#define REG_FMT "%016lx"
|
|
#define SZ_2G 0x80000000
|
|
@@ -210,6 +213,7 @@ riscv64_dump_machdep_table(ulong arg)
|
|
machdep->memsize, machdep->memsize);
|
|
fprintf(fp, " bits: %d\n", machdep->bits);
|
|
fprintf(fp, " back_trace: riscv64_back_trace_cmd()\n");
|
|
+ fprintf(fp, " eframe_search: riscv64_eframe_search()\n");
|
|
fprintf(fp, " processor_speed: riscv64_processor_speed()\n");
|
|
fprintf(fp, " uvtop: riscv64_uvtop()\n");
|
|
fprintf(fp, " kvtop: riscv64_kvtop()\n");
|
|
@@ -1398,6 +1402,7 @@ riscv64_init(int when)
|
|
machdep->cmd_mach = riscv64_cmd_mach;
|
|
machdep->get_stack_frame = riscv64_get_stack_frame;
|
|
machdep->back_trace = riscv64_back_trace_cmd;
|
|
+ machdep->eframe_search = riscv64_eframe_search;
|
|
|
|
machdep->vmalloc_start = riscv64_vmalloc_start;
|
|
machdep->processor_speed = riscv64_processor_speed;
|
|
@@ -1452,25 +1457,10 @@ riscv64_init(int when)
|
|
}
|
|
}
|
|
|
|
-/*
|
|
- * 'help -r' command output
|
|
- */
|
|
-void
|
|
-riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
|
|
+/* bool pt_regs : pass 1 to dump pt_regs , pass 0 to dump user_regs_struct */
|
|
+static void
|
|
+riscv64_dump_pt_regs(struct riscv64_register *regs, FILE *ofp, bool pt_regs)
|
|
{
|
|
- const struct machine_specific *ms = machdep->machspec;
|
|
- struct riscv64_register *regs;
|
|
-
|
|
- if (!ms->crash_task_regs) {
|
|
- error(INFO, "registers not collected for cpu %d\n", cpu);
|
|
- return;
|
|
- }
|
|
-
|
|
- regs = &ms->crash_task_regs[cpu];
|
|
- if (!regs->regs[RISCV64_REGS_SP] && !regs->regs[RISCV64_REGS_EPC]) {
|
|
- error(INFO, "registers not collected for cpu %d\n", cpu);
|
|
- return;
|
|
- }
|
|
|
|
/* Print riscv64 32 regs */
|
|
fprintf(ofp,
|
|
@@ -1496,6 +1486,171 @@ riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
|
|
regs->regs[24], regs->regs[25], regs->regs[26],
|
|
regs->regs[27], regs->regs[28], regs->regs[29],
|
|
regs->regs[30], regs->regs[31]);
|
|
+
|
|
+ if (pt_regs)
|
|
+ fprintf(ofp,
|
|
+ " status: " REG_FMT " badaddr: " REG_FMT "\n"
|
|
+ " cause: " REG_FMT " orig_a0: " REG_FMT "\n",
|
|
+ regs->regs[32], regs->regs[33], regs->regs[34],
|
|
+ regs->regs[35]);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 'help -r' command output
|
|
+ */
|
|
+void
|
|
+riscv64_display_regs_from_elf_notes(int cpu, FILE *ofp)
|
|
+{
|
|
+ const struct machine_specific *ms = machdep->machspec;
|
|
+ struct riscv64_register *regs;
|
|
+
|
|
+ if (!ms->crash_task_regs) {
|
|
+ error(INFO, "registers not collected for cpu %d\n", cpu);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ regs = &ms->crash_task_regs[cpu];
|
|
+ if (!regs->regs[RISCV64_REGS_SP] && !regs->regs[RISCV64_REGS_EPC]) {
|
|
+ error(INFO, "registers not collected for cpu %d\n", cpu);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ riscv64_dump_pt_regs(regs, ofp, 0);
|
|
+}
|
|
+
|
|
+#define USER_MODE (0)
|
|
+#define KERNEL_MODE (1)
|
|
+
|
|
+static void
|
|
+riscv64_print_exception_frame(struct bt_info *bt, ulong ptr, int mode)
|
|
+{
|
|
+
|
|
+ struct syment *sp;
|
|
+ ulong PC, RA, SP, offset;
|
|
+ struct riscv64_register *regs;
|
|
+
|
|
+ regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(ptr))];
|
|
+
|
|
+ PC = regs->regs[RISCV64_REGS_EPC];
|
|
+ RA = regs->regs[RISCV64_REGS_RA];
|
|
+ SP = regs->regs[RISCV64_REGS_SP];
|
|
+
|
|
+ switch (mode) {
|
|
+ case USER_MODE:
|
|
+ fprintf(fp,
|
|
+ " PC: %016lx RA: %016lx SP: %016lx\n"
|
|
+ " ORIG_A0: %016lx SYSCALLNO: %016lx\n",
|
|
+ PC, RA, SP, regs->regs[35], regs->regs[17]);
|
|
+
|
|
+ break;
|
|
+
|
|
+ case KERNEL_MODE:
|
|
+ fprintf(fp, " PC: %016lx ", PC);
|
|
+ if (is_kernel_text(PC) && (sp = value_search(PC, &offset))) {
|
|
+ fprintf(fp, "[%s", sp->name);
|
|
+ if (offset)
|
|
+ fprintf(fp, (*gdb_output_radix == 16) ?
|
|
+ "+0x%lx" : "+%ld", offset);
|
|
+ fprintf(fp, "]\n");
|
|
+ } else
|
|
+ fprintf(fp, "[unknown or invalid address]\n");
|
|
+
|
|
+ fprintf(fp, " RA: %016lx ", RA);
|
|
+ if (is_kernel_text(RA) && (sp = value_search(RA, &offset))) {
|
|
+ fprintf(fp, "[%s", sp->name);
|
|
+ if (offset)
|
|
+ fprintf(fp, (*gdb_output_radix == 16) ?
|
|
+ "+0x%lx" : "+%ld", offset);
|
|
+ fprintf(fp, "]\n");
|
|
+ } else
|
|
+ fprintf(fp, "[unknown or invalid address]\n");
|
|
+
|
|
+ fprintf(fp, " SP: %016lx CAUSE: %016lx\n",
|
|
+ SP, regs->regs[RISCV64_REGS_CAUSE]);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ riscv64_dump_pt_regs(regs, fp, 1);
|
|
+
|
|
+}
|
|
+
|
|
+static int
|
|
+riscv64_is_kernel_exception_frame(struct bt_info *bt, ulong stkptr)
|
|
+{
|
|
+ struct riscv64_register *regs;
|
|
+
|
|
+ if (stkptr > STACKSIZE() && !INSTACK(stkptr, bt)) {
|
|
+ if (CRASHDEBUG(1))
|
|
+ error(WARNING, "stkptr: %lx is outside the kernel stack range\n", stkptr);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
+ regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))];
|
|
+
|
|
+ if (INSTACK(regs->regs[RISCV64_REGS_SP], bt) &&
|
|
+ INSTACK(regs->regs[RISCV64_REGS_FP], bt) &&
|
|
+ is_kernel_text(regs->regs[RISCV64_REGS_RA]) &&
|
|
+ is_kernel_text(regs->regs[RISCV64_REGS_EPC]) &&
|
|
+ ((regs->regs[RISCV64_REGS_STATUS] >> 8) & 0x1) && // sstatus.SPP != 0
|
|
+ !((regs->regs[RISCV64_REGS_CAUSE] >> 63) & 0x1 ) && // scause.Interrupt != 1
|
|
+ !(regs->regs[RISCV64_REGS_CAUSE] == 0x00000008UL)) { // scause != ecall from U-mode
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+static int
|
|
+riscv64_dump_kernel_eframes(struct bt_info *bt)
|
|
+{
|
|
+ ulong ptr;
|
|
+ int count;
|
|
+
|
|
+ /*
|
|
+ * use old_regs to avoid the identical contiguous kernel exception frames
|
|
+ * created by Linux handle_exception() path ending at riscv_crash_save_regs()
|
|
+ */
|
|
+ struct riscv64_register *regs, *old_regs;
|
|
+
|
|
+ count = 0;
|
|
+ old_regs = NULL;
|
|
+
|
|
+ for (ptr = bt->stackbase; ptr < bt->stacktop - SIZE(pt_regs); ptr++) {
|
|
+
|
|
+ regs = (struct riscv64_register *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(ptr))];
|
|
+
|
|
+ if (riscv64_is_kernel_exception_frame(bt, ptr)){
|
|
+ if (!old_regs || (old_regs &&
|
|
+ memcmp(old_regs, regs, sizeof(struct riscv64_register))) != 0){
|
|
+ old_regs = regs;
|
|
+ fprintf(fp, "\nKERNEL-MODE EXCEPTION FRAME AT: %lx\n", ptr);
|
|
+ riscv64_print_exception_frame(bt, ptr, KERNEL_MODE);
|
|
+ count++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static int
|
|
+riscv64_eframe_search(struct bt_info *bt)
|
|
+{
|
|
+ ulong ptr;
|
|
+ int count;
|
|
+
|
|
+ count = riscv64_dump_kernel_eframes(bt);
|
|
+
|
|
+ if (is_kernel_thread(bt->tc->task))
|
|
+ return count;
|
|
+
|
|
+ ptr = bt->stacktop - SIZE(pt_regs);
|
|
+ fprintf(fp, "%sUSER-MODE EXCEPTION FRAME AT: %lx\n", count++ ? "\n" : "", ptr);
|
|
+ riscv64_print_exception_frame(bt, ptr, USER_MODE);
|
|
+
|
|
+ return count;
|
|
}
|
|
|
|
#else /* !RISCV64 */
|
|
--
|
|
2.41.0
|
|
|