<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, &current, &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>