Elf32_Shdr *elf_shdr(size_t index) { if(index >= elf_ehdr()->e_shnum) { printf("Warning: section index is out of bounds\n"); return nullptr; } return (Elf32_Shdr *)(g_elf_buf + NTH_SHDR_OFF(index)); }
size_t elf_find_reloc_section(size_t shndx) { /* find the relocation section */ for(size_t i = 0; i < elf_ehdr()->e_shnum; i++) { Elf32_Shdr *shdr = elf_shdr(i); if(shdr->sh_type != SHT_REL && shdr->sh_type != SHT_RELA) continue; if(shdr->sh_info != shndx) continue; return i; } return 0; }
size_t elf_map_virt_addr(uint32_t address, Elf32_Word& out_off) { /* for relocatable file, this is trivial */ for(size_t i = 0; i < elf_ehdr()->e_shnum; i++) { Elf32_Shdr *shdr = elf_shdr(i); if(shdr->sh_offset <= address && address < shdr->sh_offset + shdr->sh_size) { out_off = address - shdr->sh_offset; if(g_verbose) { printf("[map %#x to section %zi (%s) at %#x]\n", address, i, elf_get_section_name(i), out_off); } return i; } } return 0; /* section 0 is always invalid */ }
size_t elf_shnum() { return elf_ehdr()->e_shnum; }
bool elf_init() { if(g_elf_size < sizeof(Elf32_Ehdr)) { printf("Invalid ELF file: too small\n"); return false; } Elf32_Ehdr *ehdr = elf_ehdr(); if(ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) { printf("Invalid ELF file: invalid ident\n"); return false; } /* we only support relocatable files */ if(ehdr->e_type != ET_REL) { printf("Unsupported ELF file: this is not a relocatable file\n"); return false; } if(ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_machine != EM_ARM) { printf("Unsupported ELF file: this is not a 32-bit ARM ELF file\n"); return false; } /* go through sections */ if(ehdr->e_shoff == 0) { printf("Invalid ELF file: no sections\n"); return false; } if(ehdr->e_shentsize < sizeof(Elf32_Shdr)) { printf("Invalid ELF file: section entry size too small\n"); return false; } if(NTH_SHDR_OFF(ehdr->e_shnum) > g_elf_size) { printf("Invalid ELF file: sections header does not fit in the file\n"); return false; } for(size_t i = 0; i < ehdr->e_shnum; i++) { Elf32_Shdr *shdr = (Elf32_Shdr *)(g_elf_buf + NTH_SHDR_OFF(i)); if(shdr->sh_type == SHT_SYMTAB) g_elf_symtab = shdr; } /* handle symbol table */ if(g_elf_symtab) { if(g_elf_symtab->sh_offset + g_elf_symtab->sh_size > g_elf_size) { printf("Invalid ELF file: symtab does not file in the file\n"); return false; } g_elf_symtab_strtab = elf_shdr(g_elf_symtab->sh_link); if(g_elf_symtab_strtab == nullptr) { printf("Invalid ELF file: symtab's strtab is not valid\n"); } if(g_elf_symtab_strtab->sh_type != SHT_STRTAB) { printf("Invalid ELF file: symtab's strtab is not a string table\n"); return false; } } /* handle section string table */ if(ehdr->e_shstrndx != SHN_UNDEF) { g_elf_shstrtab = elf_shdr(ehdr->e_shstrndx); if(g_elf_shstrtab == nullptr) { printf("Invalid ELF file: section string table is invalid\n"); return false; } } return true; }
int parse_elf(const struct buffer *pinput, struct parsed_elf *pelf, int flags) { struct xdr *xdr = &xdr_le; int bit64 = 0; struct buffer input; Elf64_Ehdr *ehdr; /* Zero out the parsed elf structure. */ memset(pelf, 0, sizeof(*pelf)); if (!iself(buffer_get(pinput))) { ERROR("The stage file is not in ELF format!\n"); return -1; } buffer_clone(&input, pinput); ehdr = &pelf->ehdr; elf_eident(&input, ehdr); bit64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64; /* Assume LE unless we are sure otherwise. * We're not going to take on the task of * fully validating the ELF file. That way * lies madness. */ if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) xdr = &xdr_be; elf_ehdr(&input, ehdr, xdr, bit64); /* Relocation processing requires section header parsing. */ if (flags & ELF_PARSE_RELOC) flags |= ELF_PARSE_SHDR; /* String table processing requires section header parsing. */ if (flags & ELF_PARSE_STRTAB) flags |= ELF_PARSE_SHDR; /* Symbole table processing requires section header parsing. */ if (flags & ELF_PARSE_SYMTAB) flags |= ELF_PARSE_SHDR; if ((flags & ELF_PARSE_PHDR) && phdr_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_SHDR) && shdr_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_RELOC) && reloc_read(pinput, pelf, xdr, bit64)) goto fail; if ((flags & ELF_PARSE_STRTAB) && strtab_read(pinput, pelf)) goto fail; if ((flags & ELF_PARSE_SYMTAB) && symtab_read(pinput, pelf, xdr, bit64)) goto fail; return 0; fail: parsed_elf_destroy(pelf); return -1; }