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