1/* 2Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. 3Permission is hereby granted, free of charge, to any person 4obtaining a copy of this software and associated documentation 5files (the "Software"), to deal in the Software without 6restriction, including without limitation the rights to use, 7copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following 10conditions: 11 12The above copyright notice and this permission notice shall be 13included in all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23*/ 24 25#ifdef USE_CLEAN_NAMESPACE 26#define fopen _fopen 27#define fseek _fseek 28#define fread _fread 29#define fclose _fclose 30#endif /* USE_CLEAN_NAMESPACE */ 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <inttypes.h> 36#include <elf.h> 37 38#include "uwx.h" 39#include "uwx_env.h" 40 41#ifdef USE_CLEAN_NAMESPACE 42/* 43 * Moved the defines above the include of stdio.h, 44 * so we don't need these unless that causes problems 45 * and we have to move them back down here. 46 * #define fopen _fopen 47 * #define fseek _fseek 48 * #define fread _fread 49 * #define fclose _fclose 50 * extern FILE *_fopen(const char *, const char *); 51 * extern int _fseek(FILE *, long int, int); 52 * extern size_t _fread(void *, size_t, size_t, FILE *); 53 * extern int _fclose(FILE *); 54 */ 55#endif /* USE_CLEAN_NAMESPACE */ 56 57struct uwx_symbol_cache { 58 char *module_name; 59 int nsyms; 60 uint64_t *sym_values; 61 char **sym_names; 62 char *strings; 63}; 64 65 66int uwx_read_func_symbols( 67 struct uwx_env *env, 68 struct uwx_symbol_cache *cache, 69 char *module_name); 70 71 72int uwx_find_symbol( 73 struct uwx_env *env, 74 struct uwx_symbol_cache **symbol_cache_p, 75 char *module_name, 76 uint64_t relip, 77 char **func_name_p, 78 uint64_t *offset_p) 79{ 80 int status; 81 int i; 82 uint64_t offset; 83 uint64_t best_offset; 84 char *best_name; 85 struct symbol *sym; 86 struct uwx_symbol_cache *cache = NULL; 87 88 /* Allocate a symbol cache on first call */ 89 if (symbol_cache_p != NULL) 90 cache = *symbol_cache_p; 91 if (cache == NULL) { 92 cache = (struct uwx_symbol_cache *) 93 (*env->allocate_cb)(sizeof(struct uwx_symbol_cache)); 94 if (cache == NULL) 95 return UWX_ERR_NOMEM; 96 cache->module_name = NULL; 97 cache->nsyms = 0; 98 cache->sym_values = NULL; 99 cache->sym_names = NULL; 100 cache->strings = NULL; 101 if (symbol_cache_p != NULL) 102 *symbol_cache_p = cache; 103 } 104 105 /* Read function symbols from the object file */ 106 status = uwx_read_func_symbols(env, cache, module_name); 107 if (status != UWX_OK) 108 return status; 109 110 /* Search for best match */ 111 best_offset = ~(uint64_t)0; 112 best_name = NULL; 113 for (i = 0; i < cache->nsyms; i++) { 114 if (cache->sym_values[i] == relip) { 115 *func_name_p = cache->sym_names[i]; 116 *offset_p = 0; 117 if (symbol_cache_p == NULL) 118 uwx_release_symbol_cache(env, cache); 119 return UWX_OK; 120 } 121 if (relip > cache->sym_values[i]) { 122 offset = relip - cache->sym_values[i]; 123 if (offset < best_offset) { 124 best_offset = offset; 125 best_name = cache->sym_names[i]; 126 } 127 } 128 } 129 if (best_name == NULL) 130 return UWX_ERR_NOSYM; 131 132 if (symbol_cache_p == NULL) 133 uwx_release_symbol_cache(env, cache); 134 135 *func_name_p = best_name; 136 *offset_p = best_offset; 137 return UWX_OK; 138} 139 140 141void uwx_release_symbol_cache( 142 struct uwx_env *env, 143 struct uwx_symbol_cache *symbol_cache) 144{ 145 if (symbol_cache->module_name != NULL) 146 (*env->free_cb)(symbol_cache->module_name); 147 if (symbol_cache->sym_values != NULL) 148 (*env->free_cb)(symbol_cache->sym_values); 149 if (symbol_cache->sym_names != NULL) 150 (*env->free_cb)(symbol_cache->sym_names); 151 if (symbol_cache->strings != NULL) 152 (*env->free_cb)(symbol_cache->strings); 153 (*env->free_cb)(symbol_cache); 154} 155 156 157#define ELF_ERR_NOMEM UWX_ERR_NOMEM /* Out of memory */ 158#define ELF_ERR_OPEN UWX_ERR_NOSYM /* Can't open file */ 159 160#define ELF_ERR_NOHEADER UWX_ERR_NOSYM /* Can't read ELF header */ 161#define ELF_ERR_NOTELF UWX_ERR_NOSYM /* Not an ELF file */ 162#define ELF_ERR_HEADER_SIZE UWX_ERR_NOSYM /* Invalid e_ehsize */ 163#define ELF_ERR_INVALID_CLASS UWX_ERR_NOSYM /* Invalid EI_CLASS */ 164#define ELF_ERR_INVALID_DATA UWX_ERR_NOSYM /* Invalid EI_DATA */ 165 166#define ELF_ERR_READ_SECTHDR UWX_ERR_NOSYM /* Can't read section headers */ 167#define ELF_ERR_SECTHDR_SIZE UWX_ERR_NOSYM /* Invalid e_shentsize */ 168 169#define ELF_ERR_READ_PROGHDR UWX_ERR_NOSYM /* Can't read program headers */ 170#define ELF_ERR_PROGHDR_SIZE UWX_ERR_NOSYM /* Invalid e_phentsize */ 171 172#define ELF_ERR_READ_SECTION UWX_ERR_NOSYM /* Can't read section contents */ 173 174#define ELF_ERR_READ_SYMTAB UWX_ERR_NOSYM /* Can't read symbol table */ 175#define ELF_ERR_SYMTAB_SIZE UWX_ERR_NOSYM /* Invalid sh_entsize for symtab */ 176 177 178struct elf_file { 179 uint64_t phoff; 180 uint64_t shoff; 181 uint64_t text_base; 182 uint64_t text_end; 183 alloc_cb allocate_cb; 184 free_cb free_cb; 185 const char *filename; 186 FILE *fd; 187 struct elf_section *sections; 188 struct elf_symbol *symbols; 189 char *symbol_strings; 190 int native_data; 191 int source_class; 192 int source_data; 193 int ehsize; 194 int phentsize; 195 int phnum; 196 int shentsize; 197 int shnum; 198 int nsyms; 199}; 200 201struct elf_section { 202 uint64_t flags; 203 uint64_t addr; 204 uint64_t offset; 205 uint64_t size; 206 uint64_t entsize; 207 char *contents; 208 struct elf_symbol *symbols; 209 int type; 210 int link; 211 int info; 212 int nelems; 213}; 214 215struct elf_symbol { 216 uint64_t value; 217 char *namep; 218 int name; 219 int type; 220 int shndx; 221}; 222 223 224static void elf_swap_bytes(char *buf, char *template) 225{ 226 int i; 227 int sz; 228 char temp[16]; 229 230 while (sz = *template++) { 231 if (sz > 16) 232 exit(1); 233 for (i = 0; i < sz; i++) 234 temp[i] = buf[i]; 235 for (i = 0; i < sz; i++) 236 buf[i] = temp[sz-i-1]; 237 buf += sz; 238 } 239} 240 241 242static int elf_read_section(struct elf_file *ef, int shndx) 243{ 244 struct elf_section *sect; 245 246 if (shndx < 0 || shndx > ef->shnum) 247 return 0; 248 249 sect = &ef->sections[shndx]; 250 251 /* Return if section has already been read */ 252 if (sect->contents != NULL) 253 return 0; 254 255 sect->contents = (*ef->allocate_cb)(sect->size); 256 if (sect->contents == NULL) 257 return ELF_ERR_NOMEM; 258 259 fseek(ef->fd, (long)sect->offset, SEEK_SET); 260 if (fread(sect->contents, 1, sect->size, ef->fd) != sect->size) 261 return ELF_ERR_READ_SECTION; 262 263 return 0; 264} 265 266 267static char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0}; 268static char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0}; 269 270static int elf_read_symtab_section(struct elf_file *ef, int shndx) 271{ 272 int i; 273 int nsyms; 274 long size; 275 union { 276 Elf32_Sym sym32; 277 Elf64_Sym sym64; 278 } sym; 279 struct elf_section *sect; 280 struct elf_symbol *syms; 281 struct elf_symbol *symp; 282 char *strtab; 283 284 sect = &ef->sections[shndx]; 285 286 /* Return if section has already been read */ 287 if (sect->symbols != NULL) 288 return 0; 289 290 if (ef->source_class == ELFCLASS32) { 291 if (sect->entsize != sizeof(sym.sym32)) 292 return ELF_ERR_SYMTAB_SIZE; 293 } 294 else { 295 if (sect->entsize != sizeof(sym.sym64)) 296 return ELF_ERR_SYMTAB_SIZE; 297 } 298 299 nsyms = sect->nelems; 300 syms = (struct elf_symbol *) 301 (*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms); 302 if (syms == NULL) 303 return ELF_ERR_NOMEM; 304 305 /* Read the symbol table */ 306 fseek(ef->fd, (long)sect->offset, SEEK_SET); 307 for (i = 0; i < nsyms; i++) { 308 309 symp = &syms[i]; 310 311 /* Read the next symbol table entry */ 312 if (fread((char *)&sym, sect->entsize, 1, ef->fd) != 1) { 313 (*ef->free_cb)(syms); 314 return ELF_ERR_READ_SYMTAB; 315 } 316 317 /* Get fields from appropriate structure */ 318 if (ef->source_class == ELFCLASS32) { 319 /* Swap bytes if necessary */ 320 if (ef->source_data != ef->native_data) 321 elf_swap_bytes((char *)&sym, template_elf32_sym); 322 symp->name = sym.sym32.st_name; 323 symp->type = sym.sym32.st_info & 0x0f; 324 symp->shndx = sym.sym32.st_shndx; 325 symp->value = sym.sym32.st_value; 326 } 327 else { 328 /* Swap bytes if necessary */ 329 if (ef->source_data != ef->native_data) 330 elf_swap_bytes((char *)&sym, template_elf64_sym); 331 symp->name = sym.sym64.st_name; 332 symp->type = sym.sym64.st_info & 0x0f; 333 symp->shndx = sym.sym64.st_shndx; 334 symp->value = sym.sym64.st_value; 335 } 336 symp->namep = NULL; 337 338 } 339 340 /* Read the symbol string table and convert section names */ 341 /* from string table offsets to pointers */ 342 if (sect->link > 0 && sect->link < ef->shnum) { 343 if (elf_read_section(ef, sect->link) == 0) { 344 strtab = ef->sections[sect->link].contents; 345 for (i = 0; i < nsyms; i++) { 346 symp = &syms[i]; 347 symp->namep = strtab + symp->name; 348 } 349 ef->symbol_strings = strtab; 350 ef->sections[sect->link].contents = NULL; 351 } 352 } 353 354 sect->symbols = syms; 355 return 0; 356} 357 358 359static char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0}; 360static char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0}; 361 362static int elf_read_prog_hdrs(struct elf_file *ef) 363{ 364 int i; 365 union { 366 Elf32_Phdr hdr32; 367 Elf64_Phdr hdr64; 368 } header; 369 uint64_t vaddr; 370 uint64_t memsz; 371 uint64_t unwind_base; 372 int type; 373 374 if (ef->phnum == 0) 375 return 0; 376 377 if (ef->source_class == ELFCLASS32) { 378 if (ef->phentsize != sizeof(header.hdr32)) 379 return ELF_ERR_PROGHDR_SIZE; 380 } 381 else { 382 if (ef->phentsize != sizeof(header.hdr64)) 383 return ELF_ERR_PROGHDR_SIZE; 384 } 385 386 /* Look for the PT_IA_64_UNWIND segment */ 387 /* (That will help us identify the text segment) */ 388 389 fseek(ef->fd, (long)ef->phoff, SEEK_SET); 390 for (i = 0; i < ef->phnum; i++) { 391 392 /* Read the next program header */ 393 if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1) 394 return ELF_ERR_READ_PROGHDR; 395 396 /* Get fields from appropriate structure */ 397 if (ef->source_class == ELFCLASS32) { 398 /* Swap bytes in header fields if necessary */ 399 if (ef->source_data != ef->native_data) 400 elf_swap_bytes((char *)&header, template_elf32_phdr); 401 type = header.hdr32.p_type; 402 vaddr = header.hdr32.p_vaddr; 403 } 404 else { 405 /* Swap bytes in header fields if necessary */ 406 if (ef->source_data != ef->native_data) 407 elf_swap_bytes((char *)&header, template_elf64_phdr); 408 type = header.hdr64.p_type; 409 vaddr = header.hdr64.p_vaddr; 410 } 411 412 if (type == PT_IA_64_UNWIND) { 413 unwind_base = vaddr; 414 break; 415 } 416 417 } 418 419 /* Now look for the PT_LOAD segment that includes the unwind segment */ 420 421 fseek(ef->fd, (long)ef->phoff, SEEK_SET); 422 for (i = 0; i < ef->phnum; i++) { 423 424 /* Read the next program header */ 425 if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1) 426 return ELF_ERR_READ_PROGHDR; 427 428 /* Get fields from appropriate structure */ 429 if (ef->source_class == ELFCLASS32) { 430 /* Swap bytes in header fields if necessary */ 431 if (ef->source_data != ef->native_data) 432 elf_swap_bytes((char *)&header, template_elf32_phdr); 433 type = header.hdr32.p_type; 434 vaddr = header.hdr32.p_vaddr; 435 memsz = header.hdr32.p_memsz; 436 } 437 else { 438 /* Swap bytes in header fields if necessary */ 439 if (ef->source_data != ef->native_data) 440 elf_swap_bytes((char *)&header, template_elf64_phdr); 441 type = header.hdr64.p_type; 442 vaddr = header.hdr64.p_vaddr; 443 memsz = header.hdr64.p_memsz; 444 } 445 446 if (type == PT_LOAD && 447 vaddr <= unwind_base && unwind_base < vaddr + memsz) { 448 ef->text_base = vaddr; 449 ef->text_end = vaddr + memsz; 450 break; 451 } 452 453 } 454 455 return 0; 456} 457 458 459static char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0}; 460static char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0}; 461 462static int elf_read_sect_hdrs(struct elf_file *ef) 463{ 464 int i; 465 long size; 466 int err; 467 union { 468 Elf32_Shdr hdr32; 469 Elf64_Shdr hdr64; 470 } header; 471 struct elf_section *sect; 472 char *shstrtab; 473 474 if (ef->source_class == ELFCLASS32) { 475 if (ef->shentsize != sizeof(header.hdr32)) 476 return ELF_ERR_SECTHDR_SIZE; 477 } 478 else { 479 if (ef->shentsize != sizeof(header.hdr64)) 480 return ELF_ERR_SECTHDR_SIZE; 481 } 482 483 fseek(ef->fd, (long)ef->shoff, SEEK_SET); 484 ef->sections = (struct elf_section *) 485 (*ef->allocate_cb)(sizeof(struct elf_section) * ef->shnum); 486 if (ef->sections == NULL) 487 return ELF_ERR_NOMEM; 488 489 /* Read the section header table */ 490 for (i = 0; i < ef->shnum; i++) { 491 492 sect = &ef->sections[i]; 493 494 /* Read the next section header */ 495 if (fread((char *)&header, ef->shentsize, 1, ef->fd) != 1) { 496 (*ef->free_cb)(ef->sections); 497 return ELF_ERR_READ_SECTHDR; 498 } 499 500 /* Get fields from appropriate structure */ 501 if (ef->source_class == ELFCLASS32) { 502 /* Swap bytes in header fields if necessary */ 503 if (ef->source_data != ef->native_data) 504 elf_swap_bytes((char *)&header, template_elf32_shdr); 505 sect->type = header.hdr32.sh_type; 506 sect->flags = header.hdr32.sh_flags; 507 sect->addr = header.hdr32.sh_addr; 508 sect->offset = header.hdr32.sh_offset; 509 sect->size = header.hdr32.sh_size; 510 sect->link = header.hdr32.sh_link; 511 sect->info = header.hdr32.sh_info; 512 sect->entsize = header.hdr32.sh_entsize; 513 } 514 else { 515 /* Swap bytes in header fields if necessary */ 516 if (ef->source_data != ef->native_data) 517 elf_swap_bytes((char *)&header, template_elf64_shdr); 518 sect->type = header.hdr64.sh_type; 519 sect->flags = header.hdr64.sh_flags; 520 sect->addr = header.hdr64.sh_addr; 521 sect->offset = header.hdr64.sh_offset; 522 sect->size = header.hdr64.sh_size; 523 sect->link = header.hdr64.sh_link; 524 sect->info = header.hdr64.sh_info; 525 sect->entsize = header.hdr64.sh_entsize; 526 } 527 sect->contents = NULL; 528 sect->symbols = NULL; 529 if (sect->entsize > 0) 530 sect->nelems = sect->size / sect->entsize; 531 532 } 533 534 return 0; 535} 536 537 538static char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0}; 539static char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0}; 540 541static int elf_read_header(struct elf_file *ef) 542{ 543 union { 544 char ident[EI_NIDENT]; 545 Elf32_Ehdr hdr32; 546 Elf64_Ehdr hdr64; 547 } header; 548 549 /* Read the ELF header */ 550 fseek(ef->fd, 0L, SEEK_SET); 551 if (fread((char *)header.ident, EI_NIDENT, 1, ef->fd) != 1) { 552 return ELF_ERR_NOHEADER; 553 } 554 555 /* Verify that this is an ELF file */ 556 if (header.ident[EI_MAG0] != ELFMAG0 || 557 header.ident[EI_MAG1] != ELFMAG1 || 558 header.ident[EI_MAG2] != ELFMAG2 || 559 header.ident[EI_MAG3] != ELFMAG3) { 560 return ELF_ERR_NOTELF; 561 } 562 563 /* Get header fields from the byte array e_ident */ 564 /* (These are independent of EI_CLASS and EI_DATA) */ 565 ef->source_class = header.ident[EI_CLASS]; 566 ef->source_data = header.ident[EI_DATA]; 567 568 /* Verify EI_CLASS and EI_DATA */ 569 if (header.ident[EI_CLASS] != ELFCLASS32 && 570 header.ident[EI_CLASS] != ELFCLASS64) { 571 return ELF_ERR_INVALID_CLASS; 572 } 573 if (header.ident[EI_DATA] != ELFDATA2LSB && 574 header.ident[EI_DATA] != ELFDATA2MSB) { 575 return ELF_ERR_INVALID_DATA; 576 } 577 578 /* Get remaining header fields from appropriate structure */ 579 if (ef->source_class == ELFCLASS32) { 580 if (fread((char *)&header.hdr32 + EI_NIDENT, 581 sizeof(header.hdr32) - EI_NIDENT, 1, ef->fd) != 1) 582 return ELF_ERR_NOHEADER; 583 /* Swap bytes in header fields if necessary */ 584 if (ef->source_data != ef->native_data) 585 elf_swap_bytes((char *)&header + EI_NIDENT, template_elf32_ehdr); 586 ef->phoff = header.hdr32.e_phoff; 587 ef->shoff = header.hdr32.e_shoff; 588 ef->ehsize = header.hdr32.e_ehsize; 589 ef->phentsize = header.hdr32.e_phentsize; 590 ef->phnum = header.hdr32.e_phnum; 591 ef->shentsize = header.hdr32.e_shentsize; 592 ef->shnum = header.hdr32.e_shnum; 593 if (ef->ehsize != sizeof(header.hdr32)) { 594 return ELF_ERR_HEADER_SIZE; 595 } 596 } 597 else { 598 if (fread((char *)&header.hdr64 + EI_NIDENT, 599 sizeof(header.hdr64) - EI_NIDENT, 1, ef->fd) != 1) 600 return ELF_ERR_NOHEADER; 601 /* Swap bytes in header fields if necessary */ 602 if (ef->source_data != ef->native_data) 603 elf_swap_bytes((char *)&header + EI_NIDENT, template_elf64_ehdr); 604 ef->phoff = header.hdr64.e_phoff; 605 ef->shoff = header.hdr64.e_shoff; 606 ef->ehsize = header.hdr64.e_ehsize; 607 ef->phentsize = header.hdr64.e_phentsize; 608 ef->phnum = header.hdr64.e_phnum; 609 ef->shentsize = header.hdr64.e_shentsize; 610 ef->shnum = header.hdr64.e_shnum; 611 if (ef->ehsize != sizeof(header.hdr64)) { 612 return ELF_ERR_HEADER_SIZE; 613 } 614 } 615 616 return 0; 617} 618 619 620static struct elf_file *elf_new(struct uwx_env *env) 621{ 622 int native_be; 623 char *p; 624 struct elf_file *ef; 625 626 ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file)); 627 if (ef == NULL) 628 return NULL; 629 630 /* Determine the native byte order */ 631 p = (char *)&native_be; 632 native_be = 1; /* Assume big-endian */ 633 *p = 0; /* Sets be == 0 only if little-endian */ 634 635 ef->allocate_cb = env->allocate_cb; 636 ef->free_cb = env->free_cb; 637 ef->filename = NULL; 638 ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB); 639 ef->fd = NULL; 640 ef->source_class = 0; 641 ef->source_data = 0; 642 ef->phoff = 0; 643 ef->shoff = 0; 644 ef->text_base = 0; 645 ef->text_end = 0; 646 ef->ehsize = 0; 647 ef->phentsize = 0; 648 ef->phnum = 0; 649 ef->shentsize = 0; 650 ef->shnum = 0; 651 ef->sections = NULL; 652 ef->symbols = NULL; 653 ef->symbol_strings = NULL; 654 ef->nsyms = 0; 655 return ef; 656} 657 658 659static int elf_open(struct elf_file *ef, const char *filename) 660{ 661 int err; 662 663 ef->filename = filename; 664 665 ef->fd = fopen(filename, "r"); 666 if (ef->fd == NULL) 667 return ELF_ERR_OPEN; 668 669 if ((err = elf_read_header(ef)) != 0) 670 return err; 671 672 if ((err = elf_read_sect_hdrs(ef)) != 0) 673 return err; 674 675 if ((err = elf_read_prog_hdrs(ef)) != 0) 676 return err; 677 678 return 0; 679} 680 681 682static void elf_free_sections(struct elf_file *ef) 683{ 684 int i; 685 struct elf_section *sect; 686 687 for (i = 0; i < ef->shnum; i++) { 688 sect = &ef->sections[i]; 689 if (sect->contents != NULL) 690 (*ef->free_cb)(sect->contents); 691 if ((sect->type == SHT_SYMTAB || sect->type == SHT_DYNSYM) 692 && sect->symbols != NULL) 693 (*ef->free_cb)(sect->symbols); 694 } 695 (*ef->free_cb)(ef->sections); 696} 697 698 699static void elf_close(struct elf_file *ef) 700{ 701 if (ef->fd != NULL) { 702 fclose(ef->fd); 703 ef->fd = NULL; 704 } 705} 706 707 708static void elf_free(struct elf_file *ef) 709{ 710 elf_close(ef); 711 if (ef->sections != NULL) 712 elf_free_sections(ef); 713 (*ef->free_cb)(ef); 714} 715 716 717static int elf_read_symbols(struct elf_file *ef) 718{ 719 int i; 720 int err; 721 struct elf_section *sect; 722 723 for (i = 1; i < ef->shnum; i++) { 724 sect = &ef->sections[i]; 725 if (sect->type == SHT_SYMTAB) { 726 if (elf_read_symtab_section(ef, i) == 0) { 727 ef->symbols = sect->symbols; 728 ef->nsyms = sect->nelems; 729#ifdef DEBUG_SYMBOLS 730 printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms); 731#endif /* DEBUG_SYMBOLS */ 732 return 0; 733 } 734 } 735 } 736 for (i = 1; i < ef->shnum; i++) { 737 sect = &ef->sections[i]; 738 if (sect->type == SHT_DYNSYM) { 739 if (elf_read_symtab_section(ef, i) == 0) { 740 ef->symbols = sect->symbols; 741 ef->nsyms = sect->nelems; 742#ifdef DEBUG_SYMBOLS 743 printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms); 744#endif /* DEBUG_SYMBOLS */ 745 return 0; 746 } 747 } 748 } 749 return UWX_ERR_NOSYM; 750} 751 752 753#define SYM_IS_DEFINED(sym) \ 754 ((sym)->shndx != SHN_UNDEF) 755 756#define SYM_IS_IN_TEXT_SEGMENT(value) \ 757 ((value) >= ef->text_base && (value) < ef->text_end) 758 759#define SYM_HAS_INTERESTING_TYPE(type) ( \ 760 (type) == STT_FUNC || \ 761 (type) == STT_OBJECT || \ 762 (type) == STT_HP_STUB \ 763 ) 764 765#define SYM_IS_INTERESTING(sym) ( \ 766 SYM_IS_DEFINED(sym) && \ 767 SYM_IS_IN_TEXT_SEGMENT((sym)->value) && \ 768 SYM_HAS_INTERESTING_TYPE((sym)->type) \ 769 ) 770 771int uwx_read_func_symbols( 772 struct uwx_env *env, 773 struct uwx_symbol_cache *cache, 774 char *module_name) 775{ 776 int i, j; 777 int status; 778 struct elf_file *ef; 779 struct elf_symbol *sym; 780 int nfuncsyms; 781 char **names; 782 uint64_t *values; 783 784 if (module_name != NULL && 785 cache->module_name != NULL && 786 strcmp(module_name, cache->module_name) == 0) 787 return UWX_OK; 788 789 if (cache->sym_names != NULL) 790 (*env->free_cb)(cache->sym_names); 791 if (cache->sym_values != NULL) 792 (*env->free_cb)(cache->sym_values); 793 if (cache->strings != NULL) 794 (*env->free_cb)(cache->strings); 795 796 ef = elf_new(env); 797 if (ef == NULL) 798 return UWX_ERR_NOMEM; 799 status = elf_open(ef, module_name); 800 if (status != 0) 801 return UWX_ERR_NOSYM; 802 status = elf_read_symbols(ef); 803 if (status != 0) 804 return UWX_ERR_NOSYM; 805 806 nfuncsyms = 0; 807 for (i = 0; i < ef->nsyms; i++) { 808 sym = &ef->symbols[i]; 809 if (SYM_IS_INTERESTING(sym)) 810 nfuncsyms++; 811 } 812 813 names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *)); 814 if (names == NULL) 815 return UWX_ERR_NOMEM; 816 values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t)); 817 if (values == NULL) 818 return UWX_ERR_NOMEM; 819 820 j = 0; 821 for (i = 0; i < ef->nsyms; i++) { 822 sym = &ef->symbols[i]; 823 if (SYM_IS_INTERESTING(sym)) { 824 if (j >= nfuncsyms) /* should not happen! */ 825 break; 826 names[j] = sym->namep; 827 values[j] = sym->value - ef->text_base; 828 j++; 829 } 830 } 831 832 cache->module_name = (char *)(*env->allocate_cb)(strlen(module_name)+1); 833 if (cache->module_name != NULL) { 834 strcpy(cache->module_name, module_name); 835 cache->nsyms = nfuncsyms; 836 cache->sym_names = names; 837 cache->sym_values = values; 838 cache->strings = ef->symbol_strings; 839 ef->symbol_strings = NULL; 840 } 841 842 elf_close(ef); 843 elf_free(ef); 844 845#ifdef DEBUG_SYMBOLS 846 printf("Cached %d interesting symbols\n", nfuncsyms); 847#endif /* DEBUG_SYMBOLS */ 848 849 return UWX_OK; 850} 851