Helper to backtrace a user context
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 21 May 2015 20:41:27 +0000 (16:41 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 4 Jun 2015 13:40:32 +0000 (09:40 -0400)
You can backtrace a context, but only if you have one!  And if the
context is somehow messed up or if the stackframe is not using the frame
pointer, then it'll probably die in a horrendous kernel page fault.

Note that when processing as syscall, if the syscall has already
blocked, then current_ctx is not the context that originally issued the
syscall.  *That* context has long-since restarted, due to our async
syscalls.

You can attempt to backtrace the current context like so:
backtrace_user_ctx(p, current_ctx);

Try putting one of these in sys_block() on either side of the
kthread_usleep().  The latter will fail, and if it doesn't, it's
probably grabbing some arbitrary context.

kern/arch/riscv/trap.h
kern/arch/x86/kdebug.c
kern/arch/x86/trap64.h
kern/include/kdebug.h
kern/include/trap.h
kern/src/kdebug.c
kern/src/trap.c

index 64af828..4b9b257 100644 (file)
@@ -43,6 +43,20 @@ static inline uintptr_t get_hwtf_fp(struct hw_trapframe *hw_tf)
        //return hw_tf->tf_rbp;
 }
 
+static inline uintptr_t get_swtf_pc(struct sw_trapframe *sw_tf)
+{
+       #warning "fix me"
+       return 0;
+       //return sw_tf->tf_rip;
+}
+
+static inline uintptr_t get_swtf_fp(struct sw_trapframe *sw_tf)
+{
+       #warning "fix me"
+       return 0;
+       //return sw_tf->tf_rbp;
+}
+
 static inline void __attribute__((always_inline))
 set_stack_pointer(uintptr_t sp)
 {
index 68d4245..530ddd8 100644 (file)
@@ -308,11 +308,10 @@ size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
 {
        size_t nr_pcs = 0;
        while (fp && nr_pcs < nr_slots) {
-               /* could put some sanity checks in here... */
+               /* could put some sanity checks in here...  i used to at least check for
+                * kernel addrs, but now we also bt user stacks. (dangerous!) */
                pcs[nr_pcs++] = pc;
                printd("PC %p FP %p\n", pc, fp);
-               if (!is_kaddr((void*)fp))
-                       break;
                /* PC becomes the retaddr - 1.  the -1 is to put our PC back inside the
                 * function that called us.  this was necessary in case we called as the
                 * last instruction in a function (would have to never return).  not
index 21a87e8..7783358 100644 (file)
@@ -31,6 +31,16 @@ static inline uintptr_t get_hwtf_fp(struct hw_trapframe *hw_tf)
        return hw_tf->tf_rbp;
 }
 
+static inline uintptr_t get_swtf_pc(struct sw_trapframe *sw_tf)
+{
+       return sw_tf->tf_rip;
+}
+
+static inline uintptr_t get_swtf_fp(struct sw_trapframe *sw_tf)
+{
+       return sw_tf->tf_rbp;
+}
+
 static inline uintptr_t x86_get_ip_hw(struct hw_trapframe *hw_tf)
 {
        return hw_tf->tf_rip;
index 3bd290c..23a8c1f 100644 (file)
@@ -15,6 +15,8 @@ void backtrace_frame(uintptr_t pc, uintptr_t fp);
 size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
                       size_t nr_slots);
 void backtrace_kframe(struct hw_trapframe *hw_tf);
+/* for includes */ struct proc;
+void backtrace_user_ctx(struct proc *p, struct user_context *ctx);
 
 /* Arch dependent, listed here for ease-of-use */
 static inline uintptr_t get_caller_pc(void);
index 60e25d5..b6a4559 100644 (file)
@@ -36,6 +36,9 @@ void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
 void __arch_reflect_trap_hwtf(struct hw_trapframe *hw_tf, unsigned int trap_nr,
                               unsigned int err, unsigned long aux);
 
+uintptr_t get_user_ctx_pc(struct user_context *ctx);
+uintptr_t get_user_ctx_fp(struct user_context *ctx);
+
 /* Kernel messages.  This is an in-order 'active message' style messaging
  * subsystem, where you can instruct other cores (including your own) to execute
  * a function (with arguments), either immediately or whenever the kernel is
index 9b24ccd..982fca5 100644 (file)
@@ -210,3 +210,23 @@ void backtrace_kframe(struct hw_trapframe *hw_tf)
        backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
        pcpui->__lock_checking_enabled++;
 }
+
+void backtrace_user_ctx(struct proc *p, struct user_context *ctx)
+{
+       #define MAX_BT_DEPTH 20
+       uintptr_t pcs[MAX_BT_DEPTH];
+       size_t nr_pcs;
+
+       if (!ctx) {
+               printk("Null user context!\n");
+               return;
+       }
+       nr_pcs = backtrace_list(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx), pcs,
+                               MAX_BT_DEPTH);
+       printk("User context backtrace:\n");
+       printk("\tOffsets only matter for shared libraries\n");
+       for (int i = 0; i < nr_pcs; i++) {
+               printk("#%02d ", i + 1);
+               debug_addr_proc(p, pcs[i]);
+       }
+}
index ed8362f..9e0f9b9 100644 (file)
@@ -54,6 +54,32 @@ error_out:
        proc_destroy(p);
 }
 
+uintptr_t get_user_ctx_pc(struct user_context *ctx)
+{
+       switch (ctx->type) {
+               case ROS_HW_CTX:
+                       return get_hwtf_pc(&ctx->tf.hw_tf);
+               case ROS_SW_CTX:
+                       return get_swtf_pc(&ctx->tf.sw_tf);
+               default:
+                       warn("Bad context type %d for ctx %p\n", ctx->type, ctx);
+                       return 0;
+       }
+}
+
+uintptr_t get_user_ctx_fp(struct user_context *ctx)
+{
+       switch (ctx->type) {
+               case ROS_HW_CTX:
+                       return get_hwtf_fp(&ctx->tf.hw_tf);
+               case ROS_SW_CTX:
+                       return get_swtf_fp(&ctx->tf.sw_tf);
+               default:
+                       warn("Bad context type %d for ctx %p\n", ctx->type, ctx);
+                       return 0;
+       }
+}
+
 struct kmem_cache *kernel_msg_cache;
 
 void kernel_msg_init(void)