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