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