/* $Id$ */ /* Copyright (c) 2011 Pierre Pronchery */ /* This file is part of DeforaOS Devel asm */ /* 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 3 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, see . */ #include #include #include #include #include #include #include "Asm.h" /* portability */ #define Elf64_Quarter unsigned char #ifndef EM_486 # define EM_486 6 #endif /* ELF */ /* private */ /* types */ typedef struct _ElfArch { char const * arch; unsigned char machine; unsigned char capacity; unsigned char endian; uint64_t addralign; } ElfArch; typedef struct _ElfSectionValues { char const * name; Elf32_Word type; /* works for 64-bit too */ Elf32_Word flags; } ElfSectionValues; typedef struct _ElfStrtab { char * buf; size_t cnt; } ElfStrtab; typedef struct _Elf { ElfArch * arch; /* ELF32 */ Elf32_Shdr * es32; int es32_cnt; /* ELF64 */ Elf64_Shdr * es64; int es64_cnt; } Elf; /* prototypes */ static int _elf_error(FormatPlugin * format); /* plug-in */ static int _elf_init(FormatPlugin * format, char const * arch); static int _elf_exit(FormatPlugin * format); static char const * _elf_detect(FormatPlugin * format); static int _elf_decode(FormatPlugin * format); static int _elf_decode32(FormatPlugin * format); static int _elf_decode64(FormatPlugin * format); /* ELF32 */ static int _init_32(FormatPlugin * format); static int _exit_32(FormatPlugin * format); static int _section_32(FormatPlugin * format, char const * name); static void _swap_32_ehdr(Elf32_Ehdr * ehdr); static void _swap_32_phdr(Elf32_Phdr * phdr); static void _swap_32_shdr(Elf32_Shdr * shdr); /* ELF64 */ static int _init_64(FormatPlugin * format); static int _exit_64(FormatPlugin * format); static int _section_64(FormatPlugin * format, char const * name); static void _swap_64_ehdr(Elf64_Ehdr * ehdr); static void _swap_64_phdr(Elf64_Phdr * phdr); static void _swap_64_shdr(Elf64_Shdr * shdr); /* ElfStrtab */ static int _elfstrtab_set(FormatPlugin * format, ElfStrtab * strtab, char const * name); /* variables */ static ElfArch elf_arch[] = { { "amd64", EM_X86_64, ELFCLASS64, ELFDATA2LSB, 0x4 }, { "arm", EM_ARM, ELFCLASS32, ELFDATA2MSB, 0x0 }, { "i386", EM_386, ELFCLASS32, ELFDATA2LSB, 0x4 }, { "i486", EM_386, ELFCLASS32, ELFDATA2LSB, 0x4 }, { "i586", EM_386, ELFCLASS32, ELFDATA2LSB, 0x4 }, { "i686", EM_386, ELFCLASS32, ELFDATA2LSB, 0x4 }, { "mips", EM_MIPS, ELFCLASS32, ELFDATA2MSB, 0x0 }, { "sparc", EM_SPARC, ELFCLASS32, ELFDATA2MSB, 0x0 }, { "sparc64", EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, 0x0 }, { NULL, '\0', '\0', '\0', 0x0 } }; #if defined(__amd64__) static const ElfArch * elf_arch_native = &elf_arch[0]; #elif defined(__arm__) static const ElfArch * elf_arch_native = &elf_arch[1]; #elif defined(__i386__) static const ElfArch * elf_arch_native = &elf_arch[2]; #elif defined(__sparc64__) static const ElfArch * elf_arch_native = &elf_arch[8]; #elif defined(__sparc__) static const ElfArch * elf_arch_native = &elf_arch[7]; #else # error "Unsupported architecture" #endif static ElfSectionValues elf_section_values[] = { { ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE }, { ".comment", SHT_PROGBITS, 0 }, { ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE }, { ".data1", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE }, { ".debug", SHT_PROGBITS, 0 }, { ".dynamic", SHT_DYNAMIC, 0 }, { ".dynstr", SHT_STRTAB, SHF_ALLOC }, { ".dynsym", SHT_DYNSYM, SHF_ALLOC }, { ".fini", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR }, { ".got", SHT_PROGBITS, 0 }, { ".hash", SHT_HASH, SHF_ALLOC }, { ".init", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR }, { ".interp", SHT_PROGBITS, 0 }, { ".line", SHT_PROGBITS, 0 }, { ".note", SHT_NOTE, 0 }, { ".plt", SHT_PROGBITS, 0 }, { ".rodata", SHT_PROGBITS, SHF_ALLOC }, { ".rodata1", SHT_PROGBITS, SHF_ALLOC }, { ".shstrtab", SHT_STRTAB, 0 }, { ".strtab", SHT_STRTAB, 0 }, { ".symtab", SHT_SYMTAB, 0 }, { ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR }, { NULL, 0, 0 } }; static ElfStrtab shstrtab = { NULL, 0 }; /* section string table */ /* public */ /* variables */ /* format_plugin */ FormatPlugin format_plugin = { NULL, "elf", ELFMAG, SELFMAG, _elf_init, _elf_exit, NULL, NULL, _elf_detect, _elf_decode, NULL }; /* private */ /* functions */ /* elf_error */ static int _elf_error(FormatPlugin * format) { return -error_set_code(1, "%s: %s", format->helper->get_filename( format->helper->format), strerror(errno)); } /* elf_init */ static ElfArch * _init_arch(char const * arch); static int _elf_init(FormatPlugin * format, char const * arch) { Elf * elf; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, arch); #endif if((elf = object_new(sizeof(*elf))) == NULL) return -1; format->priv = elf; if(arch == NULL) { elf->arch = NULL; return 0; } if((elf->arch = _init_arch(arch)) == NULL) { object_delete(elf); return -1; } if(elf->arch->capacity == ELFCLASS32) { if(_init_32(format) != 0) return -1; format->exit = _exit_32; format->section = _section_32; } else if(elf->arch->capacity == ELFCLASS64) { if(_init_64(format) != 0) return -1; format->exit = _exit_64; format->section = _section_64; } else return -1; return 0; } static ElfArch * _init_arch(char const * arch) { ElfArch * ea; for(ea = elf_arch; ea->arch != NULL; ea++) if(strcmp(ea->arch, arch) == 0) return ea; error_set_code(1, "%s: %s", arch, "Unsupported ELF architecture"); return NULL; } /* elf_exit */ static int _elf_exit(FormatPlugin * format) { Elf * elf = format->priv; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif free(elf->es32); free(elf->es64); object_delete(elf); return 0; } /* elf_detect */ static char const * _detect_32(FormatPlugin * format, Elf32_Ehdr * ehdr); static char const * _detect_64(FormatPlugin * format, Elf64_Ehdr * ehdr); static char const * _elf_detect(FormatPlugin * format) { FormatPluginHelper * helper = format->helper; union { Elf32_Ehdr ehdr32; Elf64_Ehdr ehdr64; } ehdr; if(helper->seek(helper->format, 0, SEEK_SET) != 0) return NULL; if(helper->read(helper->format, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) return NULL; switch(ehdr.ehdr32.e_ident[EI_CLASS]) { case ELFCLASS32: return _detect_32(format, &ehdr.ehdr32); case ELFCLASS64: return _detect_64(format, &ehdr.ehdr64); } error_set_code(1, "%s: %s 0x%x\n", helper->get_filename(helper->format), "Unsupported ELF class", ehdr.ehdr32.e_ident[EI_CLASS]); return NULL; } static char const * _detect_32(FormatPlugin * format, Elf32_Ehdr * ehdr) { format->decode = _elf_decode32; if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) _swap_32_ehdr(ehdr); switch(ehdr->e_machine) { case EM_386: case EM_486: return "i686"; case EM_ALPHA: return "alpha"; case EM_ARM: return "arm"; case EM_MIPS: return "mips"; case EM_SPARC: return "sparc"; } format->decode = _elf_decode; error_set_code(1, "%s: %s 0x%x", "elf", "Unsupported ELF architecture", ehdr->e_machine); return NULL; } static char const * _detect_64(FormatPlugin * format, Elf64_Ehdr * ehdr) { format->decode = _elf_decode64; if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) _swap_64_ehdr(ehdr); switch(ehdr->e_machine) { case EM_SPARC: case EM_SPARCV9: return "sparc64"; case EM_X86_64: return "amd64"; } format->decode = _elf_decode; error_set_code(1, "%s: %s 0x%x", "elf", "Unsupported ELF architecture", ehdr->e_machine); return NULL; } /* elf_decode */ static int _elf_decode(FormatPlugin * format) { if(_elf_detect(format) == NULL) return -1; return format->decode(format); } /* elf_decode32 */ static int _decode32_shdr(FormatPlugin * format, Elf32_Ehdr * ehdr, Elf32_Shdr ** shdr); static int _decode32_addr(FormatPlugin * format, Elf32_Ehdr * ehdr, Elf32_Addr * addr); static int _decode32_strtab(FormatPlugin * format, Elf32_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt); static int _elf_decode32(FormatPlugin * format) { FormatPluginHelper * helper = format->helper; Elf32_Ehdr ehdr; Elf32_Shdr * shdr = NULL; Elf32_Addr base = 0x0; char * shstrtab = NULL; size_t shstrtab_cnt = 0; size_t i; #ifdef DEBUG fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, helper->get_filename(helper->format)); #endif if(helper->seek(helper->format, 0, SEEK_SET) != 0 || helper->read(helper->format, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) return -1; if(ehdr.e_ident[EI_DATA] != elf_arch_native->endian) _swap_32_ehdr(&ehdr); if(_decode32_shdr(format, &ehdr, &shdr) != 0) return -1; if(_decode32_addr(format, &ehdr, &base) != 0 || _decode32_strtab(format, shdr, ehdr.e_shnum, ehdr.e_shstrndx, &shstrtab, &shstrtab_cnt) != 0) { free(shdr); return -1; } for(i = 0; i < ehdr.e_shnum; i++) { if(shdr[i].sh_name >= shstrtab_cnt) continue; if(shdr[i].sh_type == SHT_PROGBITS && shdr[i].sh_flags & SHF_EXECINSTR) helper->decode(helper->format, &shstrtab[shdr[i].sh_name], shdr[i].sh_offset, shdr[i].sh_size, base); } free(shstrtab); free(shdr); return 0; } static int _decode32_shdr(FormatPlugin * format, Elf32_Ehdr * ehdr, Elf32_Shdr ** shdr) { FormatPluginHelper * helper = format->helper; ssize_t size; size_t i; if(ehdr->e_shentsize == 0) { *shdr = NULL; return 0; } if(ehdr->e_shentsize != sizeof(**shdr)) return -error_set_code(1, "%s: %s", helper->get_filename(helper->format), "Invalid section header size"); if(helper->seek(helper->format, ehdr->e_shoff, SEEK_SET) < 0) return -1; size = sizeof(**shdr) * ehdr->e_shnum; if((*shdr = malloc(size)) == NULL) return -_elf_error(format); if(helper->read(helper->format, *shdr, size) != size) { free(*shdr); return -1; } if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) for(i = 0; i < ehdr->e_shnum; i++) _swap_32_shdr(*shdr + i); return 0; } static int _decode32_addr(FormatPlugin * format, Elf32_Ehdr * ehdr, Elf32_Addr * addr) { FormatPluginHelper * helper = format->helper; Elf32_Half i; Elf32_Phdr phdr; if(helper->seek(helper->format, ehdr->e_phoff, SEEK_SET) < 0) return -1; for(i = 0; i < ehdr->e_phnum; i++) { if(helper->read(helper->format, &phdr, sizeof(phdr)) != sizeof(phdr)) return -1; if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) _swap_32_phdr(&phdr); if(phdr.p_type == PT_LOAD && phdr.p_flags & (PF_R | PF_X)) { *addr = phdr.p_vaddr; return 0; } } *addr = 0x0; return 0; } static int _decode32_strtab(FormatPlugin * format, Elf32_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt) { FormatPluginHelper * helper = format->helper; if(ndx >= shdr_cnt) return -error_set_code(1, "%s: %s", helper->get_filename(helper->format), "Unable to read the string table"); shdr = &shdr[ndx]; if(helper->seek(helper->format, shdr->sh_offset, SEEK_SET) < 0) return -1; if((*strtab = malloc(shdr->sh_size)) == NULL) return -_elf_error(format); if(helper->read(helper->format, *strtab, shdr->sh_size) != shdr->sh_size) { free(*strtab); return -1; } *strtab_cnt = shdr->sh_size; return 0; } /* elf_decode64 */ static int _decode64_shdr(FormatPlugin * format, Elf64_Ehdr * ehdr, Elf64_Shdr ** shdr); static int _decode64_addr(FormatPlugin * format, Elf64_Ehdr * ehdr, Elf64_Addr * addr); static int _decode64_strtab(FormatPlugin * format, Elf64_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt); static int _elf_decode64(FormatPlugin * format) { FormatPluginHelper * helper = format->helper; Elf64_Ehdr ehdr; Elf64_Shdr * shdr = NULL; Elf64_Addr base = 0x0; char * shstrtab = NULL; size_t shstrtab_cnt = 0; size_t i; #ifdef DEBUG fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, helper->get_filename(helper->format)); #endif if(helper->seek(helper->format, 0, SEEK_SET) != 0 || helper->read(helper->format, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) return -1; if(ehdr.e_ident[EI_DATA] != elf_arch_native->endian) _swap_64_ehdr(&ehdr); if(_decode64_shdr(format, &ehdr, &shdr) != 0) return -1; if(_decode64_addr(format, &ehdr, &base) != 0 || _decode64_strtab(format, shdr, ehdr.e_shnum, ehdr.e_shstrndx, &shstrtab, &shstrtab_cnt) != 0) { free(shdr); return -1; } for(i = 0; i < ehdr.e_shnum; i++) { if(shdr[i].sh_name >= shstrtab_cnt) continue; if(shdr[i].sh_type == SHT_PROGBITS && shdr[i].sh_flags & SHF_EXECINSTR) helper->decode(helper->format, &shstrtab[shdr[i].sh_name], shdr[i].sh_offset, shdr[i].sh_size, base + shdr[i].sh_offset); } free(shstrtab); free(shdr); return 0; } static int _decode64_shdr(FormatPlugin * format, Elf64_Ehdr * ehdr, Elf64_Shdr ** shdr) { FormatPluginHelper * helper = format->helper; ssize_t size; size_t i; if(ehdr->e_shentsize == 0) { *shdr = NULL; return 0; } if(ehdr->e_shentsize != sizeof(**shdr)) return -error_set_code(1, "%s: %s", helper->get_filename(helper->format), "Invalid section header size"); if(helper->seek(helper->format, ehdr->e_shoff, SEEK_SET) < 0) return -1; size = sizeof(**shdr) * ehdr->e_shnum; if((*shdr = malloc(size)) == NULL) return -_elf_error(format); if(helper->read(helper->format, *shdr, size) != size) { free(*shdr); return -1; } if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) for(i = 0; i < ehdr->e_shnum; i++) _swap_64_shdr(*shdr + i); return 0; } static int _decode64_addr(FormatPlugin * format, Elf64_Ehdr * ehdr, Elf64_Addr * addr) { FormatPluginHelper * helper = format->helper; Elf64_Quarter i; Elf64_Phdr phdr; if(helper->seek(helper->format, ehdr->e_phoff, SEEK_SET) < 0) return -1; for(i = 0; i < ehdr->e_phnum; i++) { if(helper->read(helper->format, &phdr, sizeof(phdr)) != sizeof(phdr)) return -1; if(ehdr->e_ident[EI_DATA] != elf_arch_native->endian) _swap_64_phdr(&phdr); if(phdr.p_type == PT_LOAD && phdr.p_flags & (PF_R | PF_X)) { *addr = phdr.p_vaddr; return 0; } } *addr = 0x0; return 0; } static int _decode64_strtab(FormatPlugin * format, Elf64_Shdr * shdr, size_t shdr_cnt, uint16_t ndx, char ** strtab, size_t * strtab_cnt) { FormatPluginHelper * helper = format->helper; ssize_t size; if(ndx >= shdr_cnt) return -error_set_code(1, "%s: %s", helper->get_filename(helper->format), "Unable to read the string table"); shdr = &shdr[ndx]; if(helper->seek(helper->format, shdr->sh_offset, SEEK_SET) < 0) return -1; size = sizeof(**strtab) * shdr->sh_size; if((*strtab = malloc(size)) == NULL) return -_elf_error(format); if(helper->read(helper->format, *strtab, size) != size) { free(*strtab); return -1; } *strtab_cnt = shdr->sh_size; return 0; } /* section_values */ static ElfSectionValues * _section_values(char const * name) { ElfSectionValues * esv; int cmp; for(esv = elf_section_values; esv->name != NULL; esv++) if((cmp = strcmp(esv->name, name)) == 0) return esv; else if(cmp > 0) break; for(; esv->name != NULL; esv++); return esv; } /* ELF32 */ /* init_32 */ static int _init_32(FormatPlugin * format) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf32_Ehdr hdr; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif memset(&hdr, 0, sizeof(hdr)); memcpy(&hdr.e_ident, ELFMAG, SELFMAG); hdr.e_ident[EI_CLASS] = ELFCLASS32; hdr.e_ident[EI_DATA] = ea->endian; hdr.e_ident[EI_VERSION] = EV_CURRENT; if(ea->endian == ELFDATA2MSB) { hdr.e_type = _htob16(ET_REL); hdr.e_machine = _htob16(ea->machine); hdr.e_version = _htob32(EV_CURRENT); hdr.e_ehsize = _htob16(sizeof(hdr)); hdr.e_shentsize = _htob16(sizeof(Elf32_Shdr)); hdr.e_shstrndx = _htob16(SHN_UNDEF); } else { hdr.e_type = _htol16(ET_REL); hdr.e_machine = _htol16(ea->machine); hdr.e_version = _htol32(EV_CURRENT); hdr.e_ehsize = _htol16(sizeof(hdr)); hdr.e_shentsize = _htol16(sizeof(Elf32_Shdr)); hdr.e_shstrndx = _htol16(SHN_UNDEF); } if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return _elf_error(format); return 0; } /* exit_32 */ static int _exit_32_phdr(FormatPlugin * format, Elf32_Off offset); static int _exit_32_shdr(FormatPlugin * format, Elf32_Off offset); static int _exit_32(FormatPlugin * format) { int ret = 0; FormatPluginHelper * helper = format->helper; long offset; if(_section_32(format, ".shstrtab") != 0) ret = -1; else if(helper->write(helper->format, shstrtab.buf, shstrtab.cnt) != (ssize_t)shstrtab.cnt) ret = -1; else if((offset = helper->seek(helper->format, 0, SEEK_CUR)) < 0) ret = -1; else if(_exit_32_phdr(format, offset) != 0 || _exit_32_shdr(format, offset) != 0) ret = -1; free(shstrtab.buf); shstrtab.buf = NULL; shstrtab.cnt = 0; ret |= _elf_exit(format); return ret; } static int _exit_32_phdr(FormatPlugin * format, Elf32_Off offset) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf32_Ehdr hdr; if(elf->es32_cnt == 0) return 0; if(helper->seek(helper->format, 0, SEEK_SET) != 0) return -1; if(helper->read(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return _elf_error(format); if(ea->endian == ELFDATA2MSB) { hdr.e_shoff = _htob32(offset); hdr.e_shnum = _htob16(elf->es32_cnt + 1); hdr.e_shstrndx = _htob16(elf->es32_cnt); } else { hdr.e_shoff = _htol32(offset); hdr.e_shnum = _htol16(elf->es32_cnt + 1); hdr.e_shstrndx = _htol16(elf->es32_cnt); } if(helper->seek(helper->format, 0, SEEK_SET) != 0) return -1; if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; return 0; } static int _exit_32_shdr(FormatPlugin * format, Elf32_Off offset) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf32_Word addralign = ea->addralign; Elf32_Shdr * es32 = elf->es32; Elf32_Shdr hdr; int i; if(helper->seek(helper->format, 0, SEEK_END) < 0) return _elf_error(format); memset(&hdr, 0, sizeof(hdr)); if(ea->endian == ELFDATA2MSB) { hdr.sh_type = _htob32(SHT_NULL); hdr.sh_link = _htob32(SHN_UNDEF); } else { hdr.sh_type = _htol32(SHT_NULL); hdr.sh_link = _htol32(SHN_UNDEF); } if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; for(i = 0; i < elf->es32_cnt; i++) { if(i + 1 == elf->es32_cnt) es32[i].sh_size = offset - es32[i].sh_offset; else es32[i].sh_size = es32[i + 1].sh_offset - es32[i].sh_offset; es32[i].sh_size = (ea->endian == ELFDATA2MSB) ? _htob32(es32[i].sh_size) : _htol32(es32[i].sh_size); if(es32[i].sh_type == SHT_PROGBITS) es32[i].sh_addralign = (ea->endian == ELFDATA2MSB) ? _htob32(addralign) : _htol32(addralign); es32[i].sh_type = (ea->endian == ELFDATA2MSB) ? _htob32(es32[i].sh_type) : _htol32(es32[i].sh_type); if(helper->write(helper->format, &es32[i], sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) return -1; } return 0; } /* section_32 */ static int _section_32(FormatPlugin * format, char const * name) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; int ss; Elf32_Shdr * p; ElfSectionValues * esv; long offset; if((ss = _elfstrtab_set(format, &shstrtab, name)) < 0) return -1; if((p = realloc(elf->es32, sizeof(*p) * (elf->es32_cnt + 1))) == NULL) return _elf_error(format); elf->es32 = p; p = &elf->es32[elf->es32_cnt++]; memset(p, 0, sizeof(*p)); esv = _section_values(name); p->sh_name = ss; p->sh_type = esv->type; p->sh_flags = esv->flags; if((offset = helper->seek(helper->format, 0, SEEK_CUR)) < 0) return -1; p->sh_offset = offset; p->sh_link = SHN_UNDEF; /* FIXME */ return 0; } /* swap_32_ehdr */ static void _swap_32_ehdr(Elf32_Ehdr * ehdr) { ehdr->e_type = _bswap16(ehdr->e_type); ehdr->e_machine = _bswap16(ehdr->e_machine); ehdr->e_version = _bswap32(ehdr->e_version); ehdr->e_entry = _bswap32(ehdr->e_entry); ehdr->e_phoff = _bswap32(ehdr->e_phoff); ehdr->e_shoff = _bswap32(ehdr->e_shoff); ehdr->e_flags = _bswap32(ehdr->e_flags); 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); } /* swap_32_phdr */ static void _swap_32_phdr(Elf32_Phdr * phdr) { phdr->p_type = _bswap32(phdr->p_type); phdr->p_offset = _bswap32(phdr->p_offset); phdr->p_vaddr = _bswap32(phdr->p_vaddr); phdr->p_paddr = _bswap32(phdr->p_paddr); phdr->p_filesz = _bswap32(phdr->p_filesz); phdr->p_memsz = _bswap32(phdr->p_memsz); phdr->p_flags = _bswap32(phdr->p_flags); phdr->p_align = _bswap32(phdr->p_align); } /* swap_32_shdr */ static void _swap_32_shdr(Elf32_Shdr * shdr) { shdr->sh_name = _bswap32(shdr->sh_name); shdr->sh_type = _bswap32(shdr->sh_type); shdr->sh_flags = _bswap32(shdr->sh_flags); shdr->sh_addr = _bswap32(shdr->sh_addr); shdr->sh_offset = _bswap32(shdr->sh_offset); shdr->sh_size = _bswap32(shdr->sh_size); shdr->sh_link = _bswap32(shdr->sh_link); shdr->sh_info = _bswap32(shdr->sh_info); shdr->sh_addralign = _bswap32(shdr->sh_addralign); shdr->sh_entsize = _bswap32(shdr->sh_entsize); } /* ELF64 */ /* init_64 */ static int _init_64(FormatPlugin * format) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf64_Ehdr hdr; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif memset(&hdr, 0, sizeof(hdr)); memcpy(&hdr.e_ident, ELFMAG, SELFMAG); hdr.e_ident[EI_CLASS] = ELFCLASS64; hdr.e_ident[EI_DATA] = ea->endian; hdr.e_ident[EI_VERSION] = EV_CURRENT; if(ea->endian == ELFDATA2MSB) { hdr.e_type = _htob16(ET_REL); hdr.e_machine = _htob16(ea->machine); hdr.e_version = _htob32(EV_CURRENT); hdr.e_ehsize = _htob16(sizeof(hdr)); hdr.e_shentsize = _htob16(sizeof(Elf64_Shdr)); } else { hdr.e_type = _htol16(ET_REL); hdr.e_machine = _htol16(ea->machine); hdr.e_version = _htol32(EV_CURRENT); hdr.e_ehsize = _htol16(sizeof(hdr)); hdr.e_shentsize = _htol16(sizeof(Elf64_Shdr)); } hdr.e_shstrndx = SHN_UNDEF; if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; return 0; } /* exit_64 */ static int _exit_64_phdr(FormatPlugin * format, Elf64_Off offset); static int _exit_64_shdr(FormatPlugin * format, Elf64_Off offset); static int _exit_64(FormatPlugin * format) { int ret = 0; FormatPluginHelper * helper = format->helper; long offset; if(_section_64(format, ".shstrtab") != 0) ret = 1; else if(helper->write(helper->format, shstrtab.buf, shstrtab.cnt) != (ssize_t)shstrtab.cnt) ret = -1; else if((offset = helper->seek(helper->format, 0, SEEK_CUR)) < 0) ret = -1; else if(_exit_64_phdr(format, offset) != 0 || _exit_64_shdr(format, offset) != 0) ret = 1; free(shstrtab.buf); shstrtab.buf = NULL; shstrtab.cnt = 0; ret |= _elf_exit(format); return ret; } static int _exit_64_phdr(FormatPlugin * format, Elf64_Off offset) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf64_Ehdr hdr; if(elf->es64_cnt == 0) return 0; if(helper->seek(helper->format, 0, SEEK_SET) != 0) return -1; if(helper->read(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; if(ea->endian == ELFDATA2MSB) { hdr.e_shoff = _htob64(offset); hdr.e_shnum = _htob16(elf->es64_cnt); hdr.e_shstrndx = _htob16(elf->es64_cnt - 1); } else { hdr.e_shoff = _htol64(offset); hdr.e_shnum = _htol16(elf->es64_cnt); hdr.e_shstrndx = _htol16(elf->es64_cnt - 1); } if(helper->seek(helper->format, 0, SEEK_SET) != 0) return -1; if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; return 0; } static int _exit_64_shdr(FormatPlugin * format, Elf64_Off offset) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; ElfArch * ea = elf->arch; Elf64_Xword addralign = ea->addralign; Elf64_Shdr * es64 = elf->es64; Elf64_Shdr hdr; int i; if(helper->seek(helper->format, 0, SEEK_END) < 0) return _elf_error(format); memset(&hdr, 0, sizeof(hdr)); if(ea->endian == ELFDATA2MSB) { hdr.sh_type = _htob32(SHT_NULL); hdr.sh_link = _htob32(SHN_UNDEF); } else { hdr.sh_type = _htol32(SHT_NULL); hdr.sh_link = _htol32(SHN_UNDEF); } if(helper->write(helper->format, &hdr, sizeof(hdr)) != sizeof(hdr)) return -1; for(i = 0; i < elf->es64_cnt; i++) { if(i + 1 == elf->es64_cnt) es64[i].sh_size = offset - es64[i].sh_offset; else es64[i].sh_size = es64[i + 1].sh_offset - es64[i].sh_offset; es64[i].sh_size = (ea->endian == ELFDATA2MSB) ? _htob64(es64[i].sh_size) : _htol64(es64[i].sh_size); if(es64[i].sh_type == SHT_PROGBITS) es64[i].sh_addralign = (ea->endian == ELFDATA2MSB) ? _htob64(addralign) : _htol64(addralign); es64[i].sh_type = (ea->endian == ELFDATA2MSB) ? _htob32(es64[i].sh_type) : _htol32(es64[i].sh_type); if(helper->write(helper->format, &es64[i], sizeof(Elf64_Shdr)) != sizeof(Elf64_Shdr)) return -1; } return 0; } /* section_64 */ static int _section_64(FormatPlugin * format, char const * name) { FormatPluginHelper * helper = format->helper; Elf * elf = format->priv; int ss; Elf64_Shdr * p; ElfSectionValues * esv; long offset; if((ss = _elfstrtab_set(format, &shstrtab, name)) < 0) return 1; if((p = realloc(elf->es64, sizeof(*p) * (elf->es64_cnt + 1))) == NULL) return _elf_error(format); elf->es64 = p; p = &elf->es64[elf->es64_cnt++]; memset(p, 0, sizeof(*p)); esv = _section_values(name); p->sh_name = ss; p->sh_type = esv->type; p->sh_flags = esv->flags; if((offset = helper->seek(helper->format, 0, SEEK_CUR)) < 0) return -1; p->sh_offset = offset; p->sh_link = SHN_UNDEF; /* FIXME */ return 0; } /* swap_64_ehdr */ static void _swap_64_ehdr(Elf64_Ehdr * ehdr) { ehdr->e_type = _bswap16(ehdr->e_type); ehdr->e_machine = _bswap16(ehdr->e_machine); ehdr->e_version = _bswap32(ehdr->e_version); ehdr->e_entry = _bswap64(ehdr->e_entry); ehdr->e_phoff = _bswap64(ehdr->e_phoff); ehdr->e_shoff = _bswap64(ehdr->e_shoff); ehdr->e_flags = _bswap32(ehdr->e_flags); 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); } /* swap_64_phdr */ static void _swap_64_phdr(Elf64_Phdr * phdr) { phdr->p_type = _bswap32(phdr->p_type); phdr->p_flags = _bswap32(phdr->p_flags); phdr->p_offset = _bswap64(phdr->p_offset); phdr->p_vaddr = _bswap64(phdr->p_vaddr); phdr->p_paddr = _bswap64(phdr->p_paddr); phdr->p_filesz = _bswap64(phdr->p_filesz); phdr->p_memsz = _bswap64(phdr->p_memsz); phdr->p_align = _bswap64(phdr->p_align); } /* swap_64_shdr */ static void _swap_64_shdr(Elf64_Shdr * shdr) { shdr->sh_name = _bswap32(shdr->sh_name); shdr->sh_type = _bswap32(shdr->sh_type); shdr->sh_flags = _bswap64(shdr->sh_flags); shdr->sh_addr = _bswap64(shdr->sh_addr); shdr->sh_offset = _bswap64(shdr->sh_offset); shdr->sh_size = _bswap64(shdr->sh_size); shdr->sh_link = _bswap32(shdr->sh_link); shdr->sh_info = _bswap32(shdr->sh_info); shdr->sh_addralign = _bswap64(shdr->sh_addralign); shdr->sh_entsize = _bswap64(shdr->sh_entsize); } /* ElfStrtab */ /* private */ /* functions */ /* elfstrtab_get */ static int _elfstrtab_set(FormatPlugin * format, ElfStrtab * strtab, char const * name) { size_t len; size_t cnt; char * p; if((len = strlen(name)) == 0 && strtab->cnt != 0) return 0; if((cnt = strtab->cnt) == 0) cnt++; if((p = realloc(strtab->buf, sizeof(char) * (cnt + len + 1))) == NULL) return -_elf_error(format); else if(strtab->buf == NULL) p[0] = '\0'; strtab->buf = p; if(len == 0) { strtab->cnt = cnt; return 0; } strtab->cnt = cnt + len + 1; memcpy(&strtab->buf[cnt], name, len + 1); return cnt; }