On Tue, Mar 08 2022, Visa Hankala <[email protected]> wrote:
> This patch adds kernel stack trace saving for riscv64, for the benefit
> of dt(4) and witness(4).
Nice!
> The unwinder is slow because of the symbol
> lookup, but this can be tweaked later.
A dumb approach that appears to work: add
cpu_exception_handler_supervisor_end and cpu_exception_handler_user_end
symbols, and perform a range check.
> The limit variable prevents the unwinder from using user-controllable
> register values. The limit has to reflect the kernel stack setup in
> cpu_fork(). To ensure consistency, the stack start address is stored
> in a variable in struct pcb.
>
> OK?
Works for me on the Unmatched with dt(4), thanks. ok jca@ fwiw
> Index: arch/riscv64/include/pcb.h
> ===================================================================
> RCS file: src/sys/arch/riscv64/include/pcb.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 pcb.h
> --- arch/riscv64/include/pcb.h 30 Jun 2021 22:20:56 -0000 1.3
> +++ arch/riscv64/include/pcb.h 8 Mar 2022 16:54:58 -0000
> @@ -39,5 +39,6 @@ struct pcb {
>
> caddr_t pcb_onfault; // On fault handler
> struct fpreg pcb_fpstate; // Floating Point state */
> + register_t pcb_kstack; /* kernel stack address */
> };
> #endif /* _MACHINE_PCB_H_ */
> Index: arch/riscv64/riscv64/db_trace.c
> ===================================================================
> RCS file: src/sys/arch/riscv64/riscv64/db_trace.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 db_trace.c
> --- arch/riscv64/riscv64/db_trace.c 22 Feb 2022 07:46:04 -0000 1.5
> +++ arch/riscv64/riscv64/db_trace.c 8 Mar 2022 16:54:58 -0000
> @@ -141,3 +141,56 @@ db_stack_trace_print(db_expr_t addr, int
> }
> (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count);
> }
> +
> +void
> +stacktrace_save_at(struct stacktrace *st, unsigned int skip)
> +{
> + struct callframe *frame, *lastframe, *limit;
> + struct pcb *pcb = curpcb;
> + Elf_Sym *sym;
> + db_expr_t diff;
> + vaddr_t ra, subr;
> +
> + st->st_count = 0;
> +
> + if (pcb == NULL)
> + return;
> +
> + ra = (vaddr_t)__builtin_return_address(0);
> + frame = (struct callframe *)__builtin_frame_address(0);
> + KASSERT(INKERNEL(frame));
> + limit = (struct callframe *)((struct trapframe *)pcb->pcb_kstack - 1);
> +
> + while (st->st_count < STACKTRACE_MAX) {
> + if (skip == 0)
> + st->st_pc[st->st_count++] = ra;
> + else
> + skip--;
> +
> + sym = db_search_symbol(ra, DB_STGY_PROC, &diff);
> + if (sym == NULL)
> + break;
> + subr = ra - (vaddr_t)diff;
> +
> + lastframe = frame;
> + if (subr == (vaddr_t)cpu_exception_handler_supervisor ||
> + subr == (vaddr_t)cpu_exception_handler_user) {
> + struct trapframe *tf = (struct trapframe *)frame;
> +
> + frame = (struct callframe *)tf->tf_s[0];
> + ra = tf->tf_ra;
> + } else {
> + frame = frame[-1].f_frame;
> + if (frame == NULL)
> + break;
> + ra = frame[-1].f_ra;
> + }
> +
> + if (frame <= lastframe)
> + break;
> + if (frame >= limit)
> + break;
> + if (!INKERNEL(ra))
> + break;
> + }
> +}
> Index: arch/riscv64/riscv64/vm_machdep.c
> ===================================================================
> RCS file: src/sys/arch/riscv64/riscv64/vm_machdep.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 vm_machdep.c
> --- arch/riscv64/riscv64/vm_machdep.c 24 Feb 2022 14:19:10 -0000 1.10
> +++ arch/riscv64/riscv64/vm_machdep.c 8 Mar 2022 16:54:58 -0000
> @@ -75,13 +75,12 @@ cpu_fork(struct proc *p1, struct proc *p
>
> pmap_activate(p2);
>
> - tf = (struct trapframe *)((u_long)p2->p_addr
> + pcb->pcb_kstack = STACKALIGN((u_long)p2->p_addr
> + USPACE
> - - sizeof(struct trapframe)
> - sizeof(register_t) /* for holding curcpu */
> - 0x10);
>
> - tf = (struct trapframe *)STACKALIGN(tf);
> + tf = (struct trapframe *)pcb->pcb_kstack - 1;
> pcb->pcb_tf = tf;
> *tf = *p1->p_addr->u_pcb.pcb_tf;
>
>
--
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE