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