printk: check for user pointers in format string parameters
[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
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
39 uintptr_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
50 static 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
83 static 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
92 static int tab_depth = 0;
93
94 /* Call this via kfunc */
95 void reset_print_func_depth(void)
96 {
97         tab_depth = 0;
98 }
99
100 static 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
117 void __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
133 void __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
150 bool printx_on = FALSE;
151
152 void 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
167 void 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
191 void 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
205 void 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
219 void 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
226 static void printk_func(void *opaque, const char *str)
227 {
228         printk("%s", str);
229 }
230
231 void 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
239 static void trace_printk_func(void *opaque, const char *str)
240 {
241         trace_printk("%s", str);
242 }
243
244 void 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
253 static void trace_printx_func(void *opaque, const char *str)
254 {
255         trace_printx("%s", str);
256 }
257
258 void 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
267 void 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(). */
280 void 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
299 void 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
307 void 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
320 void backtrace_current_ctx(void)
321 {
322         if (current)
323                 backtrace_user_ctx(current, current_ctx);
324 }
325
326 void backtrace_kthread(struct kthread *kth)
327 {
328         backtrace_frame(jmpbuf_get_pc(&kth->context),
329                         jmpbuf_get_fp(&kth->context));
330 }