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