parlib: Improve panic() and assert()
[akaros.git] / kern / arch / x86 / kdebug.c
index fb73151..7042d26 100644 (file)
@@ -1,7 +1,3 @@
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
 #include <stab.h>
 #include <string.h>
 #include <assert.h>
@@ -9,29 +5,42 @@
 #include <pmap.h>
 #include <process.h>
 #include <kmalloc.h>
+#include <arch/uaccess.h>
 
 #include <ros/memlayout.h>
 
+/* The return address is right above ebp on the stack.  We subtract an
+ * additional 1 to make sure the eip we get is actually in the function
+ * that called us.  I had a couple cases early on where call was the last
+ * instruction in a function, and simply reading the retaddr would point
+ * into another function (the next one in the object).
+ */
+#define GET_FRAME_START(ebp, eip)                                                      \
+       do {                                                                                                    \
+               ebp = read_bp();                                                                        \
+               eip = *(uintptr_t *) (ebp + sizeof(uintptr_t)) - 1; \
+               ebp = *(uintptr_t *) ebp;                                                       \
+       } while (0)
+
 // Beginning of stabs table
-extern const stab_t (RO BND(__this,__STAB_END__) __STAB_BEGIN__)[];
+extern const stab_t __STAB_BEGIN__[];
 
 // End of stabs table
-extern const stab_t (RO SNT __STAB_END__)[];
+extern const stab_t __STAB_END__[];
 
 // Beginning of string table
-extern const char (RO NT BND(__this,__STABSTR_END__) __STABSTR_BEGIN__)[];
+extern const char __STABSTR_BEGIN__[];
 
  // End of string table
-extern const char (RO SNT __STABSTR_END__)[];
+extern const char __STABSTR_END__[];
 
 typedef struct UserStabData {
-       const stab_t *BND(__this,stab_end) stabs;
-       const stab_t *SNT stab_end;
-       const char *NT BND(__this, stabstr_end) stabstr;
-       const char *SNT stabstr_end;
+       const stab_t *stabs;
+       const stab_t *stab_end;
+       const char *stabstr;
+       const char *stabstr_end;
 } user_stab_data_t;
 
-
 /* 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
@@ -82,16 +91,16 @@ static bool stab_table_valid(const char *stabstr, const char *stabstr_end)
 //     will exit setting left = 118, right = 554.
 //
 static void
-stab_binsearch(const stab_t *BND(__this, stab_end) stabs,
-           const stab_t *SNT stab_end,
-           int *region_left, int *region_right,
+stab_binsearch(const stab_t *stabs,
+               const stab_t *stab_end,
+               int *region_left, int *region_right,
               int type, uintptr_t addr)
 {
        int l = *region_left, r = *region_right, any_matches = 0;
-       
+
        while (l <= r) {
                int true_m = (l + r) / 2, m = true_m;
-               
+
                // search for earliest stab with right type
                while (m >= l && stabs[m].n_type != type)
                        m--;
@@ -138,12 +147,12 @@ stab_binsearch(const stab_t *BND(__this, stab_end) stabs,
 //     information into '*info'.
 //
 int
-debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
+debuginfo_eip(uintptr_t addr, eipdebuginfo_t *info)
 {
-       const stab_t *SNT stab_end;
-       const stab_t *BND(__this,stab_end) stabs;
-       const char *SNT stabstr_end;
-       const char *NT BND(__this,stabstr_end) stabstr;
+       const stab_t *stab_end;
+       const stab_t *stabs;
+       const char *stabstr_end;
+       const char *stabstr;
        int lfile, rfile, lfun, rfun, lline, rline;
 
        // Initialize *info
@@ -170,7 +179,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
                // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
                // __STABSTR_END__) in a structure located at virtual address
                // USTABDATA.
-               const user_stab_data_t *usd = (const user_stab_data_t *COUNT(1))TC(USTABDATA);
+               const user_stab_data_t *usd = (const user_stab_data_t *)USTABDATA;
 
                // Make sure this memory is valid.
                // Return -1 if it is not.  Hint: Call user_mem_check.
@@ -193,7 +202,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
        // 'eip'.  First, we find the basic source file containing 'eip'.
        // Then, we look in that source file for the function.  Then we look
        // for the line number.
-       
+
        // Search the entire set of stabs for the source file (type N_SO).
        lfile = 0;
        rfile = (stab_end - stabs) - 1;
@@ -226,7 +235,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
        }
        // Ignore stuff after the colon.
        info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
-       
+
        // Search within [lline, rline] for the line number stab.
        // If found, set info->eip_line to the right line number.
        // If not found, return -1.
@@ -238,12 +247,12 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
        // Your code here.
 
        stab_binsearch(stabs, stab_end, &lline, &rline, N_SLINE, addr);
-       if (lline <= rline) 
+       if (lline <= rline)
                // stabs[lline] points to the line number
                info->eip_line = stabs[lline].n_value;
        else
                return -1;
-       
+
        // Search backwards from the line number for the relevant filename
        // stab.
        // We can't just use the "lfile" stab because inlined functions
@@ -265,17 +274,17 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
                while (stabs[lfun++].n_type == N_PSYM)
                        info->eip_fn_narg++;
        }
-       
+
        return 0;
 }
 
 /* Returns a function pointer for a function name matching the given string. */
 void *debug_get_fn_addr(char *fn_name)
 {
-       const struct stab *SNT stab_end = __STAB_END__;
-       const struct stab *BND(__this,stab_end) stabs = __STAB_BEGIN__;
-       const char *SNT stabstr_end = __STABSTR_END__;
-       const char *NT BND(__this,stabstr_end) stabstr = __STABSTR_BEGIN__;
+       const struct stab *stab_end = __STAB_END__;
+       const struct stab *stabs = __STAB_BEGIN__;
+       const char *stabstr_end = __STABSTR_END__;
+       const char *stabstr = __STABSTR_BEGIN__;
 
        static int first_fn_idx = 0;
        int i = first_fn_idx;
@@ -307,60 +316,85 @@ void *debug_get_fn_addr(char *fn_name)
        return retval;
 }
 
-void backtrace_frame(uintptr_t eip, uintptr_t ebp)
-{ 
-       extern char (SNT RO _start)[];
-       eipdebuginfo_t debuginfo;
-       char buf[256];
-       char *func_name;
-       int j, i = 1;
-
-       // on each iteration, ebp holds the stack frame and eip an addr in that func
-       while (ebp) {
-               #ifdef CONFIG_X86_64
-               func_name = get_fn_name(eip);
-               printk("#%02d [<%p>] in %s\n", i++,  eip, func_name);
-               # ifdef CONFIG_RESET_STACKS
-               if (func_name && !strncmp("__smp_idle", func_name, 10))
+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);
+}
+
+static bool pc_is_asm_trampoline(uintptr_t pc)
+{
+       extern char __asm_entry_points_start[], __asm_entry_points_end[];
+       extern char __asm_pop_hwtf_start[], __asm_pop_hwtf_end[];
+       extern char __asm_pop_swtf_start[], __asm_pop_swtf_end[];
+       extern char __asm_pop_vmtf_start[], __asm_pop_vmtf_end[];
+
+       if (((uintptr_t)__asm_entry_points_start <= pc) &&
+           (pc < (uintptr_t)__asm_entry_points_end))
+               return TRUE;
+       if (((uintptr_t)__asm_pop_hwtf_start <= pc) &&
+           (pc < (uintptr_t)__asm_pop_hwtf_end))
+               return TRUE;
+       if (((uintptr_t)__asm_pop_swtf_start <= pc) &&
+           (pc < (uintptr_t)__asm_pop_swtf_end))
+               return TRUE;
+       if (((uintptr_t)__asm_pop_vmtf_start <= pc) &&
+           (pc < (uintptr_t)__asm_pop_vmtf_end))
+               return TRUE;
+       return FALSE;
+}
+
+size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
+                      size_t nr_slots)
+{
+       size_t nr_pcs = 0;
+
+       while (nr_pcs < nr_slots) {
+               pcs[nr_pcs++] = pc;
+               printd("PC %p FP %p\n", pc, fp);
+               if (pc_is_asm_trampoline(pc))
                        break;
-               # endif /* CONFIG_RESET_STACKS */
-               kfree(func_name);
-               #else
-               debuginfo_eip(eip, &debuginfo);
-               memset(buf, 0, 256);
-               strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
-               buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
-               cprintf("#%02d [<%p>] in %s+%x(%p) from %s:%d\n", i++,  eip, buf, 
-                       debuginfo.eip_fn_addr - (uintptr_t)_start,
-                       debuginfo.eip_fn_addr, debuginfo.eip_file, debuginfo.eip_line);
-               cprintf("    ebp: %x   Args:", ebp);
-               for (j = 0; j < MIN(debuginfo.eip_fn_narg, 5); j++)
-                       cprintf(" %08x", *(uintptr_t*)(ebp + 2 + j));
-               cprintf("\n");
-               # ifdef CONFIG_RESET_STACKS
-               if (!strncmp("__smp_idle", (char*)debuginfo.eip_fn_name, 10))
+               if (!fp)
                        break;
-               # endif /* CONFIG_RESET_STACKS */
-               #endif /* CONFIG_X86_64 */
-               eip = *(uintptr_t*)(ebp + sizeof(uintptr_t)) - 1;
-               ebp = *(uintptr_t*)ebp;
+               assert(KERNBASE <= fp);
+               /* We need to check the next FP before reading PC from beyond it.  FP
+                * could be 0 and be at the top of the stack, and reading PC in that
+                * case will be a wild read. */
+               if (!*(uintptr_t*)fp)
+                       break;
+               /* We used to set PC = retaddr - 1, where the -1 would put our PC back
+                * inside the function that called us.  This was for obscure cases where
+                * a no-return function calls another function and has no other code
+                * after the function call.  Or something. */
+               pc = *(uintptr_t*)(fp + sizeof(uintptr_t));
+               fp = *(uintptr_t*)fp;
        }
+       return nr_pcs;
 }
 
-void backtrace(void)
+size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
+                                                  size_t nr_slots)
 {
-       uintptr_t ebp, eip;
-       ebp = read_bp();
-       /* retaddr is right above ebp on the stack.  we subtract an additional 1 to
-        * make sure the eip we get is actually in the function that called us.
-        * i had a couple cases early on where call was the last instruction in a
-        * function, and simply reading the retaddr would point into another
-        * function (the next one in the object) */
-       eip = *(uintptr_t*)(ebp + sizeof(uintptr_t)) - 1;
-       /* jump back a frame (out of backtrace) */
-       ebp = *(uintptr_t*)ebp;
-       printk("Stack Backtrace on Core %d:\n", core_id());
-       backtrace_frame(eip, ebp);
+       int error;
+       size_t nr_pcs = 0;
+       uintptr_t frame[2];
+
+       while (nr_pcs < nr_slots) {
+               pcs[nr_pcs++] = pc;
+               if (!fp)
+                       break;
+               error = copy_from_user(frame, (const void *) fp, 2 * sizeof(uintptr_t));
+               if (unlikely(error))
+                       break;
+               pc = frame[1];
+               fp = frame[0];
+       }
+       return nr_pcs;
 }
 
 /* Assumes 32-bit header */