Print this page
3194 dis crashes disassembling aes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/dis/dis_target.c
+++ new/usr/src/cmd/dis/dis_target.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 *
25 25 * Copyright 2011 Jason King. All rights reserved.
26 26 */
27 27
28 28 #include <assert.h>
29 29 #include <errno.h>
30 30 #include <fcntl.h>
31 31 #include <gelf.h>
32 32 #include <libelf.h>
33 33 #include <stdlib.h>
34 34 #include <string.h>
35 35 #include <unistd.h>
36 36
37 37 #include <sys/fcntl.h>
38 38 #include <sys/stat.h>
39 39 #include <sys/sysmacros.h>
40 40 #include <sys/types.h>
41 41
42 42 #include "dis_target.h"
43 43 #include "dis_util.h"
44 44
45 45 /*
46 46 * Standard ELF disassembler target.
47 47 *
48 48 * We only support disassembly of ELF files, though this target interface could
49 49 * be extended in the future. Each basic type (target, func, section) contains
50 50 * enough information to uniquely identify the location within the file. The
51 51 * interfaces use libelf(3LIB) to do the actual processing of the file.
52 52 */
53 53
54 54 /*
55 55 * Symbol table entry type. We maintain our own symbol table sorted by address,
56 56 * with the symbol name already resolved against the ELF symbol table.
57 57 */
58 58 typedef struct sym_entry {
59 59 GElf_Sym se_sym; /* value of symbol */
60 60 char *se_name; /* name of symbol */
61 61 int se_shndx; /* section where symbol is located */
62 62 } sym_entry_t;
63 63
64 64 /*
65 65 * Create a map of the virtual address ranges of every section. This will
66 66 * allow us to create dummpy mappings for unassigned addresses. Otherwise
67 67 * multiple sections with unassigned addresses will appear to overlap and
68 68 * mess up symbol resolution (which uses the virtual address).
69 69 */
70 70 typedef struct dis_shnmap {
71 71 const char *dm_name; /* name of section */
72 72 uint64_t dm_start; /* virtual address of section */
73 73 size_t dm_length; /* address length */
74 74 boolean_t dm_mapped; /* did we assign the mapping */
75 75 } dis_shnmap_t;
76 76
77 77 /*
78 78 * Target data structure. This structure keeps track of the ELF file
79 79 * information, a few bits of pre-processed section index information, and
80 80 * sorted versions of the symbol table. We also keep track of the last symbol
81 81 * looked up, as the majority of lookups remain within the same symbol.
82 82 */
83 83 struct dis_tgt {
84 84 Elf *dt_elf; /* libelf handle */
85 85 Elf *dt_elf_root; /* main libelf handle (for archives) */
86 86 const char *dt_filename; /* name of file */
87 87 int dt_fd; /* underlying file descriptor */
88 88 size_t dt_shstrndx; /* section index of .shstrtab */
89 89 size_t dt_symidx; /* section index of symbol table */
90 90 sym_entry_t *dt_symcache; /* last symbol looked up */
91 91 sym_entry_t *dt_symtab; /* sorted symbol table */
92 92 int dt_symcount; /* # of symbol table entries */
93 93 struct dis_tgt *dt_next; /* next target (for archives) */
94 94 Elf_Arhdr *dt_arhdr; /* archive header (for archives) */
95 95 dis_shnmap_t *dt_shnmap; /* section address map */
96 96 size_t dt_shncount; /* # of sections in target */
97 97 };
98 98
99 99 /*
100 100 * Function data structure. We resolve the symbol and lookup the associated ELF
101 101 * data when building this structure. The offset is calculated based on the
102 102 * section's starting address.
103 103 */
104 104 struct dis_func {
105 105 sym_entry_t *df_sym; /* symbol table reference */
106 106 Elf_Data *df_data; /* associated ELF data */
107 107 size_t df_offset; /* offset within data */
108 108 };
109 109
110 110 /*
111 111 * Section data structure. We store the entire section header so that we can
112 112 * determine some properties (such as whether or not it contains text) after
113 113 * building the structure.
114 114 */
115 115 struct dis_scn {
116 116 GElf_Shdr ds_shdr;
117 117 const char *ds_name;
118 118 Elf_Data *ds_data;
119 119 };
120 120
121 121 /* Lifted from Psymtab.c, omitting STT_TLS */
122 122 #define DATA_TYPES \
123 123 ((1 << STT_OBJECT) | (1 << STT_FUNC) | (1 << STT_COMMON))
124 124 #define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0)
125 125
126 126 /*
127 127 * Save the virtual address range for this section and select the
128 128 * best section to use as the symbol table. We prefer SHT_SYMTAB
129 129 * over SHT_DYNSYM.
130 130 */
131 131 /* ARGSUSED */
132 132 static void
133 133 tgt_scn_init(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
134 134 {
135 135 int *index = data;
136 136
137 137 *index += 1;
138 138
139 139 tgt->dt_shnmap[*index].dm_name = scn->ds_name;
140 140 tgt->dt_shnmap[*index].dm_start = scn->ds_shdr.sh_addr;
141 141 tgt->dt_shnmap[*index].dm_length = scn->ds_shdr.sh_size;
142 142 tgt->dt_shnmap[*index].dm_mapped = B_FALSE;
143 143
144 144 /*
145 145 * Prefer SHT_SYMTAB over SHT_DYNSYM
146 146 */
147 147 if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0)
148 148 tgt->dt_symidx = *index;
149 149 else if (scn->ds_shdr.sh_type == SHT_SYMTAB)
150 150 tgt->dt_symidx = *index;
151 151 }
152 152
153 153 static int
154 154 sym_compare(const void *a, const void *b)
155 155 {
156 156 const sym_entry_t *syma = a;
157 157 const sym_entry_t *symb = b;
158 158 const char *aname = syma->se_name;
159 159 const char *bname = symb->se_name;
160 160
161 161 if (syma->se_sym.st_value < symb->se_sym.st_value)
162 162 return (-1);
163 163
164 164 if (syma->se_sym.st_value > symb->se_sym.st_value)
165 165 return (1);
166 166
167 167 /*
168 168 * Prefer functions over non-functions
169 169 */
170 170 if (GELF_ST_TYPE(syma->se_sym.st_info) !=
171 171 GELF_ST_TYPE(symb->se_sym.st_info)) {
172 172 if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC)
173 173 return (-1);
174 174 if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC)
175 175 return (1);
176 176 }
177 177
178 178 /*
179 179 * For symbols with the same address and type, we sort them according to
180 180 * a hierarchy:
181 181 *
182 182 * 1. weak symbols (common name)
183 183 * 2. global symbols (external name)
184 184 * 3. local symbols
185 185 */
186 186 if (GELF_ST_BIND(syma->se_sym.st_info) !=
187 187 GELF_ST_BIND(symb->se_sym.st_info)) {
188 188 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK)
189 189 return (-1);
190 190 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK)
191 191 return (1);
192 192
193 193 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL)
194 194 return (-1);
195 195 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL)
196 196 return (1);
197 197 }
198 198
199 199 /*
200 200 * As a last resort, if we have multiple symbols of the same type at the
201 201 * same address, prefer the version with the fewest leading underscores.
202 202 */
203 203 if (aname == NULL)
204 204 return (-1);
205 205 if (bname == NULL)
206 206 return (1);
207 207
208 208 while (*aname == '_' && *bname == '_') {
209 209 aname++;
210 210 bname++;
211 211 }
212 212
213 213 if (*bname == '_')
214 214 return (-1);
215 215 if (*aname == '_')
216 216 return (1);
217 217
218 218 /*
219 219 * Prefer the symbol with the smaller size.
220 220 */
221 221 if (syma->se_sym.st_size < symb->se_sym.st_size)
222 222 return (-1);
223 223 if (syma->se_sym.st_size > symb->se_sym.st_size)
224 224 return (1);
225 225
226 226 /*
227 227 * We really do have two identical symbols for some reason. Just report
228 228 * them as equal, and to the lucky one go the spoils.
229 229 */
230 230 return (0);
231 231 }
232 232
233 233 /*
234 234 * Construct an optimized symbol table sorted by starting address.
235 235 */
236 236 static void
237 237 construct_symtab(dis_tgt_t *tgt)
238 238 {
239 239 Elf_Scn *scn;
240 240 GElf_Shdr shdr;
241 241 Elf_Data *symdata;
242 242 int i;
243 243 GElf_Word *symshndx = NULL;
244 244 int symshndx_size;
245 245 sym_entry_t *sym;
246 246 sym_entry_t *p_symtab = NULL;
247 247 int nsym = 0; /* count of symbols we're not interested in */
248 248
249 249 /*
250 250 * Find the symshndx section, if any
251 251 */
252 252 for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL;
253 253 scn = elf_nextscn(tgt->dt_elf, scn)) {
254 254 if (gelf_getshdr(scn, &shdr) == NULL)
255 255 break;
256 256 if (shdr.sh_type == SHT_SYMTAB_SHNDX &&
257 257 shdr.sh_link == tgt->dt_symidx) {
258 258 Elf_Data *data;
259 259
260 260 if ((data = elf_getdata(scn, NULL)) != NULL) {
261 261 symshndx = (GElf_Word *)data->d_buf;
262 262 symshndx_size = data->d_size /
263 263 sizeof (GElf_Word);
264 264 break;
265 265 }
266 266 }
267 267 }
268 268
269 269 if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL)
270 270 die("%s: failed to get section information", tgt->dt_filename);
271 271 if (gelf_getshdr(scn, &shdr) == NULL)
272 272 die("%s: failed to get section header", tgt->dt_filename);
273 273 if (shdr.sh_entsize == 0)
274 274 die("%s: symbol table has zero size", tgt->dt_filename);
275 275
276 276 if ((symdata = elf_getdata(scn, NULL)) == NULL)
277 277 die("%s: failed to get symbol table", tgt->dt_filename);
278 278
279 279 tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM,
280 280 1, EV_CURRENT);
281 281
282 282 p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t));
283 283
284 284 for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) {
285 285 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) {
286 286 warn("%s: gelf_getsym returned NULL for %d",
287 287 tgt->dt_filename, i);
288 288 nsym++;
289 289 continue;
290 290 }
291 291
292 292 /*
293 293 * We're only interested in data symbols.
294 294 */
295 295 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) {
296 296 nsym++;
297 297 continue;
298 298 }
299 299
300 300 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) {
301 301 if (i > symshndx_size) {
302 302 warn("%s: bad SHNX_XINDEX %d",
303 303 tgt->dt_filename, i);
304 304 sym->se_shndx = -1;
305 305 } else {
306 306 sym->se_shndx = symshndx[i];
307 307 }
308 308 } else {
309 309 sym->se_shndx = sym->se_sym.st_shndx;
310 310 }
311 311
312 312 /* Deal with symbols with special section indicies */
313 313 if (sym->se_shndx == SHN_ABS) {
314 314 /*
315 315 * If st_value == 0, references to these
316 316 * symbols in code are modified in situ
317 317 * thus we will never attempt to look
318 318 * them up.
319 319 */
320 320 if (sym->se_sym.st_value == 0) {
321 321 /*
322 322 * References to these symbols in code
323 323 * are modified in situ by the runtime
324 324 * linker and no code on disk will ever
325 325 * attempt to look them up.
326 326 */
327 327 nsym++;
328 328 continue;
329 329 } else {
330 330 /*
331 331 * If st_value != 0, (such as examining
332 332 * something in /system/object/.../object)
333 333 * the values should resolve to a value
334 334 * within an existing section (such as
335 335 * .data). This also means it never needs
336 336 * to have st_value mapped.
337 337 */
338 338 sym++;
339 339 continue;
340 340 }
341 341 }
342 342
343 343 /*
344 344 * Ignore the symbol if it has some other special
345 345 * section index
346 346 */
347 347 if (sym->se_shndx == SHN_UNDEF ||
348 348 sym->se_shndx >= SHN_LORESERVE) {
349 349 nsym++;
350 350 continue;
351 351 }
352 352
353 353 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
354 354 (size_t)sym->se_sym.st_name)) == NULL) {
355 355 warn("%s: failed to lookup symbol %d name",
356 356 tgt->dt_filename, i);
357 357 nsym++;
358 358 continue;
359 359 }
360 360
361 361 /*
362 362 * If we had to map this section, its symbol value
363 363 * also needs to be mapped.
364 364 */
365 365 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
366 366 sym->se_sym.st_value +=
367 367 tgt->dt_shnmap[sym->se_shndx].dm_start;
368 368
369 369 sym++;
370 370 }
371 371
372 372 tgt->dt_symcount -= nsym;
373 373 tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount *
374 374 sizeof (sym_entry_t));
375 375
376 376 qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t),
377 377 sym_compare);
378 378 }
379 379
380 380 /*
381 381 * Assign virtual address ranges for sections that need it
382 382 */
383 383 static void
384 384 create_addrmap(dis_tgt_t *tgt)
385 385 {
386 386 uint64_t addr;
387 387 int i;
388 388
389 389 if (tgt->dt_shnmap == NULL)
390 390 return;
391 391
392 392 /* find the greatest used address */
393 393 for (addr = 0, i = 1; i < tgt->dt_shncount; i++)
394 394 if (tgt->dt_shnmap[i].dm_start > addr)
395 395 addr = tgt->dt_shnmap[i].dm_start +
396 396 tgt->dt_shnmap[i].dm_length;
397 397
398 398 addr = P2ROUNDUP(addr, 0x1000);
399 399
400 400 /*
401 401 * Assign section a starting address beyond the largest mapped section
402 402 * if no address was given.
403 403 */
404 404 for (i = 1; i < tgt->dt_shncount; i++) {
405 405 if (tgt->dt_shnmap[i].dm_start != 0)
406 406 continue;
407 407
408 408 tgt->dt_shnmap[i].dm_start = addr;
409 409 tgt->dt_shnmap[i].dm_mapped = B_TRUE;
410 410 addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000);
411 411 }
412 412 }
413 413
414 414 /*
415 415 * Create a target backed by an ELF file.
416 416 */
417 417 dis_tgt_t *
418 418 dis_tgt_create(const char *file)
419 419 {
420 420 dis_tgt_t *tgt, *current;
421 421 int idx;
422 422 Elf *elf;
423 423 GElf_Ehdr ehdr;
424 424 Elf_Arhdr *arhdr = NULL;
425 425 int cmd;
426 426
427 427 if (elf_version(EV_CURRENT) == EV_NONE)
428 428 die("libelf(3ELF) out of date");
429 429
430 430 tgt = safe_malloc(sizeof (dis_tgt_t));
431 431
432 432 if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) {
433 433 warn("%s: failed opening file, reason: %s", file,
434 434 strerror(errno));
435 435 free(tgt);
436 436 return (NULL);
437 437 }
438 438
439 439 if ((tgt->dt_elf_root =
440 440 elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) {
441 441 warn("%s: invalid or corrupt ELF file", file);
442 442 dis_tgt_destroy(tgt);
443 443 return (NULL);
444 444 }
445 445
446 446 current = tgt;
447 447 cmd = ELF_C_READ;
448 448 while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
449 449
450 450 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
451 451 (arhdr = elf_getarhdr(elf)) == NULL) {
452 452 warn("%s: malformed archive", file);
453 453 dis_tgt_destroy(tgt);
454 454 return (NULL);
455 455 }
456 456
457 457 /*
458 458 * Make sure that this Elf file is sane
459 459 */
460 460 if (gelf_getehdr(elf, &ehdr) == NULL) {
461 461 if (arhdr != NULL) {
462 462 /*
463 463 * For archives, we drive on in the face of bad
464 464 * members. The "/" and "//" members are
465 465 * special, and should be silently ignored.
466 466 */
467 467 if (strcmp(arhdr->ar_name, "/") != 0 &&
468 468 strcmp(arhdr->ar_name, "//") != 0)
469 469 warn("%s[%s]: invalid file type",
470 470 file, arhdr->ar_name);
471 471 cmd = elf_next(elf);
472 472 (void) elf_end(elf);
473 473 continue;
474 474 }
475 475
476 476 warn("%s: invalid file type", file);
477 477 dis_tgt_destroy(tgt);
478 478 return (NULL);
479 479 }
480 480
481 481 /*
482 482 * If we're seeing a new Elf object, then we have an
483 483 * archive. In this case, we create a new target, and chain it
484 484 * off the master target. We can later iterate over these
485 485 * targets using dis_tgt_next().
486 486 */
487 487 if (current->dt_elf != NULL) {
488 488 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
489 489 next->dt_elf_root = tgt->dt_elf_root;
490 490 next->dt_fd = -1;
491 491 current->dt_next = next;
492 492 current = next;
493 493 }
494 494 current->dt_elf = elf;
495 495 current->dt_arhdr = arhdr;
496 496
497 497 if (elf_getshdrstrndx(elf, ¤t->dt_shstrndx) == -1) {
498 498 warn("%s: failed to get section string table for "
499 499 "file", file);
500 500 dis_tgt_destroy(tgt);
501 501 return (NULL);
502 502 }
503 503
504 504 current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
505 505 ehdr.e_shnum);
506 506 current->dt_shncount = ehdr.e_shnum;
507 507
508 508 idx = 0;
509 509 dis_tgt_section_iter(current, tgt_scn_init, &idx);
510 510 current->dt_filename = file;
511 511
512 512 create_addrmap(current);
513 513 if (current->dt_symidx != 0)
514 514 construct_symtab(current);
515 515
516 516 cmd = elf_next(elf);
517 517 }
518 518
519 519 /*
520 520 * Final sanity check. If we had an archive with no members, then bail
521 521 * out with a nice message.
522 522 */
523 523 if (tgt->dt_elf == NULL) {
524 524 warn("%s: empty archive\n", file);
525 525 dis_tgt_destroy(tgt);
526 526 return (NULL);
527 527 }
528 528
529 529 return (tgt);
530 530 }
531 531
532 532 /*
533 533 * Return the filename associated with the target.
534 534 */
535 535 const char *
536 536 dis_tgt_name(dis_tgt_t *tgt)
537 537 {
538 538 return (tgt->dt_filename);
539 539 }
540 540
541 541 /*
542 542 * Return the archive member name, if any.
543 543 */
544 544 const char *
545 545 dis_tgt_member(dis_tgt_t *tgt)
546 546 {
547 547 if (tgt->dt_arhdr)
548 548 return (tgt->dt_arhdr->ar_name);
549 549 else
550 550 return (NULL);
551 551 }
552 552
553 553 /*
554 554 * Return the Elf_Ehdr associated with this target. Needed to determine which
555 555 * disassembler to use.
556 556 */
557 557 void
558 558 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
559 559 {
560 560 (void) gelf_getehdr(tgt->dt_elf, ehdr);
561 561 }
562 562
563 563 /*
564 564 * Return the next target in the list, if this is an archive.
565 565 */
566 566 dis_tgt_t *
567 567 dis_tgt_next(dis_tgt_t *tgt)
568 568 {
569 569 return (tgt->dt_next);
570 570 }
571 571
572 572 /*
573 573 * Destroy a target and free up any associated memory.
574 574 */
575 575 void
576 576 dis_tgt_destroy(dis_tgt_t *tgt)
577 577 {
578 578 dis_tgt_t *current, *next;
579 579
580 580 current = tgt->dt_next;
581 581 while (current != NULL) {
582 582 next = current->dt_next;
583 583 if (current->dt_elf)
584 584 (void) elf_end(current->dt_elf);
585 585 if (current->dt_symtab)
586 586 free(current->dt_symtab);
587 587 free(current);
588 588 current = next;
589 589 }
590 590
591 591 if (tgt->dt_elf)
592 592 (void) elf_end(tgt->dt_elf);
593 593 if (tgt->dt_elf_root)
594 594 (void) elf_end(tgt->dt_elf_root);
595 595
596 596 if (tgt->dt_symtab)
597 597 free(tgt->dt_symtab);
598 598
599 599 free(tgt);
600 600 }
601 601
602 602 /*
603 603 * Given an address, return the section it is in and set the offset within
604 604 * the section.
605 605 */
606 606 const char *
607 607 dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset)
608 608 {
609 609 int i;
610 610
611 611 for (i = 1; i < tgt->dt_shncount; i++) {
612 612 if ((addr >= tgt->dt_shnmap[i].dm_start) &&
613 613 (addr < tgt->dt_shnmap[i].dm_start +
614 614 tgt->dt_shnmap[i].dm_length)) {
615 615 *offset = addr - tgt->dt_shnmap[i].dm_start;
616 616 return (tgt->dt_shnmap[i].dm_name);
617 617 }
618 618 }
619 619
620 620 *offset = 0;
621 621 return (NULL);
622 622 }
623 623
624 624 /*
625 625 * Given an address, returns the name of the corresponding symbol, as well as
626 626 * the offset within that symbol. If no matching symbol is found, then NULL is
627 627 * returned.
628 628 *
629 629 * If 'cache_result' is specified, then we keep track of the resulting symbol.
630 630 * This cached result is consulted first on subsequent lookups in order to avoid
631 631 * unecessary lookups. This flag should be used for resolving the current PC,
632 632 * as the majority of addresses stay within the current function.
633 633 */
634 634 const char *
635 635 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
636 636 size_t *size, int *isfunc)
637 637 {
638 638 int lo, hi, mid;
639 639 sym_entry_t *sym, *osym, *match;
640 640 int found;
641 641
642 642 if (tgt->dt_symcache != NULL &&
643 643 addr >= tgt->dt_symcache->se_sym.st_value &&
644 644 addr < tgt->dt_symcache->se_sym.st_value +
645 645 tgt->dt_symcache->se_sym.st_size) {
646 646 *offset = addr - tgt->dt_symcache->se_sym.st_value;
647 647 *size = tgt->dt_symcache->se_sym.st_size;
648 648 return (tgt->dt_symcache->se_name);
649 649 }
650 650
651 651 lo = 0;
652 652 hi = (tgt->dt_symcount - 1);
653 653 found = 0;
654 654 match = osym = NULL;
655 655 while (lo <= hi) {
656 656 mid = (lo + hi) / 2;
657 657
658 658 sym = &tgt->dt_symtab[mid];
659 659
660 660 if (addr >= sym->se_sym.st_value &&
661 661 addr < sym->se_sym.st_value + sym->se_sym.st_size &&
662 662 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
663 663 osym = sym;
664 664 found = 1;
665 665 } else if (addr == sym->se_sym.st_value) {
666 666 /*
667 667 * Particularly for .plt objects, it's possible to have
668 668 * a zero sized object. We want to return this, but we
669 669 * want it to be a last resort.
670 670 */
671 671 match = sym;
672 672 }
673 673
674 674 if (addr < sym->se_sym.st_value)
675 675 hi = mid - 1;
676 676 else
677 677 lo = mid + 1;
678 678 }
679 679
680 680 if (!found) {
681 681 if (match)
682 682 osym = match;
683 683 else
684 684 return (NULL);
685 685 }
686 686
687 687 /*
688 688 * Walk backwards to find the best match.
689 689 */
690 690 do {
691 691 sym = osym;
692 692
693 693 if (osym == tgt->dt_symtab)
694 694 break;
695 695
696 696 osym = osym - 1;
697 697 } while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
698 698 (addr >= osym->se_sym.st_value) &&
699 699 (addr < osym->se_sym.st_value + osym->se_sym.st_size));
700 700
701 701 if (cache_result)
702 702 tgt->dt_symcache = sym;
703 703
704 704 *offset = addr - sym->se_sym.st_value;
705 705 *size = sym->se_sym.st_size;
706 706 if (isfunc)
707 707 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
708 708
709 709 return (sym->se_name);
710 710 }
711 711
↓ open down ↓ |
711 lines elided |
↑ open up ↑ |
712 712 #if !defined(__sparc)
713 713 /*
714 714 * Given an address, return the starting offset of the next symbol in the file.
715 715 * Only needed on variable length instruction architectures.
716 716 */
717 717 off_t
718 718 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
719 719 {
720 720 sym_entry_t *sym;
721 721
722 - for (sym = tgt->dt_symcache;
723 - sym != tgt->dt_symtab + tgt->dt_symcount;
724 - sym++) {
722 + sym = (tgt->dt_symcache != NULL) ? tgt->dt_symcache : tgt->dt_symtab;
723 +
724 + while (sym != (tgt->dt_symtab + tgt->dt_symcount)) {
725 725 if (sym->se_sym.st_value >= addr)
726 726 return (sym->se_sym.st_value - addr);
727 + sym++;
727 728 }
728 729
729 730 return (0);
730 731 }
731 732 #endif
732 733
733 734 /*
734 735 * Iterate over all sections in the target, executing the given callback for
735 736 * each.
736 737 */
737 738 void
738 739 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
739 740 {
740 741 dis_scn_t sdata;
741 742 Elf_Scn *scn;
742 743 int idx;
743 744
744 745 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
745 746 scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
746 747
747 748 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
748 749 warn("%s: failed to get section %d header",
749 750 tgt->dt_filename, idx);
750 751 continue;
751 752 }
752 753
753 754 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
754 755 sdata.ds_shdr.sh_name)) == NULL) {
755 756 warn("%s: failed to get section %d name",
756 757 tgt->dt_filename, idx);
757 758 continue;
758 759 }
759 760
760 761 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
761 762 warn("%s: failed to get data for section '%s'",
762 763 tgt->dt_filename, sdata.ds_name);
763 764 continue;
764 765 }
765 766
766 767 /*
767 768 * dis_tgt_section_iter is also used before the section map
768 769 * is initialized, so only check when we need to. If the
769 770 * section map is uninitialized, it will return 0 and have
770 771 * no net effect.
771 772 */
772 773 if (sdata.ds_shdr.sh_addr == 0)
773 774 sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start;
774 775
775 776 func(tgt, &sdata, data);
776 777 }
777 778 }
778 779
779 780 /*
780 781 * Return 1 if the given section contains text, 0 otherwise.
781 782 */
782 783 int
783 784 dis_section_istext(dis_scn_t *scn)
784 785 {
785 786 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
786 787 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
787 788 }
788 789
789 790 /*
790 791 * Return a pointer to the section data.
791 792 */
792 793 void *
793 794 dis_section_data(dis_scn_t *scn)
794 795 {
795 796 return (scn->ds_data->d_buf);
796 797 }
797 798
798 799 /*
799 800 * Return the size of the section data.
800 801 */
801 802 size_t
802 803 dis_section_size(dis_scn_t *scn)
803 804 {
804 805 return (scn->ds_data->d_size);
805 806 }
806 807
807 808 /*
808 809 * Return the address for the given section.
809 810 */
810 811 uint64_t
811 812 dis_section_addr(dis_scn_t *scn)
812 813 {
813 814 return (scn->ds_shdr.sh_addr);
814 815 }
815 816
816 817 /*
817 818 * Return the name of the current section.
818 819 */
819 820 const char *
820 821 dis_section_name(dis_scn_t *scn)
821 822 {
822 823 return (scn->ds_name);
823 824 }
824 825
825 826 /*
826 827 * Create an allocated copy of the given section
827 828 */
828 829 dis_scn_t *
829 830 dis_section_copy(dis_scn_t *scn)
830 831 {
831 832 dis_scn_t *new;
832 833
833 834 new = safe_malloc(sizeof (dis_scn_t));
834 835 (void) memcpy(new, scn, sizeof (dis_scn_t));
835 836
836 837 return (new);
837 838 }
838 839
839 840 /*
840 841 * Free section memory
841 842 */
842 843 void
843 844 dis_section_free(dis_scn_t *scn)
844 845 {
845 846 free(scn);
846 847 }
847 848
848 849 /*
849 850 * Iterate over all functions in the target, executing the given callback for
850 851 * each one.
851 852 */
852 853 void
853 854 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
854 855 {
855 856 int i;
856 857 sym_entry_t *sym;
857 858 dis_func_t df;
858 859 Elf_Scn *scn;
859 860 GElf_Shdr shdr;
860 861
861 862 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
862 863
863 864 /* ignore non-functions */
864 865 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
865 866 (sym->se_name == NULL) ||
866 867 (sym->se_sym.st_size == 0) ||
867 868 (sym->se_shndx >= SHN_LORESERVE))
868 869 continue;
869 870
870 871 /* get the ELF data associated with this function */
871 872 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
872 873 gelf_getshdr(scn, &shdr) == NULL ||
873 874 (df.df_data = elf_getdata(scn, NULL)) == NULL ||
874 875 df.df_data->d_size == 0) {
875 876 warn("%s: failed to read section %d",
876 877 tgt->dt_filename, sym->se_shndx);
877 878 continue;
878 879 }
879 880
880 881 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
881 882 shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start;
882 883
883 884 /*
884 885 * Verify that the address lies within the section that we think
885 886 * it does.
886 887 */
887 888 if (sym->se_sym.st_value < shdr.sh_addr ||
888 889 (sym->se_sym.st_value + sym->se_sym.st_size) >
889 890 (shdr.sh_addr + shdr.sh_size)) {
890 891 warn("%s: bad section %d for address %p",
891 892 tgt->dt_filename, sym->se_sym.st_shndx,
892 893 sym->se_sym.st_value);
893 894 continue;
894 895 }
895 896
896 897 df.df_sym = sym;
897 898 df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
898 899
899 900 func(tgt, &df, data);
900 901 }
901 902 }
902 903
903 904 /*
904 905 * Return the data associated with a given function.
905 906 */
906 907 void *
907 908 dis_function_data(dis_func_t *func)
908 909 {
909 910 return ((char *)func->df_data->d_buf + func->df_offset);
910 911 }
911 912
912 913 /*
913 914 * Return the size of a function.
914 915 */
915 916 size_t
916 917 dis_function_size(dis_func_t *func)
917 918 {
918 919 return (func->df_sym->se_sym.st_size);
919 920 }
920 921
921 922 /*
922 923 * Return the address of a function.
923 924 */
924 925 uint64_t
925 926 dis_function_addr(dis_func_t *func)
926 927 {
927 928 return (func->df_sym->se_sym.st_value);
928 929 }
929 930
930 931 /*
931 932 * Return the name of the function
932 933 */
933 934 const char *
934 935 dis_function_name(dis_func_t *func)
935 936 {
936 937 return (func->df_sym->se_name);
937 938 }
938 939
939 940 /*
940 941 * Return a copy of a function.
941 942 */
942 943 dis_func_t *
943 944 dis_function_copy(dis_func_t *func)
944 945 {
945 946 dis_func_t *new;
946 947
947 948 new = safe_malloc(sizeof (dis_func_t));
948 949 (void) memcpy(new, func, sizeof (dis_func_t));
949 950
950 951 return (new);
951 952 }
952 953
953 954 /*
954 955 * Free function memory
955 956 */
956 957 void
957 958 dis_function_free(dis_func_t *func)
958 959 {
959 960 free(func);
960 961 }
↓ open down ↓ |
224 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX