<div dir="ltr"><div dir="ltr">On Mon, Aug 1, 2022 at 12:31 PM Xianting Tian <<a href="mailto:xianting.tian@linux.alibaba.com">xianting.tian@linux.alibaba.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">1, Add the implementation to get stack frame from active & inactive<br>
task's stack.<br>
2, Add 'bt -l' command support get a line number associated with a<br>
current pc address.<br>
3, Add 'bt -f' command support to display all stack data contained<br>
in a frame<br>
<br>
With the patch, we can get the backtrace,<br>
crash> bt<br>
PID: 113 TASK: ff6000000226c200 CPU: 0 COMMAND: "sh"<br>
#0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8<br>
#1 [ff20000010333cf0] panic at ffffffff806578c6<br>
#2 [ff20000010333d50] sysrq_reset_seq_param_set at ffffffff8038c03c<br>
#3 [ff20000010333da0] __handle_sysrq at ffffffff8038c604<br>
#4 [ff20000010333e00] write_sysrq_trigger at ffffffff8038cae4<br>
#5 [ff20000010333e20] proc_reg_write at ffffffff801b7ee8<br>
#6 [ff20000010333e40] vfs_write at ffffffff80152bb2<br>
#7 [ff20000010333e80] ksys_write at ffffffff80152eda<br>
#8 [ff20000010333ed0] sys_write at ffffffff80152f52<br>
<br>
crash> bt -l<br>
PID: 113 TASK: ff6000000226c200 CPU: 0 COMMAND: "sh"<br>
#0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8<br>
/buildroot/qemu_riscv64_virt_defconfig/build/linux-custom/arch/riscv/kernel/crash_save_regs.S: 47<br>
#1 [ff20000010333cf0] panic at ffffffff806578c6<br>
/buildroot/qemu_riscv64_virt_defconfig/build/linux-custom/kernel/panic.c: 276<br>
... ...<br>
<br>
crash> bt -f<br>
PID: 113 TASK: ff6000000226c200 CPU: 0 COMMAND: "sh"<br>
#0 [ff20000010333b90] riscv_crash_save_regs at ffffffff800078f8<br>
[PC: ffffffff800078f8 RA: ffffffff806578c6 SP: ff20000010333b90 SIZE: 352]<br>
ff20000010333b90: ff20000010333bb0 ffffffff800078f8<br>
ff20000010333ba0: ffffffff8008862c ff20000010333b90<br>
ff20000010333bb0: ffffffff810dde38 ff6000000226c200<br>
ff20000010333bc0: ffffffff8032be68 0720072007200720<br>
... ...<br>
<br>
Signed-off-by: Xianting Tian <<a href="mailto:xianting.tian@linux.alibaba.com" target="_blank">xianting.tian@linux.alibaba.com</a>><br>
---<br>
netdump.c | 13 +++<br>
riscv64.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
2 files changed, 300 insertions(+)<br>
<br>
diff --git a/netdump.c b/netdump.c<br>
index 4ec12a0..1f418e6 100644<br>
--- a/netdump.c<br>
+++ b/netdump.c<br>
@@ -42,6 +42,7 @@ static void get_netdump_regs_ppc64(struct bt_info *, ulong *, ulong *);<br>
static void get_netdump_regs_arm(struct bt_info *, ulong *, ulong *);<br>
static void get_netdump_regs_arm64(struct bt_info *, ulong *, ulong *);<br>
static void get_netdump_regs_mips(struct bt_info *, ulong *, ulong *);<br>
+static void get_netdump_regs_riscv(struct bt_info *, ulong *, ulong *);<br>
static void check_dumpfile_size(char *);<br>
static int proc_kcore_init_32(FILE *, int);<br>
static int proc_kcore_init_64(FILE *, int);<br>
@@ -2675,6 +2676,10 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp)<br>
return get_netdump_regs_mips(bt, eip, esp);<br>
break;<br>
<br>
+ case EM_RISCV:<br>
+ return get_netdump_regs_riscv(bt, eip, esp);<br>
+ break;<br>
+<br></blockquote><div> </div><div>This looks weird. I guess that you are still following the old code changes. I would suggest using a better</div><div>code style as below, unless you have specific reasons.</div><div><br></div><div>+ case EM_RISCV:<br>
+ get_netdump_regs_riscv(bt, eip, esp);<br>
+ break;<br>
+</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
default:<br>
error(FATAL, <br>
"support for ELF machine type %d not available\n",<br>
@@ -2931,6 +2936,8 @@ display_regs_from_elf_notes(int cpu, FILE *ofp)<br>
mips_display_regs_from_elf_notes(cpu, ofp);<br>
} else if (machine_type("MIPS64")) {<br>
mips64_display_regs_from_elf_notes(cpu, ofp);<br>
+ } else if (machine_type("RISCV64")) {<br>
+ riscv64_display_regs_from_elf_notes(cpu, ofp);<br>
}<br>
}<br>
<br>
@@ -3877,6 +3884,12 @@ get_netdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp)<br>
machdep->get_stack_frame(bt, eip, esp);<br>
}<br>
<br>
+static void<br>
+get_netdump_regs_riscv(struct bt_info *bt, ulong *eip, ulong *esp)<br>
+{<br>
+ machdep->get_stack_frame(bt, eip, esp);<br>
+}<br>
+<br>
int <br>
is_partial_netdump(void)<br>
{<br>
diff --git a/riscv64.c b/riscv64.c<br>
index db37123..8bd35f7 100644<br>
--- a/riscv64.c<br>
+++ b/riscv64.c<br>
@@ -33,6 +33,17 @@ static int riscv64_uvtop(struct task_context *tc, ulong vaddr,<br>
static int riscv64_kvtop(struct task_context *tc, ulong kvaddr,<br>
physaddr_t *paddr, int verbose);<br>
static void riscv64_cmd_mach(void);<br>
+static void riscv64_stackframe_init(void);<br>
+static void riscv64_back_trace_cmd(struct bt_info *bt);<br>
+static int riscv64_get_dumpfile_stack_frame(struct bt_info *bt,<br>
+ ulong *nip, ulong *ksp);<br>
+static void riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp,<br>
+ ulong *spp);<br>
+static int riscv64_get_frame(struct bt_info *bt, ulong *pcp,<br>
+ ulong *spp);<br>
+static void riscv64_display_full_frame(struct bt_info *bt,<br>
+ struct riscv64_unwind_frame *current,<br>
+ struct riscv64_unwind_frame *previous);<br>
static int riscv64_translate_pte(ulong, void *, ulonglong);<br>
static int riscv64_init_active_task_regs(void);<br>
static int riscv64_get_crash_notes(void);<br>
@@ -503,6 +514,279 @@ no_page:<br>
return FALSE;<br>
}<br>
<br>
+/*<br>
+ * 'bt -f' command output<br>
+ * Display all stack data contained in a frame<br>
+ */<br>
+static void<br>
+riscv64_display_full_frame(struct bt_info *bt, struct riscv64_unwind_frame *current,<br>
+ struct riscv64_unwind_frame *previous)<br>
+{<br>
+ int i, u_idx;<br>
+ ulong *up;<br>
+ ulong words, addr;<br>
+ char buf[BUFSIZE];<br>
+<br>
+ if (previous->sp < current->sp)<br>
+ return;<br>
+<br>
+ if (!(INSTACK(previous->sp, bt) && INSTACK(current->sp, bt)))<br>
+ return;<br>
+<br>
+ words = (previous->sp - current->sp) / sizeof(ulong) + 1;<br>
+ addr = current->sp;<br>
+ u_idx = (current->sp - bt->stackbase) / sizeof(ulong);<br>
+<br>
+ for (i = 0; i < words; i++, u_idx++) {<br>
+ if (!(i & 1))<br>
+ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr);<br>
+<br>
+ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]);<br>
+ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));<br>
+ addr += sizeof(ulong);<br>
+ }<br>
+ fprintf(fp, "\n");<br>
+<br>
+ return;<br></blockquote><div> ^^^^^^^<br></div><div>Is it redundant? Could it be removed?<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<br>
+<br>
+static void<br>
+riscv64_stackframe_init(void)<br>
+{<br>
+ long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");<br>
+<br>
+ /* from arch/riscv/include/asm/processor.h */<br>
+ long thread_reg_ra = MEMBER_OFFSET("thread_struct", "ra");<br>
+ long thread_reg_sp = MEMBER_OFFSET("thread_struct", "sp");<br>
+ long thread_reg_fp = MEMBER_OFFSET("thread_struct", "s");<br>
+<br>
+ if ((task_struct_thread == INVALID_OFFSET) ||<br>
+ (thread_reg_ra == INVALID_OFFSET) ||<br>
+ (thread_reg_sp == INVALID_OFFSET) ||<br>
+ (thread_reg_fp == INVALID_OFFSET) ) {<br>
+ error(FATAL,<br>
+ "cannot determine thread_struct offsets\n");<br>
+ return;<br></blockquote><div> ^^^^^^</div><div>The "return" has no chance to execute due to the "error(<span style="color:rgb(255,0,0)">FATAL</span>, ...)".<br></div><div><br></div><div>Thanks.</div><div>Lianbo</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+ }<br>
+<br>
+ ASSIGN_OFFSET(task_struct_thread_context_pc) =<br>
+ task_struct_thread + thread_reg_ra;<br>
+ ASSIGN_OFFSET(task_struct_thread_context_sp) =<br>
+ task_struct_thread + thread_reg_sp;<br>
+ ASSIGN_OFFSET(task_struct_thread_context_fp) =<br>
+ task_struct_thread + thread_reg_fp;<br>
+}<br>
+<br>
+static void<br>
+riscv64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,<br>
+ struct riscv64_unwind_frame *current,<br>
+ struct riscv64_unwind_frame *previous, int level)<br>
+{<br>
+ const char *name = sym ? sym->name : "(invalid)";<br>
+ struct load_module *lm;<br>
+ char *name_plus_offset = NULL;<br>
+ struct syment *symp;<br>
+ ulong symbol_offset;<br>
+ char buf[BUFSIZE];<br>
+<br>
+ if (bt->flags & BT_SYMBOL_OFFSET) {<br>
+ symp = value_search(current->pc, &symbol_offset);<br>
+<br>
+ if (symp && symbol_offset)<br>
+ name_plus_offset =<br>
+ value_to_symstr(current->pc, buf, bt->radix);<br>
+ }<br>
+<br>
+ fprintf(fp, "%s#%d [%016lx] %s at %016lx",<br>
+ level < 10 ? " " : "",<br>
+ level,<br>
+ current->sp,<br>
+ name_plus_offset ? name_plus_offset : name,<br>
+ current->pc);<br>
+<br>
+ if (module_symbol(current->pc, NULL, &lm, NULL, 0))<br>
+ fprintf(fp, " [%s]", lm->mod_name);<br>
+<br>
+ fprintf(fp, "\n");<br>
+<br>
+ /*<br>
+ * 'bt -l', get a line number associated with a current pc address.<br>
+ */<br>
+ if (bt->flags & BT_LINE_NUMBERS) {<br>
+ get_line_number(current->pc, buf, FALSE);<br>
+ if (strlen(buf))<br>
+ fprintf(fp, " %s\n", buf);<br>
+ }<br>
+<br>
+ /* bt -f */<br>
+ if (bt->flags & BT_FULL) {<br>
+ fprintf(fp, " "<br>
+ "[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n",<br>
+ current->pc,<br>
+ previous->pc,<br>
+ current->sp,<br>
+ previous->sp - current->sp);<br>
+ riscv64_display_full_frame(bt, current, previous);<br>
+ }<br>
+}<br>
+<br>
+/*<br>
+ * Unroll a kernel stack.<br>
+ */<br>
+static void<br>
+riscv64_back_trace_cmd(struct bt_info *bt)<br>
+{<br>
+ struct riscv64_unwind_frame current, previous;<br>
+ struct stackframe curr_frame;<br>
+ int level = 0;<br>
+<br>
+ if (bt->flags & BT_REGS_NOT_FOUND)<br>
+ return;<br>
+<br>
+ current.pc = bt->instptr;<br>
+ current.sp = bt->stkptr;<br>
+ current.fp = bt->frameptr;<br>
+<br>
+ if (!INSTACK(current.sp, bt))<br>
+ return;<br>
+<br>
+ for (;;) {<br>
+ struct syment *symbol = NULL;<br>
+ struct stackframe *frameptr;<br>
+ ulong low, high;<br>
+ ulong offset;<br>
+<br>
+ if (CRASHDEBUG(8))<br>
+ fprintf(fp, "level %d pc %#lx sp %lx fp 0x%lx\n",<br>
+ level, current.pc, current.sp, current.fp);<br>
+<br>
+ /* Validate frame pointer */<br>
+ low = current.sp + sizeof(struct stackframe);<br>
+ high = bt->stacktop;<br>
+ if (current.fp < low || current.fp > high || current.fp & 0x7) {<br>
+ if (CRASHDEBUG(8))<br>
+ fprintf(fp, "fp 0x%lx sp 0x%lx low 0x%lx high 0x%lx\n",<br>
+ current.fp, current.sp, low, high);<br>
+ return;<br>
+ }<br>
+<br>
+ symbol = value_search(current.pc, &offset);<br>
+ if (!symbol)<br>
+ return;<br>
+<br>
+ frameptr = (struct stackframe *)current.fp - 1;<br>
+ if (!readmem((ulong)frameptr, KVADDR, &curr_frame,<br>
+ sizeof(curr_frame), "get stack frame", RETURN_ON_ERROR))<br>
+ return;<br>
+<br>
+ previous.pc = curr_frame.ra;<br>
+ previous.fp = curr_frame.fp;<br>
+ previous.sp = current.fp;<br>
+<br>
+ riscv64_dump_backtrace_entry(bt, symbol, ¤t, &previous, level++);<br>
+<br>
+ current.pc = previous.pc;<br>
+ current.fp = previous.fp;<br>
+ current.sp = previous.sp;<br>
+<br>
+ if (CRASHDEBUG(8))<br>
+ fprintf(fp, "next %d pc %#lx sp %#lx fp %lx\n",<br>
+ level, current.pc, current.sp, current.fp);<br>
+ }<br>
+}<br>
+<br>
+/*<br>
+ * Get a stack frame combination of pc and ra from the most relevant spot.<br>
+ */<br>
+static void<br>
+riscv64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)<br>
+{<br>
+ ulong ksp = 0, nip = 0;<br>
+ int ret = 0;<br>
+<br>
+ if (DUMPFILE() && is_task_active(bt->task))<br>
+ ret = riscv64_get_dumpfile_stack_frame(bt, &nip, &ksp);<br>
+ else<br>
+ ret = riscv64_get_frame(bt, &nip, &ksp);<br>
+<br>
+ if (!ret)<br>
+ error(WARNING, "cannot determine starting stack frame for task %lx\n",<br>
+ bt->task);<br>
+<br>
+ if (pcp)<br>
+ *pcp = nip;<br>
+ if (spp)<br>
+ *spp = ksp;<br>
+}<br>
+<br>
+/*<br>
+ * Get the starting point for the active cpu in a diskdump.<br>
+ */<br>
+static int<br>
+riscv64_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)<br>
+{<br>
+ const struct machine_specific *ms = machdep->machspec;<br>
+ struct riscv64_register *regs;<br>
+ ulong epc, sp;<br>
+<br>
+ if (!ms->crash_task_regs) {<br>
+ bt->flags |= BT_REGS_NOT_FOUND;<br>
+ return FALSE;<br>
+ }<br>
+<br>
+ /*<br>
+ * We got registers for panic task from crash_notes. Just return them.<br>
+ */<br>
+ regs = &ms->crash_task_regs[bt->tc->processor];<br>
+ epc = regs->regs[RISCV64_REGS_EPC];<br>
+ sp = regs->regs[RISCV64_REGS_SP];<br>
+<br>
+ /*<br>
+ * Set stack frame ptr.<br>
+ */<br>
+ bt->frameptr = regs->regs[RISCV64_REGS_FP];<br>
+<br>
+ if (nip)<br>
+ *nip = epc;<br>
+ if (ksp)<br>
+ *ksp = sp;<br>
+<br>
+ bt->machdep = regs;<br>
+<br>
+ return TRUE;<br>
+}<br>
+<br>
+/*<br>
+ * Do the work for riscv64_get_stack_frame() for non-active tasks.<br>
+ * Get SP and PC values for idle tasks.<br>
+ */<br>
+static int<br>
+riscv64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)<br>
+{<br>
+ if (!bt->tc || !(tt->flags & THREAD_INFO))<br>
+ return FALSE;<br>
+<br>
+ if (!readmem(bt->task + OFFSET(task_struct_thread_context_pc),<br>
+ KVADDR, pcp, sizeof(*pcp),<br>
+ "thread_struct.ra",<br>
+ RETURN_ON_ERROR))<br>
+ return FALSE;<br>
+<br>
+ if (!readmem(bt->task + OFFSET(task_struct_thread_context_sp),<br>
+ KVADDR, spp, sizeof(*spp),<br>
+ "thread_struct.sp",<br>
+ RETURN_ON_ERROR))<br>
+ return FALSE;<br>
+<br>
+ if (!readmem(bt->task + OFFSET(task_struct_thread_context_fp),<br>
+ KVADDR, &bt->frameptr, sizeof(bt->frameptr),<br>
+ "thread_struct.fp",<br>
+ RETURN_ON_ERROR))<br>
+ return FALSE;<br>
+<br>
+ return TRUE;<br>
+}<br>
+<br>
static int<br>
riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)<br>
{<br>
@@ -983,6 +1267,8 @@ riscv64_init(int when)<br>
machdep->uvtop = riscv64_uvtop;<br>
machdep->kvtop = riscv64_kvtop;<br>
machdep->cmd_mach = riscv64_cmd_mach;<br>
+ machdep->get_stack_frame = riscv64_get_stack_frame;<br>
+ machdep->back_trace = riscv64_back_trace_cmd;<br>
<br>
machdep->vmalloc_start = riscv64_vmalloc_start;<br>
machdep->processor_speed = riscv64_processor_speed;<br>
@@ -1003,6 +1289,7 @@ riscv64_init(int when)<br>
case POST_GDB:<br>
machdep->section_size_bits = _SECTION_SIZE_BITS;<br>
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;<br>
+ riscv64_stackframe_init();<br>
riscv64_page_type_init();<br>
<br>
if (!machdep->hz)<br>
-- <br>
2.17.1<br>
<br>
<br>
_______________________________________________<br>
kexec mailing list<br>
<a href="mailto:kexec@lists.infradead.org" target="_blank">kexec@lists.infradead.org</a><br>
<a href="http://lists.infradead.org/mailman/listinfo/kexec" rel="noreferrer" target="_blank">http://lists.infradead.org/mailman/listinfo/kexec</a><br>
<br>
</blockquote></div></div>