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