Idenfity devices by name, not by char [1/3]
[akaros.git] / kern / src / kdebug.c
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
13 struct symtab_entry gbl_symtab[1] __attribute__((weak)) = {{0, 0}};
14
15 /* Returns a null-terminated string with the function name for a given PC /
16  * instruction pointer.  kfree() the result. */
17 char *get_fn_name(uintptr_t pc)
18 {
19         struct symtab_entry *i, *prev = 0, *found = 0;
20         char *buf;
21         size_t name_len;
22         /* Table is in ascending order.  As soon as we get to an entry greater than
23          * us, we were in the previous one.  This is only true if we were given a
24          * good PC.  Random addresses will just find the previous symbol. */
25         for (i = &gbl_symtab[0]; i->name; i++) {
26                 if (i->addr > pc) {
27                         found = prev;
28                         break;
29                 }
30                 prev = i;
31         }
32         if (!found)
33                 return 0;
34         assert(found->name);
35         name_len = strlen(found->name) + 1;
36         buf = kmalloc(name_len, 0);
37         if (!buf)
38                 return 0;
39         strncpy(buf, found->name, name_len);
40         buf[name_len] = 0;
41         return buf;
42 }
43
44 uintptr_t get_symbol_addr(char *sym)
45 {
46         struct symtab_entry *i;
47         for (i = &gbl_symtab[0]; i->name; i++) {
48                 if (strcmp(i->name, sym) == 0)
49                         return i->addr;
50         }
51         return 0;
52 }
53
54 static const char *blacklist[] = {
55         "addnode",
56         "addqueue",
57         "allocroute",
58         "balancetree",
59         "calcd",
60         "freeroute",
61         "genrandom",    /* not noisy, just never returns */
62         "limborexmit",
63         "rangecompare",
64         "walkadd",
65         "bnx2x_alloc_rx_data",
66         "bnx2x_frag_alloc",
67         "__dma_map_single",
68         "__dma_mapping_error",
69         "__dma_zalloc_coherent",
70         "__dma_alloc_coherent",
71         "bnx2x_ilt_line_mem_op",
72         "bnx2x_ilt_line_init_op",
73         "bnx2x_ilt_line_wr",
74         "bnx2x_wr_64",
75         "pci_write_config_dword",
76         "bnx2x_init_str_wr",
77         "bnx2x_init_fill",
78         "bnx2x_init_block",
79         "bnx2x_write_big_buf",
80         "bnx2x_init_wr_wb",
81         "bnx2x_write_big_buf_wb",
82         "bnx2x_cl45_read",
83         "bnx2x_cl45_write",
84         "bnx2x_set_mdio_clk",
85 };
86
87 static bool is_blacklisted(const char *s)
88 {
89         for (int i = 0; i < ARRAY_SIZE(blacklist); i++) {
90                 if (!strcmp(blacklist[i], s))
91                         return TRUE;
92         }
93         return FALSE;
94 }
95
96 static int tab_depth = 0;
97
98 /* Call this via kfunc */
99 void reset_print_func_depth(void)
100 {
101         tab_depth = 0;
102 }
103
104 static spinlock_t lock = SPINLOCK_INITIALIZER_IRQSAVE;
105
106 static void __print_hdr(void)
107 {
108         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
109         printd("Core %2d ", core_id()); /* may help with multicore output */
110         if (in_irq_ctx(pcpui)) {
111                 printk("IRQ       :");
112         } else {
113                 assert(pcpui->cur_kthread);
114                 if (pcpui->cur_kthread->is_ktask) {
115                         printk("%10s:", pcpui->cur_kthread->name);
116                 } else {
117                         printk("PID %3d   :", pcpui->cur_proc ? pcpui->cur_proc->pid : 0);
118                 }
119         }
120 }
121
122 void __print_func_entry(const char *func, const char *file)
123 {
124         char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
125         char *ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
126         if (!printx_on)
127                 return;
128         if (is_blacklisted(func))
129                 return;
130         spin_lock_irqsave(&lock);
131         __print_hdr();
132         printk("%s%s() in %s\n", ourtabs, func, file);
133         spin_unlock_irqsave(&lock);
134         tab_depth++;
135 }
136
137 void __print_func_exit(const char *func, const char *file)
138 {
139         char tentabs[] = "\t\t\t\t\t\t\t\t\t\t"; // ten tabs and a \0
140         char *ourtabs;
141         if (!printx_on)
142                 return;
143         if (is_blacklisted(func))
144                 return;
145         tab_depth--;
146         ourtabs = &tentabs[10 - MIN(tab_depth, 10)];
147         spin_lock_irqsave(&lock);
148         __print_hdr();
149         printk("%s---- %s()\n", ourtabs, func);
150         spin_unlock_irqsave(&lock);
151 }
152
153 bool printx_on = FALSE;
154
155 void set_printx(int mode)
156 {
157         switch (mode) {
158                 case 0:
159                         printx_on = FALSE;
160                         break;
161                 case 1:
162                         printx_on = TRUE;
163                         break;
164                 case 2:
165                         printx_on = !printx_on;
166                         break;
167         }
168 }
169
170 void debug_addr_proc(struct proc *p, unsigned long addr)
171 {
172         struct vm_region *vmr;
173         spin_lock(&p->vmr_lock);
174         TAILQ_FOREACH(vmr, &p->vm_regions, vm_link) {
175                 if ((vmr->vm_base <= addr) && (addr < vmr->vm_end))
176                         break;
177         }
178         if (!vmr) {
179                 spin_unlock(&p->vmr_lock);
180                 printk("Addr %p has no VMR\n", addr);
181                 return;
182         }
183         if (!vmr->vm_file) {
184                 spin_unlock(&p->vmr_lock);
185                 printk("Addr %p's VMR has no file\n", addr);
186                 return;
187         }
188         printk("Addr %p is in %s at offset %p\n", addr, file_name(vmr->vm_file),
189                addr - vmr->vm_base + vmr->vm_foff);
190         spin_unlock(&p->vmr_lock);
191 }
192
193 void debug_addr_pid(int pid, unsigned long addr)
194 {
195         struct proc *p;
196         p = pid2proc(pid);
197         if (!p) {
198                 printk("No such proc for pid %d\n", pid);
199                 return;
200         }
201         debug_addr_proc(p, addr);
202         proc_decref(p);
203 }
204
205 void backtrace_kframe(struct hw_trapframe *hw_tf)
206 {
207         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
208         pcpui->__lock_checking_enabled--;
209         printk("\nBacktrace of kernel context on Core %d:\n", core_id());
210         backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf));
211         pcpui->__lock_checking_enabled++;
212 }
213
214 void backtrace_user_ctx(struct proc *p, struct user_context *ctx)
215 {
216         #define MAX_BT_DEPTH 20
217         uintptr_t pcs[MAX_BT_DEPTH];
218         size_t nr_pcs;
219
220         if (!ctx) {
221                 printk("Null user context!\n");
222                 return;
223         }
224         nr_pcs = backtrace_list(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx), pcs,
225                                 MAX_BT_DEPTH);
226         printk("User context backtrace:\n");
227         printk("\tOffsets only matter for shared libraries\n");
228         for (int i = 0; i < nr_pcs; i++) {
229                 printk("#%02d ", i + 1);
230                 debug_addr_proc(p, pcs[i]);
231         }
232 }