Refactors backtrace functions [1/2]
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 10 Dec 2015 15:56:08 +0000 (10:56 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 10 Dec 2015 16:26:40 +0000 (11:26 -0500)
We had a mess of functionality with repeated code in various spots, which
made it difficult to add new features.

As part of this, we have backtrace_hwtf(), which can print out the
appropriate BT based on whether the TF is the kernel's or the user's.  This
means that CTRL-B will work on user TFs, and it will spit out text (via
printk) that can be processed with scripts/bt-akaros.sh.

So now the answer to "how do I backtrace a deadlocked user SCP" is
"CTRL-B", instead of a long discussion.  =)

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/riscv/kdebug.c
kern/arch/x86/kdebug.c
kern/include/kdebug.h
kern/src/kdebug.c
kern/src/profiler.c

index 934e1fb..2be24b5 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <ros/memlayout.h>
 
+/* Here's the old backtrace, remove it once gen_backtrace is done: */
+#if 0
 void backtrace(void)
 {
        void **fp;
@@ -20,10 +22,11 @@ void backtrace(void)
                fp = (void**)sp;
        }
 }
+#endif
 
-void backtrace_frame(uintptr_t pc, uintptr_t fp)
+void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
 {
-       printk("\n\tTODO: backtrace frame on riscv\n\n");
+       printk("\n\tTODO: %s on riscv\n\n", __func__);
 }
 
 /* can either implement these, or use the x86 ones globally and limit the
@@ -31,6 +34,13 @@ 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)
 {
-       printk("\n\tTODO: backtrace list on riscv\n\n");
+       printk("\n\tTODO: %s on riscv\n\n", __func__);
+       return 0;
+}
+
+size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
+                                                  size_t nr_slots)
+{
+       printk("\n\tTODO: %s on riscv\n\n", __func__);
        return 0;
 }
index 3ee432c..5b7f3b9 100644 (file)
@@ -41,37 +41,6 @@ typedef struct UserStabData {
        const char *stabstr_end;
 } user_stab_data_t;
 
-static void printk_func(void *opaque, const char *str)
-{
-       printk("%s", str);
-}
-
-void gen_backtrace_frame(uintptr_t eip, uintptr_t ebp,
-                                                void (*pfunc)(void *, const char *), void *opaque)
-{
-#define MAX_BT_DEPTH 20
-       char *func_name;
-       char bt_line[128];
-       uintptr_t pcs[MAX_BT_DEPTH];
-       size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH);
-
-       for (size_t i = 0; i < nr_pcs; i++) {
-               func_name = get_fn_name(pcs[i]);
-               snprintf(bt_line, sizeof(bt_line), "#%02d [<%p>] in %s\n", i + 1,
-                                pcs[i], func_name);
-               pfunc(opaque, bt_line);
-               kfree(func_name);
-       }
-}
-
-void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
-{
-       uintptr_t ebp, eip;
-
-       GET_FRAME_START(ebp, eip);
-       gen_backtrace_frame(eip, ebp, pfunc, opaque);
-}
-
 /* We used to check for a null terminating byte for the entire strings section
  * (due to JOS, I think), but that's not what the spec says: only that all
  * strings are null terminated.  There might be random stuff tacked on at the
@@ -347,6 +316,17 @@ void *debug_get_fn_addr(char *fn_name)
        return retval;
 }
 
+void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
+{
+       uintptr_t ebp, eip;
+       uintptr_t pcs[MAX_BT_DEPTH];
+       size_t nr_pcs;
+
+       GET_FRAME_START(ebp, eip);
+       nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH);
+       print_backtrace_list(pcs, nr_pcs, pfunc, opaque);
+}
+
 size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
                       size_t nr_slots)
 {
@@ -366,7 +346,7 @@ size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
        return nr_pcs;
 }
 
-size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
+size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
                                                   size_t nr_slots)
 {
        int error;
@@ -387,17 +367,6 @@ size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
        return nr_pcs;
 }
 
-void backtrace_frame(uintptr_t eip, uintptr_t ebp)
-{
-       gen_backtrace_frame(eip, ebp, &printk_func, NULL);
-}
-
-void backtrace(void)
-{
-       printk("Stack Backtrace on Core %d:\n", core_id());
-       gen_backtrace(&printk_func, NULL);
-}
-
 /* Assumes 32-bit header */
 void print_fpu_state(struct ancillary_state *fpu)
 {
index 6b7afd7..28a852b 100644 (file)
@@ -4,6 +4,7 @@
 #include <ros/trapframe.h>
 #include <arch/kdebug.h>
 #include <profiler.h>
+/* for includes */ struct proc;
 
 struct symtab_entry {
        char *name;
@@ -12,18 +13,40 @@ struct symtab_entry {
 
 #define TRACEME() trace_printk(TRUE, "%s(%d)", __FILE__, __LINE__)
 
+/* An alternative here is to have backtrace_list kmalloc an array.  The downside
+ * is that we're calling into the allocator in potentially-delicate situations,
+ * such as the NMI handler. */
+#define MAX_BT_DEPTH 20
+
+/*** Printk Backtraces, usually used for debugging or from the monitor */
+/* Backtraces the calling kernel context */
 void backtrace(void);
-void gen_backtrace_frame(uintptr_t eip, uintptr_t ebp,
-                                                void (*pfunc)(void *, const char *), void *opaque);
-void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque);
+/* Backtraces a PC/FP, with no protections */
 void backtrace_frame(uintptr_t pc, uintptr_t fp);
+/* Backtraces a user PC/FP */
+void backtrace_user_frame(uintptr_t pc, uintptr_t fp);
+/* Backtraces a hardware TF.  Can handle user or kernel TFs */
+void backtrace_hwtf(struct hw_trapframe *hw_tf);
+/* Backtraces a user context */
+void backtrace_user_ctx(struct proc *p, struct user_context *ctx);
+
+/*** Programmatic Backtraces */
+/* Backtraces a PC/FP, stores results in *pcs, with no protections */
 size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
                       size_t nr_slots);
-size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
+/* Backtraces a user PC/FP, stores results in *pcs */
+size_t backtrace_user_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);
+/* Prints out a backtrace list, using pfunc(opaque, "line") for the printk.
+ * This does a symbol lookup on the kernel binary, so it is less useful for a
+ * user backtrace. */
+void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs,
+                                                 void (*pfunc)(void *, const char *), void *opaque);
+/* Backtraces the calling kernel context, using pfunc for printing */
+void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque);
+
+/* Temporary func */
+#define backtrace_kframe backtrace_hwtf
 
 /* Arch dependent, listed here for ease-of-use */
 static inline uintptr_t get_caller_pc(void);
index 32495d5..8756a41 100644 (file)
@@ -201,31 +201,80 @@ void debug_addr_pid(int pid, unsigned long addr)
        proc_decref(p);
 }
 
-void backtrace_kframe(struct hw_trapframe *hw_tf)
+void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs,
+                                                 void (*pfunc)(void *, const char *), void *opaque)
+{
+       char *func_name;
+       char bt_line[128];
+
+       for (size_t i = 0; i < nr_pcs; i++) {
+               func_name = get_fn_name(pcs[i]);
+               snprintf(bt_line, sizeof(bt_line), "#%02d [<%p>] in %s\n", i + 1,
+                                pcs[i], func_name);
+               pfunc(opaque, bt_line);
+               kfree(func_name);
+       }
+}
+
+static void printk_func(void *opaque, const char *str)
+{
+       printk("%s", str);
+}
+
+void backtrace(void)
+{
+       printk("Stack Backtrace on Core %d:\n", core_id());
+       gen_backtrace(&printk_func, NULL);
+}
+
+void backtrace_frame(uintptr_t eip, uintptr_t ebp)
+{
+       uintptr_t pcs[MAX_BT_DEPTH];
+       size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH);
+
+       printk("\nBacktrace of kernel context on Core %d:\n", core_id());
+       print_backtrace_list(pcs, nr_pcs, &printk_func, NULL);
+}
+
+/* TODO: change debug_addr_proc() to allow print redirection like
+ * print_backtrace_list(). */
+void backtrace_user_frame(uintptr_t eip, uintptr_t ebp)
+{
+       uintptr_t pcs[MAX_BT_DEPTH];
+       size_t nr_pcs = backtrace_user_list(eip, ebp, pcs, MAX_BT_DEPTH);
+
+       printk("\nBacktrace of user context on Core %d:\n", core_id());
+       printk("\tOffsets only matter for shared libraries\n");
+       /* This formatting is consumed by scripts/bt-akaros.sh. */
+       for (int i = 0; i < nr_pcs; i++) {
+               printk("#%02d ", i + 1);
+               /* TODO: user backtraces all assume we're working on 'current' */
+               debug_addr_proc(current, pcs[i]);
+       }
+}
+
+void backtrace_hwtf(struct hw_trapframe *hw_tf)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+
        pcpui->__lock_checking_enabled--;
-       printk("\nBacktrace of kernel context on Core %d:\n", core_id());
-       backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
+       if (in_kernel(hw_tf))
+               backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
+       else
+               backtrace_user_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;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 
        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]);
-       }
+       assert(pcpui->cur_proc);
+       pcpui->__lock_checking_enabled--;
+       backtrace_user_frame(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx));
+       pcpui->__lock_checking_enabled++;
 }
index 2cc8b85..e09b311 100644 (file)
@@ -463,7 +463,7 @@ void profiler_add_user_backtrace(uintptr_t pc, uintptr_t fp)
 
                        trace[0] = pc;
                        if (likely(fp))
-                               n = user_backtrace_list(pc, fp, trace + 1,
+                               n = backtrace_user_list(pc, fp, trace + 1,
                                                                                PROFILER_BT_DEPTH - 1) + 1;
 
                        profiler_push_user_trace64(cpu_buf, p, trace, n);