Fixes occasional STAB error on x86
[akaros.git] / kern / arch / i686 / kdebug.c
index 3ebf3c4..ded18a0 100644 (file)
@@ -31,6 +31,19 @@ typedef struct UserStabData {
 } 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
+ * end.  I had some stabs that seemed valid (lookups worked), that did not have
+ * the entire table be null terminated.  Still, something else might be jacked
+ * up.  If it turns out that's the case, put the checks in here. */
+static bool stab_table_valid(const char *stabstr, const char *stabstr_end)
+{
+       if (stabstr_end <= stabstr)
+               return FALSE;
+       return TRUE;
+}
+
 // stab_binsearch(stabs, region_left, region_right, type, addr)
 //
 //     Some stab types are arranged in increasing order by instruction
@@ -147,6 +160,9 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
                stabstr_end = __STABSTR_END__;
                stabstr = __STABSTR_BEGIN__;
        } else {
+               /* TODO: short circuiting this, til our user space apps pack stab data
+                * the kernel knows about */
+               return -1;
                // The user-application linker script, user/user.ld,
                // puts information about the application's stabs (equivalent
                // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
@@ -167,12 +183,8 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
                // LAB 3: Your code here.
        }
 
-       // String table validity checks
-       {
-               int stabstrsz = stabstr_end - stabstr;
-               if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
-                       return -1;
-       }
+       if (!stab_table_valid(stabstr, stabstr_end))
+               return -1;
 
        // Now we find the right stabs that define the function containing
        // 'eip'.  First, we find the basic source file containing 'eip'.
@@ -268,12 +280,8 @@ void *debug_get_fn_addr(char *fn_name)
        const char *stab_fn_name = 0;
        void *retval = 0;
 
-       // String table validity checks (from above)
-       {
-               int stabstrsz = stabstr_end - stabstr;
-               if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
-                       return 0;
-       }
+       if (!stab_table_valid(stabstr, stabstr_end))
+               return 0;
 
        for (/* i set */; &stabs[i] < stab_end; i++) {
                if (stabs[i].n_type != N_FUN)
@@ -295,3 +303,42 @@ void *debug_get_fn_addr(char *fn_name)
        }
        return retval;
 }
+
+void backtrace(void)
+{ 
+       extern char (SNT RO _start)[];
+       uint32_t *ebp, eip;
+       eipdebuginfo_t debuginfo;
+       char buf[256];
+       int j, i = 1;
+       ebp = (uint32_t*)read_ebp();
+       // this is part of the way back into the call() instruction's bytes
+       // eagle-eyed readers should be able to explain why this is good enough,
+       // and retaddr (just *(ebp + 1) is not)
+       eip = *(ebp + 1) - 1;
+       // jump back a frame (out of backtrace)
+       ebp = (uint32_t*)(*ebp);
+       printk("Stack Backtrace on Core %d:\n", core_id());
+       // on each iteration, ebp holds the stack frame and eip an addr in that func
+       while (1) {
+               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 - (uint32_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", *(ebp + 2 + j));
+               cprintf("\n");
+               if (!ebp)
+                       break;
+               eip = *(ebp + 1) - 1;
+               ebp = (uint32_t*)(*ebp);
+               #ifdef __CONFIG_RESET_STACKS__
+               if (!strncmp("__smp_idle", debuginfo.eip_fn_name, 10))
+                       break;
+               #endif /* __CONFIG_RESET_STACKS__ */
+       }
+}