/*------------------------------------------------------------------------------ -- This file is a part of the SocExplorer Software -- Copyright (C) 2014, Plasma Physics Laboratory - CNRS -- -- 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; either version 2 of the License, or -- (at your option) any later version. -- -- 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 -------------------------------------------------------------------------------*/ /*-- Author : Alexis Jeandet -- Mail : alexis.jeandet@member.fsf.org ----------------------------------------------------------------------------*/ #include "elffile.h" #include "srecfile.h" #include "binaryfile.h" #include ElfFile::ElfFile() :abstractBinFile() { this->opened = false; this->type_elf = false; this->elfFile = (int)NULL; this->e = NULL; } ElfFile::ElfFile(const QString &File) :abstractBinFile() { this->opened = false; this->type_elf = false; this->elfFile = (int)NULL; this->e = NULL; this->p_fileName = File; openFile(File); } ElfFile::~ElfFile() { closeFile(); if(scn)free(scn); if(data)free(data); for(int i=0;isections.count();i++) { delete this->sections.at(i); } this->sections.clear(); for(int i=0;iSegments.count();i++) { free(this->Segments.at(i)); } this->Segments.clear(); for(int i=0;isymbols.at(i); } this->symbols.clear(); } bool ElfFile::openFile(const QString &File) { this->p_fileName = File; this->closeFile(); if(elf_version(EV_CURRENT)==EV_NONE)return 0; #ifdef _ELF_WINDOWS_ this->elfFile = open(File.toStdString().c_str(),O_RDONLY|O_BINARY ,0); #else this->elfFile = open(File.toStdString().c_str(),O_RDONLY ,0); #endif if(this->elfFile==(int)NULL)return 0; this->e = elf_begin(this->elfFile,ELF_C_READ,NULL); if(this->e==NULL)return 0; this->ek = elf_kind(this->e); gelf_getehdr (this->e, &this->ehdr ); elf_getshdrstrndx (this->e, &this->shstrndx); this->updateSegments(); this->updateSections(); this->updateSymbols(); this->opened = true; return 1; } bool ElfFile::isopened() { return this->opened; } int ElfFile::closeFile() { if(this->elfFile!=(int)NULL) { if(this->e!=NULL) { elf_end(this->e); this->e = NULL; } close(this->elfFile); this->elfFile = (int)NULL; } this->opened = false; return 0; } QList ElfFile::getFragments(QStringList fragmentList) { QList fragments; if (isopened()) { for(int i =0;i ElfFile::getFragments() { return getFragments(QStringList()<<".data"<<".text"); } codeFragment *ElfFile::getFragment(const QString &name) { codeFragment* fragment= new codeFragment(); for(int i=0;idata =NULL; fragment->size = getSectionDatasz(i); fragment->address = getSectionPaddr(i); getSectionData(i,&fragment->data); } } return fragment; } QString elfresolveMachine(Elf64_Half e_machine) { QString machineName; //Update from with bash script don't write it by yourself! switch(e_machine) { case EM_NONE: machineName = " No machine "; break; case EM_M32: machineName = " AT&T WE 32100 "; break; case EM_SPARC: machineName = " SUN SPARC "; break; case EM_386: machineName = " Intel 80386 "; break; case EM_68K: machineName = " Motorola m68k family "; break; case EM_88K: machineName = " Motorola m88k family "; break; case EM_860: machineName = " Intel 80860 "; break; case EM_MIPS: machineName = " MIPS R3000 big-endian "; break; case EM_S370: machineName = " IBM System/370 "; break; case EM_MIPS_RS3_LE: machineName = " MIPS R3000 little-endian "; break; case EM_PARISC: machineName = " HPPA "; break; case EM_VPP500: machineName = " Fujitsu VPP500 "; break; case EM_SPARC32PLUS: machineName = " Sun's \"v8plus\" "; break; case EM_960: machineName = " Intel 80960 "; break; case EM_PPC: machineName = " PowerPC "; break; case EM_PPC64: machineName = " PowerPC 64-bit "; break; case EM_S390: machineName = " IBM S390 "; break; case EM_V800: machineName = " NEC V800 series "; break; case EM_FR20: machineName = " Fujitsu FR20 "; break; case EM_RH32: machineName = " TRW RH-32 "; break; case EM_RCE: machineName = " Motorola RCE "; break; case EM_ARM: machineName = " ARM "; break; case EM_FAKE_ALPHA: machineName = " Digital Alpha "; break; case EM_SH: machineName = " Hitachi SH "; break; case EM_SPARCV9: machineName = " SPARC v9 64-bit "; break; case EM_TRICORE: machineName = " Siemens Tricore "; break; case EM_ARC: machineName = " Argonaut RISC Core "; break; case EM_H8_300: machineName = " Hitachi H8/300 "; break; case EM_H8_300H: machineName = " Hitachi H8/300H "; break; case EM_H8S: machineName = " Hitachi H8S "; break; case EM_H8_500: machineName = " Hitachi H8/500 "; break; case EM_IA_64: machineName = " Intel Merced "; break; case EM_MIPS_X: machineName = " Stanford MIPS-X "; break; case EM_COLDFIRE: machineName = " Motorola Coldfire "; break; case EM_68HC12: machineName = " Motorola M68HC12 "; break; case EM_MMA: machineName = " Fujitsu MMA Multimedia Accelerator"; break; case EM_PCP: machineName = " Siemens PCP "; break; case EM_NCPU: machineName = " Sony nCPU embeeded RISC "; break; case EM_NDR1: machineName = " Denso NDR1 microprocessor "; break; case EM_STARCORE: machineName = " Motorola Start*Core processor "; break; case EM_ME16: machineName = " Toyota ME16 processor "; break; case EM_ST100: machineName = " STMicroelectronic ST100 processor "; break; case EM_TINYJ: machineName = " Advanced Logic Corp. Tinyj emb.fam"; break; case EM_X86_64: machineName = " AMD x86-64 architecture "; break; case EM_PDSP: machineName = " Sony DSP Processor "; break; case EM_FX66: machineName = " Siemens FX66 microcontroller "; break; case EM_ST9PLUS: machineName = " STMicroelectronics ST9+ 8/16 mc "; break; case EM_ST7: machineName = " STmicroelectronics ST7 8 bit mc "; break; case EM_68HC16: machineName = " Motorola MC68HC16 microcontroller "; break; case EM_68HC11: machineName = " Motorola MC68HC11 microcontroller "; break; case EM_68HC08: machineName = " Motorola MC68HC08 microcontroller "; break; case EM_68HC05: machineName = " Motorola MC68HC05 microcontroller "; break; case EM_SVX: machineName = " Silicon Graphics SVx "; break; case EM_ST19: machineName = " STMicroelectronics ST19 8 bit mc "; break; case EM_VAX: machineName = " Digital VAX "; break; case EM_CRIS: machineName = " Axis Communications 32-bit embedded processor "; break; case EM_JAVELIN: machineName = " Infineon Technologies 32-bit embedded processor "; break; case EM_FIREPATH: machineName = " Element 14 64-bit DSP Processor "; break; case EM_ZSP: machineName = " LSI Logic 16-bit DSP Processor "; break; case EM_MMIX: machineName = " Donald Knuth's educational 64-bit processor "; break; case EM_HUANY: machineName = " Harvard University machine-independent object files "; break; case EM_PRISM: machineName = " SiTera Prism "; break; case EM_AVR: machineName = " Atmel AVR 8-bit microcontroller "; break; case EM_FR30: machineName = " Fujitsu FR30 "; break; case EM_D10V: machineName = " Mitsubishi D10V "; break; case EM_D30V: machineName = " Mitsubishi D30V "; break; case EM_V850: machineName = " NEC v850 "; break; case EM_M32R: machineName = " Mitsubishi M32R "; break; case EM_MN10300: machineName = " Matsushita MN10300 "; break; case EM_MN10200: machineName = " Matsushita MN10200 "; break; case EM_PJ: machineName = " picoJava "; break; case EM_OPENRISC: machineName = " OpenRISC 32-bit embedded processor "; break; case EM_ARC_A5: machineName = " ARC Cores Tangent-A5 "; break; case EM_XTENSA: machineName = " Tensilica Xtensa Architecture "; break; case EM_AARCH64: machineName = " ARM AARCH64 "; break; case EM_TILEPRO: machineName = " Tilera TILEPro "; break; case EM_MICROBLAZE: machineName = " Xilinx MicroBlaze "; break; case EM_TILEGX: machineName = " Tilera TILE-Gx "; break; case EM_NUM: machineName = ""; break; default: machineName ="Unknow Machine"; break; } return machineName; } QString ElfFile::getClass() { if(this->e!=NULL) { int eclass = gelf_getclass(this->e); if(eclass==ELFCLASS32)return "ELF32"; if(eclass==ELFCLASS64)return "ELF64"; } return "none"; } bool ElfFile::iself() { return (this->getType()!="Unknow"); } QString ElfFile::getArchitecture() { if(this->e!=NULL) { return elfresolveMachine(this->ehdr.e_machine); } return ""; } QString ElfFile::getType() { QString kind(""); if(this->e!=NULL) { switch(this->ek) { case ELF_K_AR: kind = "Archive"; break; case ELF_K_ELF: kind = "Elf"; break; case ELF_K_COFF: kind = "COFF"; break; case ELF_K_NUM: kind = "NUM"; break; case ELF_K_NONE: kind = "Data"; break; default: kind = "Unknow"; break; } } return kind; } QString ElfFile::getEndianness() { if(this->e!=NULL) { if(this->ehdr.e_ident[EI_DATA]==ELFDATA2LSB)return "2's complement, little endian"; if(this->ehdr.e_ident[EI_DATA]==ELFDATA2MSB)return "2's complement, big endian"; } return "none"; } QString ElfFile::getABI() { if(this->e!=NULL) { if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_NONE)return "UNIX System V ABI"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_SYSV)return "Alias"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_HPUX)return "HP-UX"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_NETBSD)return "NetBSD"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_LINUX)return "Object uses GNU ELF extensions"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_SOLARIS)return "Sun Solaris"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_AIX)return "IBM AIX"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_IRIX)return "SGI Irix"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_FREEBSD)return "FreeBSD"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_TRU64)return "Compaq TRU64 UNIX"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_MODESTO)return " Novell Modesto"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_OPENBSD)return "OpenBSD"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_ARM_AEABI)return "ARM EABI"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_ARM)return "ARM"; if(this->ehdr.e_ident[EI_OSABI]==ELFOSABI_STANDALONE)return "Standalone (embedded) application"; } return "none"; } qint64 ElfFile::getVersion() { if(this->e!=NULL) { return this->ehdr.e_version; } return -1; } qint64 ElfFile::getEntryPointAddress() { if(this->e!=NULL) { return this->ehdr.e_entry; } return -1; } int ElfFile::getSectionCount() { return (int)this->SectionCount; } int ElfFile::getSymbolCount() { return (int)this->SymbolCount; } int ElfFile::getSegmentCount() { return (int)this->SegmentCount; } QString ElfFile::getSegmentType(int index) { QString type(""); if(this->e!=NULL) { if(index < this->Segments.count()) { switch(this->Segments.at(index)->p_type) { case PT_NULL: type = "Program header table entry unused"; break; case PT_LOAD: type = "Loadable program segment"; break; case PT_DYNAMIC : type = "Dynamic linking information"; break; case PT_INTERP: type ="Program interpreter"; break; case PT_NOTE: type = "Auxiliary information"; break; case PT_SHLIB: type = "Reserved"; break; case PT_PHDR: type = "Entry for header table itself"; break; case PT_TLS: type = "Thread-local storage segment"; break; case PT_NUM: type = "Number of defined types"; break; case PT_LOOS: type = "Start of OS-specific"; break; case PT_SUNWSTACK: type = "Stack segment"; break; case PT_LOPROC: type = "Start of processor-specific"; break; case PT_HIPROC: type = "End of processor-specific"; break; default: type = "Unknow Section Type"; break; } } } return type; } qint64 ElfFile::getSegmentOffset(int index) { qint64 Offset = -1; if(this->e!=NULL) { if(index < this->Segments.count()) { Offset = (qint64)this->Segments.at(index)->p_offset; } } return Offset; } qint64 ElfFile::getSegmentVaddr(int index) { int64_t Vaddr = 0; if(this->e!=NULL) { if(index < this->Segments.count()) { Vaddr = (int64_t)this->Segments.at(index)->p_vaddr; } } return Vaddr; } qint64 ElfFile::getSegmentPaddr(int index) { int64_t Paddr=0; if(this->e!=NULL) { if(index < this->Segments.count()) { Paddr = (int64_t)this->Segments.at(index)->p_paddr; } } return Paddr; } qint64 ElfFile::getSectionPaddr(int index) { int64_t Paddr=0; if(this->e!=NULL) { if(index < this->sections.count()) { Paddr = (int64_t)this->sections.at(index)->section_header->sh_addr; } } return Paddr; } qint64 ElfFile::getSegmentFilesz(int index) { int64_t FileSz=0; if(this->e!=NULL) { if(index < this->Segments.count()) { FileSz = (int64_t)this->Segments.at(index)->p_filesz; } } return FileSz; } qint64 ElfFile::getSectionDatasz(int index) { int64_t DataSz=0; if(this->e!=NULL) { if(index < this->sections.count()) { if(this->sections.at(index)->section_header->sh_type==SHT_NOBITS) { DataSz=0; } else { DataSz = (int64_t)this->sections.at(index)->data->d_size; } } } return DataSz; } bool ElfFile::getSectionData(int index, char **buffer) { if(this->e!=NULL) { if(index < this->sections.count()) { *buffer = (char *)this->sections.at(index)->data->d_buf; return true; } } return false; } qint64 ElfFile::getSegmentMemsz(int index) { int64_t MemSz=0; if(this->e!=NULL) { if(index < this->Segments.count()) { MemSz = (int64_t)this->Segments.at(index)->p_memsz; } } return MemSz; } qint64 ElfFile::getSectionMemsz(int index) { int64_t MemSz=0; if(this->e!=NULL) { if(index < this->sections.count()) { MemSz = (int64_t)this->sections.at(index)->section_header->sh_size; } } return MemSz; } QString ElfFile::getSegmentFlags(int index) { QString flags(""); if(this->e!=NULL) { if(index < this->Segments.count()) { if((this->Segments.at(index)->p_flags&PF_X) == PF_X)flags+="x"; if((this->Segments.at(index)->p_flags&PF_W) == PF_W)flags+="w"; if((this->Segments.at(index)->p_flags&PF_R) == PF_R)flags+="r"; if((this->Segments.at(index)->p_flags&PF_MASKOS) == PF_MASKOS)flags+=" OS-specific"; if((this->Segments.at(index)->p_flags&PF_MASKPROC) == PF_MASKPROC)flags+=" Processor-specific"; } } return flags; } QString ElfFile::getSectionName(int index) { if((index=0)) { char* nameChr = elf_strptr(this->e , this->shstrndx , this->sections.at(index)->section_header->sh_name); return QString(nameChr); } return ""; } void ElfFile::updateSections() { for(int i=0;isections.count();i++) { delete this->sections.at(i); } this->sections.clear(); this->scn = elf_nextscn (this->e , NULL ); this->SectionCount = 0; while( this->scn != NULL ) { GElf_Shdr* shdr = (GElf_Shdr*)malloc(sizeof(GElf_Shdr)); gelf_getshdr ( this->scn , shdr ); Elf_Data* data = elf_getdata(this->scn, NULL); this->sections.append(new Elf_Section(data,shdr)); this->SectionCount+=1; this->scn = elf_nextscn(e , scn); } } void ElfFile::updateSegments() { elf_getphdrnum (this->e , &this->SegmentCount); for(int i=0;iSegments.count();i++) { free(this->Segments.at(i)); } this->Segments.clear(); for(int i=0;i<(int)this->SegmentCount;i++) { GElf_Phdr* header=(GElf_Phdr*)malloc(sizeof(GElf_Phdr)); gelf_getphdr (this->e , i , header ); this->Segments.append(header); } } void ElfFile::updateSymbols() { for(int i=0;isymbols.at(i); } this->symbols.clear(); updateSections(); //Useless in most case but safer to do it for(int i=0;i<(int)SectionCount;i++) { //First find Symbol table if(this->getSectionName(i)==".symtab") { Elf_Section* sec = sections.at(i); this->SymbolCount = sec->section_header->sh_size / sec->section_header->sh_entsize; //Then list all symbols for(int j=0;j<(int)this->SymbolCount;j++) { GElf_Sym* esym = (GElf_Sym*)malloc(sizeof(GElf_Sym)); gelf_getsym(sec->data, j, esym); QString name = elf_strptr(this->e,sec->section_header->sh_link,esym->st_name); Elf_Symbol* sym = new Elf_Symbol(name,esym); symbols.append(sym); } } } } QString ElfFile::getSectionType(int index) { QString type(""); if(this->e!=NULL) { if(index < this->sections.count()) { switch(this->sections.at(index)->section_header->sh_type) { case SHT_NULL : type = "Section header table entry unused"; break; case SHT_PROGBITS : type = "Program data"; break; case SHT_SYMTAB : type = "Symbol table"; break; case SHT_STRTAB : type = "String table"; break; case SHT_RELA : type = "Relocation entries with addends"; break; case SHT_HASH : type = "Symbol hash table"; break; case SHT_DYNAMIC : type = "Dynamic linking information"; break; case SHT_NOTE : type = "Notes"; break; case SHT_NOBITS :type = "Program space with no data (bss)"; break; case SHT_REL :type = "Relocation entries, no addends"; break; case SHT_SHLIB : type = "Reserved"; break; case SHT_DYNSYM : type = "Dynamic linker symbol table"; break; case SHT_INIT_ARRAY : type = "Array of constructors"; break; case SHT_FINI_ARRAY : type = "Array of destructors"; break; case SHT_PREINIT_ARRAY : type = "Array of pre-constructors"; break; case SHT_GROUP : type = "Section group"; break; case SHT_SYMTAB_SHNDX : type = "Extended section indeces"; break; case SHT_NUM : type = "Number of defined types. "; break; case SHT_LOOS : type = "Start OS-specific. "; break; case SHT_LOSUNW : type = "Sun-specific low bound. "; break; case SHT_SUNW_COMDAT : type = " "; break; case SHT_SUNW_syminfo : type = " "; break; case SHT_GNU_verdef : type = "Version definition section. "; break; case SHT_GNU_verneed : type = "Version needs section. "; break; case SHT_GNU_versym : type = "Version symbol table. "; break; case SHT_LOPROC : type = "Start of processor-specific"; break; case SHT_HIPROC : type = "End of processor-specific"; break; case SHT_HIUSER : type = "End of application-specific"; break; } } } return type; } int ElfFile::getSectionIndex(QString name) { if(this->e!=NULL) { for(int i=0;ie!=NULL) { if(index < this->sections.count()) { return this->sections.at(index)->section_header->sh_type== SHT_NOBITS; } } return false; } QString ElfFile::getSymbolName(int index) { if(this->e!=NULL) { if(index < this->symbols.count()) { return symbols.at(index)->name; } } return ""; } QString ElfFile::getSymbolType(int index) { if(this->e!=NULL) { if(index < this->symbols.count()) { int type = GELF_ST_TYPE(symbols.at(index)->sym->st_info); switch(type) { case STT_NOTYPE: return "No Type"; break; case STT_OBJECT: return "Object"; break; case STT_FUNC: return "Function"; break; case STT_SECTION: return "Section"; break; case STT_FILE: return "File"; break; case STT_COMMON: return "Common data object"; break; case STT_TLS: return "Thread-local data object"; break; case STT_NUM: return "Number of defined types"; break; case STT_LOOS: return "Start of OS-specific"; break; case STT_HIOS: return "End of OS-specific"; break; case STT_LOPROC: return "Start of processor-specific"; break; case STT_HIPROC: return "End of processor-specific"; break; default: return "none"; break; } } } return "none"; } quint64 ElfFile::getSymbolSize(int index) { if(this->e!=NULL) { if((index < this->symbols.count()) && (index>=0)) { return symbols.at(index)->sym->st_size; } } return 0; } QString ElfFile::getSymbolSectionName(int index) { if(this->e!=NULL) { if((index < this->symbols.count()) && (index>=0)) { return getSectionName(symbols.at(index)->sym->st_shndx-1); } } return "none"; } int ElfFile::getSymbolSectionIndex(int index) { if(this->e!=NULL) { if((index < this->symbols.count()) && (index>=0)) { return symbols.at(index)->sym->st_shndx; } } return 0; } quint64 ElfFile::getSymbolAddress(int index) { if(this->e!=NULL) { if((index < this->symbols.count()) && (index>=0)) { return symbols.at(index)->sym->st_value; } } return 0; } QString ElfFile::getSymbolLinkType(int index) { if(this->e!=NULL) { if(index < this->symbols.count()) { int btype = GELF_ST_BIND(symbols.at(index)->sym->st_info); switch(btype) { case STB_LOCAL: return "Local"; break; case STB_GLOBAL: return "Global"; break; case STB_WEAK: return "Weak"; break; case STB_NUM: return "Number of defined types"; break; case STB_LOOS: return "Start of OS-specific"; break; case STB_HIOS: return "End of OS-specific"; break; case STB_LOPROC: return "Start of processor-specific"; break; case STB_HIPROC: return "End of processor-specific"; break; default: return "none"; break; } } } return "none"; } bool ElfFile::isElf(const QString &File) { int file =0; #ifdef _ELF_WINDOWS_ file = open(File.toStdString().c_str(),O_RDONLY|O_BINARY ,0); #else file = open(File.toStdString().c_str(),O_RDONLY ,0); #endif char Magic[4]; if(file!=-1) { size_t res = read(file,Magic,4); close(file); if((res==4) && (Magic[0]==0x7f) && (Magic[1]==0x45) && (Magic[2]==0x4c) && (Magic[3]==0x46)) { return true; } } return false; } bool ElfFile::toSrec(const QString &File) { return srecFile::toSrec(this->getFragments(),File); } bool ElfFile::toBinary(const QString &File) { return binaryFile::toBinary(getFragments(),File); }