179
180 /*
181 * Allow the architecture-specific code to allocate
182 * its private data.
183 */
184 if (arch->da_handle_attach(dhp) != 0) {
185 dis_free(dhp, sizeof (dis_handle_t));
186 /* dis errno already set */
187 return (NULL);
188 }
189
190 return (dhp);
191 }
192
193 int
194 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
195 {
196 return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
197 }
198
199 uint64_t
200 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
201 {
202 return (dhp->dh_arch->da_previnstr(dhp, pc, n));
203 }
204
205 int
206 dis_min_instrlen(dis_handle_t *dhp)
207 {
208 return (dhp->dh_arch->da_min_instrlen(dhp));
209 }
210
211 int
212 dis_max_instrlen(dis_handle_t *dhp)
213 {
214 return (dhp->dh_arch->da_max_instrlen(dhp));
215 }
216
217 int
218 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
219 {
220 return (dhp->dh_arch->da_instrlen(dhp, pc));
221 }
|
179
180 /*
181 * Allow the architecture-specific code to allocate
182 * its private data.
183 */
184 if (arch->da_handle_attach(dhp) != 0) {
185 dis_free(dhp, sizeof (dis_handle_t));
186 /* dis errno already set */
187 return (NULL);
188 }
189
190 return (dhp);
191 }
192
193 int
194 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
195 {
196 return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
197 }
198
199 /*
200 * On some instruction sets (e.g., x86), we have no choice except to
201 * disassemble everything from the start of the symbol, and stop when we
202 * have reached our instruction address. If we're not in the middle of a
203 * known symbol, then we return the same address to indicate failure.
204 */
205 static uint64_t
206 dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
207 {
208 uint64_t *hist, addr, start;
209 int cur, nseen;
210 uint64_t res = pc;
211
212 if (n <= 0)
213 return (pc);
214
215 if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
216 start == pc)
217 return (res);
218
219 hist = dis_zalloc(sizeof (uint64_t) * n);
220
221 for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
222 hist[cur] = addr;
223 cur = (cur + 1) % n;
224 nseen++;
225
226 /* if we cannot make forward progress, give up */
227 if (dis_disassemble(dhp, addr, NULL, 0) != 0)
228 goto done;
229 }
230
231 if (addr != pc) {
232 /*
233 * We scanned past %pc, but didn't find an instruction that
234 * started at %pc. This means that either the caller specified
235 * an invalid address, or we ran into something other than code
236 * during our scan. Virtually any combination of bytes can be
237 * construed as a valid Intel instruction, so any non-code bytes
238 * we encounter will have thrown off the scan.
239 */
240 goto done;
241 }
242
243 res = hist[(cur + n - MIN(n, nseen)) % n];
244
245 done:
246 dis_free(hist, sizeof (uint64_t) * n);
247 return (res);
248 }
249
250 /*
251 * Return the nth previous instruction's address. Return the same address
252 * to indicate failure.
253 */
254 uint64_t
255 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
256 {
257 if (dhp->dh_arch->da_previnstr == NULL)
258 return (dis_generic_previnstr(dhp, pc, n));
259
260 return (dhp->dh_arch->da_previnstr(dhp, pc, n));
261 }
262
263 int
264 dis_min_instrlen(dis_handle_t *dhp)
265 {
266 return (dhp->dh_arch->da_min_instrlen(dhp));
267 }
268
269 int
270 dis_max_instrlen(dis_handle_t *dhp)
271 {
272 return (dhp->dh_arch->da_max_instrlen(dhp));
273 }
274
275 int
276 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
277 {
278 return (dhp->dh_arch->da_instrlen(dhp, pc));
279 }
|