/* $Id: elf.c,v 1.2 2021/10/03 17:56:03 khorben Exp $ */ /* ELF file parser * UberWall security team \../. .\../ */ /* Copyright (c) 2010 khorben of UberWall */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "UWelfviewer.h" #include "elf.h" /* SI */ /* protected */ /* types */ typedef struct _SI { unsigned long index; char const * string; } SI; /* prototypes */ static char const * _si_get(SI * si, unsigned long index); /* UWelfviewer */ /* private */ /* variables */ static SI _si_class[] = { { ELFCLASSNONE, "ELFCLASSNONE" }, { ELFCLASS32, "ELFCLASS32" }, { ELFCLASS64, "ELFCLASS64" }, { 0, NULL } }; static SI _si_data[] = { { ELFDATANONE, "ELFDATANONE" }, { ELFDATA2LSB, "ELFDATA2LSB" }, { ELFDATA2MSB, "ELFDATA2MSB" }, { 0, NULL } }; static SI _si_type[] = { { ET_NONE, "ET_NONE" }, { ET_REL, "ET_REL" }, { ET_EXEC, "ET_EXEC" }, { ET_DYN, "ET_DYN" }, { ET_CORE, "ET_CORE" }, { ET_LOPROC, "ET_LOPROC" }, { ET_HIPROC, "ET_HIPROC" }, { 0, NULL } }; static SI _si_machine[] = { { EM_NONE, "EM_NONE" }, { EM_M32, "EM_M32" }, { EM_SPARC, "EM_SPARC" }, { EM_386, "EM_386" }, { EM_68K, "EM_68K" }, { EM_88K, "EM_88K" }, { EM_860, "EM_860" }, { EM_MIPS, "EM_MIPS" }, { EM_SPARCV9, "EM_SPARCV9" }, { EM_X86_64, "EM_X86_64" }, { 0, NULL } }; static SI _si_version[] = { { EV_NONE, "EV_NONE" }, { EV_CURRENT, "EV_CURRENT" }, { 0, NULL } }; static SI _si_ptype[] = { { PT_NULL, "PT_NULL" }, { PT_LOAD, "PT_LOAD" }, { PT_DYNAMIC, "PT_DYNAMIC" }, { PT_INTERP, "PT_INTERP" }, { PT_NOTE, "PT_NOTE" }, { PT_SHLIB, "PT_SHLIB" }, { PT_PHDR, "PT_PHDR" }, #ifdef PT_GNU_EH_FRAME { PT_GNU_EH_FRAME,"PT_GNU_EH_FRAME" }, #endif #ifdef PT_GNU_STACK { PT_GNU_STACK, "PT_GNU_STACK" }, #endif #if PT_GNU_RELRO { PT_GNU_RELRO, "PT_GNU_RELRO" }, #endif { 0, NULL } }; static SI _si_dtag[] = { { DT_NULL, "DT_NULL" }, { DT_NEEDED, "DT_NEEDED" }, { DT_PLTRELSZ, "DT_PLTRELSZ" }, { DT_PLTGOT, "DT_PLTGOT" }, { DT_HASH, "DT_HASH" }, { DT_STRTAB, "DT_STRTAB" }, { DT_SYMTAB, "DT_SYMTAB" }, { DT_RELA, "DT_RELA" }, { DT_RELASZ, "DT_RELASZ" }, { DT_RELAENT, "DT_RELAENT" }, { DT_STRSZ, "DT_STRSZ" }, { DT_SYMENT, "DT_SYMENT" }, { DT_INIT, "DT_INIT" }, { DT_FINI, "DT_FINI" }, { DT_SONAME, "DT_SONAME" }, { DT_RPATH, "DT_RPATH" }, { DT_SYMBOLIC, "DT_SYMBOLIC" }, { DT_REL, "DT_REL" }, { DT_RELSZ, "DT_RELSZ" }, { DT_RELENT, "DT_RELENT" }, { DT_PLTREL, "DT_PLTREL" }, { DT_DEBUG, "DT_DEBUG" }, { DT_TEXTREL, "DT_TEXTREL" }, { DT_JMPREL, "DT_JMPREL" }, { DT_BIND_NOW, "DT_BIND_NOW" }, { DT_INIT_ARRAY,"DT_INIT_ARRAY" }, { DT_FINI_ARRAY,"DT_FINI_ARRAY" }, { DT_INIT_ARRAYSZ,"DT_INIT_ARRAYSZ" }, { DT_FINI_ARRAYSZ,"DT_FINI_ARRAYSZ" }, { DT_NUM, "DT_NUM" }, { DT_VERSYM, "DT_VERSYM" }, { DT_FLAGS_1, "DT_FLAGS_1" }, { DT_VERDEF, "DT_VERDEF" }, { DT_VERDEFNUM, "DT_VERDEFNUM" }, { DT_VERNEED, "DT_VERNEED" }, { DT_VERNEEDNUM,"DT_VERNEEDNUM" }, { 0, NULL } }; static SI _si_shn[] = { { SHN_UNDEF, "SHN_UNDEF" }, { SHN_ABS, "SHN_ABS" }, { SHN_COMMON, "SHN_COMMON" }, { SHN_XINDEX, "SHN_XINDEX" }, { 0, NULL } }; static SI _si_shtype[] = { { SHT_NULL, "SHT_NULL" }, { SHT_PROGBITS, "SHT_PROGBITS" }, { SHT_SYMTAB, "SHT_SYMTAB" }, { SHT_STRTAB, "SHT_STRTAB" }, { SHT_RELA, "SHT_RELA" }, { SHT_HASH, "SHT_HASH" }, { SHT_DYNAMIC, "SHT_DYNAMIC" }, { SHT_NOTE, "SHT_NOTE" }, { SHT_NOBITS, "SHT_NOBITS" }, { SHT_REL, "SHT_REL" }, { SHT_SHLIB, "SHT_SHLIB" }, { SHT_DYNSYM, "SHT_DYNSYM" }, { 0, NULL } }; static SI _si_symtype[] = { { STT_NOTYPE, "STT_NOTYPE" }, { STT_OBJECT, "STT_OBJECT" }, { STT_FUNC, "STT_FUNC" }, { STT_SECTION, "STT_SECTION" }, { STT_FILE, "STT_FILE" }, { STT_NUM, "STT_NUM" }, { STT_LOOS, "STT_LOOS" }, { STT_HIOS, "STT_HIOS" }, { STT_LOPROC, "STT_LOPROC" }, { STT_HIPROC, "STT_HIPROC" }, { 0, NULL } }; static SI _si_rtype_amd64[] = { { 0, "R_X86_64_NONE" }, { 1, "R_X86_64_64" }, { 2, "R_X86_64_PC32" }, { 3, "R_X86_64_GOT32" }, { 4, "R_X86_64_PLT32" }, { 5, "R_X86_64_COPY" }, { 6, "R_X86_64_GLOB_DAT" }, { 7, "R_X86_64_JUMP_SLOT" }, { 8, "R_X86_64_RELATIVE" }, { 9, "R_X86_64_GOTPCREL" }, { 10, "R_X86_64_32" }, { 11, "R_X86_64_32S" }, { 12, "R_X86_64_16" }, { 13, "R_X86_64_PC16" }, { 14, "R_X86_64_8" }, { 15, "R_X86_64_PC8" }, { 0, NULL } }; static SI _si_rtype_i386[] = { { 0, "R_386_NONE" }, { 1, "R_386_32" }, { 2, "R_386_PC32" }, { 3, "R_386_GOT32" }, { 4, "R_386_PLT32" }, { 5, "R_386_COPY" }, { 6, "R_386_GLOB_DAT" }, { 7, "R_386_JMP_SLOT" }, { 8, "R_386_RELATIVE" }, { 9, "R_386_GOTOFF" }, { 10, "R_386_GOTPC" }, { 11, "R_386_32PLT" }, { 0, NULL } }; static SI _si_rtype_sparc[] = { { 9, "R_SPARC_HI22" }, { 19, "R_SPARC_COPY" }, { 20, "R_SPARC_GLOB_DAT" }, { 21, "R_SPARC_JMP_SLOT" }, { 22, "R_SPARC_RELATIVE" }, { 32, "R_SPARC_64" }, { 33, "R_SPARC_OLO10" }, { 46, "R_SPARC_DISP64" }, { 47, "R_SPARC_PLT64" }, { 53, "R_SPARC_REGISTER" }, { 54, "R_SPARC_UA64" }, { 0, NULL } }; static SI _si_rtype_unknown[] = { { 0, NULL } }; /* SI */ /* protected */ /* functions */ static char const * _si_get(SI * si, unsigned long index) { static char buf[32]; if(si != NULL) for(; si->string != NULL; si++) if(si->index == index) return si->string; snprintf(buf, sizeof(buf), "UNKNOWN (0x%lx)", index); return buf; } /* public */ /* functions */ /* elf */ /* elf header */ static int _elf_ehdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr); static void _ehdr_print(Elf_Ehdr * ehdr); /* program table */ static int _elf_phdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Phdr ** phdr, size_t * phdr_cnt); static void _phdr_print(Elf_Phdr * phdr); static void _phdr_dyn_print(FILE * fp, Elf_Phdr * phdr); static char const * _phdr_flags(uint32_t flags); /* section table */ static int _elf_shdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Shdr ** shdr, size_t * shdr_cnt, char ** shstrtab, size_t * shstrtab_cnt); static void _shdr_print(Elf_Shdr * shdr, char const * strtab, size_t strtab_cnt); static char const * _shdr_flags(uint64_t flags); /* string sections */ static int _elf_strtab(FILE * fp, char const * pathname, Elf_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt); static char const * _strtab_get(char const * strtab, size_t strtab_cnt, unsigned long ndx); /* symbol table */ static int _elf_symtab(FILE * fp, char const * pathname, Elf_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, Elf_Sym ** symtab, size_t * symtab_cnt, char const * shstrtab, size_t shstrtab_cnt); static void _symtab_print(Elf_Sym * sym, char const * strtab, size_t strtab_cnt, Elf_Shdr * shdr, size_t shdr_cnt, char const * shstrtab, size_t shstrtab_cnt); /* relocations */ static int _elf_rela(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Shdr * shdr, size_t shdr_cnt); static void _rela_print(Elf_Ehdr * ehdr, Elf_Rela * rela, Elf_Sym * symtab, size_t symtab_cnt, char const * symstrtab, size_t symstrtab_cnt); #if ELFSIZE == 32 int elf32(FILE * fp, char const * pathname) #elif ELFSIZE == 64 int elf64(FILE * fp, char const * pathname) #endif { int ret; Elf_Ehdr ehdr; Elf_Phdr * phdr = NULL; size_t phdr_cnt = 0; Elf_Shdr * shdr = NULL; size_t shdr_cnt = 0; char * shstrtab = NULL; size_t shstrtab_cnt = 0; uint16_t i; Elf_Sym * symtab = NULL; size_t symtab_cnt = 0; if((ret = _elf_ehdr(fp, pathname, &ehdr)) != 0) return ret; ret |= _elf_phdr(fp, pathname, &ehdr, &phdr, &phdr_cnt); ret |= _elf_shdr(fp, pathname, &ehdr, &shdr, &shdr_cnt, &shstrtab, &shstrtab_cnt); for(i = 0; i < shdr_cnt; i++) if(shdr[i].sh_type == SHT_SYMTAB) { ret |= _elf_symtab(fp, pathname, shdr, shdr_cnt, i, &symtab, &symtab_cnt, shstrtab, shstrtab_cnt); break; } ret |= _elf_rela(fp, pathname, &ehdr, shdr, shdr_cnt); free(phdr); free(shdr); free(shstrtab); free(symtab); return ret; } static int _elf_ehdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr) { if(fread(ehdr, sizeof(*ehdr), 1, fp) != 1) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if(memcmp(ehdr->e_ident, ELFMAG, sizeof(ELFMAG) - 1) != 0) return UWelfviewer_error("%s: %s", pathname, "Not an ELF file"); #if _BYTE_ORDER == _LITTLE_ENDIAN if(ehdr->e_ident[EI_DATA] == ELFDATA2MSB) #else if(ehdr->e_ident[EI_DATA] == ELFDATA2LSB) #endif { ehdr->e_type = bswap16(ehdr->e_type); ehdr->e_machine = bswap16(ehdr->e_machine); ehdr->e_version = bswap32(ehdr->e_version); ehdr->e_entry = bswap(ehdr->e_entry); ehdr->e_phoff = bswap(ehdr->e_phoff); ehdr->e_ehsize = bswap16(ehdr->e_ehsize); ehdr->e_phentsize = bswap16(ehdr->e_phentsize); ehdr->e_phnum = bswap16(ehdr->e_phnum); ehdr->e_shentsize = bswap16(ehdr->e_shentsize); ehdr->e_shnum = bswap16(ehdr->e_shnum); ehdr->e_shstrndx = bswap16(ehdr->e_shstrndx); } if(ehdr->e_ehsize != sizeof(*ehdr)) return UWelfviewer_error("%s: %s", pathname, "Unexpected ELF header size"); _ehdr_print(ehdr); return 0; } static void _ehdr_print(Elf_Ehdr * ehdr) { printf("ELF %s file for %s, %s %s, version %s\n" "Entrypoint: %010p, %u program table entries" ", %u sections\n", _si_get(_si_type, ehdr->e_type), _si_get(_si_machine, ehdr->e_machine), _si_get(_si_data, ehdr->e_ident[EI_DATA]), _si_get(_si_class, ehdr->e_ident[EI_CLASS]), _si_get(_si_version, ehdr->e_version), (void *)ehdr->e_entry, ehdr->e_phnum, ehdr->e_shnum); } static int _elf_phdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Phdr ** phdr, size_t * phdr_cnt) { size_t i; if(ehdr->e_phnum == 0) return 0; if(ehdr->e_phentsize != sizeof(**phdr)) return UWelfviewer_error("%s: %s", pathname, "Unexpected program header size"); if(fseek(fp, ehdr->e_phoff, SEEK_SET) != 0) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); /* no integer overflow: phentsize and phnum are shorts */ i = ehdr->e_phentsize * ehdr->e_phnum; if((*phdr = malloc(i)) == NULL) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if(fread(*phdr, sizeof(**phdr), ehdr->e_phnum, fp) != ehdr->e_phnum) { free(*phdr); *phdr = NULL; return UWelfviewer_error("%s: %s", pathname, strerror(errno)); } *phdr_cnt = ehdr->e_phnum; printf("\nListing program table at 0x%lx:\n" "%-10s %-5s %-10s %-10s %-10s %-10s %-10s\n", ehdr->e_phoff, "Type", "Flags", "Address", "Offset", "File size", "Memory size", "Alignment"); for(i = 0; i < *phdr_cnt; i++) _phdr_print((*phdr) + i); for(i = 0; i < *phdr_cnt; i++) if((*phdr)[i].p_type == PT_DYNAMIC) _phdr_dyn_print(fp, &(*phdr)[i]); return 0; } static void _phdr_print(Elf_Phdr * phdr) { unsigned long filesz = phdr->p_filesz; unsigned long memsz = phdr->p_memsz; unsigned long align = phdr->p_align; printf("%-10s %-5s %010p %010p 0x%08lx 0x%08lx 0x%08lx\n", _si_get(_si_ptype, phdr->p_type), _phdr_flags(phdr->p_flags), (void *)phdr->p_vaddr, (void *)phdr->p_offset, filesz, memsz, align); } static char const * _phdr_flags(uint32_t flags) { static char buf[4]; buf[0] = flags & PF_R ? 'r' : '-'; buf[1] = flags & PF_W ? 'w' : '-'; buf[2] = flags & PF_X ? 'x' : '-'; return buf; } static void _phdr_dyn_print(FILE * fp, Elf_Phdr * phdr) { size_t i; Elf_Dyn dyn; if(fseek(fp, phdr->p_offset, SEEK_SET) != 0) return; /* XXX report error */ printf("\nListing dynamic section at 0x%lx:\n" "%-12s %-10s\n", phdr->p_offset, "Tag", "Value(s)"); for(i = 0; i < phdr->p_filesz; i+=sizeof(dyn)) { if(fread(&dyn, sizeof(dyn), 1, fp) != 1) continue; /* XXX report error */ if(dyn.d_tag == DT_NULL) break; printf("%-12s", _si_get(_si_dtag, dyn.d_tag)); switch(dyn.d_tag) { case DT_NEEDED: case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: printf(" %10lu\n", dyn.d_un.d_val); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_FINI: case DT_REL: case DT_DEBUG: case DT_JMPREL: printf(" 0x%08lx\n", dyn.d_un.d_ptr); break; case DT_SYMBOLIC: case DT_TEXTREL: printf("\n"); break; case DT_LOPROC: case DT_HIPROC: default: printf(" %10lu (0x%0lx)\n", dyn.d_un.d_val, dyn.d_un.d_ptr); break; } } } static int _elf_shdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Shdr ** shdr, size_t * shdr_cnt, char ** shstrtab, size_t * shstrtab_cnt) { size_t i; if(ehdr->e_shnum == 0) return 0; if(ehdr->e_shentsize != sizeof(**shdr)) return UWelfviewer_error("%s: %s", pathname, "Unexpected section header size"); if(fseek(fp, ehdr->e_shoff, SEEK_SET) != 0) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); /* no integer overflow: phentsize and phnum are shorts */ i = ehdr->e_shentsize * ehdr->e_shnum; if((*shdr = malloc(i)) == NULL) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if(fread(*shdr, sizeof(**shdr), ehdr->e_shnum, fp) != ehdr->e_shnum) { free(*shdr); *shdr = NULL; return UWelfviewer_error("%s: %s", pathname, strerror(errno)); } /* load section name string table */ if(_elf_strtab(fp, pathname, *shdr, ehdr->e_shnum, ehdr->e_shstrndx, shstrtab, shstrtab_cnt) != 0) { free(*shdr); *shdr = NULL; return 1; } *shdr_cnt = ehdr->e_shnum; printf("\nListing sections at 0x%lx:\n" "%-19s %-12s %-5s %-10s %-10s %-10s %-4s %-4s %s\n", ehdr->e_shoff, "Name", "Type", "Flags", "Address", "Offset", "Size", "Link", "Info", "Entsize"); for(i = 0; i < *shdr_cnt; i++) _shdr_print((*shdr) + i, *shstrtab, *shstrtab_cnt); return 0; } static void _shdr_print(Elf_Shdr * shdr, char const * strtab, size_t strtab_cnt) { unsigned long size = shdr->sh_size; unsigned long entsize = shdr->sh_entsize; printf("%-19s %-12s %-5s %010p %010p 0x%08lx %-4u %-4u %lu\n", _strtab_get(strtab, strtab_cnt, shdr->sh_name), _si_get(_si_shtype, shdr->sh_type), _shdr_flags(shdr->sh_flags), (void *)shdr->sh_addr, (void *)shdr->sh_offset, size, shdr->sh_link, shdr->sh_info, entsize); } static char const * _shdr_flags(uint64_t flags) { static char buf[5]; buf[0] = flags & SHF_MASKPROC ? 'm' : '-'; buf[1] = flags & SHF_ALLOC ? 'a' : '-'; buf[2] = flags & SHF_WRITE ? 'w' : '-'; buf[3] = flags & SHF_EXECINSTR ? 'x' : '-'; return buf; } static int _elf_strtab(FILE * fp, char const * pathname, Elf_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt) { if(ndx >= shdr_cnt) return 1; shdr = &shdr[ndx]; if(fseek(fp, shdr->sh_offset, SEEK_SET) != 0) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if((*strtab = malloc(shdr->sh_size)) == NULL) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if(fread(*strtab, 1, shdr->sh_size, fp) != shdr->sh_size) { free(*strtab); *strtab = NULL; return UWelfviewer_error("%s: %s", pathname, strerror(errno)); } *strtab_cnt = shdr->sh_size; return 0; } static char const * _strtab_get(char const * strtab, size_t strtab_cnt, unsigned long ndx) { static char buf[24]; if(ndx >= strtab_cnt || strtab == NULL || strtab_cnt == 0 || strtab[strtab_cnt - 1] != '\0') { snprintf(buf, sizeof(buf), "UNKNOWN (%lu)", ndx); return buf; } return &strtab[ndx]; } static int _elf_symtab(FILE * fp, char const * pathname, Elf_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, Elf_Sym ** symtab, size_t * symtab_cnt, char const * shstrtab, size_t shstrtab_cnt) { size_t i; size_t cnt; char * strtab = NULL; size_t strtab_cnt = 0; if(ndx >= shdr_cnt) return 1; if(shdr[ndx].sh_entsize != sizeof(**symtab)) return UWelfviewer_error("%s: %s", pathname, "Unexpected symbol size"); if(shdr[ndx].sh_size % sizeof(**symtab) != 0) return UWelfviewer_error("%s: %s", pathname, "Unexpected symbol table size"); cnt = shdr[ndx].sh_size / sizeof(**symtab); if(fseek(fp, shdr[ndx].sh_offset, SEEK_SET) != 0) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if((*symtab = malloc(shdr[ndx].sh_size)) == NULL) return UWelfviewer_error("%s: %s", pathname, strerror(errno)); if(fread(*symtab, shdr[ndx].sh_size, 1, fp) != 1) { free(*symtab); *symtab = NULL; return UWelfviewer_error("%s: %s", pathname, strerror(errno)); } if(shstrtab == NULL) { /* XXX ugly hack: do not list anything */ *symtab_cnt = cnt; return 0; } /* load symbol table string table */ if(_elf_strtab(fp, pathname, shdr, shdr_cnt, shdr[ndx].sh_link, &strtab, &strtab_cnt) != 0) { free(*symtab); *symtab = NULL; return 1; } *symtab_cnt = cnt; printf("\nListing symbols at 0x%lx:\n" "%-19s %-19s %-11s %-10s %-10s\n", shdr[ndx].sh_offset, "Name", "Section", "Type", "Value", "Size"); for(i = 0; i < cnt; i++) _symtab_print((*symtab) + i, strtab, strtab_cnt, shdr, shdr_cnt, shstrtab, shstrtab_cnt); free(strtab); return 0; } static void _symtab_print(Elf_Sym * sym, char const * strtab, size_t strtab_cnt, Elf_Shdr * shdr, size_t shdr_cnt, char const * shstrtab, size_t shstrtab_cnt) { char const * section; unsigned long size = sym->st_size; if(sym->st_shndx >= SHN_LORESERVE) section = _si_get(_si_shn, sym->st_shndx); else if(sym->st_shndx < shdr_cnt) section = _strtab_get(shstrtab, shstrtab_cnt, shdr[sym->st_shndx].sh_name); else section = _si_get(NULL, sym->st_shndx); printf("%-19s %-19s %-11s %010p 0x%08lx\n", _strtab_get(strtab, strtab_cnt, sym->st_name), section, _si_get(_si_symtype, ELF_ST_TYPE(sym->st_info)), (void *)sym->st_value, size); } static int _elf_rela(FILE * fp, char const * pathname, Elf_Ehdr * ehdr, Elf_Shdr * shdr, size_t shdr_cnt) { int ret = 0; size_t i; size_t j; size_t cnt; Elf_Rela rela; Elf_Sym * symtab = NULL; size_t symtab_cnt = 0; char * strtab = NULL; size_t strtab_cnt = 0; for(i = 0; i < shdr_cnt; i++) { if(shdr[i].sh_type == SHT_RELA) { if(shdr[i].sh_entsize != sizeof(rela)) { UWelfviewer_error("%s: %s", pathname, "Unexpected relocation size"); continue; } } else if(shdr[i].sh_type == SHT_REL) { if(shdr[i].sh_entsize != sizeof(Elf_Rel)) { UWelfviewer_error("%s: %s", pathname, "Unexpected relocation size"); continue; } } else continue; if(shdr[i].sh_size % shdr[i].sh_entsize != 0) { UWelfviewer_error("%s: %s", pathname, "Unexpected relocation section size"); continue; } /* load symbol table */ printf("symbol table %u\n", shdr[i].sh_link); if(_elf_symtab(fp, pathname, shdr, shdr_cnt, shdr[i].sh_link, &symtab, &symtab_cnt, NULL, 0) != 0) break; /* load symbol table string table */ if(_elf_strtab(fp, pathname, shdr, shdr_cnt, shdr[shdr[i].sh_link].sh_link, &strtab, &strtab_cnt) != 0) { free(symtab); break; } if(fseek(fp, shdr[i].sh_offset, SEEK_SET) != 0) { ret |= UWelfviewer_error("%s: %s", pathname, strerror( errno)); continue; } cnt = shdr[i].sh_size / shdr[i].sh_entsize; printf("\nListing relocations at 0x%lx:\n" "%-19s %-10s %-19s %s\n", shdr[i].sh_offset, "Symbol", "Offset", "Type", "Addend"); rela.r_addend = 0; for(j = 0; j < cnt; j++) { if(fread(&rela, shdr[i].sh_entsize, 1, fp) != 1) { ret |= UWelfviewer_error("%s: %s", pathname, strerror(errno)); break; } #if _BYTE_ORDER == _LITTLE_ENDIAN if(ehdr->e_ident[EI_DATA] == ELFDATA2MSB) #else if(ehdr->e_ident[EI_DATA] == ELFDATA2LSB) #endif { rela.r_offset = bswap(rela.r_offset); rela.r_info = bswap(rela.r_info); rela.r_addend = bswap32(rela.r_addend); } _rela_print(ehdr, &rela, symtab, symtab_cnt, strtab, strtab_cnt); } free(strtab); free(symtab); } return 0; } static void _rela_print(Elf_Ehdr * ehdr, Elf_Rela * rela, Elf_Sym * symtab, size_t symtab_cnt, char const * symstrtab, size_t symstrtab_cnt) { Elf_Sym * sym = NULL; char const * name = ""; unsigned long addend = rela->r_addend; SI * rtype; if(ELF_R_SYM(rela->r_info) < symtab_cnt) { sym = &symtab[ELF_R_SYM(rela->r_info)]; name = _strtab_get(symstrtab, symstrtab_cnt, sym->st_name); } switch(ehdr->e_machine) { case EM_386: case EM_486: rtype = &_si_rtype_i386; break; case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: rtype = &_si_rtype_sparc; break; case EM_X86_64: rtype = &_si_rtype_amd64; break; default: rtype = &_si_rtype_unknown; break; } printf("%-19s %010p %-19s 0x%08lx\n", name, (void *)rela->r_offset, _si_get(rtype, ELF_R_TYPE(rela->r_info)), addend); }