x86: interrupt return path checks kmsgs
[akaros.git] / kern / arch / i686 / 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 // stab_binsearch(stabs, region_left, region_right, type, addr)
35 //
36 //      Some stab types are arranged in increasing order by instruction
37 //      address.  For example, N_FUN stabs (stab entries with n_type ==
38 //      N_FUN), which mark functions, and N_SO stabs, which mark source files.
39 //
40 //      Given an instruction address, this function finds the single stab
41 //      entry of type 'type' that contains that address.
42 //
43 //      The search takes place within the range [*region_left, *region_right].
44 //      Thus, to search an entire set of N stabs, you might do:
45 //
46 //              left = 0;
47 //              right = N - 1;     /* rightmost stab */
48 //              stab_binsearch(stabs, &left, &right, type, addr);
49 //
50 //      The search modifies *region_left and *region_right to bracket the
51 //      'addr'.  *region_left points to the matching stab that contains
52 //      'addr', and *region_right points just before the next stab.  If
53 //      *region_left > *region_right, then 'addr' is not contained in any
54 //      matching stab.
55 //
56 //      For example, given these N_SO stabs:
57 //              Index  Type   Address
58 //              0      SO     f0100000
59 //              13     SO     f0100040
60 //              117    SO     f0100176
61 //              118    SO     f0100178
62 //              555    SO     f0100652
63 //              556    SO     f0100654
64 //              657    SO     f0100849
65 //      this code:
66 //              left = 0, right = 657;
67 //              stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
68 //      will exit setting left = 118, right = 554.
69 //
70 static void
71 stab_binsearch(const stab_t *BND(__this, stab_end) stabs,
72            const stab_t *SNT stab_end,
73            int *region_left, int *region_right,
74                int type, uintptr_t addr)
75 {
76         int l = *region_left, r = *region_right, any_matches = 0;
77         
78         while (l <= r) {
79                 int true_m = (l + r) / 2, m = true_m;
80                 
81                 // search for earliest stab with right type
82                 while (m >= l && stabs[m].n_type != type)
83                         m--;
84                 if (m < l) {    // no match in [l, m]
85                         l = true_m + 1;
86                         continue;
87                 }
88
89                 // actual binary search
90                 any_matches = 1;
91                 if (stabs[m].n_value < addr) {
92                         *region_left = m;
93                         l = true_m + 1;
94                 } else if (stabs[m].n_value > addr) {
95                         *region_right = m - 1;
96                         r = m - 1;
97                 } else {
98                         // exact match for 'addr', but continue loop to find
99                         // *region_right
100                         *region_left = m;
101                         l = m;
102                         addr++;
103                 }
104         }
105
106         if (!any_matches)
107                 *region_right = *region_left - 1;
108         else {
109                 // find rightmost region containing 'addr'
110                 for (l = *region_right;
111                      l > *region_left && stabs[l].n_type != type;
112                      l--)
113                         /* do nothing */;
114                 *region_left = l;
115         }
116 }
117
118
119 // debuginfo_eip(addr, info)
120 //
121 //      Fill in the 'info' structure with information about the specified
122 //      instruction address, 'addr'.  Returns 0 if information was found, and
123 //      negative if not.  But even if it returns negative it has stored some
124 //      information into '*info'.
125 //
126 int
127 debuginfo_eip(uintptr_t addr, eipdebuginfo_t *NONNULL info)
128 {
129         const stab_t *SNT stab_end;
130         const stab_t *BND(__this,stab_end) stabs;
131         const char *SNT stabstr_end;
132         const char *NT BND(__this,stabstr_end) stabstr;
133         int lfile, rfile, lfun, rfun, lline, rline;
134
135         // Initialize *info
136         info->eip_file = "<unknown>";
137         info->eip_line = 0;
138         info->eip_fn_name = "<unknown>";
139         info->eip_fn_namelen = 9;
140         info->eip_fn_addr = addr;
141         info->eip_fn_narg = 0;
142
143         // Find the relevant set of stabs
144         if (addr >= ULIM) {
145                 stab_end = __STAB_END__;
146                 stabs = __STAB_BEGIN__;
147                 stabstr_end = __STABSTR_END__;
148                 stabstr = __STABSTR_BEGIN__;
149         } else {
150                 // The user-application linker script, user/user.ld,
151                 // puts information about the application's stabs (equivalent
152                 // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
153                 // __STABSTR_END__) in a structure located at virtual address
154                 // USTABDATA.
155                 const user_stab_data_t *usd = (const user_stab_data_t *COUNT(1))TC(USTABDATA);
156
157                 // Make sure this memory is valid.
158                 // Return -1 if it is not.  Hint: Call user_mem_check.
159                 // LAB 3: Your code here.
160
161                 stab_end = usd->stab_end;
162                 stabs = usd->stabs;
163                 stabstr_end = usd->stabstr_end;
164                 stabstr = usd->stabstr;
165
166                 // Make sure the STABS and string table memory is valid.
167                 // LAB 3: Your code here.
168         }
169
170         // String table validity checks
171         {
172                 int stabstrsz = stabstr_end - stabstr;
173                 if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
174                         return -1;
175         }
176
177         // Now we find the right stabs that define the function containing
178         // 'eip'.  First, we find the basic source file containing 'eip'.
179         // Then, we look in that source file for the function.  Then we look
180         // for the line number.
181         
182         // Search the entire set of stabs for the source file (type N_SO).
183         lfile = 0;
184         rfile = (stab_end - stabs) - 1;
185         stab_binsearch(stabs, stab_end, &lfile, &rfile, N_SO, addr);
186         if (lfile == 0)
187                 return -1;
188
189         // Search within that file's stabs for the function definition
190         // (N_FUN).
191         lfun = lfile;
192         rfun = rfile;
193         stab_binsearch(stabs, stab_end, &lfun, &rfun, N_FUN, addr);
194
195         if (lfun <= rfun) {
196                 // stabs[lfun] points to the function name
197                 // in the string table, but check bounds just in case.
198                 if (stabs[lfun].n_strx < stabstr_end - stabstr)
199                         info->eip_fn_name = stabstr + stabs[lfun].n_strx;
200                 info->eip_fn_addr = stabs[lfun].n_value;
201                 addr -= info->eip_fn_addr;
202                 // Search within the function definition for the line number.
203                 lline = lfun;
204                 rline = rfun;
205         } else {
206                 // Couldn't find function stab!  Maybe we're in an assembly
207                 // file.  Search the whole file for the line number.
208                 info->eip_fn_addr = addr;
209                 lline = lfile;
210                 rline = rfile;
211         }
212         // Ignore stuff after the colon.
213         info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
214         
215         // Search within [lline, rline] for the line number stab.
216         // If found, set info->eip_line to the right line number.
217         // If not found, return -1.
218         //
219         // Hint:
220         //      There's a particular stabs type used for line numbers.
221         //      Look at the STABS documentation and <inc/stab.h> to find
222         //      which one.
223         // Your code here.
224
225         stab_binsearch(stabs, stab_end, &lline, &rline, N_SLINE, addr);
226         if (lline <= rline) 
227                 // stabs[lline] points to the line number
228                 info->eip_line = stabs[lline].n_value;
229         else
230                 return -1;
231         
232         // Search backwards from the line number for the relevant filename
233         // stab.
234         // We can't just use the "lfile" stab because inlined functions
235         // can interpolate code from a different file!
236         // Such included source files use the N_SOL stab type.
237         while (lline >= lfile
238                && stabs[lline].n_type != N_SOL
239                && (stabs[lline].n_type != N_SO || !stabs[lline].n_value))
240                 lline--;
241         if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
242                 info->eip_file = stabstr + stabs[lline].n_strx;
243
244         // Set eip_fn_narg to the number of arguments taken by the function,
245         // or 0 if there was no containing function.
246         // Your code here.
247         info->eip_fn_narg = 0;
248         if (lfun <= rfun) {
249                 lfun++;
250                 while (stabs[lfun++].n_type == N_PSYM)
251                         info->eip_fn_narg++;
252         }
253         
254         return 0;
255 }
256
257 /* Returns a function pointer for a function name matching the given string. */
258 void *debug_get_fn_addr(char *fn_name)
259 {
260         const struct stab *SNT stab_end = __STAB_END__;
261         const struct stab *BND(__this,stab_end) stabs = __STAB_BEGIN__;
262         const char *SNT stabstr_end = __STABSTR_END__;
263         const char *NT BND(__this,stabstr_end) stabstr = __STABSTR_BEGIN__;
264
265         static int first_fn_idx = 0;
266         int i = first_fn_idx;
267         int len;
268         const char *stab_fn_name = 0;
269         void *retval = 0;
270
271         // String table validity checks (from above)
272         {
273                 int stabstrsz = stabstr_end - stabstr;
274                 if (stabstr_end <= stabstr || stabstr[stabstrsz-1] != 0)
275                         return 0;
276         }
277
278         for (/* i set */; &stabs[i] < stab_end; i++) {
279                 if (stabs[i].n_type != N_FUN)
280                         continue;
281                 first_fn_idx = first_fn_idx ? first_fn_idx : i;
282                 /* broken stab, just keep going */
283                 if (!(stabs[i].n_strx < stabstr_end - stabstr))
284                         continue;
285                 stab_fn_name = stabstr + stabs[i].n_strx;
286                 len = strfind(stab_fn_name, ':') - stab_fn_name;
287                 if (!len)
288                         continue;
289                 /* we have a match. */
290                 if (!strncmp(stab_fn_name, fn_name, len)) {
291                         printd("FN name: %s, Addr: %p\n", stab_fn_name, stabs[i].n_value);
292                         retval = (void*)stabs[i].n_value;
293                         break;
294                 }
295         }
296         return retval;
297 }