akaros/kern/src/kdebug.c
<<
>>
Prefs
   1/* Copyright (c) 2011 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * Arch-independent kernel debugging */
   6
   7#include <kdebug.h>
   8#include <kmalloc.h>
   9#include <string.h>
  10#include <assert.h>
  11#include <smp.h>
  12
  13struct symtab_entry gbl_symtab[1] __attribute__((weak)) = {{0, 0}};
  14
  15/* Returns a null-terminated string from the reflected symbol table with the
  16 * function name for a given PC / instruction pointer.  Returns NULL on
  17 * failure. */
  18const char *get_fn_name(uintptr_t pc)
  19{
  20        struct symtab_entry *i, *prev = 0, *found = 0;
  21
  22        /* Table is in ascending order.  As soon as we get to an entry greater
  23         * than us, we were in the previous one.  This is only true if we were
  24         * given a good PC.  Random addresses will just find the previous
  25         * symbol. */
  26        for (i = &gbl_symtab[0]; i->name; i++) {
  27                if (i->addr > pc) {
  28                        found = prev;
  29                        break;
  30                }
  31                prev = i;
  32        }
  33        if (!found)
  34                return NULL;
  35        assert(found->name);
  36        return found->name;
  37}
  38
  39uintptr_t get_symbol_addr(char *sym)
  40{
  41        struct symtab_entry *i;
  42
  43        for (i = &gbl_symtab[0]; i->name; i++) {
  44                if (strcmp(i->name, sym) == 0)
  45                        return i->addr;
  46        }
  47        return 0;
  48}
  49
  50static const char *blacklist[] = {
  51        "addnode",
  52        "addqueue",
  53        "allocroute",
  54        "balancetree",
  55        "calcd",
  56        "freeroute",
  57        "genrandom",    /* not noisy, just never returns */
  58        "limborexmit",
  59        "rangecompare",
  60        "walkadd",
  61        "bnx2x_alloc_rx_data",
  62        "bnx2x_frag_alloc",
  63        "__dma_map_single",
  64        "__dma_mapping_error",
  65        "__dma_zalloc_coherent",
  66        "__dma_alloc_coherent",
  67        "bnx2x_ilt_line_mem_op",
  68        "bnx2x_ilt_line_init_op",
  69        "bnx2x_ilt_line_wr",
  70        "bnx2x_wr_64",
  71        "pci_write_config_dword",
  72        "bnx2x_init_str_wr",
  73        "bnx2x_init_fill",
  74        "bnx2x_init_block",
  75        "bnx2x_write_big_buf",
  76        "bnx2x_init_wr_wb",
  77        "bnx2x_write_big_buf_wb",
  78        "bnx2x_cl45_read",
  79        "bnx2x_cl45_write",
  80        "bnx2x_set_mdio_clk",
  81};
  82
  83static bool is_blacklisted(const char *s)
  84{
  85        for (int i = 0; i < ARRAY_SIZE(blacklist); i++) {
  86                if (!strcmp(blacklist[i], s))
  87                        return TRUE;
  88        }
  89        return FALSE;
  90}
  91
  92static int tab_depth = 0;
  93
  94/* Call this via kfunc */
  95void reset_print_func_depth(void)
  96{
  97        tab_depth = 0;
  98}
  99
 100static void __print_hdr(void)
 101{
 102        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 103        printd("Core %2d ", core_id()); /* may help with multicore output */
 104        if (in_irq_ctx(pcpui)) {
 105                printk("IRQ       :");
 106        } else {
 107                assert(pcpui->cur_kthread);
 108                if (is_ktask(pcpui->cur_kthread)) {
 109                        printk("%10s:", pcpui->cur_kthread->name);
 110                } else {
 111                        printk("PID %3d   :", pcpui->cur_proc ?
 112                               pcpui->cur_proc->pid : 0);
 113                }
 114        }
 115}
 116
 117void __print_func_entry(const char *func, const char *file)
 118{
 119        char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
 120        char *ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
 121
 122        if (!printx_on)
 123                return;
 124        if (is_blacklisted(func))
 125                return;
 126        print_lock();
 127        __print_hdr();
 128        printk("%s%s() in %s\n", ourtabs, func, file);
 129        print_unlock();
 130        tab_depth++;
 131}
 132
 133void __print_func_exit(const char *func, const char *file)
 134{
 135        char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
 136        char *ourtabs;
 137
 138        if (!printx_on)
 139                return;
 140        if (is_blacklisted(func))
 141                return;
 142        tab_depth--;
 143        ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
 144        print_lock();
 145        __print_hdr();
 146        printk("%s---- %s()\n", ourtabs, func);
 147        print_unlock();
 148}
 149
 150bool printx_on = FALSE;
 151
 152void set_printx(int mode)
 153{
 154        switch (mode) {
 155        case 0:
 156                printx_on = FALSE;
 157                break;
 158        case 1:
 159                printx_on = TRUE;
 160                break;
 161        case 2:
 162                printx_on = !printx_on;
 163                break;
 164        }
 165}
 166
 167void debug_addr_proc(struct proc *p, unsigned long addr)
 168{
 169        struct vm_region *vmr;
 170
 171        spin_lock(&p->vmr_lock);
 172        TAILQ_FOREACH(vmr, &p->vm_regions, vm_link) {
 173                if ((vmr->vm_base <= addr) && (addr < vmr->vm_end))
 174                        break;
 175        }
 176        if (!vmr) {
 177                spin_unlock(&p->vmr_lock);
 178                printk("Addr %p has no VMR\n", addr);
 179                return;
 180        }
 181        if (!vmr_has_file(vmr)) {
 182                spin_unlock(&p->vmr_lock);
 183                printk("Addr %p's VMR has no file\n", addr);
 184                return;
 185        }
 186        printk("Addr %p is in %s at offset %p\n", addr, vmr_to_filename(vmr),
 187               addr - vmr->vm_base + vmr->vm_foff);
 188        spin_unlock(&p->vmr_lock);
 189}
 190
 191void debug_addr_pid(int pid, unsigned long addr)
 192{
 193        struct proc *p;
 194        p = pid2proc(pid);
 195        if (!p) {
 196                printk("No such proc for pid %d\n", pid);
 197                return;
 198        }
 199        debug_addr_proc(p, addr);
 200        proc_decref(p);
 201}
 202
 203#define BT_FMT "#%02d [<%p>] in %s\n"
 204
 205void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs, void (*pfunc)(void *,
 206                                                                       const
 207                                                                       char *),
 208                          void *opaque)
 209{
 210        char bt_line[128];
 211
 212        for (size_t i = 0; i < nr_pcs; i++) {
 213                snprintf(bt_line, sizeof(bt_line), BT_FMT, i + 1, pcs[i],
 214                         get_fn_name(pcs[i]));
 215                pfunc(opaque, bt_line);
 216        }
 217}
 218
 219void sza_print_backtrace_list(struct sized_alloc *sza, uintptr_t *pcs,
 220                              size_t nr_pcs)
 221{
 222        for (size_t i = 0; i < nr_pcs; i++)
 223                sza_printf(sza, BT_FMT, i + 1, pcs[i], get_fn_name(pcs[i]));
 224}
 225
 226static void printk_func(void *opaque, const char *str)
 227{
 228        printk("%s", str);
 229}
 230
 231void backtrace(void)
 232{
 233        print_lock();
 234        printk("Stack Backtrace on Core %d:\n", core_id());
 235        gen_backtrace(&printk_func, NULL);
 236        print_unlock();
 237}
 238
 239static void trace_printk_func(void *opaque, const char *str)
 240{
 241        trace_printk("%s", str);
 242}
 243
 244void backtrace_trace(void)
 245{
 246        /* Don't need this strictly, but it helps serialize to the trace buf */
 247        print_lock();
 248        trace_printk("Stack Backtrace on Core %d:\n", core_id());
 249        gen_backtrace(&trace_printk_func, NULL);
 250        print_unlock();
 251}
 252
 253static void trace_printx_func(void *opaque, const char *str)
 254{
 255        trace_printx("%s", str);
 256}
 257
 258void backtrace_trace_printx(void)
 259{
 260        /* Don't need this strictly, but it helps serialize to the trace buf */
 261        print_lock();
 262        trace_printx("Stack Backtrace on Core %d:\n", core_id());
 263        gen_backtrace(&trace_printk_func, NULL);
 264        print_unlock();
 265}
 266
 267void backtrace_frame(uintptr_t eip, uintptr_t ebp)
 268{
 269        uintptr_t pcs[MAX_BT_DEPTH];
 270        size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH);
 271
 272        print_lock();
 273        printk("\nBacktrace of kernel context on Core %d:\n", core_id());
 274        print_backtrace_list(pcs, nr_pcs, &printk_func, NULL);
 275        print_unlock();
 276}
 277
 278/* TODO: change debug_addr_proc() to allow print redirection like
 279 * print_backtrace_list(). */
 280void backtrace_user_frame(uintptr_t eip, uintptr_t ebp)
 281{
 282        uintptr_t pcs[MAX_BT_DEPTH];
 283        /* TODO: this assumes we have the user's address space loaded (current).
 284         */
 285        size_t nr_pcs = backtrace_user_list(eip, ebp, pcs, MAX_BT_DEPTH);
 286
 287        print_lock();
 288        printk("\nBacktrace of user context on Core %d:\n", core_id());
 289        printk("\tOffsets only matter for shared libraries\n");
 290        /* This formatting is consumed by scripts/bt-akaros.sh. */
 291        for (int i = 0; i < nr_pcs; i++) {
 292                printk("#%02d ", i + 1);
 293                /* TODO: user backtraces all assume we're working on 'current'*/
 294                debug_addr_proc(current, pcs[i]);
 295        }
 296        print_unlock();
 297}
 298
 299void backtrace_hwtf(struct hw_trapframe *hw_tf)
 300{
 301        if (in_kernel(hw_tf))
 302                backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
 303        else
 304                backtrace_user_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
 305}
 306
 307void backtrace_user_ctx(struct proc *p, struct user_context *ctx)
 308{
 309        uintptr_t st_save;
 310
 311        if (!ctx) {
 312                printk("Null user context!\n");
 313                return;
 314        }
 315        st_save = switch_to(p);
 316        backtrace_user_frame(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx));
 317        switch_back(p, st_save);
 318}
 319
 320void backtrace_current_ctx(void)
 321{
 322        if (current)
 323                backtrace_user_ctx(current, current_ctx);
 324}
 325
 326void backtrace_kthread(struct kthread *kth)
 327{
 328        backtrace_frame(jmpbuf_get_pc(&kth->context),
 329                        jmpbuf_get_fp(&kth->context));
 330}
 331