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
;
23 // stab_binsearch(stabs, region_left, region_right, type, addr)
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.
29 // Given an instruction address, this function finds the single stab
30 // entry of type 'type' that contains that address.
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:
36 // right = N - 1; /* rightmost stab */
37 // stab_binsearch(stabs, &left, &right, type, addr);
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
45 // For example, given these N_SO stabs:
55 // left = 0, right = 657;
56 // stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
57 // will exit setting left = 118, right = 554.
60 stab_binsearch(const struct Stab
*stabs
, int *region_left
, int *region_right
,
61 int type
, uintptr_t addr
)
63 int l
= *region_left
, r
= *region_right
, any_matches
= 0;
66 int true_m
= (l
+ r
) / 2, m
= true_m
;
68 // search for earliest stab with right type
69 while (m
>= l
&& stabs
[m
].n_type
!= type
)
71 if (m
< l
) { // no match in [l, m]
76 // actual binary search
78 if (stabs
[m
].n_value
< addr
) {
81 } else if (stabs
[m
].n_value
> addr
) {
82 *region_right
= m
- 1;
85 // exact match for 'addr', but continue loop to find
94 *region_right
= *region_left
- 1;
96 // find rightmost region containing 'addr'
97 for (l
= *region_right
;
98 l
> *region_left
&& stabs
[l
].n_type
!= type
;
106 // debuginfo_eip(addr, info)
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'.
114 debuginfo_eip(uintptr_t addr
, struct Eipdebuginfo
*info
)
116 const struct Stab
*stabs
, *stab_end
;
117 const char *stabstr
, *stabstr_end
;
118 int lfile
, rfile
, lfun
, rfun
, lline
, rline
;
121 info
->eip_file
= "<unknown>";
123 info
->eip_fn_name
= "<unknown>";
124 info
->eip_fn_namelen
= 9;
125 info
->eip_fn_addr
= addr
;
126 info
->eip_fn_narg
= 0;
128 // Find the relevant set of stabs
130 stabs
= __STAB_BEGIN__
;
131 stab_end
= __STAB_END__
;
132 stabstr
= __STABSTR_BEGIN__
;
133 stabstr_end
= __STABSTR_END__
;
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
140 const struct UserStabData
*usd
= (const struct UserStabData
*) USTABDATA
;
142 // Make sure this memory is valid in the current environment.
143 // Return -1 if it is not. Hint: Call user_mem_check.
144 // LAB 3: Your code here.
147 stab_end
= usd
->stab_end
;
148 stabstr
= usd
->stabstr
;
149 stabstr_end
= usd
->stabstr_end
;
151 // Make sure the STABS and string table memory is valid.
152 // LAB 3: Your code here.
155 // String table validity checks
156 if (stabstr_end
<= stabstr
|| stabstr_end
[-1] != 0)
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.
164 // Search the entire set of stabs for the source file (type N_SO).
166 rfile
= (stab_end
- stabs
) - 1;
167 stab_binsearch(stabs
, &lfile
, &rfile
, N_SO
, addr
);
171 // Search within that file's stabs for the function definition
175 stab_binsearch(stabs
, &lfun
, &rfun
, N_FUN
, addr
);
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
< (uint32_t) (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.
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
;
194 // Ignore stuff after the colon.
195 info
->eip_fn_namelen
= strfind(info
->eip_fn_name
, ':') - info
->eip_fn_name
;
198 // Search within [lline, rline] for the line number stab.
199 // If found, set info->eip_line to the right line number.
200 // If not found, return -1.
203 // There's a particular stabs type used for line numbers.
204 // Look at the STABS documentation and <inc/stab.h> to find
209 // Search backwards from the line number for the relevant filename
211 // We can't just use the "lfile" stab because inlined functions
212 // can interpolate code from a different file!
213 // Such included source files use the N_SOL stab type.
214 while (lline
>= lfile
215 && stabs
[lline
].n_type
!= N_SOL
216 && (stabs
[lline
].n_type
!= N_SO
|| !stabs
[lline
].n_value
))
219 && stabs
[lline
].n_strx
< (uint32_t) (stabstr_end
- stabstr
))
220 info
->eip_file
= stabstr
+ stabs
[lline
].n_strx
;
223 // Set eip_fn_narg to the number of arguments taken by the function,
224 // or 0 if there was no containing function.