parlib: Improve panic() and assert()
[akaros.git] / kern / arch / x86 / kdebug.c
index 2d3ba0d..7042d26 100644 (file)
@@ -97,10 +97,10 @@ stab_binsearch(const stab_t *stabs,
               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--;
@@ -202,7 +202,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *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;
@@ -235,7 +235,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *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.
@@ -247,12 +247,12 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *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
@@ -274,7 +274,7 @@ debuginfo_eip(uintptr_t addr, eipdebuginfo_t *info)
                while (stabs[lfun++].n_type == N_PSYM)
                        info->eip_fn_narg++;
        }
-       
+
        return 0;
 }
 
@@ -327,15 +327,46 @@ void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
        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 ((fp > MMAP_LOWEST_VA) && (nr_pcs < nr_slots)) {
-               /* could put some sanity checks in here...  i used to at least check for
-                * kernel addrs, but now we also bt user stacks. (dangerous!) */
+
+       while (nr_pcs < nr_slots) {
                pcs[nr_pcs++] = pc;
                printd("PC %p FP %p\n", pc, fp);
+               if (pc_is_asm_trampoline(pc))
+                       break;
+               if (!fp)
+                       break;
+               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
@@ -353,17 +384,16 @@ size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
        size_t nr_pcs = 0;
        uintptr_t frame[2];
 
-       for (;;) {
+       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) || unlikely(nr_pcs >= nr_slots))
+               if (unlikely(error))
                        break;
-
-               /* For now straight memory access, waiting for copy_from_user(). */
-               pcs[nr_pcs++] = pc;
                pc = frame[1];
                fp = frame[0];
        }
-
        return nr_pcs;
 }