2 #include <inc/string.h>
3 #include <inc/memlayout.h>
4 #include <inc/assert.h>
6 #include <kern/kdebug.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
16 const struct Stab
*stabs
;
17 const struct Stab
*stab_end
;
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:
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
44 // For example, given these N_SO stabs:
54 // left = 0, right = 657;
55 // stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
56 // will exit setting left = 118, right = 554.
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;
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
)
70 if (m
< l
) { // no match in [l, m]
75 // actual binary search
77 if (stabs
[m
].n_value
< addr
) {
80 } else if (stabs
[m
].n_value
> addr
) {
81 *region_right
= m
- 1;
84 // exact match for 'addr', but continue loop to find
93 *region_right
= *region_left
- 1;
95 // find rightmost region containing 'addr'
96 for (l
= *region_right
;
97 l
> *region_left
&& stabs
[l
].n_type
!= type
;
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
;
120 info
->eip_file
= "<unknown>";
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
129 stabs
= __STAB_BEGIN__
;
130 stab_end
= __STAB_END__
;
131 stabstr
= __STABSTR_BEGIN__
;
132 stabstr_end
= __STABSTR_END__
;
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
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.
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)
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).
165 rfile
= (stab_end
- stabs
) - 1;
166 stab_binsearch(stabs
, &lfile
, &rfile
, N_SO
, addr
);
170 // Search within that file's stabs for the function definition
174 stab_binsearch(stabs
, &lfun
, &rfun
, N_FUN
, addr
);
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.
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
;
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.
202 // There's a particular stabs type used for line numbers.
203 // Look at the STABS documentation and <inc/stab.h> to find
208 stab_binsearch(stabs
, &lline
, &rline
, N_SLINE
, addr
);
210 info
->eip_line
= stabs
[lline
].n_desc
;
212 // Search backwards from the line number for the relevant filename
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
))
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.
229 // but it seems that it is not used?
231 while (lline
<= rline
&& stabs
[lline
].n_type
== N_PSYM
) {
235 info
->eip_fn_narg
= i
;