Permissions on IDTs.
[akaros.git] / kern / kdebug.c
1 #include <inc/stab.h>
2 #include <inc/string.h>
3 #include <inc/memlayout.h>
4 #include <inc/assert.h>
5
6 #include <kern/kdebug.h>
7 #include <kern/pmap.h>
8 #include <kern/env.h>
9
10 extern const struct Stab __STAB_BEGIN__[];      // Beginning of stabs table
11 extern const struct Stab __STAB_END__[];        // End of stabs table
12 extern const char __STABSTR_BEGIN__[];          // Beginning of string table
13 extern const char __STABSTR_END__[];            // End of string table
14
15 struct UserStabData {
16         const struct Stab *stabs;
17         const struct Stab *stab_end;
18         const char *stabstr;
19         const char *stabstr_end;
20 };
21
22
23 // stab_binsearch(stabs, region_left, region_right, type, addr)
24 //
25 //      Some stab types are arranged in increasing order by instruction
26 //      address.  For example, N_FUN stabs (stab entries with n_type ==
27 //      N_FUN), which mark functions, and N_SO stabs, which mark source files.
28 //
29 //      Given an instruction address, this function finds the single stab
30 //      entry of type 'type' that contains that address.
31 //
32 //      The search takes place within the range [*region_left, *region_right].
33 //      Thus, to search an entire set of N stabs, you might do:
34 //
35 //              left = 0;
36 //              right = N - 1;     /* rightmost stab */
37 //              stab_binsearch(stabs, &left, &right, type, addr);
38 //
39 //      The search modifies *region_left and *region_right to bracket the
40 //      'addr'.  *region_left points to the matching stab that contains
41 //      'addr', and *region_right points just before the next stab.  If
42 //      *region_left > *region_right, then 'addr' is not contained in any
43 //      matching stab.
44 //
45 //      For example, given these N_SO stabs:
46 //              Index  Type   Address
47 //              0      SO     f0100000
48 //              13     SO     f0100040
49 //              117    SO     f0100176
50 //              118    SO     f0100178
51 //              555    SO     f0100652
52 //              556    SO     f0100654
53 //              657    SO     f0100849
54 //      this code:
55 //              left = 0, right = 657;
56 //              stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
57 //      will exit setting left = 118, right = 554.
58 //
59 static void
60 stab_binsearch(const struct Stab *stabs, int *region_left, int *region_right,
61                int type, uintptr_t addr)
62 {
63         int l = *region_left, r = *region_right, any_matches = 0;
64         
65         while (l <= r) {
66                 int true_m = (l + r) / 2, m = true_m;
67                 
68                 // search for earliest stab with right type
69                 while (m >= l && stabs[m].n_type != type)
70                         m--;
71                 if (m < l) {    // no match in [l, m]
72                         l = true_m + 1;
73                         continue;
74                 }
75
76                 // actual binary search
77                 any_matches = 1;
78                 if (stabs[m].n_value < addr) {
79                         *region_left = m;
80                         l = true_m + 1;
81                 } else if (stabs[m].n_value > addr) {
82                         *region_right = m - 1;
83                         r = m - 1;
84                 } else {
85                         // exact match for 'addr', but continue loop to find
86                         // *region_right
87                         *region_left = m;
88                         l = m;
89                         addr++;
90                 }
91         }
92
93         if (!any_matches)
94                 *region_right = *region_left - 1;
95         else {
96                 // find rightmost region containing 'addr'
97                 for (l = *region_right;
98                      l > *region_left && stabs[l].n_type != type;
99                      l--)
100                         /* do nothing */;
101                 *region_left = l;
102         }
103 }
104
105
106 // debuginfo_eip(addr, info)
107 //
108 //      Fill in the 'info' structure with information about the specified
109 //      instruction address, 'addr'.  Returns 0 if information was found, and
110 //      negative if not.  But even if it returns negative it has stored some
111 //      information into '*info'.
112 //
113 int
114 debuginfo_eip(uintptr_t addr, struct Eipdebuginfo *info)
115 {
116         const struct Stab *stabs, *stab_end;
117         const char *stabstr, *stabstr_end;
118         int lfile, rfile, lfun, rfun, lline, rline;
119
120         // Initialize *info
121         info->eip_file = "<unknown>";
122         info->eip_line = 0;
123         info->eip_fn_name = "<unknown>";
124         info->eip_fn_namelen = 9;
125         info->eip_fn_addr = addr;
126         info->eip_fn_narg = 0;
127
128         // Find the relevant set of stabs
129         if (addr >= ULIM) {
130                 stabs = __STAB_BEGIN__;
131                 stab_end = __STAB_END__;
132                 stabstr = __STABSTR_BEGIN__;
133                 stabstr_end = __STABSTR_END__;
134         } else {
135                 // The user-application linker script, user/user.ld,
136                 // puts information about the application's stabs (equivalent
137                 // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
138                 // __STABSTR_END__) in a structure located at virtual address
139                 // USTABDATA.
140                 const struct UserStabData *usd = (const struct UserStabData *) USTABDATA;
141
142                 // Make sure this memory is valid.
143                 // Return -1 if it is not.  Hint: Call user_mem_check.
144                 // LAB 3: Your code here.
145                 
146                 stabs = usd->stabs;
147                 stab_end = usd->stab_end;
148                 stabstr = usd->stabstr;
149                 stabstr_end = usd->stabstr_end;
150
151                 // Make sure the STABS and string table memory is valid.
152                 // LAB 3: Your code here.
153         }
154
155         // String table validity checks
156         if (stabstr_end <= stabstr || stabstr_end[-1] != 0)
157                 return -1;
158
159         // Now we find the right stabs that define the function containing
160         // 'eip'.  First, we find the basic source file containing 'eip'.
161         // Then, we look in that source file for the function.  Then we look
162         // for the line number.
163         
164         // Search the entire set of stabs for the source file (type N_SO).
165         lfile = 0;
166         rfile = (stab_end - stabs) - 1;
167         stab_binsearch(stabs, &lfile, &rfile, N_SO, addr);
168         if (lfile == 0)
169                 return -1;
170
171         // Search within that file's stabs for the function definition
172         // (N_FUN).
173         lfun = lfile;
174         rfun = rfile;
175         stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr);
176
177         if (lfun <= rfun) {
178                 // stabs[lfun] points to the function name
179                 // in the string table, but check bounds just in case.
180                 if (stabs[lfun].n_strx < stabstr_end - stabstr)
181                         info->eip_fn_name = stabstr + stabs[lfun].n_strx;
182                 info->eip_fn_addr = stabs[lfun].n_value;
183                 addr -= info->eip_fn_addr;
184                 // Search within the function definition for the line number.
185                 lline = lfun;
186                 rline = rfun;
187         } else {
188                 // Couldn't find function stab!  Maybe we're in an assembly
189                 // file.  Search the whole file for the line number.
190                 info->eip_fn_addr = addr;
191                 lline = lfile;
192                 rline = rfile;
193         }
194         // Ignore stuff after the colon.
195         info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
196         
197         // Search within [lline, rline] for the line number stab.
198         // If found, set info->eip_line to the right line number.
199         // If not found, return -1.
200         //
201         // Hint:
202         //      There's a particular stabs type used for line numbers.
203         //      Look at the STABS documentation and <inc/stab.h> to find
204         //      which one.
205         // Your code here.
206
207         stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
208         if (lline <= rline) 
209                 // stabs[lline] points to the line number
210                 info->eip_line = stabs[lline].n_value;
211         else
212                 return -1;
213         
214         // Search backwards from the line number for the relevant filename
215         // stab.
216         // We can't just use the "lfile" stab because inlined functions
217         // can interpolate code from a different file!
218         // Such included source files use the N_SOL stab type.
219         while (lline >= lfile
220                && stabs[lline].n_type != N_SOL
221                && (stabs[lline].n_type != N_SO || !stabs[lline].n_value))
222                 lline--;
223         if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
224                 info->eip_file = stabstr + stabs[lline].n_strx;
225
226         // Set eip_fn_narg to the number of arguments taken by the function,
227         // or 0 if there was no containing function.
228         // Your code here.
229         info->eip_fn_narg = 0;
230         if (lfun <= rfun) {
231                 lfun++;
232                 while (stabs[lfun++].n_type == N_PSYM)
233                         info->eip_fn_narg++;
234         }
235         
236         return 0;
237 }