[Crash-utility] [PATCH 1/3] RISCV64: Add support for 'bt -e' option

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 defs.h    |  15 +++--
 riscv64.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 182 insertions(+), 25 deletions(-)

diff --git a/defs.h b/defs.h
index 5218a94..a1d821d 100644
--- a/defs.h
+++ b/defs.h
@@ -6996,17 +6996,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;
@@ -7070,6 +7069,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 872be59..f6c83ff 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,172 @@ 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.20.1
--
Crash-utility mailing list -- devel@xxxxxxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxxxxxxxxxxxx
https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
Contribution Guidelines: https://github.com/crash-utility/crash/wiki




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux