Print this page
4004 dis(1) can't deal with extended sections
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
↓ open down ↓ |
438 lines elided |
↑ open up ↑ |
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 + size_t shnum = 0;
449 450
450 451 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
451 452 (arhdr = elf_getarhdr(elf)) == NULL) {
452 453 warn("%s: malformed archive", file);
453 454 dis_tgt_destroy(tgt);
454 455 return (NULL);
455 456 }
456 457
457 458 /*
458 459 * Make sure that this Elf file is sane
459 460 */
460 461 if (gelf_getehdr(elf, &ehdr) == NULL) {
461 462 if (arhdr != NULL) {
462 463 /*
463 464 * For archives, we drive on in the face of bad
464 465 * members. The "/" and "//" members are
465 466 * special, and should be silently ignored.
466 467 */
467 468 if (strcmp(arhdr->ar_name, "/") != 0 &&
468 469 strcmp(arhdr->ar_name, "//") != 0)
469 470 warn("%s[%s]: invalid file type",
470 471 file, arhdr->ar_name);
471 472 cmd = elf_next(elf);
472 473 (void) elf_end(elf);
473 474 continue;
474 475 }
475 476
476 477 warn("%s: invalid file type", file);
477 478 dis_tgt_destroy(tgt);
478 479 return (NULL);
479 480 }
480 481
481 482 /*
482 483 * If we're seeing a new Elf object, then we have an
483 484 * archive. In this case, we create a new target, and chain it
484 485 * off the master target. We can later iterate over these
485 486 * targets using dis_tgt_next().
486 487 */
487 488 if (current->dt_elf != NULL) {
488 489 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
489 490 next->dt_elf_root = tgt->dt_elf_root;
490 491 next->dt_fd = -1;
491 492 current->dt_next = next;
492 493 current = next;
493 494 }
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
494 495 current->dt_elf = elf;
495 496 current->dt_arhdr = arhdr;
496 497
497 498 if (elf_getshdrstrndx(elf, ¤t->dt_shstrndx) == -1) {
498 499 warn("%s: failed to get section string table for "
499 500 "file", file);
500 501 dis_tgt_destroy(tgt);
501 502 return (NULL);
502 503 }
503 504
505 + if (elf_getshdrnum(elf, &shnum) == -1) {
506 + warn("%s: failed to get number of sections in file",
507 + file);
508 + dis_tgt_destroy(tgt);
509 + return (NULL);
510 + }
511 +
504 512 current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
505 - ehdr.e_shnum);
506 - current->dt_shncount = ehdr.e_shnum;
513 + shnum);
514 + current->dt_shncount = shnum;
507 515
508 516 idx = 0;
509 517 dis_tgt_section_iter(current, tgt_scn_init, &idx);
510 518 current->dt_filename = file;
511 519
512 520 create_addrmap(current);
513 521 if (current->dt_symidx != 0)
514 522 construct_symtab(current);
515 523
516 524 cmd = elf_next(elf);
517 525 }
518 526
519 527 /*
520 528 * Final sanity check. If we had an archive with no members, then bail
521 529 * out with a nice message.
522 530 */
523 531 if (tgt->dt_elf == NULL) {
524 532 warn("%s: empty archive\n", file);
525 533 dis_tgt_destroy(tgt);
526 534 return (NULL);
527 535 }
528 536
529 537 return (tgt);
530 538 }
531 539
532 540 /*
533 541 * Return the filename associated with the target.
534 542 */
535 543 const char *
536 544 dis_tgt_name(dis_tgt_t *tgt)
537 545 {
538 546 return (tgt->dt_filename);
539 547 }
540 548
541 549 /*
542 550 * Return the archive member name, if any.
543 551 */
544 552 const char *
545 553 dis_tgt_member(dis_tgt_t *tgt)
546 554 {
547 555 if (tgt->dt_arhdr)
548 556 return (tgt->dt_arhdr->ar_name);
549 557 else
550 558 return (NULL);
551 559 }
552 560
553 561 /*
554 562 * Return the Elf_Ehdr associated with this target. Needed to determine which
555 563 * disassembler to use.
556 564 */
557 565 void
558 566 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
559 567 {
560 568 (void) gelf_getehdr(tgt->dt_elf, ehdr);
561 569 }
562 570
563 571 /*
564 572 * Return the next target in the list, if this is an archive.
565 573 */
566 574 dis_tgt_t *
567 575 dis_tgt_next(dis_tgt_t *tgt)
568 576 {
569 577 return (tgt->dt_next);
570 578 }
571 579
572 580 /*
573 581 * Destroy a target and free up any associated memory.
574 582 */
575 583 void
576 584 dis_tgt_destroy(dis_tgt_t *tgt)
577 585 {
578 586 dis_tgt_t *current, *next;
579 587
580 588 current = tgt->dt_next;
581 589 while (current != NULL) {
582 590 next = current->dt_next;
583 591 if (current->dt_elf)
584 592 (void) elf_end(current->dt_elf);
585 593 if (current->dt_symtab)
586 594 free(current->dt_symtab);
587 595 free(current);
588 596 current = next;
589 597 }
590 598
591 599 if (tgt->dt_elf)
592 600 (void) elf_end(tgt->dt_elf);
593 601 if (tgt->dt_elf_root)
594 602 (void) elf_end(tgt->dt_elf_root);
595 603
596 604 if (tgt->dt_symtab)
597 605 free(tgt->dt_symtab);
598 606
599 607 free(tgt);
600 608 }
601 609
602 610 /*
603 611 * Given an address, return the section it is in and set the offset within
604 612 * the section.
605 613 */
606 614 const char *
607 615 dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset)
608 616 {
609 617 int i;
610 618
611 619 for (i = 1; i < tgt->dt_shncount; i++) {
612 620 if ((addr >= tgt->dt_shnmap[i].dm_start) &&
613 621 (addr < tgt->dt_shnmap[i].dm_start +
614 622 tgt->dt_shnmap[i].dm_length)) {
615 623 *offset = addr - tgt->dt_shnmap[i].dm_start;
616 624 return (tgt->dt_shnmap[i].dm_name);
617 625 }
618 626 }
619 627
620 628 *offset = 0;
621 629 return (NULL);
622 630 }
623 631
624 632 /*
625 633 * Given an address, returns the name of the corresponding symbol, as well as
626 634 * the offset within that symbol. If no matching symbol is found, then NULL is
627 635 * returned.
628 636 *
629 637 * If 'cache_result' is specified, then we keep track of the resulting symbol.
630 638 * This cached result is consulted first on subsequent lookups in order to avoid
631 639 * unecessary lookups. This flag should be used for resolving the current PC,
632 640 * as the majority of addresses stay within the current function.
633 641 */
634 642 const char *
635 643 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
636 644 size_t *size, int *isfunc)
637 645 {
638 646 int lo, hi, mid;
639 647 sym_entry_t *sym, *osym, *match;
640 648 int found;
641 649
642 650 if (tgt->dt_symcache != NULL &&
643 651 addr >= tgt->dt_symcache->se_sym.st_value &&
644 652 addr < tgt->dt_symcache->se_sym.st_value +
645 653 tgt->dt_symcache->se_sym.st_size) {
646 654 *offset = addr - tgt->dt_symcache->se_sym.st_value;
647 655 *size = tgt->dt_symcache->se_sym.st_size;
648 656 return (tgt->dt_symcache->se_name);
649 657 }
650 658
651 659 lo = 0;
652 660 hi = (tgt->dt_symcount - 1);
653 661 found = 0;
654 662 match = osym = NULL;
655 663 while (lo <= hi) {
656 664 mid = (lo + hi) / 2;
657 665
658 666 sym = &tgt->dt_symtab[mid];
659 667
660 668 if (addr >= sym->se_sym.st_value &&
661 669 addr < sym->se_sym.st_value + sym->se_sym.st_size &&
662 670 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
663 671 osym = sym;
664 672 found = 1;
665 673 } else if (addr == sym->se_sym.st_value) {
666 674 /*
667 675 * Particularly for .plt objects, it's possible to have
668 676 * a zero sized object. We want to return this, but we
669 677 * want it to be a last resort.
670 678 */
671 679 match = sym;
672 680 }
673 681
674 682 if (addr < sym->se_sym.st_value)
675 683 hi = mid - 1;
676 684 else
677 685 lo = mid + 1;
678 686 }
679 687
680 688 if (!found) {
681 689 if (match)
682 690 osym = match;
683 691 else
684 692 return (NULL);
685 693 }
686 694
687 695 /*
688 696 * Walk backwards to find the best match.
689 697 */
690 698 do {
691 699 sym = osym;
692 700
693 701 if (osym == tgt->dt_symtab)
694 702 break;
695 703
696 704 osym = osym - 1;
697 705 } while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
698 706 (addr >= osym->se_sym.st_value) &&
699 707 (addr < osym->se_sym.st_value + osym->se_sym.st_size));
700 708
701 709 if (cache_result)
702 710 tgt->dt_symcache = sym;
703 711
704 712 *offset = addr - sym->se_sym.st_value;
705 713 *size = sym->se_sym.st_size;
706 714 if (isfunc)
707 715 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
708 716
709 717 return (sym->se_name);
710 718 }
711 719
712 720 #if !defined(__sparc)
713 721 /*
714 722 * Given an address, return the starting offset of the next symbol in the file.
715 723 * Only needed on variable length instruction architectures.
716 724 */
717 725 off_t
718 726 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
719 727 {
720 728 sym_entry_t *sym;
721 729
722 730 for (sym = tgt->dt_symcache;
723 731 sym != tgt->dt_symtab + tgt->dt_symcount;
724 732 sym++) {
725 733 if (sym->se_sym.st_value >= addr)
726 734 return (sym->se_sym.st_value - addr);
727 735 }
728 736
729 737 return (0);
730 738 }
731 739 #endif
732 740
733 741 /*
734 742 * Iterate over all sections in the target, executing the given callback for
735 743 * each.
736 744 */
737 745 void
738 746 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
739 747 {
740 748 dis_scn_t sdata;
741 749 Elf_Scn *scn;
742 750 int idx;
743 751
744 752 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
745 753 scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
746 754
747 755 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
748 756 warn("%s: failed to get section %d header",
749 757 tgt->dt_filename, idx);
750 758 continue;
751 759 }
752 760
753 761 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
754 762 sdata.ds_shdr.sh_name)) == NULL) {
755 763 warn("%s: failed to get section %d name",
756 764 tgt->dt_filename, idx);
757 765 continue;
758 766 }
759 767
760 768 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
761 769 warn("%s: failed to get data for section '%s'",
762 770 tgt->dt_filename, sdata.ds_name);
763 771 continue;
764 772 }
765 773
766 774 /*
767 775 * dis_tgt_section_iter is also used before the section map
768 776 * is initialized, so only check when we need to. If the
769 777 * section map is uninitialized, it will return 0 and have
770 778 * no net effect.
771 779 */
772 780 if (sdata.ds_shdr.sh_addr == 0)
773 781 sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start;
774 782
775 783 func(tgt, &sdata, data);
776 784 }
777 785 }
778 786
779 787 /*
780 788 * Return 1 if the given section contains text, 0 otherwise.
781 789 */
782 790 int
783 791 dis_section_istext(dis_scn_t *scn)
784 792 {
785 793 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
786 794 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
787 795 }
788 796
789 797 /*
790 798 * Return a pointer to the section data.
791 799 */
792 800 void *
793 801 dis_section_data(dis_scn_t *scn)
794 802 {
795 803 return (scn->ds_data->d_buf);
796 804 }
797 805
798 806 /*
799 807 * Return the size of the section data.
800 808 */
801 809 size_t
802 810 dis_section_size(dis_scn_t *scn)
803 811 {
804 812 return (scn->ds_data->d_size);
805 813 }
806 814
807 815 /*
808 816 * Return the address for the given section.
809 817 */
810 818 uint64_t
811 819 dis_section_addr(dis_scn_t *scn)
812 820 {
813 821 return (scn->ds_shdr.sh_addr);
814 822 }
815 823
816 824 /*
817 825 * Return the name of the current section.
818 826 */
819 827 const char *
820 828 dis_section_name(dis_scn_t *scn)
821 829 {
822 830 return (scn->ds_name);
823 831 }
824 832
825 833 /*
826 834 * Create an allocated copy of the given section
827 835 */
828 836 dis_scn_t *
829 837 dis_section_copy(dis_scn_t *scn)
830 838 {
831 839 dis_scn_t *new;
832 840
833 841 new = safe_malloc(sizeof (dis_scn_t));
834 842 (void) memcpy(new, scn, sizeof (dis_scn_t));
835 843
836 844 return (new);
837 845 }
838 846
839 847 /*
840 848 * Free section memory
841 849 */
842 850 void
843 851 dis_section_free(dis_scn_t *scn)
844 852 {
845 853 free(scn);
846 854 }
847 855
848 856 /*
849 857 * Iterate over all functions in the target, executing the given callback for
850 858 * each one.
851 859 */
852 860 void
853 861 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
854 862 {
855 863 int i;
856 864 sym_entry_t *sym;
857 865 dis_func_t df;
858 866 Elf_Scn *scn;
859 867 GElf_Shdr shdr;
860 868
861 869 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
862 870
863 871 /* ignore non-functions */
864 872 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
865 873 (sym->se_name == NULL) ||
866 874 (sym->se_sym.st_size == 0) ||
867 875 (sym->se_shndx >= SHN_LORESERVE))
868 876 continue;
869 877
870 878 /* get the ELF data associated with this function */
871 879 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
872 880 gelf_getshdr(scn, &shdr) == NULL ||
873 881 (df.df_data = elf_getdata(scn, NULL)) == NULL ||
874 882 df.df_data->d_size == 0) {
875 883 warn("%s: failed to read section %d",
876 884 tgt->dt_filename, sym->se_shndx);
877 885 continue;
878 886 }
879 887
880 888 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
881 889 shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start;
882 890
883 891 /*
884 892 * Verify that the address lies within the section that we think
885 893 * it does.
886 894 */
887 895 if (sym->se_sym.st_value < shdr.sh_addr ||
888 896 (sym->se_sym.st_value + sym->se_sym.st_size) >
889 897 (shdr.sh_addr + shdr.sh_size)) {
890 898 warn("%s: bad section %d for address %p",
891 899 tgt->dt_filename, sym->se_sym.st_shndx,
892 900 sym->se_sym.st_value);
893 901 continue;
894 902 }
895 903
896 904 df.df_sym = sym;
897 905 df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
898 906
899 907 func(tgt, &df, data);
900 908 }
901 909 }
902 910
903 911 /*
904 912 * Return the data associated with a given function.
905 913 */
906 914 void *
907 915 dis_function_data(dis_func_t *func)
908 916 {
909 917 return ((char *)func->df_data->d_buf + func->df_offset);
910 918 }
911 919
912 920 /*
913 921 * Return the size of a function.
914 922 */
915 923 size_t
916 924 dis_function_size(dis_func_t *func)
917 925 {
918 926 return (func->df_sym->se_sym.st_size);
919 927 }
920 928
921 929 /*
922 930 * Return the address of a function.
923 931 */
924 932 uint64_t
925 933 dis_function_addr(dis_func_t *func)
926 934 {
927 935 return (func->df_sym->se_sym.st_value);
928 936 }
929 937
930 938 /*
931 939 * Return the name of the function
932 940 */
933 941 const char *
934 942 dis_function_name(dis_func_t *func)
935 943 {
936 944 return (func->df_sym->se_name);
937 945 }
938 946
939 947 /*
940 948 * Return a copy of a function.
941 949 */
942 950 dis_func_t *
943 951 dis_function_copy(dis_func_t *func)
944 952 {
945 953 dis_func_t *new;
946 954
947 955 new = safe_malloc(sizeof (dis_func_t));
948 956 (void) memcpy(new, func, sizeof (dis_func_t));
949 957
950 958 return (new);
951 959 }
952 960
953 961 /*
954 962 * Free function memory
955 963 */
956 964 void
957 965 dis_function_free(dis_func_t *func)
958 966 {
959 967 free(func);
960 968 }
↓ open down ↓ |
444 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX