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