13 #include <ros/memlayout.h>
15 // Beginning of stabs table
16 extern const stab_t (RO BND(__this,__STAB_END__) __STAB_BEGIN__)[];
19 extern const stab_t (RO SNT __STAB_END__)[];
21 // Beginning of string table
22 extern const char (RO NT BND(__this,__STABSTR_END__) __STABSTR_BEGIN__)[];
24 // End of string table
25 extern const char (RO SNT __STABSTR_END__)[];
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;
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)
43 if (stabstr_end <= stabstr)
48 // stab_binsearch(stabs, region_left, region_right, type, addr)
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.
54 // Given an instruction address, this function finds the single stab
55 // entry of type 'type' that contains that address.
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:
61 // right = N - 1; /* rightmost stab */
62 // stab_binsearch(stabs, &left, &right, type, addr);
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
70 // For example, given these N_SO stabs:
80 // left = 0, right = 657;
81 // stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
82 // will exit setting left = 118, right = 554.
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)
90 int l = *region_left, r = *region_right, any_matches = 0;
93 int true_m = (l + r) / 2, m = true_m;
95 // search for earliest stab with right type
96 while (m >= l && stabs[m].n_type != type)
98 if (m < l) { // no match in [l, m]
103 // actual binary search
105 if (stabs[m].n_value < addr) {
108 } else if (stabs[m].n_value > addr) {
109 *region_right = m - 1;
112 // exact match for 'addr', but continue loop to find
121 *region_right = *region_left - 1;
123 // find rightmost region containing 'addr'
124 for (l = *region_right;
125 l > *region_left && stabs[l].n_type != type;
133 // debuginfo_eip(addr, info)
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'.
141 debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
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;
150 info->eip_file = "<unknown>";
152 info->eip_fn_name = "<unknown>";
153 info->eip_fn_namelen = 9;
154 info->eip_fn_addr = addr;
155 info->eip_fn_narg = 0;
157 // Find the relevant set of stabs
159 stab_end = __STAB_END__;
160 stabs = __STAB_BEGIN__;
161 stabstr_end = __STABSTR_END__;
162 stabstr = __STABSTR_BEGIN__;
164 /* TODO: short circuiting this, til our user space apps pack stab data
165 * the kernel knows about */
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
173 const user_stab_data_t *usd = (const user_stab_data_t *COUNT(1))TC(USTABDATA);
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.
179 stab_end = usd->stab_end;
181 stabstr_end = usd->stabstr_end;
182 stabstr = usd->stabstr;
184 // Make sure the STABS and string table memory is valid.
185 // LAB 3: Your code here.
189 if (!stab_table_valid(stabstr, stabstr_end))
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.
197 // Search the entire set of stabs for the source file (type N_SO).
199 rfile = (stab_end - stabs) - 1;
200 stab_binsearch(stabs, stab_end, &lfile, &rfile, N_SO, addr);
204 // Search within that file's stabs for the function definition
208 stab_binsearch(stabs, stab_end, &lfun, &rfun, N_FUN, addr);
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.
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;
227 // Ignore stuff after the colon.
228 info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
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.
235 // There's a particular stabs type used for line numbers.
236 // Look at the STABS documentation and <inc/stab.h> to find
240 stab_binsearch(stabs, stab_end, &lline, &rline, N_SLINE, addr);
242 // stabs[lline] points to the line number
243 info->eip_line = stabs[lline].n_value;
247 // Search backwards from the line number for the relevant filename
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))
256 if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
257 info->eip_file = stabstr + stabs[lline].n_strx;
259 // Set eip_fn_narg to the number of arguments taken by the function,
260 // or 0 if there was no containing function.
262 info->eip_fn_narg = 0;
265 while (stabs[lfun++].n_type == N_PSYM)
272 /* Returns a function pointer for a function name matching the given string. */
273 void *debug_get_fn_addr(char *fn_name)
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__;
280 static int first_fn_idx = 0;
281 int i = first_fn_idx;
283 const char *stab_fn_name = 0;
286 if (!stab_table_valid(stabstr, stabstr_end))
289 for (/* i set */; &stabs[i] < stab_end; i++) {
290 if (stabs[i].n_type != N_FUN)
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))
296 stab_fn_name = stabstr + stabs[i].n_strx;
297 len = strfind(stab_fn_name, ':') - stab_fn_name;
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;
310 void backtrace_frame(uintptr_t eip, uintptr_t ebp)
312 extern char (SNT RO _start)[];
313 eipdebuginfo_t debuginfo;
318 // on each iteration, ebp holds the stack frame and eip an addr in that func
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))
326 # endif /* CONFIG_RESET_STACKS */
329 debuginfo_eip(eip, &debuginfo);
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));
340 # ifdef CONFIG_RESET_STACKS
341 if (!strncmp("__smp_idle", (char*)debuginfo.eip_fn_name, 10))
343 # endif /* CONFIG_RESET_STACKS */
344 #endif /* CONFIG_X86_64 */
345 eip = *(uintptr_t*)(ebp + sizeof(uintptr_t)) - 1;
346 ebp = *(uintptr_t*)ebp;
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);
366 /* Assumes 32-bit header */
367 void print_fpu_state(struct ancillary_state *fpu)
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);
380 for (int i = 0; i < sizeof(struct ancillary_state); i++) {
383 printk("%02x ", *((uint8_t*)fpu + i));