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;
 

Reply via email to