1160157Smarcel/* 2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P. 3160157SmarcelPermission is hereby granted, free of charge, to any person 4160157Smarcelobtaining a copy of this software and associated documentation 5160157Smarcelfiles (the "Software"), to deal in the Software without 6160157Smarcelrestriction, including without limitation the rights to use, 7160157Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell 8160157Smarcelcopies of the Software, and to permit persons to whom the 9160157SmarcelSoftware is furnished to do so, subject to the following 10160157Smarcelconditions: 11160157Smarcel 12160157SmarcelThe above copyright notice and this permission notice shall be 13160157Smarcelincluded in all copies or substantial portions of the Software. 14160157Smarcel 15160157SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16160157SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17160157SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18160157SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19160157SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20160157SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21160157SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22160157SmarcelOTHER DEALINGS IN THE SOFTWARE. 23160157Smarcel*/ 24160157Smarcel 25160157Smarcel#ifdef USE_CLEAN_NAMESPACE 26160157Smarcel#define fopen _fopen 27160157Smarcel#define fseek _fseek 28160157Smarcel#define fread _fread 29160157Smarcel#define fclose _fclose 30160157Smarcel#endif /* USE_CLEAN_NAMESPACE */ 31160157Smarcel 32160157Smarcel#include <stdio.h> 33160157Smarcel#include <stdlib.h> 34160157Smarcel#include <string.h> 35160157Smarcel#include <inttypes.h> 36160157Smarcel#include <elf.h> 37160157Smarcel 38160157Smarcel#include "uwx.h" 39160157Smarcel#include "uwx_env.h" 40160157Smarcel 41160157Smarcel#ifdef USE_CLEAN_NAMESPACE 42160157Smarcel/* 43160157Smarcel * Moved the defines above the include of stdio.h, 44160157Smarcel * so we don't need these unless that causes problems 45160157Smarcel * and we have to move them back down here. 46160157Smarcel * #define fopen _fopen 47160157Smarcel * #define fseek _fseek 48160157Smarcel * #define fread _fread 49160157Smarcel * #define fclose _fclose 50160157Smarcel * extern FILE *_fopen(const char *, const char *); 51160157Smarcel * extern int _fseek(FILE *, long int, int); 52160157Smarcel * extern size_t _fread(void *, size_t, size_t, FILE *); 53160157Smarcel * extern int _fclose(FILE *); 54160157Smarcel */ 55160157Smarcel#endif /* USE_CLEAN_NAMESPACE */ 56160157Smarcel 57160157Smarcelstruct uwx_symbol_cache { 58160157Smarcel char *module_name; 59160157Smarcel int nsyms; 60160157Smarcel uint64_t *sym_values; 61160157Smarcel char **sym_names; 62160157Smarcel char *strings; 63160157Smarcel}; 64160157Smarcel 65160157Smarcel 66160157Smarcelint uwx_read_func_symbols( 67160157Smarcel struct uwx_env *env, 68160157Smarcel struct uwx_symbol_cache *cache, 69160157Smarcel char *module_name); 70160157Smarcel 71160157Smarcel 72160157Smarcelint uwx_find_symbol( 73160157Smarcel struct uwx_env *env, 74160157Smarcel struct uwx_symbol_cache **symbol_cache_p, 75160157Smarcel char *module_name, 76160157Smarcel uint64_t relip, 77160157Smarcel char **func_name_p, 78160157Smarcel uint64_t *offset_p) 79160157Smarcel{ 80160157Smarcel int status; 81160157Smarcel int i; 82160157Smarcel uint64_t offset; 83160157Smarcel uint64_t best_offset; 84160157Smarcel char *best_name; 85160157Smarcel struct symbol *sym; 86160157Smarcel struct uwx_symbol_cache *cache = NULL; 87160157Smarcel 88160157Smarcel /* Allocate a symbol cache on first call */ 89160157Smarcel if (symbol_cache_p != NULL) 90160157Smarcel cache = *symbol_cache_p; 91160157Smarcel if (cache == NULL) { 92160157Smarcel cache = (struct uwx_symbol_cache *) 93160157Smarcel (*env->allocate_cb)(sizeof(struct uwx_symbol_cache)); 94160157Smarcel if (cache == NULL) 95160157Smarcel return UWX_ERR_NOMEM; 96160157Smarcel cache->module_name = NULL; 97160157Smarcel cache->nsyms = 0; 98160157Smarcel cache->sym_values = NULL; 99160157Smarcel cache->sym_names = NULL; 100160157Smarcel cache->strings = NULL; 101160157Smarcel if (symbol_cache_p != NULL) 102160157Smarcel *symbol_cache_p = cache; 103160157Smarcel } 104160157Smarcel 105160157Smarcel /* Read function symbols from the object file */ 106160157Smarcel status = uwx_read_func_symbols(env, cache, module_name); 107160157Smarcel if (status != UWX_OK) 108160157Smarcel return status; 109160157Smarcel 110160157Smarcel /* Search for best match */ 111160157Smarcel best_offset = ~(uint64_t)0; 112160157Smarcel best_name = NULL; 113160157Smarcel for (i = 0; i < cache->nsyms; i++) { 114160157Smarcel if (cache->sym_values[i] == relip) { 115160157Smarcel *func_name_p = cache->sym_names[i]; 116160157Smarcel *offset_p = 0; 117160157Smarcel if (symbol_cache_p == NULL) 118160157Smarcel uwx_release_symbol_cache(env, cache); 119160157Smarcel return UWX_OK; 120160157Smarcel } 121160157Smarcel if (relip > cache->sym_values[i]) { 122160157Smarcel offset = relip - cache->sym_values[i]; 123160157Smarcel if (offset < best_offset) { 124160157Smarcel best_offset = offset; 125160157Smarcel best_name = cache->sym_names[i]; 126160157Smarcel } 127160157Smarcel } 128160157Smarcel } 129160157Smarcel if (best_name == NULL) 130160157Smarcel return UWX_ERR_NOSYM; 131160157Smarcel 132160157Smarcel if (symbol_cache_p == NULL) 133160157Smarcel uwx_release_symbol_cache(env, cache); 134160157Smarcel 135160157Smarcel *func_name_p = best_name; 136160157Smarcel *offset_p = best_offset; 137160157Smarcel return UWX_OK; 138160157Smarcel} 139160157Smarcel 140160157Smarcel 141160157Smarcelvoid uwx_release_symbol_cache( 142160157Smarcel struct uwx_env *env, 143160157Smarcel struct uwx_symbol_cache *symbol_cache) 144160157Smarcel{ 145160157Smarcel if (symbol_cache->module_name != NULL) 146160157Smarcel (*env->free_cb)(symbol_cache->module_name); 147160157Smarcel if (symbol_cache->sym_values != NULL) 148160157Smarcel (*env->free_cb)(symbol_cache->sym_values); 149160157Smarcel if (symbol_cache->sym_names != NULL) 150160157Smarcel (*env->free_cb)(symbol_cache->sym_names); 151160157Smarcel if (symbol_cache->strings != NULL) 152160157Smarcel (*env->free_cb)(symbol_cache->strings); 153160157Smarcel (*env->free_cb)(symbol_cache); 154160157Smarcel} 155160157Smarcel 156160157Smarcel 157160157Smarcel#define ELF_ERR_NOMEM UWX_ERR_NOMEM /* Out of memory */ 158160157Smarcel#define ELF_ERR_OPEN UWX_ERR_NOSYM /* Can't open file */ 159160157Smarcel 160160157Smarcel#define ELF_ERR_NOHEADER UWX_ERR_NOSYM /* Can't read ELF header */ 161160157Smarcel#define ELF_ERR_NOTELF UWX_ERR_NOSYM /* Not an ELF file */ 162160157Smarcel#define ELF_ERR_HEADER_SIZE UWX_ERR_NOSYM /* Invalid e_ehsize */ 163160157Smarcel#define ELF_ERR_INVALID_CLASS UWX_ERR_NOSYM /* Invalid EI_CLASS */ 164160157Smarcel#define ELF_ERR_INVALID_DATA UWX_ERR_NOSYM /* Invalid EI_DATA */ 165160157Smarcel 166160157Smarcel#define ELF_ERR_READ_SECTHDR UWX_ERR_NOSYM /* Can't read section headers */ 167160157Smarcel#define ELF_ERR_SECTHDR_SIZE UWX_ERR_NOSYM /* Invalid e_shentsize */ 168160157Smarcel 169160157Smarcel#define ELF_ERR_READ_PROGHDR UWX_ERR_NOSYM /* Can't read program headers */ 170160157Smarcel#define ELF_ERR_PROGHDR_SIZE UWX_ERR_NOSYM /* Invalid e_phentsize */ 171160157Smarcel 172160157Smarcel#define ELF_ERR_READ_SECTION UWX_ERR_NOSYM /* Can't read section contents */ 173160157Smarcel 174160157Smarcel#define ELF_ERR_READ_SYMTAB UWX_ERR_NOSYM /* Can't read symbol table */ 175160157Smarcel#define ELF_ERR_SYMTAB_SIZE UWX_ERR_NOSYM /* Invalid sh_entsize for symtab */ 176160157Smarcel 177160157Smarcel 178160157Smarcelstruct elf_file { 179160157Smarcel uint64_t phoff; 180160157Smarcel uint64_t shoff; 181160157Smarcel uint64_t text_base; 182160157Smarcel uint64_t text_end; 183160157Smarcel alloc_cb allocate_cb; 184160157Smarcel free_cb free_cb; 185160157Smarcel const char *filename; 186160157Smarcel FILE *fd; 187160157Smarcel struct elf_section *sections; 188160157Smarcel struct elf_symbol *symbols; 189160157Smarcel char *symbol_strings; 190160157Smarcel int native_data; 191160157Smarcel int source_class; 192160157Smarcel int source_data; 193160157Smarcel int ehsize; 194160157Smarcel int phentsize; 195160157Smarcel int phnum; 196160157Smarcel int shentsize; 197160157Smarcel int shnum; 198160157Smarcel int nsyms; 199160157Smarcel}; 200160157Smarcel 201160157Smarcelstruct elf_section { 202160157Smarcel uint64_t flags; 203160157Smarcel uint64_t addr; 204160157Smarcel uint64_t offset; 205160157Smarcel uint64_t size; 206160157Smarcel uint64_t entsize; 207160157Smarcel char *contents; 208160157Smarcel struct elf_symbol *symbols; 209160157Smarcel int type; 210160157Smarcel int link; 211160157Smarcel int info; 212160157Smarcel int nelems; 213160157Smarcel}; 214160157Smarcel 215160157Smarcelstruct elf_symbol { 216160157Smarcel uint64_t value; 217160157Smarcel char *namep; 218160157Smarcel int name; 219160157Smarcel int type; 220160157Smarcel int shndx; 221160157Smarcel}; 222160157Smarcel 223160157Smarcel 224160157Smarcelstatic void elf_swap_bytes(char *buf, char *template) 225160157Smarcel{ 226160157Smarcel int i; 227160157Smarcel int sz; 228160157Smarcel char temp[16]; 229160157Smarcel 230160157Smarcel while (sz = *template++) { 231160157Smarcel if (sz > 16) 232160157Smarcel exit(1); 233160157Smarcel for (i = 0; i < sz; i++) 234160157Smarcel temp[i] = buf[i]; 235160157Smarcel for (i = 0; i < sz; i++) 236160157Smarcel buf[i] = temp[sz-i-1]; 237160157Smarcel buf += sz; 238160157Smarcel } 239160157Smarcel} 240160157Smarcel 241160157Smarcel 242160157Smarcelstatic int elf_read_section(struct elf_file *ef, int shndx) 243160157Smarcel{ 244160157Smarcel struct elf_section *sect; 245160157Smarcel 246160157Smarcel if (shndx < 0 || shndx > ef->shnum) 247160157Smarcel return 0; 248160157Smarcel 249160157Smarcel sect = &ef->sections[shndx]; 250160157Smarcel 251160157Smarcel /* Return if section has already been read */ 252160157Smarcel if (sect->contents != NULL) 253160157Smarcel return 0; 254160157Smarcel 255160157Smarcel sect->contents = (*ef->allocate_cb)(sect->size); 256160157Smarcel if (sect->contents == NULL) 257160157Smarcel return ELF_ERR_NOMEM; 258160157Smarcel 259160157Smarcel fseek(ef->fd, (long)sect->offset, SEEK_SET); 260160157Smarcel if (fread(sect->contents, 1, sect->size, ef->fd) != sect->size) 261160157Smarcel return ELF_ERR_READ_SECTION; 262160157Smarcel 263160157Smarcel return 0; 264160157Smarcel} 265160157Smarcel 266160157Smarcel 267160157Smarcelstatic char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0}; 268160157Smarcelstatic char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0}; 269160157Smarcel 270160157Smarcelstatic int elf_read_symtab_section(struct elf_file *ef, int shndx) 271160157Smarcel{ 272160157Smarcel int i; 273160157Smarcel int nsyms; 274160157Smarcel long size; 275160157Smarcel union { 276160157Smarcel Elf32_Sym sym32; 277160157Smarcel Elf64_Sym sym64; 278160157Smarcel } sym; 279160157Smarcel struct elf_section *sect; 280160157Smarcel struct elf_symbol *syms; 281160157Smarcel struct elf_symbol *symp; 282160157Smarcel char *strtab; 283160157Smarcel 284160157Smarcel sect = &ef->sections[shndx]; 285160157Smarcel 286160157Smarcel /* Return if section has already been read */ 287160157Smarcel if (sect->symbols != NULL) 288160157Smarcel return 0; 289160157Smarcel 290160157Smarcel if (ef->source_class == ELFCLASS32) { 291160157Smarcel if (sect->entsize != sizeof(sym.sym32)) 292160157Smarcel return ELF_ERR_SYMTAB_SIZE; 293160157Smarcel } 294160157Smarcel else { 295160157Smarcel if (sect->entsize != sizeof(sym.sym64)) 296160157Smarcel return ELF_ERR_SYMTAB_SIZE; 297160157Smarcel } 298160157Smarcel 299160157Smarcel nsyms = sect->nelems; 300160157Smarcel syms = (struct elf_symbol *) 301160157Smarcel (*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms); 302160157Smarcel if (syms == NULL) 303160157Smarcel return ELF_ERR_NOMEM; 304160157Smarcel 305160157Smarcel /* Read the symbol table */ 306160157Smarcel fseek(ef->fd, (long)sect->offset, SEEK_SET); 307160157Smarcel for (i = 0; i < nsyms; i++) { 308160157Smarcel 309160157Smarcel symp = &syms[i]; 310160157Smarcel 311160157Smarcel /* Read the next symbol table entry */ 312160157Smarcel if (fread((char *)&sym, sect->entsize, 1, ef->fd) != 1) { 313160157Smarcel (*ef->free_cb)(syms); 314160157Smarcel return ELF_ERR_READ_SYMTAB; 315160157Smarcel } 316160157Smarcel 317160157Smarcel /* Get fields from appropriate structure */ 318160157Smarcel if (ef->source_class == ELFCLASS32) { 319160157Smarcel /* Swap bytes if necessary */ 320160157Smarcel if (ef->source_data != ef->native_data) 321160157Smarcel elf_swap_bytes((char *)&sym, template_elf32_sym); 322160157Smarcel symp->name = sym.sym32.st_name; 323160157Smarcel symp->type = sym.sym32.st_info & 0x0f; 324160157Smarcel symp->shndx = sym.sym32.st_shndx; 325160157Smarcel symp->value = sym.sym32.st_value; 326160157Smarcel } 327160157Smarcel else { 328160157Smarcel /* Swap bytes if necessary */ 329160157Smarcel if (ef->source_data != ef->native_data) 330160157Smarcel elf_swap_bytes((char *)&sym, template_elf64_sym); 331160157Smarcel symp->name = sym.sym64.st_name; 332160157Smarcel symp->type = sym.sym64.st_info & 0x0f; 333160157Smarcel symp->shndx = sym.sym64.st_shndx; 334160157Smarcel symp->value = sym.sym64.st_value; 335160157Smarcel } 336160157Smarcel symp->namep = NULL; 337160157Smarcel 338160157Smarcel } 339160157Smarcel 340160157Smarcel /* Read the symbol string table and convert section names */ 341160157Smarcel /* from string table offsets to pointers */ 342160157Smarcel if (sect->link > 0 && sect->link < ef->shnum) { 343160157Smarcel if (elf_read_section(ef, sect->link) == 0) { 344160157Smarcel strtab = ef->sections[sect->link].contents; 345160157Smarcel for (i = 0; i < nsyms; i++) { 346160157Smarcel symp = &syms[i]; 347160157Smarcel symp->namep = strtab + symp->name; 348160157Smarcel } 349160157Smarcel ef->symbol_strings = strtab; 350160157Smarcel ef->sections[sect->link].contents = NULL; 351160157Smarcel } 352160157Smarcel } 353160157Smarcel 354160157Smarcel sect->symbols = syms; 355160157Smarcel return 0; 356160157Smarcel} 357160157Smarcel 358160157Smarcel 359160157Smarcelstatic char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0}; 360160157Smarcelstatic char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0}; 361160157Smarcel 362160157Smarcelstatic int elf_read_prog_hdrs(struct elf_file *ef) 363160157Smarcel{ 364160157Smarcel int i; 365160157Smarcel union { 366160157Smarcel Elf32_Phdr hdr32; 367160157Smarcel Elf64_Phdr hdr64; 368160157Smarcel } header; 369160157Smarcel uint64_t vaddr; 370160157Smarcel uint64_t memsz; 371160157Smarcel uint64_t unwind_base; 372160157Smarcel int type; 373160157Smarcel 374160157Smarcel if (ef->phnum == 0) 375160157Smarcel return 0; 376160157Smarcel 377160157Smarcel if (ef->source_class == ELFCLASS32) { 378160157Smarcel if (ef->phentsize != sizeof(header.hdr32)) 379160157Smarcel return ELF_ERR_PROGHDR_SIZE; 380160157Smarcel } 381160157Smarcel else { 382160157Smarcel if (ef->phentsize != sizeof(header.hdr64)) 383160157Smarcel return ELF_ERR_PROGHDR_SIZE; 384160157Smarcel } 385160157Smarcel 386160157Smarcel /* Look for the PT_IA_64_UNWIND segment */ 387160157Smarcel /* (That will help us identify the text segment) */ 388160157Smarcel 389160157Smarcel fseek(ef->fd, (long)ef->phoff, SEEK_SET); 390160157Smarcel for (i = 0; i < ef->phnum; i++) { 391160157Smarcel 392160157Smarcel /* Read the next program header */ 393160157Smarcel if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1) 394160157Smarcel return ELF_ERR_READ_PROGHDR; 395160157Smarcel 396160157Smarcel /* Get fields from appropriate structure */ 397160157Smarcel if (ef->source_class == ELFCLASS32) { 398160157Smarcel /* Swap bytes in header fields if necessary */ 399160157Smarcel if (ef->source_data != ef->native_data) 400160157Smarcel elf_swap_bytes((char *)&header, template_elf32_phdr); 401160157Smarcel type = header.hdr32.p_type; 402160157Smarcel vaddr = header.hdr32.p_vaddr; 403160157Smarcel } 404160157Smarcel else { 405160157Smarcel /* Swap bytes in header fields if necessary */ 406160157Smarcel if (ef->source_data != ef->native_data) 407160157Smarcel elf_swap_bytes((char *)&header, template_elf64_phdr); 408160157Smarcel type = header.hdr64.p_type; 409160157Smarcel vaddr = header.hdr64.p_vaddr; 410160157Smarcel } 411160157Smarcel 412160157Smarcel if (type == PT_IA_64_UNWIND) { 413160157Smarcel unwind_base = vaddr; 414160157Smarcel break; 415160157Smarcel } 416160157Smarcel 417160157Smarcel } 418160157Smarcel 419160157Smarcel /* Now look for the PT_LOAD segment that includes the unwind segment */ 420160157Smarcel 421160157Smarcel fseek(ef->fd, (long)ef->phoff, SEEK_SET); 422160157Smarcel for (i = 0; i < ef->phnum; i++) { 423160157Smarcel 424160157Smarcel /* Read the next program header */ 425160157Smarcel if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1) 426160157Smarcel return ELF_ERR_READ_PROGHDR; 427160157Smarcel 428160157Smarcel /* Get fields from appropriate structure */ 429160157Smarcel if (ef->source_class == ELFCLASS32) { 430160157Smarcel /* Swap bytes in header fields if necessary */ 431160157Smarcel if (ef->source_data != ef->native_data) 432160157Smarcel elf_swap_bytes((char *)&header, template_elf32_phdr); 433160157Smarcel type = header.hdr32.p_type; 434160157Smarcel vaddr = header.hdr32.p_vaddr; 435160157Smarcel memsz = header.hdr32.p_memsz; 436160157Smarcel } 437160157Smarcel else { 438160157Smarcel /* Swap bytes in header fields if necessary */ 439160157Smarcel if (ef->source_data != ef->native_data) 440160157Smarcel elf_swap_bytes((char *)&header, template_elf64_phdr); 441160157Smarcel type = header.hdr64.p_type; 442160157Smarcel vaddr = header.hdr64.p_vaddr; 443160157Smarcel memsz = header.hdr64.p_memsz; 444160157Smarcel } 445160157Smarcel 446160157Smarcel if (type == PT_LOAD && 447160157Smarcel vaddr <= unwind_base && unwind_base < vaddr + memsz) { 448160157Smarcel ef->text_base = vaddr; 449160157Smarcel ef->text_end = vaddr + memsz; 450160157Smarcel break; 451160157Smarcel } 452160157Smarcel 453160157Smarcel } 454160157Smarcel 455160157Smarcel return 0; 456160157Smarcel} 457160157Smarcel 458160157Smarcel 459160157Smarcelstatic char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0}; 460160157Smarcelstatic char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0}; 461160157Smarcel 462160157Smarcelstatic int elf_read_sect_hdrs(struct elf_file *ef) 463160157Smarcel{ 464160157Smarcel int i; 465160157Smarcel long size; 466160157Smarcel int err; 467160157Smarcel union { 468160157Smarcel Elf32_Shdr hdr32; 469160157Smarcel Elf64_Shdr hdr64; 470160157Smarcel } header; 471160157Smarcel struct elf_section *sect; 472160157Smarcel char *shstrtab; 473160157Smarcel 474160157Smarcel if (ef->source_class == ELFCLASS32) { 475160157Smarcel if (ef->shentsize != sizeof(header.hdr32)) 476160157Smarcel return ELF_ERR_SECTHDR_SIZE; 477160157Smarcel } 478160157Smarcel else { 479160157Smarcel if (ef->shentsize != sizeof(header.hdr64)) 480160157Smarcel return ELF_ERR_SECTHDR_SIZE; 481160157Smarcel } 482160157Smarcel 483160157Smarcel fseek(ef->fd, (long)ef->shoff, SEEK_SET); 484160157Smarcel ef->sections = (struct elf_section *) 485160157Smarcel (*ef->allocate_cb)(sizeof(struct elf_section) * ef->shnum); 486160157Smarcel if (ef->sections == NULL) 487160157Smarcel return ELF_ERR_NOMEM; 488160157Smarcel 489160157Smarcel /* Read the section header table */ 490160157Smarcel for (i = 0; i < ef->shnum; i++) { 491160157Smarcel 492160157Smarcel sect = &ef->sections[i]; 493160157Smarcel 494160157Smarcel /* Read the next section header */ 495160157Smarcel if (fread((char *)&header, ef->shentsize, 1, ef->fd) != 1) { 496160157Smarcel (*ef->free_cb)(ef->sections); 497160157Smarcel return ELF_ERR_READ_SECTHDR; 498160157Smarcel } 499160157Smarcel 500160157Smarcel /* Get fields from appropriate structure */ 501160157Smarcel if (ef->source_class == ELFCLASS32) { 502160157Smarcel /* Swap bytes in header fields if necessary */ 503160157Smarcel if (ef->source_data != ef->native_data) 504160157Smarcel elf_swap_bytes((char *)&header, template_elf32_shdr); 505160157Smarcel sect->type = header.hdr32.sh_type; 506160157Smarcel sect->flags = header.hdr32.sh_flags; 507160157Smarcel sect->addr = header.hdr32.sh_addr; 508160157Smarcel sect->offset = header.hdr32.sh_offset; 509160157Smarcel sect->size = header.hdr32.sh_size; 510160157Smarcel sect->link = header.hdr32.sh_link; 511160157Smarcel sect->info = header.hdr32.sh_info; 512160157Smarcel sect->entsize = header.hdr32.sh_entsize; 513160157Smarcel } 514160157Smarcel else { 515160157Smarcel /* Swap bytes in header fields if necessary */ 516160157Smarcel if (ef->source_data != ef->native_data) 517160157Smarcel elf_swap_bytes((char *)&header, template_elf64_shdr); 518160157Smarcel sect->type = header.hdr64.sh_type; 519160157Smarcel sect->flags = header.hdr64.sh_flags; 520160157Smarcel sect->addr = header.hdr64.sh_addr; 521160157Smarcel sect->offset = header.hdr64.sh_offset; 522160157Smarcel sect->size = header.hdr64.sh_size; 523160157Smarcel sect->link = header.hdr64.sh_link; 524160157Smarcel sect->info = header.hdr64.sh_info; 525160157Smarcel sect->entsize = header.hdr64.sh_entsize; 526160157Smarcel } 527160157Smarcel sect->contents = NULL; 528160157Smarcel sect->symbols = NULL; 529160157Smarcel if (sect->entsize > 0) 530160157Smarcel sect->nelems = sect->size / sect->entsize; 531160157Smarcel 532160157Smarcel } 533160157Smarcel 534160157Smarcel return 0; 535160157Smarcel} 536160157Smarcel 537160157Smarcel 538160157Smarcelstatic char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0}; 539160157Smarcelstatic char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0}; 540160157Smarcel 541160157Smarcelstatic int elf_read_header(struct elf_file *ef) 542160157Smarcel{ 543160157Smarcel union { 544160157Smarcel char ident[EI_NIDENT]; 545160157Smarcel Elf32_Ehdr hdr32; 546160157Smarcel Elf64_Ehdr hdr64; 547160157Smarcel } header; 548160157Smarcel 549160157Smarcel /* Read the ELF header */ 550160157Smarcel fseek(ef->fd, 0L, SEEK_SET); 551160157Smarcel if (fread((char *)header.ident, EI_NIDENT, 1, ef->fd) != 1) { 552160157Smarcel return ELF_ERR_NOHEADER; 553160157Smarcel } 554160157Smarcel 555160157Smarcel /* Verify that this is an ELF file */ 556160157Smarcel if (header.ident[EI_MAG0] != ELFMAG0 || 557160157Smarcel header.ident[EI_MAG1] != ELFMAG1 || 558160157Smarcel header.ident[EI_MAG2] != ELFMAG2 || 559160157Smarcel header.ident[EI_MAG3] != ELFMAG3) { 560160157Smarcel return ELF_ERR_NOTELF; 561160157Smarcel } 562160157Smarcel 563160157Smarcel /* Get header fields from the byte array e_ident */ 564160157Smarcel /* (These are independent of EI_CLASS and EI_DATA) */ 565160157Smarcel ef->source_class = header.ident[EI_CLASS]; 566160157Smarcel ef->source_data = header.ident[EI_DATA]; 567160157Smarcel 568160157Smarcel /* Verify EI_CLASS and EI_DATA */ 569160157Smarcel if (header.ident[EI_CLASS] != ELFCLASS32 && 570160157Smarcel header.ident[EI_CLASS] != ELFCLASS64) { 571160157Smarcel return ELF_ERR_INVALID_CLASS; 572160157Smarcel } 573160157Smarcel if (header.ident[EI_DATA] != ELFDATA2LSB && 574160157Smarcel header.ident[EI_DATA] != ELFDATA2MSB) { 575160157Smarcel return ELF_ERR_INVALID_DATA; 576160157Smarcel } 577160157Smarcel 578160157Smarcel /* Get remaining header fields from appropriate structure */ 579160157Smarcel if (ef->source_class == ELFCLASS32) { 580160157Smarcel if (fread((char *)&header.hdr32 + EI_NIDENT, 581160157Smarcel sizeof(header.hdr32) - EI_NIDENT, 1, ef->fd) != 1) 582160157Smarcel return ELF_ERR_NOHEADER; 583160157Smarcel /* Swap bytes in header fields if necessary */ 584160157Smarcel if (ef->source_data != ef->native_data) 585160157Smarcel elf_swap_bytes((char *)&header + EI_NIDENT, template_elf32_ehdr); 586160157Smarcel ef->phoff = header.hdr32.e_phoff; 587160157Smarcel ef->shoff = header.hdr32.e_shoff; 588160157Smarcel ef->ehsize = header.hdr32.e_ehsize; 589160157Smarcel ef->phentsize = header.hdr32.e_phentsize; 590160157Smarcel ef->phnum = header.hdr32.e_phnum; 591160157Smarcel ef->shentsize = header.hdr32.e_shentsize; 592160157Smarcel ef->shnum = header.hdr32.e_shnum; 593160157Smarcel if (ef->ehsize != sizeof(header.hdr32)) { 594160157Smarcel return ELF_ERR_HEADER_SIZE; 595160157Smarcel } 596160157Smarcel } 597160157Smarcel else { 598160157Smarcel if (fread((char *)&header.hdr64 + EI_NIDENT, 599160157Smarcel sizeof(header.hdr64) - EI_NIDENT, 1, ef->fd) != 1) 600160157Smarcel return ELF_ERR_NOHEADER; 601160157Smarcel /* Swap bytes in header fields if necessary */ 602160157Smarcel if (ef->source_data != ef->native_data) 603160157Smarcel elf_swap_bytes((char *)&header + EI_NIDENT, template_elf64_ehdr); 604160157Smarcel ef->phoff = header.hdr64.e_phoff; 605160157Smarcel ef->shoff = header.hdr64.e_shoff; 606160157Smarcel ef->ehsize = header.hdr64.e_ehsize; 607160157Smarcel ef->phentsize = header.hdr64.e_phentsize; 608160157Smarcel ef->phnum = header.hdr64.e_phnum; 609160157Smarcel ef->shentsize = header.hdr64.e_shentsize; 610160157Smarcel ef->shnum = header.hdr64.e_shnum; 611160157Smarcel if (ef->ehsize != sizeof(header.hdr64)) { 612160157Smarcel return ELF_ERR_HEADER_SIZE; 613160157Smarcel } 614160157Smarcel } 615160157Smarcel 616160157Smarcel return 0; 617160157Smarcel} 618160157Smarcel 619160157Smarcel 620160157Smarcelstatic struct elf_file *elf_new(struct uwx_env *env) 621160157Smarcel{ 622160157Smarcel int native_be; 623160157Smarcel char *p; 624160157Smarcel struct elf_file *ef; 625160157Smarcel 626160157Smarcel ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file)); 627160157Smarcel if (ef == NULL) 628160157Smarcel return NULL; 629160157Smarcel 630160157Smarcel /* Determine the native byte order */ 631160157Smarcel p = (char *)&native_be; 632160157Smarcel native_be = 1; /* Assume big-endian */ 633160157Smarcel *p = 0; /* Sets be == 0 only if little-endian */ 634160157Smarcel 635160157Smarcel ef->allocate_cb = env->allocate_cb; 636160157Smarcel ef->free_cb = env->free_cb; 637160157Smarcel ef->filename = NULL; 638160157Smarcel ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB); 639160157Smarcel ef->fd = NULL; 640160157Smarcel ef->source_class = 0; 641160157Smarcel ef->source_data = 0; 642160157Smarcel ef->phoff = 0; 643160157Smarcel ef->shoff = 0; 644160157Smarcel ef->text_base = 0; 645160157Smarcel ef->text_end = 0; 646160157Smarcel ef->ehsize = 0; 647160157Smarcel ef->phentsize = 0; 648160157Smarcel ef->phnum = 0; 649160157Smarcel ef->shentsize = 0; 650160157Smarcel ef->shnum = 0; 651160157Smarcel ef->sections = NULL; 652160157Smarcel ef->symbols = NULL; 653160157Smarcel ef->symbol_strings = NULL; 654160157Smarcel ef->nsyms = 0; 655160157Smarcel return ef; 656160157Smarcel} 657160157Smarcel 658160157Smarcel 659160157Smarcelstatic int elf_open(struct elf_file *ef, const char *filename) 660160157Smarcel{ 661160157Smarcel int err; 662160157Smarcel 663160157Smarcel ef->filename = filename; 664160157Smarcel 665160157Smarcel ef->fd = fopen(filename, "r"); 666160157Smarcel if (ef->fd == NULL) 667160157Smarcel return ELF_ERR_OPEN; 668160157Smarcel 669160157Smarcel if ((err = elf_read_header(ef)) != 0) 670160157Smarcel return err; 671160157Smarcel 672160157Smarcel if ((err = elf_read_sect_hdrs(ef)) != 0) 673160157Smarcel return err; 674160157Smarcel 675160157Smarcel if ((err = elf_read_prog_hdrs(ef)) != 0) 676160157Smarcel return err; 677160157Smarcel 678160157Smarcel return 0; 679160157Smarcel} 680160157Smarcel 681160157Smarcel 682160157Smarcelstatic void elf_free_sections(struct elf_file *ef) 683160157Smarcel{ 684160157Smarcel int i; 685160157Smarcel struct elf_section *sect; 686160157Smarcel 687160157Smarcel for (i = 0; i < ef->shnum; i++) { 688160157Smarcel sect = &ef->sections[i]; 689160157Smarcel if (sect->contents != NULL) 690160157Smarcel (*ef->free_cb)(sect->contents); 691160157Smarcel if ((sect->type == SHT_SYMTAB || sect->type == SHT_DYNSYM) 692160157Smarcel && sect->symbols != NULL) 693160157Smarcel (*ef->free_cb)(sect->symbols); 694160157Smarcel } 695160157Smarcel (*ef->free_cb)(ef->sections); 696160157Smarcel} 697160157Smarcel 698160157Smarcel 699160157Smarcelstatic void elf_close(struct elf_file *ef) 700160157Smarcel{ 701160157Smarcel if (ef->fd != NULL) { 702160157Smarcel fclose(ef->fd); 703160157Smarcel ef->fd = NULL; 704160157Smarcel } 705160157Smarcel} 706160157Smarcel 707160157Smarcel 708160157Smarcelstatic void elf_free(struct elf_file *ef) 709160157Smarcel{ 710160157Smarcel elf_close(ef); 711160157Smarcel if (ef->sections != NULL) 712160157Smarcel elf_free_sections(ef); 713160157Smarcel (*ef->free_cb)(ef); 714160157Smarcel} 715160157Smarcel 716160157Smarcel 717160157Smarcelstatic int elf_read_symbols(struct elf_file *ef) 718160157Smarcel{ 719160157Smarcel int i; 720160157Smarcel int err; 721160157Smarcel struct elf_section *sect; 722160157Smarcel 723160157Smarcel for (i = 1; i < ef->shnum; i++) { 724160157Smarcel sect = &ef->sections[i]; 725160157Smarcel if (sect->type == SHT_SYMTAB) { 726160157Smarcel if (elf_read_symtab_section(ef, i) == 0) { 727160157Smarcel ef->symbols = sect->symbols; 728160157Smarcel ef->nsyms = sect->nelems; 729160157Smarcel#ifdef DEBUG_SYMBOLS 730160157Smarcel printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms); 731160157Smarcel#endif /* DEBUG_SYMBOLS */ 732160157Smarcel return 0; 733160157Smarcel } 734160157Smarcel } 735160157Smarcel } 736160157Smarcel for (i = 1; i < ef->shnum; i++) { 737160157Smarcel sect = &ef->sections[i]; 738160157Smarcel if (sect->type == SHT_DYNSYM) { 739160157Smarcel if (elf_read_symtab_section(ef, i) == 0) { 740160157Smarcel ef->symbols = sect->symbols; 741160157Smarcel ef->nsyms = sect->nelems; 742160157Smarcel#ifdef DEBUG_SYMBOLS 743160157Smarcel printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms); 744160157Smarcel#endif /* DEBUG_SYMBOLS */ 745160157Smarcel return 0; 746160157Smarcel } 747160157Smarcel } 748160157Smarcel } 749160157Smarcel return UWX_ERR_NOSYM; 750160157Smarcel} 751160157Smarcel 752160157Smarcel 753160157Smarcel#define SYM_IS_DEFINED(sym) \ 754160157Smarcel ((sym)->shndx != SHN_UNDEF) 755160157Smarcel 756160157Smarcel#define SYM_IS_IN_TEXT_SEGMENT(value) \ 757160157Smarcel ((value) >= ef->text_base && (value) < ef->text_end) 758160157Smarcel 759160157Smarcel#define SYM_HAS_INTERESTING_TYPE(type) ( \ 760160157Smarcel (type) == STT_FUNC || \ 761160157Smarcel (type) == STT_OBJECT || \ 762160157Smarcel (type) == STT_HP_STUB \ 763160157Smarcel ) 764160157Smarcel 765160157Smarcel#define SYM_IS_INTERESTING(sym) ( \ 766160157Smarcel SYM_IS_DEFINED(sym) && \ 767160157Smarcel SYM_IS_IN_TEXT_SEGMENT((sym)->value) && \ 768160157Smarcel SYM_HAS_INTERESTING_TYPE((sym)->type) \ 769160157Smarcel ) 770160157Smarcel 771160157Smarcelint uwx_read_func_symbols( 772160157Smarcel struct uwx_env *env, 773160157Smarcel struct uwx_symbol_cache *cache, 774160157Smarcel char *module_name) 775160157Smarcel{ 776160157Smarcel int i, j; 777160157Smarcel int status; 778160157Smarcel struct elf_file *ef; 779160157Smarcel struct elf_symbol *sym; 780160157Smarcel int nfuncsyms; 781160157Smarcel char **names; 782160157Smarcel uint64_t *values; 783160157Smarcel 784160157Smarcel if (module_name != NULL && 785160157Smarcel cache->module_name != NULL && 786160157Smarcel strcmp(module_name, cache->module_name) == 0) 787160157Smarcel return UWX_OK; 788160157Smarcel 789160157Smarcel if (cache->sym_names != NULL) 790160157Smarcel (*env->free_cb)(cache->sym_names); 791160157Smarcel if (cache->sym_values != NULL) 792160157Smarcel (*env->free_cb)(cache->sym_values); 793160157Smarcel if (cache->strings != NULL) 794160157Smarcel (*env->free_cb)(cache->strings); 795160157Smarcel 796160157Smarcel ef = elf_new(env); 797160157Smarcel if (ef == NULL) 798160157Smarcel return UWX_ERR_NOMEM; 799160157Smarcel status = elf_open(ef, module_name); 800160157Smarcel if (status != 0) 801160157Smarcel return UWX_ERR_NOSYM; 802160157Smarcel status = elf_read_symbols(ef); 803160157Smarcel if (status != 0) 804160157Smarcel return UWX_ERR_NOSYM; 805160157Smarcel 806160157Smarcel nfuncsyms = 0; 807160157Smarcel for (i = 0; i < ef->nsyms; i++) { 808160157Smarcel sym = &ef->symbols[i]; 809160157Smarcel if (SYM_IS_INTERESTING(sym)) 810160157Smarcel nfuncsyms++; 811160157Smarcel } 812160157Smarcel 813160157Smarcel names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *)); 814160157Smarcel if (names == NULL) 815160157Smarcel return UWX_ERR_NOMEM; 816160157Smarcel values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t)); 817160157Smarcel if (values == NULL) 818160157Smarcel return UWX_ERR_NOMEM; 819160157Smarcel 820160157Smarcel j = 0; 821160157Smarcel for (i = 0; i < ef->nsyms; i++) { 822160157Smarcel sym = &ef->symbols[i]; 823160157Smarcel if (SYM_IS_INTERESTING(sym)) { 824160157Smarcel if (j >= nfuncsyms) /* should not happen! */ 825160157Smarcel break; 826160157Smarcel names[j] = sym->namep; 827160157Smarcel values[j] = sym->value - ef->text_base; 828160157Smarcel j++; 829160157Smarcel } 830160157Smarcel } 831160157Smarcel 832160157Smarcel cache->module_name = (char *)(*env->allocate_cb)(strlen(module_name)+1); 833160157Smarcel if (cache->module_name != NULL) { 834160157Smarcel strcpy(cache->module_name, module_name); 835160157Smarcel cache->nsyms = nfuncsyms; 836160157Smarcel cache->sym_names = names; 837160157Smarcel cache->sym_values = values; 838160157Smarcel cache->strings = ef->symbol_strings; 839160157Smarcel ef->symbol_strings = NULL; 840160157Smarcel } 841160157Smarcel 842160157Smarcel elf_close(ef); 843160157Smarcel elf_free(ef); 844160157Smarcel 845160157Smarcel#ifdef DEBUG_SYMBOLS 846160157Smarcel printf("Cached %d interesting symbols\n", nfuncsyms); 847160157Smarcel#endif /* DEBUG_SYMBOLS */ 848160157Smarcel 849160157Smarcel return UWX_OK; 850160157Smarcel} 851