x86: vmm: Use a separate vector for posted IRQs
[akaros.git] / kern / src / kdebug.c
index 2853037..8480c1e 100644 (file)
-#ifdef __DEPUTY__
-#pragma nodeputy
-#endif
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Arch-independent kernel debugging */
 
-#include <arch/stab.h>
+#include <kdebug.h>
+#include <kmalloc.h>
 #include <string.h>
 #include <assert.h>
-#include <kdebug.h>
-#include <pmap.h>
-#include <process.h>
-
-#include <ros/memlayout.h>
-
-extern const stab_t __STAB_BEGIN__[];  // Beginning of stabs table
-extern const stab_t __STAB_END__[];    // End of stabs table
-extern const char __STABSTR_BEGIN__[];         // Beginning of string table
-extern const char __STABSTR_END__[];           // End of string table
-
-typedef struct UserStabData {
-       const stab_t *stabs;
-       const stab_t *stab_end;
-       const char *stabstr;
-       const char *stabstr_end;
-} user_stab_data_t;
-
-
-// stab_binsearch(stabs, region_left, region_right, type, addr)
-//
-//     Some stab types are arranged in increasing order by instruction
-//     address.  For example, N_FUN stabs (stab entries with n_type ==
-//     N_FUN), which mark functions, and N_SO stabs, which mark source files.
-//
-//     Given an instruction address, this function finds the single stab
-//     entry of type 'type' that contains that address.
-//
-//     The search takes place within the range [*region_left, *region_right].
-//     Thus, to search an entire set of N stabs, you might do:
-//
-//             left = 0;
-//             right = N - 1;     /* rightmost stab */
-//             stab_binsearch(stabs, &left, &right, type, addr);
-//
-//     The search modifies *region_left and *region_right to bracket the
-//     'addr'.  *region_left points to the matching stab that contains
-//     'addr', and *region_right points just before the next stab.  If
-//     *region_left > *region_right, then 'addr' is not contained in any
-//     matching stab.
-//
-//     For example, given these N_SO stabs:
-//             Index  Type   Address
-//             0      SO     f0100000
-//             13     SO     f0100040
-//             117    SO     f0100176
-//             118    SO     f0100178
-//             555    SO     f0100652
-//             556    SO     f0100654
-//             657    SO     f0100849
-//     this code:
-//             left = 0, right = 657;
-//             stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
-//     will exit setting left = 118, right = 554.
-//
-static void
-stab_binsearch(const stab_t *stabs, 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--;
-               if (m < l) {    // no match in [l, m]
-                       l = true_m + 1;
-                       continue;
+#include <smp.h>
+
+struct symtab_entry gbl_symtab[1] __attribute__((weak)) = {{0, 0}};
+
+/* Returns a null-terminated string with the function name for a given PC /
+ * instruction pointer.  kfree() the result. */
+char *get_fn_name(uintptr_t pc)
+{
+       struct symtab_entry *i, *prev = 0, *found = 0;
+       char *buf;
+       size_t name_len;
+       /* Table is in ascending order.  As soon as we get to an entry greater than
+        * us, we were in the previous one.  This is only true if we were given a
+        * good PC.  Random addresses will just find the previous symbol. */
+       for (i = &gbl_symtab[0]; i->name; i++) {
+               if (i->addr > pc) {
+                       found = prev;
+                       break;
                }
+               prev = i;
+       }
+       if (!found)
+               return 0;
+       assert(found->name);
+       name_len = strlen(found->name) + 1;
+       buf = kmalloc(name_len, 0);
+       if (!buf)
+               return 0;
+       strlcpy(buf, found->name, name_len);
+       return buf;
+}
 
-               // actual binary search
-               any_matches = 1;
-               if (stabs[m].n_value < addr) {
-                       *region_left = m;
-                       l = true_m + 1;
-               } else if (stabs[m].n_value > addr) {
-                       *region_right = m - 1;
-                       r = m - 1;
+uintptr_t get_symbol_addr(char *sym)
+{
+       struct symtab_entry *i;
+       for (i = &gbl_symtab[0]; i->name; i++) {
+               if (strcmp(i->name, sym) == 0)
+                       return i->addr;
+       }
+       return 0;
+}
+
+static const char *blacklist[] = {
+       "addnode",
+       "addqueue",
+       "allocroute",
+       "balancetree",
+       "calcd",
+       "freeroute",
+       "genrandom",    /* not noisy, just never returns */
+       "limborexmit",
+       "rangecompare",
+       "walkadd",
+       "bnx2x_alloc_rx_data",
+       "bnx2x_frag_alloc",
+       "__dma_map_single",
+       "__dma_mapping_error",
+       "__dma_zalloc_coherent",
+       "__dma_alloc_coherent",
+       "bnx2x_ilt_line_mem_op",
+       "bnx2x_ilt_line_init_op",
+       "bnx2x_ilt_line_wr",
+       "bnx2x_wr_64",
+       "pci_write_config_dword",
+       "bnx2x_init_str_wr",
+       "bnx2x_init_fill",
+       "bnx2x_init_block",
+       "bnx2x_write_big_buf",
+       "bnx2x_init_wr_wb",
+       "bnx2x_write_big_buf_wb",
+       "bnx2x_cl45_read",
+       "bnx2x_cl45_write",
+       "bnx2x_set_mdio_clk",
+};
+
+static bool is_blacklisted(const char *s)
+{
+       for (int i = 0; i < ARRAY_SIZE(blacklist); i++) {
+               if (!strcmp(blacklist[i], s))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static int tab_depth = 0;
+
+/* Call this via kfunc */
+void reset_print_func_depth(void)
+{
+       tab_depth = 0;
+}
+
+static spinlock_t lock = SPINLOCK_INITIALIZER_IRQSAVE;
+
+static void __print_hdr(void)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       printd("Core %2d ", core_id()); /* may help with multicore output */
+       if (in_irq_ctx(pcpui)) {
+               printk("IRQ       :");
+       } else {
+               assert(pcpui->cur_kthread);
+               if (is_ktask(pcpui->cur_kthread)) {
+                       printk("%10s:", pcpui->cur_kthread->name);
                } else {
-                       // exact match for 'addr', but continue loop to find
-                       // *region_right
-                       *region_left = m;
-                       l = m;
-                       addr++;
+                       printk("PID %3d   :", pcpui->cur_proc ? pcpui->cur_proc->pid : 0);
                }
        }
+}
+
+void __print_func_entry(const char *func, const char *file)
+{
+       char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
+       char *ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
+       if (!printx_on)
+               return;
+       if (is_blacklisted(func))
+               return;
+       spin_lock_irqsave(&lock);
+       __print_hdr();
+       printk("%s%s() in %s\n", ourtabs, func, file);
+       spin_unlock_irqsave(&lock);
+       tab_depth++;
+}
 
-       if (!any_matches)
-               *region_right = *region_left - 1;
-       else {
-               // find rightmost region containing 'addr'
-               for (l = *region_right;
-                    l > *region_left && stabs[l].n_type != type;
-                    l--)
-                       /* do nothing */;
-               *region_left = l;
+void __print_func_exit(const char *func, const char *file)
+{
+       char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
+       char *ourtabs;
+       if (!printx_on)
+               return;
+       if (is_blacklisted(func))
+               return;
+       tab_depth--;
+       ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
+       spin_lock_irqsave(&lock);
+       __print_hdr();
+       printk("%s---- %s()\n", ourtabs, func);
+       spin_unlock_irqsave(&lock);
+}
+
+bool printx_on = FALSE;
+
+void set_printx(int mode)
+{
+       switch (mode) {
+               case 0:
+                       printx_on = FALSE;
+                       break;
+               case 1:
+                       printx_on = TRUE;
+                       break;
+               case 2:
+                       printx_on = !printx_on;
+                       break;
        }
 }
 
+void debug_addr_proc(struct proc *p, unsigned long addr)
+{
+       struct vm_region *vmr;
+       spin_lock(&p->vmr_lock);
+       TAILQ_FOREACH(vmr, &p->vm_regions, vm_link) {
+               if ((vmr->vm_base <= addr) && (addr < vmr->vm_end))
+                       break;
+       }
+       if (!vmr) {
+               spin_unlock(&p->vmr_lock);
+               printk("Addr %p has no VMR\n", addr);
+               return;
+       }
+       if (!vmr->vm_file) {
+               spin_unlock(&p->vmr_lock);
+               printk("Addr %p's VMR has no file\n", addr);
+               return;
+       }
+       printk("Addr %p is in %s at offset %p\n", addr, file_name(vmr->vm_file),
+              addr - vmr->vm_base + vmr->vm_foff);
+       spin_unlock(&p->vmr_lock);
+}
 
-// debuginfo_eip(addr, info)
-//
-//     Fill in the 'info' structure with information about the specified
-//     instruction address, 'addr'.  Returns 0 if information was found, and
-//     negative if not.  But even if it returns negative it has stored some
-//     information into '*info'.
-//
-int
-debuginfo_eip(uintptr_t addr, eipdebuginfo_t *info)
-{
-       const stab_t *stabs, *stab_end;
-       const char *stabstr, *stabstr_end;
-       int lfile, rfile, lfun, rfun, lline, rline;
-
-       // Initialize *info
-       info->eip_file = "<unknown>";
-       info->eip_line = 0;
-       info->eip_fn_name = "<unknown>";
-       info->eip_fn_namelen = 9;
-       info->eip_fn_addr = addr;
-       info->eip_fn_narg = 0;
-
-       // Find the relevant set of stabs
-       if (addr >= ULIM) {
-               stabs = __STAB_BEGIN__;
-               stab_end = __STAB_END__;
-               stabstr = __STABSTR_BEGIN__;
-               stabstr_end = __STABSTR_END__;
-       } else {
-               // The user-application linker script, user/user.ld,
-               // puts information about the application's stabs (equivalent
-               // 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 *) USTABDATA;
-
-               // Make sure this memory is valid.
-               // Return -1 if it is not.  Hint: Call user_mem_check.
-               // LAB 3: Your code here.
-               
-               stabs = usd->stabs;
-               stab_end = usd->stab_end;
-               stabstr = usd->stabstr;
-               stabstr_end = usd->stabstr_end;
-
-               // Make sure the STABS and string table memory is valid.
-               // LAB 3: Your code here.
+void debug_addr_pid(int pid, unsigned long addr)
+{
+       struct proc *p;
+       p = pid2proc(pid);
+       if (!p) {
+               printk("No such proc for pid %d\n", pid);
+               return;
        }
+       debug_addr_proc(p, addr);
+       proc_decref(p);
+}
 
-       // String table validity checks
-       if (stabstr_end <= stabstr || stabstr_end[-1] != 0)
-               return -1;
-
-       // Now we find the right stabs that define the function containing
-       // '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;
-       stab_binsearch(stabs, &lfile, &rfile, N_SO, addr);
-       if (lfile == 0)
-               return -1;
-
-       // Search within that file's stabs for the function definition
-       // (N_FUN).
-       lfun = lfile;
-       rfun = rfile;
-       stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr);
-
-       if (lfun <= rfun) {
-               // stabs[lfun] points to the function name
-               // in the string table, but check bounds just in case.
-               if (stabs[lfun].n_strx < stabstr_end - stabstr)
-                       info->eip_fn_name = stabstr + stabs[lfun].n_strx;
-               info->eip_fn_addr = stabs[lfun].n_value;
-               addr -= info->eip_fn_addr;
-               // Search within the function definition for the line number.
-               lline = lfun;
-               rline = rfun;
-       } else {
-               // Couldn't find function stab!  Maybe we're in an assembly
-               // file.  Search the whole file for the line number.
-               info->eip_fn_addr = addr;
-               lline = lfile;
-               rline = rfile;
+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]);
        }
-       // 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.
-       //
-       // Hint:
-       //      There's a particular stabs type used for line numbers.
-       //      Look at the STABS documentation and <inc/stab.h> to find
-       //      which one.
-       // Your code here.
-
-       stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
-       if (lline <= rline) 
-               // stabs[lline] points to the line number
-               info->eip_line = stabs[lline].n_value;
+}
+
+void backtrace_hwtf(struct hw_trapframe *hw_tf)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+
+       pcpui->__lock_checking_enabled--;
+       if (in_kernel(hw_tf))
+               backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
        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
-       // can interpolate code from a different file!
-       // Such included source files use the N_SOL stab type.
-       while (lline >= lfile
-              && stabs[lline].n_type != N_SOL
-              && (stabs[lline].n_type != N_SO || !stabs[lline].n_value))
-               lline--;
-       if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
-               info->eip_file = stabstr + stabs[lline].n_strx;
-
-       // Set eip_fn_narg to the number of arguments taken by the function,
-       // or 0 if there was no containing function.
-       // Your code here.
-       info->eip_fn_narg = 0;
-       if (lfun <= rfun) {
-               lfun++;
-               while (stabs[lfun++].n_type == N_PSYM)
-                       info->eip_fn_narg++;
+               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)
+{
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       uintptr_t st_save;
+
+       if (!ctx) {
+               printk("Null user context!\n");
+               return;
        }
-       
-       return 0;
+       st_save = switch_to(p);
+       pcpui->__lock_checking_enabled--;
+       backtrace_user_frame(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx));
+       pcpui->__lock_checking_enabled++;
+       switch_back(p, st_save);
+}
+
+static spinlock_t __px_lock = SPINLOCK_INITIALIZER_IRQSAVE;
+void px_lock(void)
+{
+       if (printx_on)
+               spin_lock_irqsave(&__px_lock);
+}
+void px_unlock(void)
+{
+       if (printx_on)
+               spin_unlock_irqsave(&__px_lock);
 }