From 9bd58cb2945a8f77ba7f215b21b79322c3a5367e Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Sat, 14 Jul 2018 16:11:44 +0200 Subject: [PATCH] ElfReader: read 64-bit ELF binaries ElfReader now detects whether a 32- or 64-bit ELF is opened, and uses the corresponding elf.h data structures. Internally maps 32-bit ELF structures onto 64-bit structures to use common processing code. Change-Id: Ib42a4b21701aeadac7568e369a80c08f2807694e --- src/core/util/CMakeLists.txt | 2 - src/core/util/ElfReader.cc | 274 +++++++++---- src/core/util/ElfReader.hpp | 38 +- src/core/util/elfinfo/elfinfo.cc | 646 +++++++++++++++++-------------- src/core/util/elfinfo/elfinfo.h | 6 +- 5 files changed, 580 insertions(+), 386 deletions(-) diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt index 53479a8e..c4c50632 100644 --- a/src/core/util/CMakeLists.txt +++ b/src/core/util/CMakeLists.txt @@ -13,8 +13,6 @@ set(SRCS Disassembler.cc DwarfReader.cc DwarfReader.hpp - elfinfo/elfinfo.cc - elfinfo/elfinfo.h gzstream/gzstream.C gzstream/gzstream.h Logger.cc diff --git a/src/core/util/ElfReader.cc b/src/core/util/ElfReader.cc index 78f248c3..a3018ac0 100644 --- a/src/core/util/ElfReader.cc +++ b/src/core/util/ElfReader.cc @@ -26,7 +26,7 @@ std::ostream& operator<< (std::ostream &out, const ElfSymbol &symbol) { -ElfReader::ElfReader() : m_log("FAIL*Elfinfo", false) { +ElfReader::ElfReader() : m_log("ElfReader", false) { // try to open elf file from environment variable char * elfpath = getenv("FAIL_ELF_PATH"); if (elfpath == NULL) { @@ -42,7 +42,7 @@ ElfReader::ElfReader(const char* path) : m_log("FAIL*Elfinfo", false) { void ElfReader::setup(const char* path) { // Try to open the ELF file - FILE * fp = fopen(path, "r"); + FILE *fp = fopen(path, "rb"); if (!fp) { m_log << "Error: Could not open " << path << std::endl; return; @@ -51,70 +51,61 @@ void ElfReader::setup(const char* path) { m_filename = std::string(path); // Evaluate headers - Elf32_Ehdr ehdr; - Elf32_Shdr sec_hdr; - int num_hdrs,i; - fseek(fp,(off_t)0,SEEK_SET); - read_ELF_file_header(fp, &ehdr); - num_hdrs=ehdr.e_shnum; - m_log << "Evaluating ELF File: " << path << std::endl; + Elf64_Ehdr ehdr; + Elf64_Shdr sec_hdr; + int num_hdrs; + if (!read_ELF_file_header(fp, &ehdr)) { + m_log << "Error: " << path << " is not an ELF file" << std::endl; + return; + } + num_hdrs = ehdr.e_shnum; + m_log << "Evaluating " + << (m_elfclass == ELFCLASS32 ? "32-bit" : "64-bit") + << " ELF file: " << path << std::endl; + // Parse symbol table and generate internal map - for (i=0;ish_name; // m_sections_map.push_back( sect_hdr->sh_addr, sect_hdr->sh_size, sect_name_buff+idx ); @@ -123,54 +114,169 @@ int ElfReader::process_section(Elf32_Shdr *sect_hdr, char* sect_name_buff) { return 0; } -int ElfReader::process_symboltable(int sect_num, FILE* fp) { +static void Elf32to64_Sym(Elf32_Sym const *src, Elf64_Sym *dest) +{ + dest->st_name = src->st_name; + dest->st_value = src->st_value; + dest->st_size = src->st_size; + dest->st_info = src->st_info; + dest->st_other = src->st_other; + dest->st_shndx = src->st_shndx; +} - Elf32_Shdr sect_hdr; - Elf32_Sym mysym; - char *name_buf=NULL; - int num_sym,link,i,idx; +bool ElfReader::process_symboltable(FILE *fp, Elf64_Ehdr const *ehdr, int sect_num) { + + Elf64_Shdr sect_hdr; + Elf32_Sym mysym32; + Elf64_Sym mysym; + char *name_buf = 0; + int num_sym, link, idx; off_t sym_data_offset; int sym_data_size; - if (read_ELF_section_header(sect_num,§_hdr,fp)==-1) - { - return -1; + + if (!read_ELF_section_header(fp, ehdr, sect_num, §_hdr)) { + return false; } // we have to check to which strtab it is linked - link=sect_hdr.sh_link; - sym_data_offset=sect_hdr.sh_offset; - sym_data_size=sect_hdr.sh_size; - num_sym=sym_data_size/sizeof(Elf32_Sym); + link = sect_hdr.sh_link; + sym_data_offset = sect_hdr.sh_offset; + sym_data_size = sect_hdr.sh_size; + num_sym = sym_data_size / + (m_elfclass == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); - // read the coresponding strtab - if (read_ELF_section_header(link,§_hdr,fp)==-1) - { - return -1; + // read the corresponding strtab + if (!read_ELF_section_header(fp, ehdr, link, §_hdr)) { + return false; } // get the size of strtab in file and allocate a buffer - name_buf=(char*)malloc(sect_hdr.sh_size); - if (!name_buf) - return -1; + name_buf = (char *) malloc(sect_hdr.sh_size); + if (!name_buf) { + return false; + } // get the offset of strtab in file and seek to it - fseek(fp,sect_hdr.sh_offset,SEEK_SET); + fseek(fp, sect_hdr.sh_offset, SEEK_SET); // read all data from the section to the buffer. - fread(name_buf,sect_hdr.sh_size,1,fp); + if (fread(name_buf, sect_hdr.sh_size, 1, fp) != 1) { + return false; + } // so we have the namebuf now seek to symtab data - fseek(fp,sym_data_offset,SEEK_SET); + fseek(fp, sym_data_offset, SEEK_SET); - for (i=0;ie_ident, src->e_ident, sizeof(dest->e_ident)); + dest->e_type = src->e_type; + dest->e_machine = src->e_machine; + dest->e_version = src->e_version; + dest->e_entry = src->e_entry; + dest->e_phoff = src->e_phoff; + dest->e_shoff = src->e_shoff; + dest->e_flags = src->e_flags; + dest->e_ehsize = src->e_ehsize; + dest->e_phentsize = src->e_phentsize; + dest->e_phnum = src->e_phnum; + dest->e_shentsize = src->e_shentsize; + dest->e_shnum = src->e_shnum; + dest->e_shstrndx = src->e_shstrndx; +} + +bool ElfReader::read_ELF_file_header(FILE *fp, Elf64_Ehdr *filehdr) +{ + Elf32_Ehdr filehdr32; + size_t ret; + + rewind(fp); + ret = fread(&filehdr32, sizeof(filehdr32), 1, fp); + + if (ret != 1 || + strncmp((const char *)filehdr32.e_ident, "\177ELF", 4) != 0) { + return false; + } + + m_elfclass = filehdr32.e_ident[EI_CLASS]; + if (m_elfclass == ELFCLASS32) { + Elf32to64_Ehdr(&filehdr32, filehdr); + } else if (m_elfclass == ELFCLASS64) { + rewind(fp); + ret = fread(filehdr, sizeof(*filehdr), 1, fp); + + if (ret != 1) { + return false; + } + } else { + return false; + } + return true; +} + +static void Elf32to64_Shdr(Elf32_Shdr const *src, Elf64_Shdr *dest) +{ + dest->sh_name = src->sh_name; + dest->sh_type = src->sh_type; + dest->sh_flags = src->sh_flags; + dest->sh_addr = src->sh_addr; + dest->sh_offset = src->sh_offset; + dest->sh_size = src->sh_size; + dest->sh_link = src->sh_link; + dest->sh_info = src->sh_info; + dest->sh_addralign = src->sh_addralign; + dest->sh_entsize = src->sh_entsize; +} + +bool ElfReader::read_ELF_section_header(FILE *fp, Elf64_Ehdr const *filehdr, int section, Elf64_Shdr *sect_hdr) +{ + int numsect = filehdr->e_shnum; + off_t sect_hdr_off; + Elf32_Shdr sect_hdr32; + + if (numsect < section || section < 0) { + return false; + } + sect_hdr_off = filehdr->e_shoff; + sect_hdr_off += filehdr->e_shentsize * section; + fseek(fp, (off_t) sect_hdr_off, SEEK_SET); + if (m_elfclass == ELFCLASS32) { + int ret = fread(§_hdr32, sizeof(sect_hdr32), 1, fp); + if (ret != 1) { + return false; + } + + Elf32to64_Shdr(§_hdr32, sect_hdr); + } else if (m_elfclass == ELFCLASS64) { + int ret = fread(sect_hdr, sizeof(*sect_hdr), 1, fp); + if (ret != 1) { + return false; + } + } else { + return false; + } + + return true; } const ElfSymbol& ElfReader::getSymbol(guest_address_t address) { diff --git a/src/core/util/ElfReader.hpp b/src/core/util/ElfReader.hpp index c1c61283..b7babbdd 100644 --- a/src/core/util/ElfReader.hpp +++ b/src/core/util/ElfReader.hpp @@ -3,11 +3,11 @@ #include #include -#include "sal/SALConfig.hpp" // for ADDR_INV -#include "Logger.hpp" -#include "elfinfo/elfinfo.h" #include #include +#include +#include "sal/SALConfig.hpp" // for ADDR_INV +#include "Logger.hpp" #include "Demangler.hpp" namespace fail { @@ -28,19 +28,19 @@ class ElfSymbol { ElfSymbol(const std::string & name = ELF::NOTFOUND, guest_address_t addr = ADDR_INV, size_t size = -1, int type = UNDEF, int symbol_type = 0) - : name(name), address(addr), size(size), m_type(type), m_symbol_type(symbol_type) {}; + : name(name), address(addr), size(size), m_type(type), m_symbol_type(symbol_type) {} - const std::string& getName() const { return name; }; - std::string getDemangledName() const { return Demangler::demangle(name); }; - guest_address_t getAddress() const { return address; }; - size_t getSize() const { return size; }; - guest_address_t getStart() const { return getAddress(); }; // alias - guest_address_t getEnd() const { return address + size; }; - int getSymbolType() const { return m_symbol_type; }; + const std::string& getName() const { return name; } + std::string getDemangledName() const { return Demangler::demangle(name); } + guest_address_t getAddress() const { return address; } + size_t getSize() const { return size; } + guest_address_t getStart() const { return getAddress(); } // alias + guest_address_t getEnd() const { return address + size; } + int getSymbolType() const { return m_symbol_type; } - bool isSection() const { return m_type == SECTION; }; - bool isSymbol() const { return m_type == SYMBOL; }; - bool isValid() const { return name != ELF::NOTFOUND; }; + bool isSection() const { return m_type == SECTION; } + bool isSymbol() const { return m_type == SYMBOL; } + bool isValid() const { return name != ELF::NOTFOUND; } bool operator==(const std::string& rhs) const { if (rhs == name) { @@ -157,10 +157,16 @@ public: private: Logger m_log; std::string m_filename; + int m_elfclass; void setup(const char*); - int process_symboltable(int sect_num, FILE* fp); - int process_section(Elf32_Shdr *sect_hdr, char* sect_name_buff); + bool process_symboltable(FILE *fp, Elf64_Ehdr const *ehdr, int sect_num); + int process_section(Elf64_Shdr *sect_hdr, char *sect_name_buff); + + // Returns true if it finds a valid ELF header. Stores ELFCLASS32 or 64 in m_elfclass. + bool read_ELF_file_header(FILE *fp, Elf64_Ehdr *ehdr); + // Returns true if it finds a valid ELF section header. + bool read_ELF_section_header(FILE *fp, Elf64_Ehdr const *filehdr, int sect_num, Elf64_Shdr *sect_hdr); container_t m_symboltable; container_t m_sectiontable; diff --git a/src/core/util/elfinfo/elfinfo.cc b/src/core/util/elfinfo/elfinfo.cc index 642ac528..229c19b5 100644 --- a/src/core/util/elfinfo/elfinfo.cc +++ b/src/core/util/elfinfo/elfinfo.cc @@ -28,318 +28,400 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include - -void read_ELF_file_header(FILE* fp,Elf32_Ehdr *filehdr) +static void Elf32to64_Ehdr(Elf32_Ehdr const *src, Elf64_Ehdr *dest) { - //rewind(fp); - fread(filehdr,sizeof(Elf32_Ehdr),1,fp); + memcpy(dest->e_ident, src->e_ident, sizeof(dest->e_ident)); + dest->e_type = src->e_type; + dest->e_machine = src->e_machine; + dest->e_version = src->e_version; + dest->e_entry = src->e_entry; + dest->e_phoff = src->e_phoff; + dest->e_shoff = src->e_shoff; + dest->e_flags = src->e_flags; + dest->e_ehsize = src->e_ehsize; + dest->e_phentsize = src->e_phentsize; + dest->e_phnum = src->e_phnum; + dest->e_shentsize = src->e_shentsize; + dest->e_shnum = src->e_shnum; + dest->e_shstrndx = src->e_shstrndx; } -int is_ELF(Elf32_Ehdr *hdr) +bool read_ELF_file_header(FILE *fp, Elf64_Ehdr *filehdr, int *elfclass) { - if(strncmp(reinterpret_cast(hdr->e_ident),"\177ELF",4)==0) - return 1; - else - return -1; + Elf32_Ehdr filehdr32; + size_t ret; + rewind(fp); + ret = fread(&filehdr32, sizeof(filehdr32), 1, fp); + + if (ret != 1 || + strncmp((const char *)filehdr32.e_ident, "\177ELF", 4) != 0) { + return false; + } + + *elfclass = filehdr32.e_ident[EI_CLASS]; + if (*elfclass == ELFCLASS32) { + Elf32to64_Ehdr(&filehdr32, filehdr); + } else if (*elfclass == ELFCLASS64) { + rewind(fp); + ret = fread(filehdr, sizeof(*filehdr), 1, fp); + + if (ret != 1) { + return false; + } + } else { + return false; + } + return true; } -int read_ELF_section_header(int sect_num,Elf32_Shdr *sect_hdr,FILE *fp) +static void Elf32to64_Shdr(Elf32_Shdr const *src, Elf64_Shdr *dest) { - int numsect; - Elf32_Ehdr elfhdr; - off_t sect_hdr_off; - fseek(fp,(off_t)0,SEEK_SET); - read_ELF_file_header(fp,&elfhdr); - numsect=elfhdr.e_shnum; - if ((numsectsh_name = src->sh_name; + dest->sh_type = src->sh_type; + dest->sh_flags = src->sh_flags; + dest->sh_addr = src->sh_addr; + dest->sh_offset = src->sh_offset; + dest->sh_size = src->sh_size; + dest->sh_link = src->sh_link; + dest->sh_info = src->sh_info; + dest->sh_addralign = src->sh_addralign; + dest->sh_entsize = src->sh_entsize; } -void process_sect_hdr(Elf32_Shdr *sect_hdr,char *sect_name_buff) +bool read_ELF_section_header(FILE *fp, Elf64_Ehdr const *filehdr, int elfclass, int section, Elf64_Shdr *sect_hdr) { - int idx; - idx=sect_hdr->sh_name; - printf(" %-20s (0x%x++0x%x) ",sect_name_buff+idx, sect_hdr->sh_addr, sect_hdr->sh_size); - if(sect_hdr->sh_entsize) - printf(" %c ",'*'); - else - printf(" %c ",' '); - switch(sect_hdr->sh_type) - { - case 0: printf("NULL \t"); - break; - case 1: printf("PROGBITS \t"); - break; - case 2: printf("SYMTAB \t"); - break; - case 3: printf("STRTAB \t"); - break; - case 4: printf("RELOC ADN \t"); - break; - case 5: printf("HASH \t"); - break; - case 6: printf("SYMTAB \t"); - break; - case 7: printf("NOTE \t"); - break; - case 8: printf("NOBIT \t"); - break; - case 9: printf("RELOC \t"); - break; - case 10: printf("*reserved* \t"); - break; - case 11: printf("DYNSYM \t"); - break; - case 14: printf("INITARR \t"); - break; - case 15: printf("FINIARR \t"); - break; - case 16: printf("PREINIT \t"); - break; - case 17: printf("SECTGRP \t"); - break; - case 18: printf("EXT-SHNDX \t"); - break; - case 19: printf("NUM-DEF-TYP \t"); - break; - case 0x60000000: printf("OS SPECIFIC \t"); - break; - case 0x6ffffff5: printf("GNU_ATTR \t"); - break; - case 0x6ffffff6: printf("GNU_HASH \t"); - break; - case 0x6ffffff7: printf("PRELNKLIBLST \t"); - break; - case 0x6ffffff8: printf("CKSUM \t"); - break; - case 0x6ffffffa: printf("SUN SPECIFIC \t"); - break; - case 0x6ffffffb: printf("SUNCOMDAT \t"); - break; - case 0x6ffffffc: printf("SUNSYMINFO \t"); - break; - case 0x6ffffffd: printf("GNUVERDEF \t"); - break; - case 0x6ffffffe: printf("GNUVERNEED \t"); - break; - case 0x6fffffff: printf("GNUVERSYM \t"); - break; - case 0x70000000: printf("LOPROC \t"); - break; - case 0x7fffffff: printf("HIPROC \t"); - break; - case 0x80000000: printf("APP beg \t"); - break; - case 0x8fffffff: printf("APP end \t"); - break; - } - printf("linked to %3d sect\n",sect_hdr->sh_link); + int numsect = filehdr->e_shnum; + off_t sect_hdr_off; + Elf32_Shdr sect_hdr32; + + if (numsect < section || section < 0) { + return false; + } + sect_hdr_off = filehdr->e_shoff; + sect_hdr_off += filehdr->e_shentsize * section; + fseek(fp, (off_t) sect_hdr_off, SEEK_SET); + if (elfclass == ELFCLASS32) { + int ret = fread(§_hdr32, sizeof(sect_hdr32), 1, fp); + if (ret != 1) { + return false; + } + + Elf32to64_Shdr(§_hdr32, sect_hdr); + } else if (elfclass == ELFCLASS64) { + int ret = fread(sect_hdr, sizeof(*sect_hdr), 1, fp); + if (ret != 1) { + return false; + } + } else { + return false; + } + + return true; +} + +#ifdef TESTPROGRAM +void process_sect_hdr(Elf64_Shdr const *sect_hdr, char const *sect_name_buff) +{ + int idx; + idx = sect_hdr->sh_name; + printf(" %-20s (0x%lx++0x%lx) ", sect_name_buff + idx, sect_hdr->sh_addr, sect_hdr->sh_size); + if (sect_hdr->sh_entsize) { + printf(" %c ",'*'); + } else { + printf(" %c ",' '); + } + switch (sect_hdr->sh_type) { + case 0: printf("NULL \t"); + break; + case 1: printf("PROGBITS \t"); + break; + case 2: printf("SYMTAB \t"); + break; + case 3: printf("STRTAB \t"); + break; + case 4: printf("RELOC ADN \t"); + break; + case 5: printf("HASH \t"); + break; + case 6: printf("SYMTAB \t"); + break; + case 7: printf("NOTE \t"); + break; + case 8: printf("NOBIT \t"); + break; + case 9: printf("RELOC \t"); + break; + case 10: printf("*reserved* \t"); + break; + case 11: printf("DYNSYM \t"); + break; + case 14: printf("INITARR \t"); + break; + case 15: printf("FINIARR \t"); + break; + case 16: printf("PREINIT \t"); + break; + case 17: printf("SECTGRP \t"); + break; + case 18: printf("EXT-SHNDX \t"); + break; + case 19: printf("NUM-DEF-TYP \t"); + break; + case 0x60000000: printf("OS SPECIFIC \t"); + break; + case 0x6ffffff5: printf("GNU_ATTR \t"); + break; + case 0x6ffffff6: printf("GNU_HASH \t"); + break; + case 0x6ffffff7: printf("PRELNKLIBLST \t"); + break; + case 0x6ffffff8: printf("CKSUM \t"); + break; + case 0x6ffffffa: printf("SUN SPECIFIC \t"); + break; + case 0x6ffffffb: printf("SUNCOMDAT \t"); + break; + case 0x6ffffffc: printf("SUNSYMINFO \t"); + break; + case 0x6ffffffd: printf("GNUVERDEF \t"); + break; + case 0x6ffffffe: printf("GNUVERNEED \t"); + break; + case 0x6fffffff: printf("GNUVERSYM \t"); + break; + case 0x70000000: printf("LOPROC \t"); + break; + case 0x7fffffff: printf("HIPROC \t"); + break; + case 0x80000000: printf("APP beg \t"); + break; + case 0x8fffffff: printf("APP end \t"); + break; + } + printf("linked to %3d sect\n", sect_hdr->sh_link); } void display_sections(FILE *fp) { - Elf32_Ehdr ehdr; - Elf32_Shdr sec_hdr; - int num_hdrs,i; - char *buff=NULL; - fseek(fp,(off_t)0,SEEK_SET); - read_ELF_file_header(fp, &ehdr); - if(is_ELF(&ehdr)==-1) - { - printf("Not an ELF file\n"); - exit(0); - } - num_hdrs=ehdr.e_shnum; - if(read_ELF_section_header(ehdr.e_shstrndx,&sec_hdr,fp)==-1) - { - printf("Error: reading section string table sect_num= %d\n",ehdr.e_shstrndx); - exit(0); - } - //we read the shstrtab - // read content from the file - buff=(char*)malloc(sec_hdr.sh_size); - if (!buff) - { - printf("Malloc failed to allocate buffer for shstrtab\n"); - exit(0); - } - //seek to the offset in the file, - fseek(fp,(off_t)sec_hdr.sh_offset,SEEK_SET); - fread(buff,sec_hdr.sh_size,1,fp); - printf("There are [%d] sections\n",num_hdrs); - for(i=0;ist_name = src->st_name; + dest->st_value = src->st_value; + dest->st_size = src->st_size; + dest->st_info = src->st_info; + dest->st_other = src->st_other; + dest->st_shndx = src->st_shndx; +} - //read the coresponding strtab - if(read_ELF_section_header(link,§_hdr,fp)==-1) - { - return -1; - } - //get the size of strtab in file and allocate a buffer - name_buf=(char*)malloc(sect_hdr.sh_size); - if(!name_buf) - return -1; - //get the offset of strtab in file and seek to it - fseek(fp,sect_hdr.sh_offset,SEEK_SET); - //read all data from the section to the buffer. - fread(name_buf,sect_hdr.sh_size,1,fp); - //so we have the namebuf now seek to symtab data - fseek(fp,sym_data_offset,SEEK_SET); - printf("[%d] symbols\n",num_sym); - for(i=0;i // ELFinfo -void read_ELF_file_header(FILE* fp,Elf32_Ehdr *filehdr); -int read_ELF_section_header(int sect_num,Elf32_Shdr *sect_hdr,FILE *fp); +// Returns true if it finds a valid ELF header. Stores ELFCLASS32 or 64 in elfclass. +bool read_ELF_file_header(FILE *fp, Elf64_Ehdr *filehdr, int *elfclass); +// Returns true if it finds a valid ELF section header. +bool read_ELF_section_header(FILE *fp, Elf64_Ehdr const *filehdr, int elfclass, int sect_num, Elf64_Shdr *sect_hdr); void display_sections(FILE *fp); #endif // ELFINFO_H