Added generic backtrace functions to allow backtrace output on buffers
[akaros.git] / kern / arch / x86 / kdebug.c
1 #include <stab.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <kdebug.h>
5 #include <pmap.h>
6 #include <process.h>
7 #include <kmalloc.h>
8
9 #include <ros/memlayout.h>
10
11 /* The return address is right above ebp on the stack.  We subtract an
12  * additional 1 to make sure the eip we get is actually in the function
13  * that called us.  I had a couple cases early on where call was the last
14  * instruction in a function, and simply reading the retaddr would point
15  * into another function (the next one in the object).
16  */
17 #define GET_FRAME_START(ebp, eip)                                                       \
18         do {                                                                                                    \
19                 ebp = read_bp();                                                                        \
20                 eip = *(uintptr_t *) (ebp + sizeof(uintptr_t)) - 1; \
21                 ebp = *(uintptr_t *) ebp;                                                       \
22         } while (0)
23
24 // Beginning of stabs table
25 extern const stab_t __STAB_BEGIN__[];
26
27 // End of stabs table
28 extern const stab_t __STAB_END__[];
29
30 // Beginning of string table
31 extern const char __STABSTR_BEGIN__[];
32
33  // End of string table
34 extern const char __STABSTR_END__[];
35
36 typedef struct UserStabData {
37         const stab_t *stabs;
38         const stab_t *stab_end;
39         const char *stabstr;
40         const char *stabstr_end;
41 } user_stab_data_t;
42
43 static void printk_func(void *opaque, const char *str)
44 {
45         printk("%s", str);
46 }
47
48 void gen_backtrace_frame(uintptr_t eip, uintptr_t ebp,
49                                                  void (*pfunc)(void *, const char *), void *opaque)
50 {
51 #define MAX_BT_DEPTH 20
52         char *func_name;
53         char bt_line[128];
54         uintptr_t pcs[MAX_BT_DEPTH];
55         size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH);
56
57         for (size_t i = 0; i < nr_pcs; i++) {
58                 func_name = get_fn_name(pcs[i]);
59                 snprintf(bt_line, sizeof(bt_line), "#%02d [<%p>] in %s\n", i + 1,
60                                  pcs[i], func_name);
61                 pfunc(opaque, bt_line);
62                 kfree(func_name);
63         }
64 }
65
66 void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque)
67 {
68         uintptr_t ebp, eip;
69
70         GET_FRAME_START(ebp, eip);
71         gen_backtrace_frame(eip, ebp, pfunc, opaque);
72 }
73
74 /* We used to check for a null terminating byte for the entire strings section
75  * (due to JOS, I think), but that's not what the spec says: only that all
76  * strings are null terminated.  There might be random stuff tacked on at the
77  * end.  I had some stabs that seemed valid (lookups worked), that did not have
78  * the entire table be null terminated.  Still, something else might be jacked
79  * up.  If it turns out that's the case, put the checks in here. */
80 static bool stab_table_valid(const char *stabstr, const char *stabstr_end)
81 {
82         if (stabstr_end <= stabstr)
83                 return FALSE;
84         return TRUE;
85 }
86
87 // stab_binsearch(stabs, region_left, region_right, type, addr)
88 //
89 //      Some stab types are arranged in increasing order by instruction
90 //      address.  For example, N_FUN stabs (stab entries with n_type ==
91 //      N_FUN), which mark functions, and N_SO stabs, which mark source files.
92 //
93 //      Given an instruction address, this function finds the single stab
94 //      entry of type 'type' that contains that address.
95 //
96 //      The search takes place within the range [*region_left, *region_right].
97 //      Thus, to search an entire set of N stabs, you might do:
98 //
99 //              left = 0;
100 //              right = N - 1;     /* rightmost stab */
101 //              stab_binsearch(stabs, &left, &right, type, addr);
102 //
103 //      The search modifies *region_left and *region_right to bracket the
104 //      'addr'.  *region_left points to the matching stab that contains
105 //      'addr', and *region_right points just before the next stab.  If
106 //      *region_left > *region_right, then 'addr' is not contained in any
107 //      matching stab.
108 //
109 //      For example, given these N_SO stabs:
110 //              Index  Type   Address
111 //              0      SO     f0100000
112 //              13     SO     f0100040
113 //              117    SO     f0100176
114 //              118    SO     f0100178
115 //              555    SO     f0100652
116 //              556    SO     f0100654
117 //              657    SO     f0100849
118 //      this code:
119 //              left = 0, right = 657;
120 //              stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
121 //      will exit setting left = 118, right = 554.
122 //
123 static void
124 stab_binsearch(const stab_t *stabs,
125            const stab_t *stab_end,
126            int *region_left, int *region_right,
127                int type, uintptr_t addr)
128 {
129         int l = *region_left, r = *region_right, any_matches = 0;
130         
131         while (l <= r) {
132                 int true_m = (l + r) / 2, m = true_m;
133                 
134                 // search for earliest stab with right type
135                 while (m >= l && stabs[m].n_type != type)
136                         m--;
137                 if (m < l) {    // no match in [l, m]
138                         l = true_m + 1;
139                         continue;
140                 }
141
142                 // actual binary search
143                 any_matches = 1;
144                 if (stabs[m].n_value < addr) {
145                         *region_left = m;
146                         l = true_m + 1;
147                 } else if (stabs[m].n_value > addr) {
148                         *region_right = m - 1;
149                         r = m - 1;
150                 } else {
151                         // exact match for 'addr', but continue loop to find
152                         // *region_right
153                         *region_left = m;
154                         l = m;
155                         addr++;
156                 }
157         }
158
159         if (!any_matches)
160                 *region_right = *region_left - 1;
161         else {
162                 // find rightmost region containing 'addr'
163                 for (l = *region_right;
164                      l > *region_left && stabs[l].n_type != type;
165                      l--)
166                         /* do nothing */;
167                 *region_left = l;
168         }
169 }
170
171
172 // debuginfo_eip(addr, info)
173 //
174 //      Fill in the 'info' structure with information about the specified
175 //      instruction address, 'addr'.  Returns 0 if information was found, and
176 //      negative if not.  But even if it returns negative it has stored some
177 //      information into '*info'.
178 //
179 int
180 debuginfo_eip(uintptr_t addr, eipdebuginfo_t *info)
181 {
182         const stab_t *stab_end;
183         const stab_t *stabs;
184         const char *stabstr_end;
185         const char *stabstr;
186         int lfile, rfile, lfun, rfun, lline, rline;
187
188         // Initialize *info
189         info->eip_file = "<unknown>";
190         info->eip_line = 0;
191         info->eip_fn_name = "<unknown>";
192         info->eip_fn_namelen = 9;
193         info->eip_fn_addr = addr;
194         info->eip_fn_narg = 0;
195
196         // Find the relevant set of stabs
197         if (addr >= ULIM) {
198                 stab_end = __STAB_END__;
199                 stabs = __STAB_BEGIN__;
200                 stabstr_end = __STABSTR_END__;
201                 stabstr = __STABSTR_BEGIN__;
202         } else {
203                 /* TODO: short circuiting this, til our user space apps pack stab data
204                  * the kernel knows about */
205                 return -1;
206                 #if 0
207                 // The user-application linker script, user/user.ld,
208                 // puts information about the application's stabs (equivalent
209                 // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
210                 // __STABSTR_END__) in a structure located at virtual address
211                 // USTABDATA.
212                 const user_stab_data_t *usd = (const user_stab_data_t *)USTABDATA;
213
214                 // Make sure this memory is valid.
215                 // Return -1 if it is not.  Hint: Call user_mem_check.
216                 // LAB 3: Your code here.
217
218                 stab_end = usd->stab_end;
219                 stabs = usd->stabs;
220                 stabstr_end = usd->stabstr_end;
221                 stabstr = usd->stabstr;
222
223                 // Make sure the STABS and string table memory is valid.
224                 // LAB 3: Your code here.
225                 #endif
226         }
227
228         if (!stab_table_valid(stabstr, stabstr_end))
229                 return -1;
230
231         // Now we find the right stabs that define the function containing
232         // 'eip'.  First, we find the basic source file containing 'eip'.
233         // Then, we look in that source file for the function.  Then we look
234         // for the line number.
235         
236         // Search the entire set of stabs for the source file (type N_SO).
237         lfile = 0;
238         rfile = (stab_end - stabs) - 1;
239         stab_binsearch(stabs, stab_end, &lfile, &rfile, N_SO, addr);
240         if (lfile == 0)
241                 return -1;
242
243         // Search within that file's stabs for the function definition
244         // (N_FUN).
245         lfun = lfile;
246         rfun = rfile;
247         stab_binsearch(stabs, stab_end, &lfun, &rfun, N_FUN, addr);
248
249         if (lfun <= rfun) {
250                 // stabs[lfun] points to the function name
251                 // in the string table, but check bounds just in case.
252                 if (stabs[lfun].n_strx < stabstr_end - stabstr)
253                         info->eip_fn_name = stabstr + stabs[lfun].n_strx;
254                 info->eip_fn_addr = stabs[lfun].n_value;
255                 addr -= info->eip_fn_addr;
256                 // Search within the function definition for the line number.
257                 lline = lfun;
258                 rline = rfun;
259         } else {
260                 // Couldn't find function stab!  Maybe we're in an assembly
261                 // file.  Search the whole file for the line number.
262                 info->eip_fn_addr = addr;
263                 lline = lfile;
264                 rline = rfile;
265         }
266         // Ignore stuff after the colon.
267         info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
268         
269         // Search within [lline, rline] for the line number stab.
270         // If found, set info->eip_line to the right line number.
271         // If not found, return -1.
272         //
273         // Hint:
274         //      There's a particular stabs type used for line numbers.
275         //      Look at the STABS documentation and <inc/stab.h> to find
276         //      which one.
277         // Your code here.
278
279         stab_binsearch(stabs, stab_end, &lline, &rline, N_SLINE, addr);
280         if (lline <= rline) 
281                 // stabs[lline] points to the line number
282                 info->eip_line = stabs[lline].n_value;
283         else
284                 return -1;
285         
286         // Search backwards from the line number for the relevant filename
287         // stab.
288         // We can't just use the "lfile" stab because inlined functions
289         // can interpolate code from a different file!
290         // Such included source files use the N_SOL stab type.
291         while (lline >= lfile
292                && stabs[lline].n_type != N_SOL
293                && (stabs[lline].n_type != N_SO || !stabs[lline].n_value))
294                 lline--;
295         if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
296                 info->eip_file = stabstr + stabs[lline].n_strx;
297
298         // Set eip_fn_narg to the number of arguments taken by the function,
299         // or 0 if there was no containing function.
300         // Your code here.
301         info->eip_fn_narg = 0;
302         if (lfun <= rfun) {
303                 lfun++;
304                 while (stabs[lfun++].n_type == N_PSYM)
305                         info->eip_fn_narg++;
306         }
307         
308         return 0;
309 }
310
311 /* Returns a function pointer for a function name matching the given string. */
312 void *debug_get_fn_addr(char *fn_name)
313 {
314         const struct stab *stab_end = __STAB_END__;
315         const struct stab *stabs = __STAB_BEGIN__;
316         const char *stabstr_end = __STABSTR_END__;
317         const char *stabstr = __STABSTR_BEGIN__;
318
319         static int first_fn_idx = 0;
320         int i = first_fn_idx;
321         int len;
322         const char *stab_fn_name = 0;
323         void *retval = 0;
324
325         if (!stab_table_valid(stabstr, stabstr_end))
326                 return 0;
327
328         for (/* i set */; &stabs[i] < stab_end; i++) {
329                 if (stabs[i].n_type != N_FUN)
330                         continue;
331                 first_fn_idx = first_fn_idx ? first_fn_idx : i;
332                 /* broken stab, just keep going */
333                 if (!(stabs[i].n_strx < stabstr_end - stabstr))
334                         continue;
335                 stab_fn_name = stabstr + stabs[i].n_strx;
336                 len = strfind(stab_fn_name, ':') - stab_fn_name;
337                 if (!len)
338                         continue;
339                 /* we have a match. */
340                 if (!strncmp(stab_fn_name, fn_name, len)) {
341                         printd("FN name: %s, Addr: %p\n", stab_fn_name, stabs[i].n_value);
342                         retval = (void*)stabs[i].n_value;
343                         break;
344                 }
345         }
346         return retval;
347 }
348
349 size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs,
350                       size_t nr_slots)
351 {
352         size_t nr_pcs = 0;
353         while ((fp > MMAP_LOWEST_VA) && (nr_pcs < nr_slots)) {
354                 /* could put some sanity checks in here...  i used to at least check for
355                  * kernel addrs, but now we also bt user stacks. (dangerous!) */
356                 pcs[nr_pcs++] = pc;
357                 printd("PC %p FP %p\n", pc, fp);
358                 /* We used to set PC = retaddr - 1, where the -1 would put our PC back
359                  * inside the function that called us.  This was for obscure cases where
360                  * a no-return function calls another function and has no other code
361                  * after the function call.  Or something. */
362                 pc = *(uintptr_t*)(fp + sizeof(uintptr_t));
363                 fp = *(uintptr_t*)fp;
364         }
365         return nr_pcs;
366 }
367
368 void backtrace_frame(uintptr_t eip, uintptr_t ebp)
369 {
370         gen_backtrace_frame(eip, ebp, &printk_func, NULL);
371 }
372
373 void backtrace(void)
374 {
375         printk("Stack Backtrace on Core %d:\n", core_id());
376         gen_backtrace(&printk_func, NULL);
377 }
378
379 /* Assumes 32-bit header */
380 void print_fpu_state(struct ancillary_state *fpu)
381 {
382         printk("fcw:        0x%04x\n", fpu->fp_head_n64.fcw);
383         printk("fsw:        0x%04x\n", fpu->fp_head_n64.fsw);
384         printk("ftw:          0x%02x\n", fpu->fp_head_n64.ftw);
385         printk("fop:        0x%04x\n", fpu->fp_head_n64.fop);
386         printk("fpu_ip: 0x%08x\n", fpu->fp_head_n64.fpu_ip);
387         printk("cs:         0x%04x\n", fpu->fp_head_n64.cs);
388         printk("fpu_dp: 0x%08x\n", fpu->fp_head_n64.fpu_dp);
389         printk("ds:         0x%04x\n", fpu->fp_head_n64.ds);
390         printk("mxcsr:  0x%08x\n", fpu->fp_head_n64.mxcsr);
391         printk("mxcsrm: 0x%08x\n", fpu->fp_head_n64.mxcsr_mask);
392
393         for (int i = 0; i < sizeof(struct ancillary_state); i++) {
394                 if (i % 20 == 0)
395                         printk("\n");
396                 printk("%02x ", *((uint8_t*)fpu + i));
397         }
398         printk("\n");
399 }