Rename RCU CB context to 'cannot block' context
[akaros.git] / kern / src / kdebug.c
index 5890731..d320144 100644 (file)
 
 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)
+/* Returns a null-terminated string from the reflected symbol table with the
+ * function name for a given PC / instruction pointer.  Returns NULL on
+ * failure. */
+const 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. */
@@ -30,15 +30,9 @@ char *get_fn_name(uintptr_t pc)
                prev = i;
        }
        if (!found)
-               return 0;
+               return NULL;
        assert(found->name);
-       name_len = strlen(found->name) + 1;
-       buf = kmalloc(name_len, 0);
-       if (!buf)
-               return 0;
-       strncpy(buf, found->name, name_len);
-       buf[name_len] = 0;
-       return buf;
+       return found->name;
 }
 
 uintptr_t get_symbol_addr(char *sym)
@@ -101,8 +95,6 @@ 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()];
@@ -111,7 +103,7 @@ static void __print_hdr(void)
                printk("IRQ       :");
        } else {
                assert(pcpui->cur_kthread);
-               if (pcpui->cur_kthread->is_ktask) {
+               if (is_ktask(pcpui->cur_kthread)) {
                        printk("%10s:", pcpui->cur_kthread->name);
                } else {
                        printk("PID %3d   :", pcpui->cur_proc ? pcpui->cur_proc->pid : 0);
@@ -123,14 +115,15 @@ 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_lock();
        __print_hdr();
        printk("%s%s() in %s\n", ourtabs, func, file);
-       spin_unlock_irqsave(&lock);
+       print_unlock();
        tab_depth++;
 }
 
@@ -138,16 +131,17 @@ 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_lock();
        __print_hdr();
        printk("%s---- %s()\n", ourtabs, func);
-       spin_unlock_irqsave(&lock);
+       print_unlock();
 }
 
 bool printx_on = FALSE;
@@ -180,12 +174,12 @@ void debug_addr_proc(struct proc *p, unsigned long addr)
                printk("Addr %p has no VMR\n", addr);
                return;
        }
-       if (!vmr->vm_file) {
+       if (!vmr_has_file(vmr)) {
                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),
+       printk("Addr %p is in %s at offset %p\n", addr, vmr_to_filename(vmr),
               addr - vmr->vm_base + vmr->vm_foff);
        spin_unlock(&p->vmr_lock);
 }
@@ -201,3 +195,129 @@ void debug_addr_pid(int pid, unsigned long addr)
        debug_addr_proc(p, addr);
        proc_decref(p);
 }
+
+#define BT_FMT "#%02d [<%p>] in %s\n"
+
+void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs,
+                                                 void (*pfunc)(void *, const char *), void *opaque)
+{
+       char bt_line[128];
+
+       for (size_t i = 0; i < nr_pcs; i++) {
+               snprintf(bt_line, sizeof(bt_line), BT_FMT, i + 1, pcs[i],
+                        get_fn_name(pcs[i]));
+               pfunc(opaque, bt_line);
+       }
+}
+
+void sza_print_backtrace_list(struct sized_alloc *sza, uintptr_t *pcs,
+                              size_t nr_pcs)
+{
+       for (size_t i = 0; i < nr_pcs; i++)
+               sza_printf(sza, BT_FMT, i + 1, pcs[i], get_fn_name(pcs[i]));
+}
+
+static void printk_func(void *opaque, const char *str)
+{
+       printk("%s", str);
+}
+
+void backtrace(void)
+{
+       print_lock();
+       printk("Stack Backtrace on Core %d:\n", core_id());
+       gen_backtrace(&printk_func, NULL);
+       print_unlock();
+}
+
+static void trace_printk_func(void *opaque, const char *str)
+{
+       trace_printk("%s", str);
+}
+
+void backtrace_trace(void)
+{
+       /* Don't need this strictly, but it helps serialize to the trace buf */
+       print_lock();
+       trace_printk("Stack Backtrace on Core %d:\n", core_id());
+       gen_backtrace(&trace_printk_func, NULL);
+       print_unlock();
+}
+
+static void trace_printx_func(void *opaque, const char *str)
+{
+       trace_printx("%s", str);
+}
+
+void backtrace_trace_printx(void)
+{
+       /* Don't need this strictly, but it helps serialize to the trace buf */
+       print_lock();
+       trace_printx("Stack Backtrace on Core %d:\n", core_id());
+       gen_backtrace(&trace_printk_func, NULL);
+       print_unlock();
+}
+
+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);
+
+       print_lock();
+       printk("\nBacktrace of kernel context on Core %d:\n", core_id());
+       print_backtrace_list(pcs, nr_pcs, &printk_func, NULL);
+       print_unlock();
+}
+
+/* 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];
+       /* TODO: this assumes we have the user's address space loaded (current). */
+       size_t nr_pcs = backtrace_user_list(eip, ebp, pcs, MAX_BT_DEPTH);
+
+       print_lock();
+       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]);
+       }
+       print_unlock();
+}
+
+void backtrace_hwtf(struct hw_trapframe *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));
+}
+
+void backtrace_user_ctx(struct proc *p, struct user_context *ctx)
+{
+       uintptr_t st_save;
+
+       if (!ctx) {
+               printk("Null user context!\n");
+               return;
+       }
+       st_save = switch_to(p);
+       backtrace_user_frame(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx));
+       switch_back(p, st_save);
+}
+
+void backtrace_current_ctx(void)
+{
+       if (current)
+               backtrace_user_ctx(current, current_ctx);
+}
+
+void backtrace_kthread(struct kthread *kth)
+{
+       backtrace_frame(jmpbuf_get_pc(&kth->context),
+                       jmpbuf_get_fp(&kth->context));
+}