This patch adds kernel stack trace saving for riscv64, for the benefit of dt(4) and witness(4). The unwinder is slow because of the symbol lookup, but this can be tweaked later.
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? 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;