2 Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
25 #ifdef USE_CLEAN_NAMESPACE
29 #define fclose _fclose
30 #endif /* USE_CLEAN_NAMESPACE */
41 #ifdef USE_CLEAN_NAMESPACE
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 *);
55 #endif /* USE_CLEAN_NAMESPACE */
57 struct uwx_symbol_cache {
66 int uwx_read_func_symbols(
68 struct uwx_symbol_cache *cache,
74 struct uwx_symbol_cache **symbol_cache_p,
86 struct uwx_symbol_cache *cache = NULL;
88 /* Allocate a symbol cache on first call */
89 if (symbol_cache_p != NULL)
90 cache = *symbol_cache_p;
92 cache = (struct uwx_symbol_cache *)
93 (*env->allocate_cb)(sizeof(struct uwx_symbol_cache));
96 cache->module_name = NULL;
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;
105 /* Read function symbols from the object file */
106 status = uwx_read_func_symbols(env, cache, module_name);
107 if (status != UWX_OK)
110 /* Search for best match */
111 best_offset = ~(uint64_t)0;
113 for (i = 0; i < cache->nsyms; i++) {
114 if (cache->sym_values[i] == relip) {
115 *func_name_p = cache->sym_names[i];
117 if (symbol_cache_p == NULL)
118 uwx_release_symbol_cache(env, cache);
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];
129 if (best_name == NULL)
130 return UWX_ERR_NOSYM;
132 if (symbol_cache_p == NULL)
133 uwx_release_symbol_cache(env, cache);
135 *func_name_p = best_name;
136 *offset_p = best_offset;
141 void uwx_release_symbol_cache(
143 struct uwx_symbol_cache *symbol_cache)
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);
157 #define ELF_ERR_NOMEM UWX_ERR_NOMEM /* Out of memory */
158 #define ELF_ERR_OPEN UWX_ERR_NOSYM /* Can't open file */
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 */
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 */
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 */
172 #define ELF_ERR_READ_SECTION UWX_ERR_NOSYM /* Can't read section contents */
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 */
183 alloc_cb allocate_cb;
185 const char *filename;
187 struct elf_section *sections;
188 struct elf_symbol *symbols;
189 char *symbol_strings;
208 struct elf_symbol *symbols;
224 static void elf_swap_bytes(char *buf, char *template)
230 while (sz = *template++) {
233 for (i = 0; i < sz; i++)
235 for (i = 0; i < sz; i++)
236 buf[i] = temp[sz-i-1];
242 static int elf_read_section(struct elf_file *ef, int shndx)
244 struct elf_section *sect;
246 if (shndx < 0 || shndx > ef->shnum)
249 sect = &ef->sections[shndx];
251 /* Return if section has already been read */
252 if (sect->contents != NULL)
255 sect->contents = (*ef->allocate_cb)(sect->size);
256 if (sect->contents == NULL)
257 return ELF_ERR_NOMEM;
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;
267 static char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0};
268 static char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0};
270 static int elf_read_symtab_section(struct elf_file *ef, int shndx)
279 struct elf_section *sect;
280 struct elf_symbol *syms;
281 struct elf_symbol *symp;
284 sect = &ef->sections[shndx];
286 /* Return if section has already been read */
287 if (sect->symbols != NULL)
290 if (ef->source_class == ELFCLASS32) {
291 if (sect->entsize != sizeof(sym.sym32))
292 return ELF_ERR_SYMTAB_SIZE;
295 if (sect->entsize != sizeof(sym.sym64))
296 return ELF_ERR_SYMTAB_SIZE;
299 nsyms = sect->nelems;
300 syms = (struct elf_symbol *)
301 (*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms);
303 return ELF_ERR_NOMEM;
305 /* Read the symbol table */
306 fseek(ef->fd, (long)sect->offset, SEEK_SET);
307 for (i = 0; i < nsyms; i++) {
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;
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;
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;
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++) {
347 symp->namep = strtab + symp->name;
349 ef->symbol_strings = strtab;
350 ef->sections[sect->link].contents = NULL;
354 sect->symbols = syms;
359 static char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0};
360 static char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0};
362 static int elf_read_prog_hdrs(struct elf_file *ef)
371 uint64_t unwind_base;
377 if (ef->source_class == ELFCLASS32) {
378 if (ef->phentsize != sizeof(header.hdr32))
379 return ELF_ERR_PROGHDR_SIZE;
382 if (ef->phentsize != sizeof(header.hdr64))
383 return ELF_ERR_PROGHDR_SIZE;
386 /* Look for the PT_IA_64_UNWIND segment */
387 /* (That will help us identify the text segment) */
389 fseek(ef->fd, (long)ef->phoff, SEEK_SET);
390 for (i = 0; i < ef->phnum; i++) {
392 /* Read the next program header */
393 if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
394 return ELF_ERR_READ_PROGHDR;
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;
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;
412 if (type == PT_IA_64_UNWIND) {
419 /* Now look for the PT_LOAD segment that includes the unwind segment */
421 fseek(ef->fd, (long)ef->phoff, SEEK_SET);
422 for (i = 0; i < ef->phnum; i++) {
424 /* Read the next program header */
425 if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
426 return ELF_ERR_READ_PROGHDR;
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;
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;
446 if (type == PT_LOAD &&
447 vaddr <= unwind_base && unwind_base < vaddr + memsz) {
448 ef->text_base = vaddr;
449 ef->text_end = vaddr + memsz;
459 static char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0};
460 static char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0};
462 static int elf_read_sect_hdrs(struct elf_file *ef)
471 struct elf_section *sect;
474 if (ef->source_class == ELFCLASS32) {
475 if (ef->shentsize != sizeof(header.hdr32))
476 return ELF_ERR_SECTHDR_SIZE;
479 if (ef->shentsize != sizeof(header.hdr64))
480 return ELF_ERR_SECTHDR_SIZE;
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;
489 /* Read the section header table */
490 for (i = 0; i < ef->shnum; i++) {
492 sect = &ef->sections[i];
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;
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;
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;
527 sect->contents = NULL;
528 sect->symbols = NULL;
529 if (sect->entsize > 0)
530 sect->nelems = sect->size / sect->entsize;
538 static char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0};
539 static char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0};
541 static int elf_read_header(struct elf_file *ef)
544 char ident[EI_NIDENT];
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;
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;
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];
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;
573 if (header.ident[EI_DATA] != ELFDATA2LSB &&
574 header.ident[EI_DATA] != ELFDATA2MSB) {
575 return ELF_ERR_INVALID_DATA;
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;
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;
620 static struct elf_file *elf_new(struct uwx_env *env)
626 ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file));
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 */
635 ef->allocate_cb = env->allocate_cb;
636 ef->free_cb = env->free_cb;
638 ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB);
640 ef->source_class = 0;
653 ef->symbol_strings = NULL;
659 static int elf_open(struct elf_file *ef, const char *filename)
663 ef->filename = filename;
665 ef->fd = fopen(filename, "r");
669 if ((err = elf_read_header(ef)) != 0)
672 if ((err = elf_read_sect_hdrs(ef)) != 0)
675 if ((err = elf_read_prog_hdrs(ef)) != 0)
682 static void elf_free_sections(struct elf_file *ef)
685 struct elf_section *sect;
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);
695 (*ef->free_cb)(ef->sections);
699 static void elf_close(struct elf_file *ef)
701 if (ef->fd != NULL) {
708 static void elf_free(struct elf_file *ef)
711 if (ef->sections != NULL)
712 elf_free_sections(ef);
717 static int elf_read_symbols(struct elf_file *ef)
721 struct elf_section *sect;
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;
730 printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms);
731 #endif /* DEBUG_SYMBOLS */
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;
743 printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms);
744 #endif /* DEBUG_SYMBOLS */
749 return UWX_ERR_NOSYM;
753 #define SYM_IS_DEFINED(sym) \
754 ((sym)->shndx != SHN_UNDEF)
756 #define SYM_IS_IN_TEXT_SEGMENT(value) \
757 ((value) >= ef->text_base && (value) < ef->text_end)
759 #define SYM_HAS_INTERESTING_TYPE(type) ( \
760 (type) == STT_FUNC || \
761 (type) == STT_OBJECT || \
762 (type) == STT_HP_STUB \
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) \
771 int uwx_read_func_symbols(
773 struct uwx_symbol_cache *cache,
779 struct elf_symbol *sym;
784 if (module_name != NULL &&
785 cache->module_name != NULL &&
786 strcmp(module_name, cache->module_name) == 0)
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);
798 return UWX_ERR_NOMEM;
799 status = elf_open(ef, module_name);
801 return UWX_ERR_NOSYM;
802 status = elf_read_symbols(ef);
804 return UWX_ERR_NOSYM;
807 for (i = 0; i < ef->nsyms; i++) {
808 sym = &ef->symbols[i];
809 if (SYM_IS_INTERESTING(sym))
813 names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *));
815 return UWX_ERR_NOMEM;
816 values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t));
818 return UWX_ERR_NOMEM;
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! */
826 names[j] = sym->namep;
827 values[j] = sym->value - ef->text_base;
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;
846 printf("Cached %d interesting symbols\n", nfuncsyms);
847 #endif /* DEBUG_SYMBOLS */