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