diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-06 19:20:34 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-06 19:20:34 -0500 |
| commit | 828fff839f4e4de3e9582405dfec567531000ebc (patch) | |
| tree | ee0db0607edb0c76c653078672201c85e8a96d19 /view/elf/elfview.cpp | |
| parent | 47894a1ce20090849ad304c68e6c0b889665eda3 (diff) | |
Move view modules into the API repo
Diffstat (limited to 'view/elf/elfview.cpp')
| -rw-r--r-- | view/elf/elfview.cpp | 2772 |
1 files changed, 2772 insertions, 0 deletions
diff --git a/view/elf/elfview.cpp b/view/elf/elfview.cpp new file mode 100644 index 00000000..94b3c37b --- /dev/null +++ b/view/elf/elfview.cpp @@ -0,0 +1,2772 @@ +#include <string.h> +#ifndef _MSC_VER +#include <cxxabi.h> +#endif +#include <inttypes.h> +#include "elfview.h" + +#define STRING_READ_CHUNK_SIZE 32 + +using namespace BinaryNinja; +using namespace std; + + +static ElfViewType* g_elfViewType = nullptr; + + +void BinaryNinja::InitElfViewType() +{ + static ElfViewType type; + BinaryViewType::Register(&type); + g_elfViewType = &type; + + Ref<Settings> settings = Settings::Instance(); + settings->RegisterSetting("files.elf.maxSectionHeaderCount", + R"({ + "title" : "Maximum ELF Section Header Count", + "type" : "number", + "default" : 100, + "minValue" : 0, + "maxValue" : 65536, + "description" : "Maximum number of entries to include in section header array", + "ignore" : ["SettingsProjectScope"] + })"); +} + + +ElfView::ElfView(BinaryView* data, bool parseOnly): BinaryView("ELF", data->GetFile(), data), m_parseOnly(parseOnly) +{ + Elf64Header header; + string errorMsg; + BNEndianness endian; + if (!g_elfViewType->ParseHeaders(data, m_ident, m_commonHeader, header, &m_arch, &m_plat, errorMsg, endian)) + throw ElfFormatException(errorMsg); + + CreateLogger("BinaryView"); + m_logger = CreateLogger("BinaryView.ElfView"); + m_elf32 = m_ident.fileClass == 1; + m_addressSize = (m_ident.fileClass == 1) ? 4 : 8; + m_endian = endian; + m_relocatable = m_commonHeader.type == ET_DYN || m_commonHeader.type == ET_REL; + m_objectFile = m_commonHeader.type == ET_REL; + m_backedByDatabase = data->GetFile()->IsBackedByDatabase("ELF"); + + memset(&m_symbolTableSection, 0, sizeof(m_symbolTableSection)); + memset(&m_dynamicSymbolTableSection, 0, sizeof(m_dynamicSymbolTableSection)); + memset(&m_dynamicStringTable, 0, sizeof(m_dynamicStringTable)); + memset(&m_dynamicTable, 0, sizeof(m_dynamicTable)); + memset(&m_tlsSegment, 0, sizeof(m_tlsSegment)); + memset(&m_auxSymbolTable, 0, sizeof(m_auxSymbolTable)); + memset(&m_sectionStringTable, 0, sizeof(m_sectionStringTable)); + memset(&m_sectionOpd, 0, sizeof(m_sectionOpd)); + + m_logger->LogInfo("Detected %s endian ELF", m_endian == LittleEndian ? "Little Endian" : "Big Endian"); + + + if (m_elf32 && (header.sectionHeaderSize != sizeof(Elf32SectionHeader))) + { + m_logger->LogWarn( + "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf32_Shdr (0x%lx). " + "The parsing proceeds with the size of Elf32_Shdr.", + header.sectionHeaderSize, sizeof(Elf32SectionHeader)); + header.sectionHeaderSize = sizeof(Elf32SectionHeader); + } + else if (!m_elf32 && (header.sectionHeaderSize != sizeof(Elf64SectionHeader))) + { + m_logger->LogWarn( + "The section header size reported by e_shentsize (0x%lx) is different from the size of Elf64_Shdr (0x%lx). " + "The parsing proceeds with the size of Elf64_Shdr.", + header.sectionHeaderSize, sizeof(Elf64SectionHeader)); + header.sectionHeaderSize = sizeof(Elf64SectionHeader); + } + + if (m_elf32 && (header.programHeaderSize != sizeof(Elf32ProgramHeader))) + { + m_logger->LogWarn( + "The program header size reported by e_phentsize (0x%lx) is different from the size of Elf32_Phdr (0x%lx). " + "The parsing proceeds with the size of Elf32_Phdr.", + header.programHeaderSize, sizeof(Elf32ProgramHeader)); + header.programHeaderSize = sizeof(Elf32ProgramHeader); + } + else if (!m_elf32 && (header.programHeaderSize != sizeof(Elf64ProgramHeader))) + { + m_logger->LogWarn( + "The program header size reported by e_phentsize (0x%lx) is different from the size of Elf64_Phdr (0x%lx). " + "The parsing proceeds with the size of Elf64_Phdr.", + header.programHeaderSize, sizeof(Elf64ProgramHeader)); + header.programHeaderSize = sizeof(Elf64ProgramHeader); + } + + m_entryPoint = header.entry; + m_sectionHeaderOffset = header.sectionHeaderOffset; + m_sectionHeaderCount = header.sectionHeaderCount; + m_programHeaderOffset = header.programHeaderOffset; + m_programHeaderCount = header.programHeaderCount; + m_headerFlags = header.flags; + m_fileSize = data->GetLength(); + + m_logger->LogDebug( + "ELF Header\n" + "\t%d bits\n" + "\theader.entry %016x\n" + "\theader.programHeaderOffset %016x\n" + "\theader.sectionHeaderOffset %016x\n" + "\theader.flags %016x\n" + "\theader.headerSize %016x\n" + "\theader.programHeaderSize %016x\n" + "\theader.programHeaderCount %016x\n" + "\theader.sectionHeaderSize %016x\n" + "\theader.sectionHeaderCount %016x\n" + "\theader.stringTable %016x\n", + m_addressSize * 8, header.entry, header.programHeaderOffset, header.sectionHeaderOffset, header.flags, + header.headerSize, header.programHeaderSize, header.programHeaderCount, header.sectionHeaderSize, + header.sectionHeaderCount, header.stringTable); + + BinaryReader reader(data); + reader.SetEndianness(m_endian); + + // Parse program headers + reader.Seek(header.programHeaderOffset); + for (size_t i = 0; i < header.programHeaderCount; i++) + { + Elf64ProgramHeader progHeader; + if (m_elf32) // 32-bit ELF + { + progHeader.type = reader.Read32(); + progHeader.offset = reader.Read32(); + progHeader.virtualAddress = reader.Read32(); + progHeader.physicalAddress = reader.Read32(); + progHeader.fileSize = reader.Read32(); + progHeader.memorySize = reader.Read32(); + progHeader.flags = reader.Read32(); + progHeader.align = reader.Read32(); + } + else // 64-bit ELF + { + progHeader.type = reader.Read32(); + progHeader.flags = reader.Read32(); + progHeader.offset = reader.Read64(); + progHeader.virtualAddress = reader.Read64(); + progHeader.physicalAddress = reader.Read64(); + progHeader.fileSize = reader.Read64(); + progHeader.memorySize = reader.Read64(); + progHeader.align = reader.Read64(); + } + + m_logger->LogDebug( + "\tSegment: %d\n" + "\t\tprogHeader.type %08x\n" + "\t\tprogHeader.offset %08x\n" + "\t\tprogHeader.virtualAddress %016x\n" + "\t\tprogHeader.physicalAddress %016x\n" + "\t\tprogHeader.fileSize %016x\n" + "\t\tprogHeader.memorySize %016x\n" + "\t\tprogHeader.flags %016x\n" + "\t\tprogHeader.align %016x\n", + i, progHeader.type, progHeader.offset, progHeader.virtualAddress, progHeader.physicalAddress, + progHeader.fileSize, progHeader.memorySize, progHeader.flags, progHeader.align); + + if (!memcmp(m_ident.signature, "\x7f" "CGC", 4)) + { + // CGC uses physical address for loading + uint64_t temp = progHeader.virtualAddress; + progHeader.virtualAddress = progHeader.physicalAddress; + progHeader.physicalAddress = temp; + } + + m_programHeaders.push_back(progHeader); + + if (progHeader.type == ELF_PT_DYNAMIC) + m_dynamicTable = progHeader; + if (progHeader.type == ELF_PT_TLS) + m_tlsSegment = progHeader; + } + + // Parse section headers + try + { + reader.Seek(header.sectionHeaderOffset); + m_logger->LogDebug("Section List"); + for (size_t i = 0; i < header.sectionHeaderCount; i++) + { + Elf64SectionHeader section; + reader.Seek(header.sectionHeaderOffset + (i * header.sectionHeaderSize)); + if (m_elf32) // 32-bit ELF + { + section.name = reader.Read32(); + section.type = reader.Read32(); + section.flags = reader.Read32(); + section.address = reader.Read32(); + section.offset = reader.Read32(); + section.size = reader.Read32(); + section.link = reader.Read32(); + section.info = reader.Read32(); + section.align = reader.Read32(); + section.entrySize = reader.Read32(); + } + else // 64-bit ELF + { + section.name = reader.Read32(); + section.type = reader.Read32(); + section.flags = reader.Read64(); + section.address = reader.Read64(); + section.offset = reader.Read64(); + section.size = reader.Read64(); + section.link = reader.Read32(); + section.info = reader.Read32(); + section.align = reader.Read64(); + section.entrySize = reader.Read64(); + } + + m_elfSections.push_back(section); + + if (section.size > m_fileSize) + { + m_logger->LogWarn("Section %lu has a size (0x%lx) larger than file size (0x%lx), skipping creation", i, + section.size, m_fileSize); + continue; + } + + if (section.type == ELF_SHT_SYMTAB) + m_symbolTableSection = section; + else if (section.type == ELF_SHT_DYNSYM) + m_dynamicSymbolTableSection = section; + else if (section.type == ELF_SHT_STRTAB) + { + ApplyTypesToParentStringTable(section); + if (i == header.stringTable) + { + m_sectionStringTable = section; + } + continue; + } + + if (section.flags & ELF_SHF_STRINGS) + ApplyTypesToParentStringTable(section, false); + } + } + catch (ReadException&) + { + // Section headers are not required for a valid ELF, skip errors + m_logger->LogError("ELF section headers invalid"); + } + + for (size_t i = 0; i < m_elfSections.size(); i++) + { + const string scnNameString = ReadStringTable(reader, m_sectionStringTable, m_elfSections[i].name); + m_logger->LogDebug("\tSection: %d\n" + "\t\tsection.name %08x (%s)\n" + "\t\tsection.type %08x\n" + "\t\tsection.flags %016x\n" + "\t\tsection.address %016x\n" + "\t\tsection.offset %016x\n" + "\t\tsection.size %016x\n" + "\t\tsection.link %08x\n" + "\t\tsection.info %016x\n" + "\t\tsection.align %016x\n" + "\t\tsection.entrySize %016x", + i, + m_elfSections[i].name, scnNameString.c_str(), + m_elfSections[i].type, + m_elfSections[i].flags, + m_elfSections[i].address, + m_elfSections[i].offset, + m_elfSections[i].size, + m_elfSections[i].link, + m_elfSections[i].info, + m_elfSections[i].align, + m_elfSections[i].entrySize + ); + + if (!m_elf32 && m_commonHeader.arch == EM_PPC64 && scnNameString == ".opd") + m_sectionOpd = m_elfSections[i]; + } + + /* TODO: PPC64 specific entrypoint handling to be moved to architecture extension for ELF */ + if (m_commonHeader.arch == EM_PPC64) + { + uint64_t entry; + if (DerefPpc64Descriptor(reader, m_entryPoint, entry)) + { + m_logger->LogDebug("PPC64 dereference m_entryPoint=%016x to %016x\n", m_entryPoint, entry); + m_entryPoint = entry; + } + else + { + m_logger->LogDebug("PPC64 unable to dereference m_entryPoint=%016x\n", m_entryPoint); + } + } +} + + +ElfView::~ElfView() +{ + for (auto& i : m_relocationInfo) + { + auto cur = i.next; + while (cur) + { + auto next = cur->next; + delete cur; + cur = next; + } + } +} + + +static BNSymbolBinding TranslateELFBindingType(uint8_t type) +{ + switch (type) + { + case ELF_STB_LOCAL: return LocalBinding; + case ELF_STB_GLOBAL: return GlobalBinding; + case ELF_STB_WEAK: return WeakBinding; + default: + return NoBinding; + } +} + + +bool ElfView::ParseSymbolTableEntry(BinaryReader& reader, ElfSymbolTableEntry& entry, uint64_t sym, + const Elf64SectionHeader& symbolTable, const Elf64SectionHeader& stringTable, bool dynamic) +{ + try + { + entry.dynamic = dynamic; + if (m_elf32) + { + reader.Seek(symbolTable.offset + (sym * 16)); + entry.nameOffset = reader.Read32(); + entry.value = reader.Read32(); + entry.size = reader.Read32(); + uint8_t info = reader.Read8(); + entry.type = ELF_ST_TYPE(info); + entry.binding = TranslateELFBindingType(ELF_ST_BIND(info)); + entry.other = reader.Read8(); + entry.section = reader.Read16(); + } + else + { + reader.Seek(symbolTable.offset + (sym * 24)); + entry.nameOffset = reader.Read32(); + uint8_t info = reader.Read8(); + entry.type = ELF_ST_TYPE(info); + entry.binding = TranslateELFBindingType(ELF_ST_BIND(info)); + entry.other = reader.Read8(); + entry.section = reader.Read16(); + entry.value = reader.Read64(); + entry.size = reader.Read64(); + } + + if (entry.type == ELF_STT_SECTION) + { + if (entry.section < m_elfSections.size()) + { + entry.name = ReadStringTable(reader, m_sectionStringTable, m_elfSections[entry.section].name); + } + } + else + { + entry.name = ReadStringTable(reader, stringTable, entry.nameOffset); + } + } + catch (ReadException&) + { + return false; + } + + m_logger->LogDebug( + "Symbol: %d - symbolSection.offset: %lx - stringSection.offset: %lx\n" + "\tnameOffset = %#08lx\n" + "\ttype = %#02x\n" + "\tbinding = %#02x\n" + "\tother = %#02x\n" + "\tsection = %#04x\n" + "\tvalue = %#012lx\n" + "\tsize = %#012lx\n" + "\tname = %#s", + sym, symbolTable.offset, stringTable.offset, + entry.nameOffset, + entry.type, + entry.binding, + entry.other, + entry.section, + entry.value, + entry.size, + entry.name.c_str()); + return true; +} + +void ElfView::GetRelocEntries(BinaryReader& reader, const vector<Elf64SectionHeader>& sections, + bool implicit, vector<ELFRelocEntry>& result) +{ + size_t relocSize = m_elf32 ? 8 : 16; + if (!implicit) + relocSize += m_elf32 ? 4 : 8; + + for (auto& section : sections) + { + for (uint64_t j = 0; j < section.size / relocSize; j++) + { + reader.Seek(section.offset + (j * relocSize)); + uint64_t ofs = m_elf32 ? reader.Read32() : reader.Read64(); + uint64_t info = m_elf32 ? reader.Read32() : reader.Read64(); + uint64_t addend = 0; + if (!implicit) + addend = m_elf32 ? reader.Read32() : reader.Read64(); + + result.push_back(ELFRelocEntry(ofs, info >> (m_elf32 ? 8 : 32), info & (m_elf32 ? 0xff : 0xffffffff), + addend, section.info, implicit)); + } + } +} + +static bool In(const string& str, const vector<string>& list) +{ + for (auto& a : list) + if (a == str) + return true; + return false; +} + +bool ElfView::Init() +{ + std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now(); + // Add segments for the program headers + BinaryReader reader(GetParentView()); + BinaryReader virtualReader(this); + + uint64_t initialImageBase = 0; + bool initialImageBaseSet = false; + for (const auto& i : m_programHeaders) + { + if ((i.type != ELF_PT_LOAD) || (!i.fileSize)) + continue; + + if (!initialImageBaseSet) + { + initialImageBase = i.virtualAddress; + initialImageBaseSet = true; + } + else if (i.virtualAddress < initialImageBase) + initialImageBase = i.virtualAddress; + } + + SetOriginalBase(initialImageBase); + uint64_t preferredImageBase = initialImageBase; + Ref<Settings> viewSettings = Settings::Instance(); + m_extractMangledTypes = viewSettings->Get<bool>("analysis.extractTypesFromMangledNames", this); + m_simplifyTemplates = viewSettings->Get<bool>("analysis.types.templateSimplifier", this); + + Ref<Settings> settings = GetLoadSettings(GetTypeName()); + if (settings && settings->Contains("loader.imageBase") && settings->Contains("loader.architecture")) // handle overrides + { + preferredImageBase = settings->Get<uint64_t>("loader.imageBase", this); + + Ref<Architecture> arch = Architecture::GetByName(settings->Get<string>("loader.architecture", this)); + if (!m_arch || (arch && (arch->GetName() != m_arch->GetName()))) + m_arch = arch; + } + + int64_t imageBaseAdjustment = 0; + if (!initialImageBase) + imageBaseAdjustment = preferredImageBase; + else if (initialImageBase <= preferredImageBase) + imageBaseAdjustment = preferredImageBase - initialImageBase; + else + imageBaseAdjustment = -(int64_t)(initialImageBase - preferredImageBase); + + m_entryPoint = m_entryPoint + imageBaseAdjustment; + + for (auto& i : m_programHeaders) + { + uint64_t adjustedVirtualAddr = i.virtualAddress + imageBaseAdjustment; + + if (i.type == ELF_PT_LOAD) // || i.type == ELF_PT_GNU_RELRO) + { + uint32_t flags = 0; + if (i.flags & 1) + flags |= SegmentExecutable; + if (i.flags & 2) + flags |= SegmentWritable; + if (i.flags & 4) + flags |= SegmentReadable; + AddAutoSegment(adjustedVirtualAddr, i.memorySize, i.offset, i.fileSize, flags); + } + + // Create sections for the program headers with the standard section names. This will ensure that + // the standard name for sections such as .dynamic will always refer to what the loader actually uses. + if (i.type == ELF_PT_DYNAMIC) + { + uint64_t entrySize = m_elf32 ? 8 : 16; + + bool foundMatch = false; + for (size_t j = 1; j < m_elfSections.size(); j++) + { + uint64_t adjustedSectionAddr = m_elfSections[j].address + imageBaseAdjustment; + + if (m_elfSections[j].type != ELF_SHT_DYNAMIC) + continue; + if (adjustedSectionAddr != adjustedVirtualAddr) + continue; + if (m_elfSections[j].size != i.memorySize) + continue; + if (m_elfSections[j].entrySize != entrySize) + continue; + if (ReadStringTable(reader, m_sectionStringTable, m_elfSections[j].name) != ".dynamic") + continue; + foundMatch = true; + break; + } + + if (!foundMatch) + AddAutoSection(".dynamic", adjustedVirtualAddr, i.memorySize, ReadOnlyDataSectionSemantics, "DYNAMIC", i.align, entrySize); + } + else if (i.type == ELF_PT_INTERP) + { + bool foundMatch = false; + for (size_t j = 1; j < m_elfSections.size(); j++) + { + uint64_t adjustedSectionAddr = m_elfSections[j].address + imageBaseAdjustment; + + if (m_elfSections[j].type != ELF_SHT_PROGBITS) + continue; + if (adjustedSectionAddr != adjustedVirtualAddr) + continue; + if (m_elfSections[j].size != i.memorySize) + continue; + if (ReadStringTable(reader, m_sectionStringTable, m_elfSections[j].name) != ".interp") + continue; + foundMatch = true; + break; + } + + if (!foundMatch) + AddAutoSection(".interp", adjustedVirtualAddr, i.memorySize, ReadOnlyDataSectionSemantics, "PROGBITS", i.align); + + DefineDataVariable(adjustedVirtualAddr, Type::ArrayType(Type::IntegerType(1, true), i.fileSize)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_interp", adjustedVirtualAddr, LocalBinding)); + } + } + + // Gather names for the sections + vector<string> sectionNames {""}; + for (size_t i = 1; i < m_elfSections.size(); i++) + sectionNames.push_back(ReadStringTable(reader, m_sectionStringTable, m_elfSections[i].name)); + sectionNames = GetUniqueSectionNames(sectionNames); + + // Add sections to the view + vector<Elf64SectionHeader> dynRelocSections, dynRelocASections; + vector<Elf64SectionHeader> relocSections, relocASections; + Elf64SectionHeader symbolTableSection; + + uint64_t segmentStart = 0; + for (size_t i = 1; i < m_elfSections.size(); i++) + { + string type; + string linkedSection, infoSection; + switch (m_elfSections[i].type) + { + case ELF_SHT_PROGBITS: + type = "PROGBITS"; + break; + case ELF_SHT_SYMTAB: + type = "SYMTAB"; + symbolTableSection = m_elfSections[i]; + break; + case ELF_SHT_STRTAB: + type = "STRTAB"; + break; + case ELF_SHT_RELA: + type = "RELA"; + relocASections.push_back(m_elfSections[i]); + break; + case ELF_SHT_REL: + type = "REL"; + relocSections.push_back(m_elfSections[i]); + break; + case ELF_SHT_HASH: + type = "HASH"; + break; + case ELF_SHT_DYNAMIC: + type = "DYNAMIC"; + break; + case ELF_SHT_NOTE: + type = "NOTE"; + break; + case ELF_SHT_NOBITS: + type = "NOBITS"; + break; + case ELF_SHT_SHLIB: + type = "SHLIB"; + break; + case ELF_SHT_DYNSYM: + type = "DYNSYM"; + break; + default: + break; + } + + // Add sections that aren't in the virtual address space only to the raw parent view + if (!(m_elfSections[i].flags & ELF_SHF_ALLOC)) + { + if (m_elfSections[i].size != 0 && m_elfSections[i].type != ELF_SHT_NOBITS) + GetParentView()->AddAutoSection(sectionNames[i], m_elfSections[i].offset, m_elfSections[i].size, DefaultSectionSemantics, + type, m_elfSections[i].align, m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); + continue; + } + + if (m_elfSections[i].type == ELF_SHT_STRTAB) + ApplyTypesToStringTable(m_elfSections[i], imageBaseAdjustment); + else if (m_elfSections[i].flags & ELF_SHF_STRINGS) + ApplyTypesToStringTable(m_elfSections[i], imageBaseAdjustment, false); + + if (m_elfSections[i].link < m_elfSections.size()) + linkedSection = sectionNames[m_elfSections[i].link]; + + BNSectionSemantics semantics = DefaultSectionSemantics; + vector<string> readOnlyCodeSectionNames = {".text", ".init", ".fini"}; + vector<string> readWriteDataSectionNames = {".data", ".bss"}; + vector<string> readOnlyDataSectionNames = {".rodata", ".dynamic", ".dynsym", ".dynstr", ".ehframe", + ".ctors", ".dtors", ".got", ".got2", ".data.rel.ro", ".gnu.hash"}; + if ((m_elfSections[i].flags & ELF_SHF_EXECINSTR) || In(sectionNames[i], readOnlyCodeSectionNames)) + semantics = ReadOnlyCodeSectionSemantics; + else if (!(m_elfSections[i].flags & ELF_SHF_WRITE) || In(sectionNames[i], readOnlyDataSectionNames)) + semantics = ReadOnlyDataSectionSemantics; + else if ((m_elfSections[i].flags & ELF_SHF_WRITE) || In(sectionNames[i], readWriteDataSectionNames)) + semantics = ReadWriteDataSectionSemantics; + + if (m_elfSections[i].size != 0) + { + if (m_programHeaders.size() == 0) + { + // We have an object file so we'll just create segments for the sections + uint32_t flags = 0; + if (semantics == ReadOnlyCodeSectionSemantics) + flags = SegmentReadable | SegmentExecutable; + else if (semantics == ReadWriteDataSectionSemantics) + flags = SegmentReadable | SegmentWritable; + else if (semantics == ReadOnlyDataSectionSemantics) + flags = SegmentReadable; + m_elfSections[i].address = segmentStart; + size_t size = m_elfSections[i].type == ELF_SHT_NOBITS ? 0 : m_elfSections[i].size; + uint64_t adjustedSectionAddr = m_elfSections[i].address + imageBaseAdjustment; + AddAutoSegment(adjustedSectionAddr, m_elfSections[i].size, m_elfSections[i].offset, size, flags); + segmentStart += ((m_elfSections[i].size + 15) & ~15); + } + else if ((m_elfSections[i].address + m_elfSections[i].size + imageBaseAdjustment) > GetEnd() || ((m_elfSections[i].address + imageBaseAdjustment) < GetStart())) + { + LogWarn("Section %s is outside of the address space of the file and will not be added", sectionNames[i].c_str()); + continue; + } + + uint64_t adjustedVirtualAddr = m_elfSections[i].address + imageBaseAdjustment; + AddAutoSection(sectionNames[i], adjustedVirtualAddr, m_elfSections[i].size, semantics, type, m_elfSections[i].align, + m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); + if (m_elfSections[i].type != ELF_SHT_NOBITS) + GetParentView()->AddAutoSection(sectionNames[i], m_elfSections[i].offset, m_elfSections[i].size, DefaultSectionSemantics, type, m_elfSections[i].align, m_elfSections[i].entrySize, linkedSection, infoSection, m_elfSections[i].info); + } + } + + // Apply architecture and platform + if (!m_arch) + { + switch (m_commonHeader.arch) + { + case 3: + m_logger->LogError("Support for ELF architecture 'x86' is not present"); + break; + case 8: + #ifndef DEMO_VERSION + m_logger->LogError("Support for ELF architecture 'mips' is not present"); + #else + m_logger->LogError("Binary Ninja free does not support ELF architecture 'mips'. " + "Purchase Binary Ninja to unlock all features."); + #endif + break; + case 20: + #ifndef DEMO_VERSION + m_logger->LogError("Support for ELF architecture 'ppc' is not present"); + #else + m_logger->LogError("Binary Ninja free does not support ELF architecture 'ppc'. " + "Purchase Binary Ninja to unlock all features."); + #endif + break; + case 21: + #ifndef DEMO_VERSION + m_logger->LogError("Support for ELF architecture 'ppc64' is not present"); + #else + m_logger->LogError("Binary Ninja free does not support ELF architecture 'ppc64'. " + "Purchase Binary Ninja to unlock all features."); + #endif + break; + case 40: + m_logger->LogError("Support for ELF architecture 'armv7' is not present"); + break; + case 62: + m_logger->LogError("Support for ELF architecture 'x86_64' is not present"); + break; + case 183: + #ifndef DEMO_VERSION + m_logger->LogError("Support for ELF architecture 'arm64' is not present"); + #else + m_logger->LogError("Binary Ninja free does not support ELF architecture 'arm64'. " + "Purchase Binary Ninja to unlock all features."); + #endif + break; + default: + m_logger->LogError("ELF architecture %d is not supported", m_commonHeader.arch); + break; + } + return false; + } + + // Add the entry point as a function if the architecture is supported + uint64_t entryPointAddress = m_entryPoint; + Ref<Architecture> entryPointArch = m_arch->GetAssociatedArchitectureByAddress(entryPointAddress); + SetDefaultArchitecture(entryPointArch); + GetParentView()->SetDefaultArchitecture(entryPointArch); + + Ref<Platform> platform = m_plat ? m_plat : g_elfViewType->GetPlatform(m_ident.os, m_arch); + if (platform && (entryPointArch != m_arch)) + platform = platform->GetRelatedPlatform(entryPointArch); + if (!platform) + platform = entryPointArch->GetStandalonePlatform(); + + if (settings && settings->Contains("loader.platform")) // handle overrides + { + Ref<Platform> platformOverride = Platform::GetByName(settings->Get<string>("loader.platform", this)); + if (platformOverride) + platform = platformOverride; + } + + SetDefaultPlatform(platform); + GetParentView()->SetDefaultPlatform(platform); + + // Finished for parse only mode + if (m_parseOnly) + { + m_stringTableCache.clear(); + return true; + } + + // Set reader endianness + reader.SetEndianness(m_endian); + virtualReader.SetEndianness(m_endian); + + // FIXME: MIPS specific GOT entries should be done in the MIPS plugin, once there is a way to have + // ELF parsing extensions in an architecture plugin + uint64_t gotStart = 0; + uint64_t localMipsSyms = 0; + uint64_t firstMipsSym = 0; + uint64_t baseAddress = GetStart(); + vector<uint64_t> neededLibraries; + bool mipsSymValid = false; + // FIXME: ARM specific GOT entries should be done in the MIPS plugin, as above + bool isArmV7 = m_arch->GetName() == "armv7"; + vector<uint64_t> tlsModuleStarts; + vector<uint64_t> tlsOffsets; + + // Parse dynamic table + if (auto dynSeg = GetSegmentAt(m_dynamicTable.virtualAddress + imageBaseAdjustment); dynSeg && m_dynamicTable.virtualAddress) + { + try + { + uint64_t adjustedVirtualAddr = m_dynamicTable.virtualAddress + imageBaseAdjustment; + reader.Seek(adjustedVirtualAddr - dynSeg->GetStart() + dynSeg->GetDataOffset()); + + Elf64SectionHeader reloca, plt, rel; + memset(&reloca, 0, sizeof(reloca)); + memset(&plt, 0, sizeof(plt)); + memset(&rel, 0, sizeof(rel)); + uint64_t pltType = ELF_DT_RELA; + bool end = false; + uint64_t entrySize = m_elf32 ? 8 : 16; + size_t i = 0; + while (!end) + { + uint64_t tag, value; + if (m_elf32) // 32-bit ELF + { + tag = reader.Read32(); + value = reader.Read32(); + i += 8; + } + else // 64-bit ELF + { + tag = reader.Read64(); + value = reader.Read64(); + i += 16; + } + + switch (tag) + { + case ELF_DT_NULL: + end = true; + m_numDynamicTableEntries = i ? i / entrySize : 0; + break; + case ELF_DT_NEEDED: + neededLibraries.push_back(value); + break; + case ELF_DT_PLTREL: + pltType = value; + break; + case ELF_DT_JMPREL: + plt.offset = value + imageBaseAdjustment; + break; + case ELF_DT_PLTRELSZ: + plt.size = value; + break; + case ELF_DT_STRTAB: + m_dynamicStringTable.offset = value + imageBaseAdjustment; + break; + case ELF_DT_SYMTAB: + m_auxSymbolTable.offset = value + imageBaseAdjustment; + break; + case ELF_DT_SYMENT: + m_auxSymbolTableEntrySize = value; + break; + case ELF_DT_INIT: + case ELF_DT_FINI: + { + uint64_t target = value + imageBaseAdjustment; + string autoName = (tag == ELF_DT_INIT) ? "_init" : "_fini"; + DefineAutoSymbol(new Symbol(FunctionSymbol, autoName, target, NoBinding)); + Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(target); + AddFunctionForAnalysis(targetPlatform, target); + break; + } + case ELF_DT_HASH: + m_hashHeader = value + imageBaseAdjustment; + break; + case ELF_DT_GNU_HASH: + m_gnuHashHeader = value + imageBaseAdjustment; + break; + case ELF_DT_RELA: + reloca.offset = value + imageBaseAdjustment; + break; + case ELF_DT_RELASZ: + reloca.size = value; + break; + case ELF_DT_RELAENT: + reloca.entrySize = value; + break; + case ELF_DT_STRSZ: + m_dynamicStringTable.size = value; + break; + case ELF_DT_REL: + rel.offset = value + imageBaseAdjustment; + break; + case ELF_DT_RELSZ: + rel.size = value; + break; + case ELF_DT_RELENT: + rel.entrySize = value; + break; + case ELF_DT_PLTGOT: + gotStart = value + imageBaseAdjustment; + break; + case ELF_DT_MIPS_SYMTABNO: + m_auxSymbolTable.size = m_elf32 ? value * 16 : value * 24; + break; + case ELF_DT_MIPS_LOCAL_GOTNO: + localMipsSyms = value; + break; + case ELF_DT_MIPS_GOTSYM: + firstMipsSym = value; + mipsSymValid = true; + break; + case ELF_DT_MIPS_BASE_ADDRESS: + baseAddress = value + imageBaseAdjustment; + break; + default: + break; + } + } + + vector<Ref<Metadata>> libraries; + vector<Ref<Metadata>> libraryFound; + for (auto& libNameOffset : neededLibraries) + { + const string libName = ReadStringTable(virtualReader, m_dynamicStringTable, libNameOffset); + if (!GetExternalLibrary(libName)) + { + AddExternalLibrary(libName, {}, true); + } + libraries.push_back(new Metadata(string(libName))); + Ref<TypeLibrary> typeLib = GetTypeLibrary(libName); + if (!typeLib) + { + vector<Ref<TypeLibrary>> typeLibs = platform->GetTypeLibrariesByName(libName); + if (typeLibs.size()) + { + typeLib = typeLibs[0]; + AddTypeLibrary(typeLib); + + m_logger->LogDebug("elf: adding type library for '%s': %s (%s)", libName.c_str(), typeLib->GetName().c_str(), + typeLib->GetGuid().c_str()); + } + } + + if (typeLib) + libraryFound.push_back(new Metadata(typeLib->GetName())); + else + libraryFound.push_back(new Metadata(string(""))); + } + StoreMetadata("Libraries", new Metadata(libraries), true); + StoreMetadata("LibraryFound", new Metadata(libraryFound), true); + + if (reloca.size > 0) + { + bool alreadyExists = false; + for (auto& relSec : relocASections) + if (relSec.offset == reloca.offset) + alreadyExists = true; + if (!alreadyExists) + { + dynRelocASections.push_back(reloca); + AddAutoSection(".dynamic_rela", reloca.offset, reloca.size, ReadOnlyDataSectionSemantics); + } + } + if (plt.size > 0) + { + if (pltType == ELF_DT_REL) + { + bool alreadyExists = false; + for (auto& relSec : relocSections) + if ((relSec.address + imageBaseAdjustment) == plt.offset) + alreadyExists = true; + if (!alreadyExists) + { + dynRelocSections.push_back(plt); + AddAutoSection(".dynamic_jmprel", plt.offset, plt.size, ReadOnlyDataSectionSemantics); + } + } + else + { + bool alreadyExists = false; + for (auto& relSec : relocASections) + if ((relSec.address + imageBaseAdjustment) == plt.offset) + alreadyExists = true; + if (!alreadyExists) + { + dynRelocASections.push_back(plt); + AddAutoSection(".dynamic_jmprel", plt.offset, plt.size, ReadOnlyDataSectionSemantics); + } + } + } + if (rel.size > 0) + { + bool alreadyExists = false; + for (auto& relSec : relocSections) + if ((relSec.address + imageBaseAdjustment) == rel.offset) + alreadyExists = true; + if (!alreadyExists) + { + dynRelocSections.push_back(rel); + AddAutoSection(".dynamic_rel", rel.offset, rel.size, ReadOnlyDataSectionSemantics); + } + } + } + catch (ReadException&) + { + m_logger->LogError("ELF dynamic table invalid"); + } + } + + // Parse symbol table + vector<ElfSymbolTableEntry> symbolTable, dynamicSymbolTable; + try + { + if ((m_symbolTableSection.size > 0) && (m_symbolTableSection.link < m_elfSections.size())) + { + symbolTable = ParseSymbolTable(reader, m_symbolTableSection, m_elfSections[m_symbolTableSection.link], false); + } + + if ((m_dynamicSymbolTableSection.size > 0) && (m_dynamicSymbolTableSection.link < m_elfSections.size())) + { + dynamicSymbolTable = ParseSymbolTable(reader, m_dynamicSymbolTableSection, + m_elfSections[m_dynamicSymbolTableSection.link], true); + } + } + catch (ReadException&) + { + // Symbol table is not critical to execution, skip errors + m_logger->LogError("ELF symbol table invalid"); + } + + vector<ELFRelocEntry> relocs; + try + { + GetRelocEntries(virtualReader, dynRelocSections, true, relocs); + GetRelocEntries(virtualReader, dynRelocASections, false, relocs); + GetRelocEntries(reader, relocSections, true, relocs); + GetRelocEntries(reader, relocASections, false, relocs); + for (auto& reloc : relocs) + reloc.offset += imageBaseAdjustment; + } + catch (ReadException&) + { + // Skip errors in relocation tables + m_logger->LogError("ELF relocation table invalid"); + } + + BeginBulkModifySymbols(); + + vector<ElfSymbolTableEntry> auxSymbolTable; + try + { + if (!m_auxSymbolTableEntrySize) + m_auxSymbolTableEntrySize = m_elf32 ? 16 : 24; + + // Parse and create types for ELF hash table + if (m_hashHeader) + { + virtualReader.Seek(m_hashHeader); + uint32_t nbucket = virtualReader.Read32(); + uint32_t nchain = virtualReader.Read32(); + m_auxSymbolTable.size = m_auxSymbolTableEntrySize * nchain; + auxSymbolTable = ParseSymbolTable(virtualReader, m_auxSymbolTable, m_dynamicStringTable, true); + + StructureBuilder hashTableBuilder; + hashTableBuilder.AddMember(Type::IntegerType(4, false), "nbucket"); + hashTableBuilder.AddMember(Type::IntegerType(4, false), "nchain"); + hashTableBuilder.AddMember(Type::ArrayType(Type::IntegerType(4, false), nbucket), "buckets"); + hashTableBuilder.AddMember(Type::ArrayType(Type::IntegerType(4, false), nchain), "chains"); + Ref<Structure> hashTableStruct = hashTableBuilder.Finalize(); + Ref<Type> hashTableType = Type::StructureType(hashTableStruct); + QualifiedName hashTableName = string("Elf_HashTable"); + const string hashTableTypeId = Type::GenerateAutoTypeId("elf", hashTableName); + QualifiedName hashTableTypeName = DefineType(hashTableTypeId, hashTableName, hashTableType); + DefineDataVariable(m_hashHeader, Type::NamedType(this, hashTableTypeName)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_hash_table", m_hashHeader, NoBinding)); + + // Gratuitously create sections for the symbol and string tables if none exist + if (!GetSectionsAt(m_auxSymbolTable.offset).size()) + AddAutoSection(".dynamic_symtab", m_auxSymbolTable.offset, m_auxSymbolTable.size, ReadOnlyDataSectionSemantics); + if (!GetSectionsAt(m_dynamicStringTable.offset).size()) + AddAutoSection(".dynamic_strtab", m_dynamicStringTable.offset, m_dynamicStringTable.size, ReadOnlyDataSectionSemantics); + } + + // Parse and create types for ELF GNU hash table + if (m_gnuHashHeader) + { + // try to extract dynamic symbol table size from section information if it exists + if (!m_auxSymbolTable.size) + { + auto sections = GetSectionsAt(m_auxSymbolTable.offset); + if (sections.size() && (sections[0]->GetStart() == m_auxSymbolTable.offset)) + m_auxSymbolTable.size = sections[0]->GetLength(); + else + { + // TODO section information not available; calculate the dynamic symbol table size from the gnu hash table + } + } + } + } + catch (ReadException&) + { + // Skip errors in hash tables + m_logger->LogError("ELF hash/symbol table parsing failed"); + } + + try + { + if (mipsSymValid && (gotStart != 0)) + { + for (size_t i = 2; i < localMipsSyms; i++) + { + m_gotEntryLocations.emplace(gotStart + i * (m_elf32 ? 4 : 8)); + } + for (uint64_t i = firstMipsSym; i < (m_auxSymbolTable.size / (m_elf32 ? 16 : 24)); i++) + { + uint64_t gotEntry = gotStart + ((localMipsSyms + i - firstMipsSym) * (m_elf32 ? 4 : 8)); + + ElfSymbolTableEntry entry; + if (!ParseSymbolTableEntry(virtualReader, entry, i, m_auxSymbolTable, m_dynamicStringTable, true)) + continue; + // TODO dynamic symbol table already parsed above; don't add duplicate entries + if (!m_hashHeader) + auxSymbolTable.push_back(entry); + switch (entry.type) + { + case ELF_STT_OBJECT: + case ELF_STT_NOTYPE: + if (entry.section != ELF_SHN_UNDEF) + DefineElfSymbol(DataSymbol, entry.name, gotEntry, true, entry.binding, 4, Type::PointerType( + GetDefaultPlatform()->GetArchitecture(), Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE)); + else + { + bool relocationExists = false; + for (auto& reloc : relocs) + { + if (reloc.offset == gotEntry) + { + relocationExists = true; + break; + } + } + if (!relocationExists) + { + int relocType = m_arch->GetAddressSize() == 4 ? 126 /* R_MIPS_COPY */ : 125 /* R_MIPS64_COPY */; + relocs.push_back(ELFRelocEntry(gotEntry, i, relocType, 0, 0, false)); + } + DefineElfSymbol(ImportAddressSymbol, entry.name, gotEntry, true, entry.binding, entry.size); + } + break; + case ELF_STT_FUNC: + if (entry.section != ELF_SHN_UNDEF) + DefineElfSymbol(DataSymbol, entry.name, gotEntry, true, entry.binding, 4, + Type::PointerType(GetDefaultPlatform()->GetArchitecture(), + Type::FunctionType(Type::IntegerType(GetDefaultPlatform()->GetArchitecture()->GetAddressSize(), true), + GetDefaultPlatform()->GetDefaultCallingConvention(), vector<FunctionParameter>())->WithConfidence(0))); + else + { + bool relocationExists = false; + for (auto& reloc : relocs) + { + if (reloc.offset == gotEntry) + { + relocationExists = true; + break; + } + } + if (!relocationExists) + { + int relocType = m_arch->GetAddressSize() == 4 ? 127 /*R_MIPS_JUMP_SLOT*/ : 125 /* R_MIPS64_COPY */; + relocs.push_back(ELFRelocEntry(gotEntry, i, relocType, 0, 0, false)); + } + DefineElfSymbol(ImportAddressSymbol, entry.name, gotEntry, true, entry.binding, entry.size); + // TODO for now create associated PLT entry if it exists. At some point we could extend the detection in RecognizeELFPLTEntries in arch_mips. + Ref<Symbol> sym = GetSymbolByAddress(gotEntry); + if (entry.value && sym && (sym->GetType() == ImportAddressSymbol)) + { + Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(entry.value); + Ref<Function> func = AddFunctionForAnalysis(targetPlatform, entry.value); + if (func) + { + Ref<Symbol> funcSym = new Symbol(ImportedFunctionSymbol, + sym->GetShortName(), sym->GetFullName(), sym->GetRawName(), + entry.value, NoBinding, sym->GetNameSpace(), sym->GetOrdinal()); + DefineAutoSymbol(funcSym); + func->ApplyImportedTypes(funcSym); + } + } + } + break; + default: + m_logger->LogDebug("ELF symbol type of %d not handled.", entry.type); + break; + } + } + } + } + catch (ReadException&) + { + // Symbol table is not critical to execution, skip errors + m_logger->LogError("ELF symbol table invalid"); + } + + // No longer need to look up symbols during creation, start a parallelized queue for + // demangling and preparing symbols. + m_symbolQueue = new SymbolQueue(); + + // Now define symbols and resolve relocations + vector<ElfSymbolTableEntry> combinedSymbolTable; + if (symbolTable.size() > 1) + combinedSymbolTable.insert(combinedSymbolTable.end(), symbolTable.begin() + 1, symbolTable.end()); + if (dynamicSymbolTable.size() > 1) + combinedSymbolTable.insert(combinedSymbolTable.end(), dynamicSymbolTable.begin() + 1, dynamicSymbolTable.end()); + if (auxSymbolTable.size() > 1) + combinedSymbolTable.insert(combinedSymbolTable.end(), auxSymbolTable.begin() + 1, auxSymbolTable.end()); + for (auto entry = combinedSymbolTable.begin(); entry != combinedSymbolTable.end(); entry++) + { + if (m_objectFile) + { + if (entry->section >= m_elfSections.size()) + continue; + + // Object files "entry.value" is section relative + uint64_t adjustedSectionAddr = m_elfSections[entry->section].address + imageBaseAdjustment; + auto secs = GetSectionsAt(adjustedSectionAddr); + if (secs.size() < 1) + continue; + + entry->value += secs[0]->GetStart(); + } + else + entry->value += imageBaseAdjustment; + + if (entry->section == ELF_SHN_UNDEF) + { + DefineElfSymbol(ExternalSymbol, entry->name, 0, false, entry->binding, entry->size); + } + else + { + switch (entry->type) + { + case ELF_STT_GNU_IFUNC: + // Only handle this symbol type if the platform is a linux. Otherwise, we don't know what it is. + if (GetDefaultPlatform()->GetName().rfind("linux", 0) != 0) + goto unknownType; + DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding, entry->size); + break; + case ELF_STT_FUNC: + DefineElfSymbol(FunctionSymbol, entry->name, entry->value, false, entry->binding, entry->size); + break; + case ELF_STT_TLS: + /* - only create Binja symbols for .symtab (not .dynsym) symbols + - ignore mapping symbols, all is assumed data + - ignore 0-length symbols (like _TLS_MODULE_BASE_) that are just informative */ + if (entry->dynamic || entry->size == 0 || entry->name == "$d") + /* is the value a valid offset in the TLS template? */ + if (m_tlsSegment.virtualAddress == 0 || (entry->value + entry->size) > m_tlsSegment.memorySize) + break; + /* the value is the offset into the TLS template, specified by program header type 7 (PT_TLS) */ + DefineElfSymbol(DataSymbol, entry->name, m_tlsSegment.virtualAddress + entry->value, false, entry->binding, entry->size); + break; + case ELF_STT_NOTYPE: + // TODO: ARM specific local entry handling to be moved to architecture extension for ELF + if (entry->binding == LocalBinding && In(m_arch->GetName(), {"aarch64", "armv7", "armv7eb", "thumb2", "thumb2eb"})) + { + // ARM Mapping Symbols + // $a labels the first byte of a sequence of ARM instructions. Its type is STT_FUNC. + // $b labels a Thumb BL instruction. Its type is STT_FUNC. + // $d labels the first byte of a sequence of data items. Its type is STT_OBJECT. + // $f labels a function pointer constant (static pointer to code). Its type is STT_OBJECT. + // $t labels the first byte of a sequence of Thumb instructions. Its type is STT_FUNC. + // $*.<symbolName> is an optional long form + + // AArch64 Mapping Symbols + // $x labels start of sequence of A64 instructions + // $d labels start of sequence of data items + // $*.<symbolName> is an optional long form + bool isMappingSymbol = false; + bool isMappingFunctionSymbol = false; + string entryName(entry->name); + uint64_t target = entry->value; + if (m_arch->GetName() == "aarch64") + { + if (!entryName.rfind("$x", 0)) + isMappingSymbol = isMappingFunctionSymbol = true; + else if (!entryName.rfind("$d", 0)) + isMappingSymbol = true; + } + else + { + if (!entryName.rfind("$a", 0)) + isMappingSymbol = isMappingFunctionSymbol = true; + else if (!entryName.rfind("$b", 0) || !entryName.rfind("$t", 0)) + { + target |= 1; + isMappingSymbol = isMappingFunctionSymbol = true; + } + else if (!entryName.rfind("$d", 0) || !entryName.rfind("$f", 0)) + isMappingSymbol = true; + } + + if (isMappingSymbol) + { + if (!m_elfSections[entry->section].address) // only add artifacts for mapped sections + break; + + // Note: It appears that several '$a' or '$t' mapping symbols to not always indicate function starts. Occasionally, an address is marked + // immediately after a literal pool which is not a function. We explicitly allow mapping symbols for .plt sections for now. + if (isMappingFunctionSymbol && (sectionNames[entry->section] == ".plt")) + { + Ref<Platform> targetPlatform = platform->GetAssociatedPlatformByAddress(target); + AddFunctionForAnalysis(targetPlatform, target); + } + // else // TODO $d and %f + // m_logger->LogError("TODO: %s %p", entryName.c_str(), entry->value); + + // handle long form symbols + if (auto pos = entryName.find(".", 2); (pos != std::string::npos)) + { + entryName = entryName.substr(pos + 1); + if (entryName.size()) + DefineElfSymbol(isMappingFunctionSymbol ? FunctionSymbol : DataSymbol, entryName, entry->value, false, entry->binding, entry->size); + } + break; + } + } + DefineElfSymbol(DataSymbol, entry->name, entry->value, false, entry->binding, entry->size); + break; + case ELF_STT_OBJECT: + DefineElfSymbol(DataSymbol, entry->name, entry->value, false, entry->binding, entry->size); + break; + default: + unknownType: + m_logger->LogDebug("ELF symbol type of %d not handled.", entry->type); + break; + } + } + } + + // Process the queued symbols + m_symbolQueue->Process(); + delete m_symbolQueue; + m_symbolQueue = nullptr; + + EndBulkModifySymbols(); + + auto relocHandler = m_arch->GetRelocationHandler("ELF"); + if (relocHandler) + { + try + { + for (auto& reloc: relocs) + { + BNRelocationInfo relocInfo; + memset(&relocInfo, 0, sizeof(BNRelocationInfo)); + if (m_objectFile) + { + // In unlinked images reloc.offset is relative to the info section specified + if (reloc.sectionIdx >= m_elfSections.size()) + throw ReadException(); + auto sectionName = ReadStringTable(reader, m_sectionStringTable, m_elfSections[reloc.sectionIdx].name); + auto sec = GetSectionByName(sectionName); + if (!sec) + continue; + reloc.offset += sec->GetStart() - imageBaseAdjustment; + } + + relocInfo.symbolIndex = reloc.sym; + relocInfo.address = reloc.offset; + relocInfo.nativeType = reloc.relocType; + relocInfo.addend = reloc.addend; + relocInfo.implicitAddend = reloc.implicit; + relocInfo.base = baseAddress; + virtualReader.Seek(relocInfo.address); + memset(relocInfo.relocationDataCache, 0, sizeof(relocInfo.relocationDataCache)); + virtualReader.TryRead(relocInfo.relocationDataCache, MAX_RELOCATION_SIZE); + m_relocationInfo.push_back(relocInfo); + + if (isArmV7) + { + if(reloc.relocType == R_ARM_TLS_DTPOFF32) + tlsOffsets.push_back(reloc.offset); + else if(reloc.relocType == R_ARM_TLS_DTPMOD32) + tlsModuleStarts.push_back(reloc.offset); + } + } + + if (relocHandler->GetRelocationInfo(this, m_arch, m_relocationInfo)) + { + vector<ElfSymbolTableEntry>* symTable = &symbolTable; + if (!m_objectFile) + symTable = &dynamicSymbolTable; + + size_t anonymousEntryCount = 0; + for (auto& relocInfo : m_relocationInfo) + { + if (relocInfo.type == IgnoredRelocation) + continue; + + // Define absolute relocations with no symbol specified such as R_PPC_RELATIVE and R_ARM_IRELATIVE + // Define unhandled relocations in order to detect them and avoid creating functions at invalid target addresses + if ((relocInfo.symbolIndex == 0) || (relocInfo.type == UnhandledRelocation)) + { + relocInfo.baseRelative = imageBaseAdjustment != 0; + DefineRelocation(m_arch, relocInfo, imageBaseAdjustment, relocInfo.address); + } + else + { + ElfSymbolTableEntry entry; + if (relocInfo.symbolIndex < symTable->size()) + entry = (*symTable)[relocInfo.symbolIndex]; + else if (!ParseSymbolTableEntry(virtualReader, entry, relocInfo.symbolIndex, m_auxSymbolTable, m_dynamicStringTable, true)) + continue; + + if (relocInfo.type == ELFGlobalRelocationType) + DefineElfSymbol(ImportAddressSymbol, entry.name, relocInfo.address, true, entry.binding, entry.size); + else if (relocInfo.type == ELFCopyRelocationType) + DefineElfSymbol(ImportedDataSymbol, entry.name, relocInfo.address, false, entry.binding, entry.size); + else if (relocInfo.type == ELFJumpSlotRelocationType) + DefineElfSymbol(ImportAddressSymbol, entry.name, relocInfo.address, true, entry.binding, entry.size); + + if (entry.type == ELF_STT_SECTION) + { + // Section relative relocation + if (auto section = GetSectionByName(entry.name); section) + { + DefineRelocation(m_arch, relocInfo, section->GetStart(), relocInfo.address); + continue; + } + } + else if (!entry.section) + { + // handle anonymous symbol generation + if (!entry.name.size()) + { + entry.name = "anonymous_"; + if (entry.type == ELF_STT_FUNC) + entry.name += "func"; + else if (entry.type == ELF_STT_OBJECT) + entry.name += "object"; + else + entry.name += "data"; + entry.name += "_"; + + switch(entry.binding) + { + case NoBinding: + entry.name += "bind_none"; + break; + case LocalBinding: + entry.name += "bind_local"; + break; + case GlobalBinding: + entry.name += "bind_global"; + break; + case WeakBinding: + entry.name += "bind_weak"; + break; + default: + break; + } + entry.name += "_"; + entry.name += std::to_string(anonymousEntryCount++); + DefineElfSymbol(ExternalSymbol, entry.name, 0, false, entry.binding, entry.size); + } + + // section undefined so query for external symbol directly + auto symbol = GetSymbolByRawName(entry.name, GetExternalNameSpace()); + if (symbol) + { + DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); + continue; + } + } + else if (entry.section < m_elfSections.size()) + { + // symbol is relative to a section, look up by address instead of name to avoid ambiguity + uint64_t target = m_elfSections[entry.section].address + entry.value; + auto symbol = GetSymbolByAddress(target); + if (symbol) + { + DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); + continue; + } + } + + // retrieve first symbol that is not a symbol relocation + auto symbols = GetSymbolsByName(entry.name); + for (const auto& symbol : symbols) + { + if (symbol->GetAddress() == relocInfo.address) + continue; + DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); + break; + } + } + } + } + } + catch (ReadException&) + { + // Skip errors in relocation tables + m_logger->LogError("Failed to parse relocations"); + } + } + + // Add additional function starts, after symbols have been processed + for (const auto& section : GetSections()) + { + if ((section->GetLength() > 0) && ((section->GetName() == ".init") || (section->GetName() == ".fini"))) + { + string autoSectionName = section->GetName(); + autoSectionName.replace(0, 1, "_"); + auto funcs = GetAnalysisFunctionsForAddress(section->GetStart()); + + if (!m_backedByDatabase) // Don't create symbols that are present in the database snapshot now + { + auto symbol = GetSymbolByAddress(section->GetStart()); + if (!symbol) + DefineAutoSymbol(new Symbol(FunctionSymbol, autoSectionName, section->GetStart(), GlobalBinding)); + } + + // Prefer function creation via recursive descent when encountering mixed architecture binaries where the entry point arch differs from the file arch + if ((funcs.size() == 0) && (entryPointArch == m_arch)) + { + AddFunctionForAnalysis(GetDefaultPlatform(), section->GetStart()); + m_logger->LogDebug("Adding function start: %#" PRIx64 "\n", section->GetStart()); + } + } + else if (!(section->GetLength() % m_addressSize) && + ((section->GetName() == ".init_array") || (section->GetName() == ".fini_array") || + (section->GetName() == ".ctors") || (section->GetName() == ".dtors"))) + { + // define a function pointer array: void (*init_array[])(void) + auto function = Type::FunctionType(Type::VoidType(), platform->GetDefaultCallingConvention(), vector<FunctionParameter>())->WithConfidence(0); + auto function_pointer = Type::PointerType(m_addressSize, function)->WithConfidence(0); + auto array = Type::ArrayType(function_pointer, section->GetLength() / m_addressSize); + DefineDataVariable(section->GetStart(), array); + // trim the first '.' from the section name + string autoSectionName = section->GetName().substr(1); + // define a symbol for the array + if (auto symbol = GetSymbolByAddress(section->GetStart()); !symbol) + DefineAutoSymbol(new Symbol(DataSymbol, autoSectionName, section->GetStart(), NoBinding)); + + virtualReader.Seek(section->GetStart()); + for (uint32_t i = 0; i < section->GetLength() / m_addressSize; i++) + { + uint64_t entry; + try + { + entry = virtualReader.ReadPointer(); + if ((int64_t)entry == -1) + continue; + } + catch (const ReadException& r) + { + m_logger->LogWarn("Fail to read pointer at %#" PRIx64 " while parsing section %s", + virtualReader.GetOffset(), autoSectionName.c_str()); + break; + } + + if (entry) + { + entry += imageBaseAdjustment; + Ref<Architecture> entryArch = entryPointArch->GetAssociatedArchitectureByAddress(entry); + if (entryArch != entryPointArch) + AddFunctionForAnalysis(platform->GetRelatedPlatform(entryArch), entry); + else + AddFunctionForAnalysis(platform, entry); + m_logger->LogDebug("Adding function start: %#" PRIx64 "\n", entry); + } + } + + } + } + + if (m_gotEntryLocations.size() > 0) + { + Ref<Section> got = GetSectionByName(".got"); + if (!got) + { + m_logger->LogWarn( + "ELF view did not find a .got section despite detected relocations; " + "attempting to create sections with appropriate semantics"); + + // Ensure the collected GOT entry locations include the program header specified GOT address. + if (gotStart) + { + m_gotEntryLocations.emplace(gotStart); + // A common setup observed is GOT[0] being the resolver, GOT[1] a constant, then pointers. + // If gotStart and a collected address sandwich a constant, include the constant. + if (m_gotEntryLocations.find(gotStart + 2 * m_addressSize) != m_gotEntryLocations.end()) + m_gotEntryLocations.emplace(gotStart + m_addressSize); + } + + map<uint64_t, size_t> gotSectionsToCreate; + + auto it = m_gotEntryLocations.begin(); + uint64_t start = *it; + uint64_t next = start + m_addressSize; + it++; + + while (true) + { + bool end = (it == m_gotEntryLocations.end()); + + if (end || (*it != next)) + { + gotSectionsToCreate[start] = next - start; + + if (end) + break; + + start = *it; + next = start; + } + + next += m_addressSize; + it++; + } + + for (auto& s : gotSectionsToCreate) + { + // Don't try creating a section if it starts in an already-created + // section. + if (GetSectionsAt(s.first).size() > 0) + continue; + + stringstream ss; + ss << ".got_recovered_" << std::hex << s.first; + AddAutoSection(ss.str(), s.first, s.second, ReadOnlyDataSectionSemantics); + } + } + } + + // Sometimes ELF will specify Thumb entry points w/o the bottom bit set + // To deal with this we delay adding entry points until after symbols have been resolved + // and ALL the functions have been created. This allows us to query the existing functions + // platform. All in an effort to not create a function with the wrong architecture + if (entryPointAddress && (entryPointAddress != GetStart())) + { + auto func = GetAnalysisFunctionsForAddress(entryPointAddress); + if (func.size() == 1) + AddEntryPointForAnalysis(func[0]->GetPlatform(), entryPointAddress); + else + AddEntryPointForAnalysis(GetDefaultPlatform(), entryPointAddress); + } + + // Add a symbol for the entry point + if (entryPointAddress && (entryPointAddress != GetStart()) && !GetSymbolByAddress(entryPointAddress)) + DefineAutoSymbol(new Symbol(FunctionSymbol, "_start", entryPointAddress, GlobalBinding)); + + // Create type for ELF identification + const string structNamePrefix = (m_addressSize == 4) ? "Elf32_" : "Elf64_"; + + StructureBuilder identBuilder; + identBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 4), "signature"); + identBuilder.AddMember(Type::IntegerType(1, false), "file_class"); + identBuilder.AddMember(Type::IntegerType(1, false), "encoding"); + identBuilder.AddMember(Type::IntegerType(1, false), "version"); + identBuilder.AddMember(Type::IntegerType(1, false), "os"); + identBuilder.AddMember(Type::IntegerType(1, false), "abi_version"); + identBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 7), "pad"); + Ref<Structure> identStruct = identBuilder.Finalize(); + Ref<Type> identType = Type::StructureType(identStruct); + QualifiedName identStructName = structNamePrefix + "Ident"; + const string identStructTypeId = Type::GenerateAutoTypeId("elf", identStructName); + QualifiedName elfIdentStructName = DefineType(identStructTypeId, identStructName, identType); + QualifiedName rawIdentStructName = GetParentView()->DefineType(identStructTypeId, identStructName, identType); + + // Create enum for ELF header machine + EnumerationBuilder elfHeaderMachineBuilder; + elfHeaderMachineBuilder.AddMemberWithValue("EM_NONE", EM_NONE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_M32", EM_M32); + elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARC", EM_SPARC); + elfHeaderMachineBuilder.AddMemberWithValue("EM_386", EM_386); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68K", EM_68K); + elfHeaderMachineBuilder.AddMemberWithValue("EM_88K", EM_88K); + elfHeaderMachineBuilder.AddMemberWithValue("EM_860", EM_860); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS", EM_MIPS); + elfHeaderMachineBuilder.AddMemberWithValue("EM_S370", EM_S370); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS_RS3_LE", EM_MIPS_RS3_LE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PARISC", EM_PARISC); + elfHeaderMachineBuilder.AddMemberWithValue("EM_VPP500", EM_VPP500); + elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARC32PLUS", EM_SPARC32PLUS); + elfHeaderMachineBuilder.AddMemberWithValue("EM_960", EM_960); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PPC", EM_PPC); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PPC64", EM_PPC64); + elfHeaderMachineBuilder.AddMemberWithValue("EM_S390", EM_S390); + elfHeaderMachineBuilder.AddMemberWithValue("EM_V800", EM_V800); + elfHeaderMachineBuilder.AddMemberWithValue("EM_FR20", EM_FR20); + elfHeaderMachineBuilder.AddMemberWithValue("EM_RH32", EM_RH32); + elfHeaderMachineBuilder.AddMemberWithValue("EM_RCE", EM_RCE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ARM", EM_ARM); + elfHeaderMachineBuilder.AddMemberWithValue("EM_FAKE_ALPHA", EM_FAKE_ALPHA); + elfHeaderMachineBuilder.AddMemberWithValue("EM_SH", EM_SH); + elfHeaderMachineBuilder.AddMemberWithValue("EM_SPARCV9", EM_SPARCV9); + elfHeaderMachineBuilder.AddMemberWithValue("EM_TRICORE", EM_TRICORE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ARC", EM_ARC); + elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_300", EM_H8_300); + elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_300H", EM_H8_300H); + elfHeaderMachineBuilder.AddMemberWithValue("EM_H8S", EM_H8S); + elfHeaderMachineBuilder.AddMemberWithValue("EM_H8_500", EM_H8_500); + elfHeaderMachineBuilder.AddMemberWithValue("EM_IA_64", EM_IA_64); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MIPS_X", EM_MIPS_X); + elfHeaderMachineBuilder.AddMemberWithValue("EM_COLDFIRE", EM_COLDFIRE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC12", EM_68HC12); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MMA", EM_MMA); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PCP", EM_PCP); + elfHeaderMachineBuilder.AddMemberWithValue("EM_NCPU", EM_NCPU); + elfHeaderMachineBuilder.AddMemberWithValue("EM_NDR1", EM_NDR1); + elfHeaderMachineBuilder.AddMemberWithValue("EM_STARCORE", EM_STARCORE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ME16", EM_ME16); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ST100", EM_ST100); + elfHeaderMachineBuilder.AddMemberWithValue("EM_TINYJ", EM_TINYJ); + elfHeaderMachineBuilder.AddMemberWithValue("EM_X86_64", EM_X86_64); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PDSP", EM_PDSP); + elfHeaderMachineBuilder.AddMemberWithValue("EM_FX66", EM_FX66); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ST9PLUS", EM_ST9PLUS); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ST7", EM_ST7); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC16", EM_68HC16); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC11", EM_68HC11); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC08", EM_68HC08); + elfHeaderMachineBuilder.AddMemberWithValue("EM_68HC05", EM_68HC05); + elfHeaderMachineBuilder.AddMemberWithValue("EM_SVX", EM_SVX); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ST19", EM_ST19); + elfHeaderMachineBuilder.AddMemberWithValue("EM_VAX", EM_VAX); + elfHeaderMachineBuilder.AddMemberWithValue("EM_CRIS", EM_CRIS); + elfHeaderMachineBuilder.AddMemberWithValue("EM_JAVELIN", EM_JAVELIN); + elfHeaderMachineBuilder.AddMemberWithValue("EM_FIREPATH", EM_FIREPATH); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ZSP", EM_ZSP); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MMIX", EM_MMIX); + elfHeaderMachineBuilder.AddMemberWithValue("EM_HUANY", EM_HUANY); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PRISM", EM_PRISM); + elfHeaderMachineBuilder.AddMemberWithValue("EM_AVR", EM_AVR); + elfHeaderMachineBuilder.AddMemberWithValue("EM_FR30", EM_FR30); + elfHeaderMachineBuilder.AddMemberWithValue("EM_D10V", EM_D10V); + elfHeaderMachineBuilder.AddMemberWithValue("EM_D30V", EM_D30V); + elfHeaderMachineBuilder.AddMemberWithValue("EM_V850", EM_V850); + elfHeaderMachineBuilder.AddMemberWithValue("EM_M32R", EM_M32R); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MN10300", EM_MN10300); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MN10200", EM_MN10200); + elfHeaderMachineBuilder.AddMemberWithValue("EM_PJ", EM_PJ); + elfHeaderMachineBuilder.AddMemberWithValue("EM_OPENRISC", EM_OPENRISC); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ARC_A5", EM_ARC_A5); + elfHeaderMachineBuilder.AddMemberWithValue("EM_XTENSA", EM_XTENSA); + elfHeaderMachineBuilder.AddMemberWithValue("EM_ALTERA_NIOS2", EM_ALTERA_NIOS2); + elfHeaderMachineBuilder.AddMemberWithValue("EM_AARCH64", EM_AARCH64); + elfHeaderMachineBuilder.AddMemberWithValue("EM_TILEPRO", EM_TILEPRO); + elfHeaderMachineBuilder.AddMemberWithValue("EM_MICROBLAZE", EM_MICROBLAZE); + elfHeaderMachineBuilder.AddMemberWithValue("EM_TILEGX", EM_TILEGX); + elfHeaderMachineBuilder.AddMemberWithValue("EM_NUM", EM_NUM); + + Ref<Enumeration> elfHeaderMachineEnum = elfHeaderMachineBuilder.Finalize(); + Ref<Type> elfHeaderMachineEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), elfHeaderMachineEnum, 2, false); + const string elfHeaderMachineEnumName = "e_machine"; + const string elfHeaderMachineEnumId = Type::GenerateAutoTypeId("elf", elfHeaderMachineEnumName); + QualifiedName elfElfHeaderMachineEnumName = DefineType(elfHeaderMachineEnumId, elfHeaderMachineEnumName, elfHeaderMachineEnumType); + QualifiedName rawElfHeaderMachineEnumName = GetParentView()->DefineType(elfHeaderMachineEnumId, elfHeaderMachineEnumName, elfHeaderMachineEnumType); + + // Create enum for ELF header type + EnumerationBuilder elfHeaderTypeBuilder; + elfHeaderTypeBuilder.AddMemberWithValue("ET_NONE", ET_NONE); + elfHeaderTypeBuilder.AddMemberWithValue("ET_REL", ET_REL); + elfHeaderTypeBuilder.AddMemberWithValue("ET_EXEC", ET_EXEC); + elfHeaderTypeBuilder.AddMemberWithValue("ET_DYN", ET_DYN); + elfHeaderTypeBuilder.AddMemberWithValue("ET_CORE", ET_CORE); + elfHeaderTypeBuilder.AddMemberWithValue("ET_NUM", ET_NUM); + + Ref<Enumeration> elfHeaderTypeEnum = elfHeaderTypeBuilder.Finalize(); + Ref<Type> elfHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), elfHeaderTypeEnum, 2, false); + const string elfHeaderTypeEnumName = "e_type"; + const string elfHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", elfHeaderTypeEnumName); + QualifiedName elfElfHeaderTypeEnumName = DefineType(elfHeaderTypeEnumId, elfHeaderTypeEnumName, elfHeaderTypeEnumType); + QualifiedName rawElfHeaderTypeEnumName = GetParentView()->DefineType(elfHeaderTypeEnumId, elfHeaderTypeEnumName, elfHeaderTypeEnumType); + + // Create type for ELF header + StructureBuilder elfHeaderBuilder; + elfHeaderBuilder.AddMember(Type::NamedType(this, elfIdentStructName), "ident"); + elfHeaderBuilder.AddMember(Type::NamedType(this, elfElfHeaderTypeEnumName), "type"); + elfHeaderBuilder.AddMember(Type::NamedType(this, elfElfHeaderMachineEnumName), "machine"); + elfHeaderBuilder.AddMember(Type::IntegerType(4, false), "version"); + + if (platform) + { + elfHeaderBuilder.AddMember(Type::PointerType(m_addressSize, Type::FunctionType(Type::VoidType(), + platform->GetDefaultCallingConvention(), vector<FunctionParameter>())), "entry"); + } + else + { + elfHeaderBuilder.AddMember(Type::PointerType(m_addressSize, Type::VoidType()), "entry"); + } + + elfHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "program_header_offset"); + elfHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "section_header_offset"); + elfHeaderBuilder.AddMember(Type::IntegerType(4, false), "flags"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "header_size"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "program_header_size"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "program_header_count"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "section_header_size"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "section_header_count"); + elfHeaderBuilder.AddMember(Type::IntegerType(2, false), "string_table"); + Ref<Structure> elfHeaderStruct = elfHeaderBuilder.Finalize(); + Ref<Type> elfHeaderType = Type::StructureType(elfHeaderStruct); + QualifiedName headerName = structNamePrefix + "Header"; + const string headerTypeId = Type::GenerateAutoTypeId("elf", headerName); + QualifiedName elfHeaderName = DefineType(headerTypeId, headerName, elfHeaderType); + + elfHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawIdentStructName), "ident"); + elfHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawElfHeaderTypeEnumName), "type"); + elfHeaderBuilder.ReplaceMember(2, Type::NamedType(GetParentView(), rawElfHeaderMachineEnumName), "machine"); + elfHeaderBuilder.ReplaceMember(4, Type::IntegerType(m_addressSize, false), "entry"); + Ref<Structure> rawElfHeaderStruct = elfHeaderBuilder.Finalize(); + Ref<Type> rawElfHeaderType = Type::StructureType(rawElfHeaderStruct); + QualifiedName rawHeaderName = GetParentView()->DefineType(headerTypeId, headerName, rawElfHeaderType); + + // Define variable for ELF header + uint64_t addr; + if (GetAddressForDataOffset(0, addr)) + { + DefineDataVariable(addr, Type::NamedType(this, elfHeaderName)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_header", addr, LocalBinding)); + } + GetParentView()->DefineDataVariable(0, Type::NamedType(GetParentView(), rawHeaderName)); + GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_header", 0, LocalBinding)); + + + // Create enum for ELF program header type + EnumerationBuilder programHeaderTypeBuilder; + programHeaderTypeBuilder.AddMemberWithValue("PT_NULL", ELF_PT_NULL); + programHeaderTypeBuilder.AddMemberWithValue("PT_LOAD", ELF_PT_LOAD); + programHeaderTypeBuilder.AddMemberWithValue("PT_DYNAMIC", ELF_PT_DYNAMIC); + programHeaderTypeBuilder.AddMemberWithValue("PT_INTERP", ELF_PT_INTERP); + programHeaderTypeBuilder.AddMemberWithValue("PT_NOTE", ELF_PT_NOTE); + programHeaderTypeBuilder.AddMemberWithValue("PT_SHLIB", ELF_PT_SHLIB); + programHeaderTypeBuilder.AddMemberWithValue("PT_PHDR", ELF_PT_PHDR); + programHeaderTypeBuilder.AddMemberWithValue("PT_TLS", ELF_PT_TLS); + programHeaderTypeBuilder.AddMemberWithValue("PT_NUM", ELF_PT_NUM); + programHeaderTypeBuilder.AddMemberWithValue("PT_LOOS", ELF_PT_LOOS); + programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_EH_FRAME", ELF_PT_GNU_EH_FRAME); + programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_STACK", ELF_PT_GNU_STACK); + programHeaderTypeBuilder.AddMemberWithValue("PT_GNU_RELRO", ELF_PT_GNU_RELRO); + programHeaderTypeBuilder.AddMemberWithValue("PT_LOSUNW", ELF_PT_LOSUNW); + programHeaderTypeBuilder.AddMemberWithValue("PT_SUNWBSS", ELF_PT_SUNWBSS); + programHeaderTypeBuilder.AddMemberWithValue("PT_SUNWSTACK", ELF_PT_SUNWSTACK); + programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_REGINFO", ELF_PT_MIPS_REGINFO); + programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_RTPROC", ELF_PT_MIPS_RTPROC); + programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_OPTIONS", ELF_PT_MIPS_OPTIONS); + programHeaderTypeBuilder.AddMemberWithValue("PT_MIPS_ABIFLAGS", ELF_PT_MIPS_ABIFLAGS); + + Ref<Enumeration> programHeaderTypeEnum = programHeaderTypeBuilder.Finalize(); + Ref<Type> programHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), programHeaderTypeEnum, 4, false); + const string programHeaderTypeEnumName = "p_type"; + const string programHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", programHeaderTypeEnumName); + QualifiedName elfProgramHeaderTypeEnumName = DefineType(programHeaderTypeEnumId, programHeaderTypeEnumName, programHeaderTypeEnumType); + QualifiedName rawProgramHeaderTypeEnumName = GetParentView()->DefineType(programHeaderTypeEnumId, programHeaderTypeEnumName, programHeaderTypeEnumType); + + + // Create enum for ELF program header flags + EnumerationBuilder programHeaderFlagsBuilder; + programHeaderFlagsBuilder.AddMemberWithValue("PF_X", PF_X); + programHeaderFlagsBuilder.AddMemberWithValue("PF_W", PF_W); + programHeaderFlagsBuilder.AddMemberWithValue("PF_R", PF_R); + + Ref<Enumeration> programHeaderFlagsEnum = programHeaderFlagsBuilder.Finalize(); + Ref<Type> programHeaderFlagsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), programHeaderFlagsEnum, 4, false); + const string programHeaderFlagsEnumName = "p_flags"; + const string programHeaderFlagsEnumId = Type::GenerateAutoTypeId("elf", programHeaderFlagsEnumName); + QualifiedName elfProgramHeaderFlagsEnumName = DefineType(programHeaderFlagsEnumId, programHeaderFlagsEnumName, programHeaderFlagsEnumType); + QualifiedName rawProgramHeaderFlagsEnumName = GetParentView()->DefineType(programHeaderFlagsEnumId, programHeaderFlagsEnumName, programHeaderFlagsEnumType); + + // Create type for ELF program headers + StructureBuilder programHeaderBuilder; + if (m_addressSize == 4) + { + programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderTypeEnumName), "type"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "offset"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "virtual_address"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "physical_address"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "file_size"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "memory_size"); + programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderFlagsEnumName), "flags"); + programHeaderBuilder.AddMember(Type::IntegerType(4, false), "align"); + } + else + { + programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderTypeEnumName), "type"); + programHeaderBuilder.AddMember(Type::NamedType(this, elfProgramHeaderFlagsEnumName), "flags"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "offset"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "virtual_address"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "physical_address"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "file_size"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "memory_size"); + programHeaderBuilder.AddMember(Type::IntegerType(8, false), "align"); + } + Ref<Structure> programHeaderStruct = programHeaderBuilder.Finalize(); + Ref<Type> programHeaderType = Type::StructureType(programHeaderStruct); + QualifiedName programHeaderName = structNamePrefix + "ProgramHeader"; + const string programHeaderTypeId = Type::GenerateAutoTypeId("elf", programHeaderName); + QualifiedName elfProgramHeaderName = DefineType(programHeaderTypeId, programHeaderName, programHeaderType); + + if (m_addressSize == 4) + { + programHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawProgramHeaderTypeEnumName), "type"); + programHeaderBuilder.ReplaceMember(6, Type::NamedType(GetParentView(), rawProgramHeaderFlagsEnumName), "flags"); + } + else + { + programHeaderBuilder.ReplaceMember(0, Type::NamedType(GetParentView(), rawProgramHeaderTypeEnumName), "type"); + programHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawProgramHeaderFlagsEnumName), "flags"); + } + Ref<Structure> rawProgramHeaderStruct = programHeaderBuilder.Finalize(); + Ref<Type> rawProgramHeaderType = Type::StructureType(rawProgramHeaderStruct); + QualifiedName rawProgramHeaderName = GetParentView()->DefineType(programHeaderTypeId, programHeaderName, rawProgramHeaderType); + + // Define variable for ELF program headers + if (m_programHeaderCount != 0) + { + if (GetAddressForDataOffset(m_programHeaderOffset, addr)) + { + DefineDataVariable(addr, Type::ArrayType(Type::NamedType(this, elfProgramHeaderName), + m_programHeaderCount)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_program_headers", addr, LocalBinding)); + } + GetParentView()->DefineDataVariable(m_programHeaderOffset, Type::ArrayType(Type::NamedType( + GetParentView(), rawProgramHeaderName), m_programHeaderCount)); + GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_program_headers", m_programHeaderOffset, LocalBinding)); + } + + // Create enum for ELF section header type + EnumerationBuilder sectionHeaderTypeBuilder; + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NULL", ELF_SHT_NULL); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PROGBITS", ELF_SHT_PROGBITS); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_SYMTAB", ELF_SHT_SYMTAB); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_STRTAB", ELF_SHT_STRTAB); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_RELA", ELF_SHT_RELA); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HASH", ELF_SHT_HASH); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_DYNAMIC", ELF_SHT_DYNAMIC); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NOTE", ELF_SHT_NOTE); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_NOBITS", ELF_SHT_NOBITS); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_REL", ELF_SHT_REL); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_SHLIB", ELF_SHT_SHLIB); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_DYNSYM", ELF_SHT_DYNSYM); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_LOUSER", ELF_SHT_LOUSER); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HIUSER", ELF_SHT_HIUSER); + + // Machine specific section header types + if (m_commonHeader.arch == EM_PARISC) + { + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_EXT", ELF_SHT_EXT); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_UNWIND", ELF_SHT_UNWIND); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_DOC", ELF_SHT_PARISC_DOC); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_PARISC_ANNOT", ELF_SHT_PARISC_ANNOT); + } + else if (m_commonHeader.arch == EM_IA_64) + { + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_EXT", ELF_SHT_EXT); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_UNWIND", ELF_SHT_UNWIND); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_LOPSREG", ELF_SHT_IA_64_LOPSREG); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_HIPSREG", ELF_SHT_IA_64_HIPSREG); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_IA_64_PRIORITY_INIT", ELF_SHT_IA_64_PRIORITY_INIT); + } + else if (m_commonHeader.arch == EM_X86_64) + { + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_AMD64_UNWIND", ELF_SHT_UNWIND); + } + else + { + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_LOPROC", ELF_SHT_LOPROC); + sectionHeaderTypeBuilder.AddMemberWithValue("SHT_HIPROC", ELF_SHT_HIPROC); + } + + Ref<Enumeration> sectionHeaderTypeEnum = sectionHeaderTypeBuilder.Finalize(); + Ref<Type> sectionHeaderTypeEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), sectionHeaderTypeEnum, 4, false); + const string sectionHeaderTypeEnumName = "sh_type"; + const string sectionHeaderTypeEnumId = Type::GenerateAutoTypeId("elf", sectionHeaderTypeEnumName); + QualifiedName elfSectionHeaderTypeEnumName = DefineType(sectionHeaderTypeEnumId, sectionHeaderTypeEnumName, sectionHeaderTypeEnumType); + QualifiedName rawSectionHeaderTypeEnumName = GetParentView()->DefineType(sectionHeaderTypeEnumId, sectionHeaderTypeEnumName, sectionHeaderTypeEnumType); + + // Create enum for ELF section header flags + EnumerationBuilder sectionHeaderFlagsBuilder; + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_WRITE", ELF_SHF_WRITE); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_ALLOC", ELF_SHF_ALLOC); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_EXECINSTR", ELF_SHF_EXECINSTR); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MERGE", ELF_SHF_MERGE); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_STRINGS", ELF_SHF_STRINGS); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_INFO_LINK", ELF_SHF_INFO_LINK); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_LINK_ORDER", ELF_SHF_LINK_ORDER); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_OS_NONCONFORMING", ELF_SHF_OS_NONCONFORMING); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_GROUP", ELF_SHF_GROUP); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_TLS", ELF_SHF_TLS); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_COMPRESSED", ELF_SHF_COMPRESSED); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MASKOS", ELF_SHF_MASKOS); + + // Machine specific section header flags + if (m_commonHeader.arch == EM_PARISC) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_SHORT", ELF_SHF_PARISC_SHORT); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_HUGE", ELF_SHF_PARISC_HUGE); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_PARISC_SBP", ELF_SHF_PARISC_SBP); + } + else if (m_commonHeader.arch == EM_IA_64) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_IA_64_SHORT", ELF_SHF_IA_64_SHORT); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_IA_64_NORECOV", ELF_SHF_IA_64_NORECOV); + } + else if (m_commonHeader.arch == EM_X86_64) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_AMD64_LARGE", ELF_SHF_AMD64_LARGE); + } + else if (In(m_arch->GetName(), {"aarch64", "armv7", "armv7eb", "thumb2", "thumb2eb"})) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_ENTRYSECT", ELF_SHF_ENTRYSECT); + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_COMDEF", ELF_SHF_COMDEF); + } + else if (In(m_arch->GetName(), {"mipsel32", "mips32"})) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MIPS_GPREL", ELF_SHF_MIPS_GPREL); + } + else if (In(m_arch->GetName(), {"ppc", "ppc64", "ppc_le", "ppc64_le"})) + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_EXCLUDE", ELF_SHF_EXCLUDE); + } + else + { + sectionHeaderFlagsBuilder.AddMemberWithValue("SHF_MASKPROC", ELF_SHF_MASKPROC); + } + + Ref<Enumeration> sectionHeaderFlagsEnum = sectionHeaderFlagsBuilder.Finalize(); + Ref<Type> sectionHeaderFlagsEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), sectionHeaderFlagsEnum, m_addressSize, false); + const string sectionHeaderFlagsEnumName = "sh_flags"; + const string sectionHeaderFlagsEnumId = Type::GenerateAutoTypeId("elf", sectionHeaderFlagsEnumName); + QualifiedName elfSectionHeaderFlagsEnumName = DefineType(sectionHeaderFlagsEnumId, sectionHeaderFlagsEnumName, sectionHeaderFlagsEnumType); + QualifiedName rawSectionHeaderFlagsEnumName = GetParentView()->DefineType(sectionHeaderFlagsEnumId, sectionHeaderFlagsEnumName, sectionHeaderFlagsEnumType); + + // Create type for ELF section headers + StructureBuilder sectionHeaderBuilder; + sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "name"); + sectionHeaderBuilder.AddMember(Type::NamedType(this, elfSectionHeaderTypeEnumName), "type"); + sectionHeaderBuilder.AddMember(Type::NamedType(this, elfSectionHeaderFlagsEnumName), "flags"); + sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "address"); + sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "offset"); + sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "size"); + sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "link"); + sectionHeaderBuilder.AddMember(Type::IntegerType(4, false), "info"); + sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "align"); + sectionHeaderBuilder.AddMember(Type::IntegerType(m_addressSize, false), "entry_size"); + Ref<Structure> sectionHeaderStruct = sectionHeaderBuilder.Finalize(); + Ref<Type> sectionHeaderType = Type::StructureType(sectionHeaderStruct); + QualifiedName sectionHeaderName = structNamePrefix + "SectionHeader"; + const string sectionHeaderTypeId = Type::GenerateAutoTypeId("elf", sectionHeaderName); + QualifiedName elfSectionHeaderName = DefineType(sectionHeaderTypeId, sectionHeaderName, sectionHeaderType); + + sectionHeaderBuilder.ReplaceMember(1, Type::NamedType(GetParentView(), rawSectionHeaderTypeEnumName), "type"); + sectionHeaderBuilder.ReplaceMember(2, Type::NamedType(GetParentView(), rawSectionHeaderFlagsEnumName), "flags"); + Ref<Structure> rawSectionHeaderStruct = sectionHeaderBuilder.Finalize(); + Ref<Type> rawSectionHeaderType = Type::StructureType(rawSectionHeaderStruct); + QualifiedName rawSectionHeaderName = GetParentView()->DefineType(sectionHeaderTypeId, sectionHeaderName, rawSectionHeaderType); + + // Define variable for ELF program headers + if (m_sectionHeaderCount != 0) + { + uint64_t configuredSectionCount = 100; + if (viewSettings && viewSettings->Contains("files.elf.maxSectionHeaderCount")) + configuredSectionCount = viewSettings->Get<uint64_t>("files.elf.maxSectionHeaderCount", this); + uint64_t sectionCount = std::min<uint64_t>(m_sectionHeaderCount, configuredSectionCount); + if (GetAddressForDataOffset(m_sectionHeaderOffset, addr)) + { + DefineDataVariable(addr, Type::ArrayType(Type::NamedType(this, elfSectionHeaderName), sectionCount)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_section_headers", addr, LocalBinding)); + } + GetParentView()->DefineDataVariable(m_sectionHeaderOffset, Type::ArrayType(Type::NamedType(GetParentView(), rawSectionHeaderName), sectionCount)); + GetParentView()->DefineAutoSymbol(new Symbol(DataSymbol, "__elf_section_headers", m_sectionHeaderOffset, LocalBinding)); + } + + // Add types for dynamic table + if (m_dynamicTable.virtualAddress && m_numDynamicTableEntries) + { + EnumerationBuilder dynTagEnumBuilder; + dynTagEnumBuilder.AddMemberWithValue("DT_NULL", ELF_DT_NULL); + dynTagEnumBuilder.AddMemberWithValue("DT_NEEDED", ELF_DT_NEEDED); + dynTagEnumBuilder.AddMemberWithValue("DT_PLTRELSZ", ELF_DT_PLTRELSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_PLTGOT", ELF_DT_PLTGOT); + dynTagEnumBuilder.AddMemberWithValue("DT_HASH", ELF_DT_HASH); + dynTagEnumBuilder.AddMemberWithValue("DT_STRTAB", ELF_DT_STRTAB); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMTAB", ELF_DT_SYMTAB); + dynTagEnumBuilder.AddMemberWithValue("DT_RELA", ELF_DT_RELA); + dynTagEnumBuilder.AddMemberWithValue("DT_RELASZ", ELF_DT_RELASZ); + dynTagEnumBuilder.AddMemberWithValue("DT_RELAENT", ELF_DT_RELAENT); + dynTagEnumBuilder.AddMemberWithValue("DT_STRSZ", ELF_DT_STRSZ); + //dynTagEnumBuilder.AddMemberWithValue("DT_DYNSYM", ELF_DT_DYNSYM); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMENT", ELF_DT_SYMENT); + dynTagEnumBuilder.AddMemberWithValue("DT_INIT", ELF_DT_INIT); + dynTagEnumBuilder.AddMemberWithValue("DT_FINI", ELF_DT_FINI); + dynTagEnumBuilder.AddMemberWithValue("DT_SONAME", ELF_DT_SONAME); + dynTagEnumBuilder.AddMemberWithValue("DT_RPATH", ELF_DT_RPATH); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMBOLIC", ELF_DT_SYMBOLIC); + dynTagEnumBuilder.AddMemberWithValue("DT_REL", ELF_DT_REL); + dynTagEnumBuilder.AddMemberWithValue("DT_RELSZ", ELF_DT_RELSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_RELENT", ELF_DT_RELENT); + dynTagEnumBuilder.AddMemberWithValue("DT_PLTREL", ELF_DT_PLTREL); + dynTagEnumBuilder.AddMemberWithValue("DT_DEBUG", ELF_DT_DEBUG); + dynTagEnumBuilder.AddMemberWithValue("DT_TEXTREL", ELF_DT_TEXTREL); + dynTagEnumBuilder.AddMemberWithValue("DT_JMPREL", ELF_DT_JMPREL); + dynTagEnumBuilder.AddMemberWithValue("DT_BIND_NOW", ELF_DT_BIND_NOW); + dynTagEnumBuilder.AddMemberWithValue("DT_INIT_ARRAY", ELF_DT_INIT_ARRAY); + dynTagEnumBuilder.AddMemberWithValue("DT_FINI_ARRAY", ELF_DT_FINI_ARRAY); + dynTagEnumBuilder.AddMemberWithValue("DT_INIT_ARRAYSZ", ELF_DT_INIT_ARRAYSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_FINI_ARRAYSZ", ELF_DT_FINI_ARRAYSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_RUNPATH", ELF_DT_RUNPATH); + dynTagEnumBuilder.AddMemberWithValue("DT_FLAGS", ELF_DT_FLAGS); + dynTagEnumBuilder.AddMemberWithValue("DT_ENCODING", ELF_DT_ENCODING); + dynTagEnumBuilder.AddMemberWithValue("DT_PREINIT_ARRAY", ELF_DT_PREINIT_ARRAY); + dynTagEnumBuilder.AddMemberWithValue("DT_PREINIT_ARRAYSZ", ELF_DT_PREINIT_ARRAYSZ); + + dynTagEnumBuilder.AddMemberWithValue("DT_LOOS", ELF_DT_LOOS); + dynTagEnumBuilder.AddMemberWithValue("DT_SUNW_RTLDINF", ELF_DT_SUNW_RTLDINF); + dynTagEnumBuilder.AddMemberWithValue("DT_HIOS", ELF_DT_HIOS); + dynTagEnumBuilder.AddMemberWithValue("DT_VALRNGLO", ELF_DT_VALRNGLO); + dynTagEnumBuilder.AddMemberWithValue("DT_CHECKSUM", ELF_DT_CHECKSUM); + dynTagEnumBuilder.AddMemberWithValue("DT_PLTPADSZ", ELF_DT_PLTPADSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_MOVEENT", ELF_DT_MOVEEN); + dynTagEnumBuilder.AddMemberWithValue("DT_MOVESZ", ELF_DT_MOVES); + dynTagEnumBuilder.AddMemberWithValue("DT_FEATURE_1", ELF_DT_FEATURE_1); + dynTagEnumBuilder.AddMemberWithValue("DT_POSFLAG_1", ELF_DT_POSFLAG_1); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMINSZ", ELF_DT_SYMINSZ); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMINENT", ELF_DT_SYMINENT); + dynTagEnumBuilder.AddMemberWithValue("DT_VALRNGHI", ELF_DT_VALRNGH); + dynTagEnumBuilder.AddMemberWithValue("DT_ADDRRNGLO", ELF_DT_ADDRRNGLO); + dynTagEnumBuilder.AddMemberWithValue("DT_GNU_HASH", ELF_DT_GNU_HASH); + dynTagEnumBuilder.AddMemberWithValue("DT_CONFIG", ELF_DT_CONFIG); + dynTagEnumBuilder.AddMemberWithValue("DT_DEPAUDIT", ELF_DT_DEPAUDIT); + dynTagEnumBuilder.AddMemberWithValue("DT_AUDIT", ELF_DT_AUDIT); + dynTagEnumBuilder.AddMemberWithValue("DT_PLTPAD", ELF_DT_PLTPAD); + dynTagEnumBuilder.AddMemberWithValue("DT_MOVETAB", ELF_DT_MOVETAB); + dynTagEnumBuilder.AddMemberWithValue("DT_SYMINFO", ELF_DT_SYMINFO); + dynTagEnumBuilder.AddMemberWithValue("DT_ADDRRNGHI", ELF_DT_ADDRRNGHI); + dynTagEnumBuilder.AddMemberWithValue("DT_RELACOUNT", ELF_DT_RELACOUNT); + dynTagEnumBuilder.AddMemberWithValue("DT_RELCOUNT", ELF_DT_RELCOUNT); + dynTagEnumBuilder.AddMemberWithValue("DT_FLAGS_1", ELF_DT_FLAGS_1); + dynTagEnumBuilder.AddMemberWithValue("DT_VERDEF", ELF_DT_VERDEF); + dynTagEnumBuilder.AddMemberWithValue("DT_VERDEFNUM", ELF_DT_VERDEFNUM); + dynTagEnumBuilder.AddMemberWithValue("DT_VERNEED", ELF_DT_VERNEED); + dynTagEnumBuilder.AddMemberWithValue("DT_VERNEEDNUM", ELF_DT_VERNEEDNUM); + dynTagEnumBuilder.AddMemberWithValue("DT_VERSYM", ELF_DT_VERSYM); + + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_VERSION", ELF_DT_MIPS_RLD_VERSION); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_TIME_STAMP", ELF_DT_MIPS_TIME_STAMP); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_ICHECKSUM", ELF_DT_MIPS_ICHECKSUM); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_IVERSION", ELF_DT_MIPS_IVERSION); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_FLAGS", ELF_DT_MIPS_FLAGS); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_BASE_ADDRESS", ELF_DT_MIPS_BASE_ADDRESS); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_CONFLICT", ELF_DT_MIPS_CONFLICT); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LIBLIST", ELF_DT_MIPS_LIBLIST); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LOCAL_GOTNO", ELF_DT_MIPS_LOCAL_GOTNO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_CONFLICTNO", ELF_DT_MIPS_CONFLICTNO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_LIBLISTNO", ELF_DT_MIPS_LIBLISTNO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_SYMTABNO", ELF_DT_MIPS_SYMTABNO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_UNREFEXTNO", ELF_DT_MIPS_UNREFEXTNO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_GOTSYM", ELF_DT_MIPS_GOTSYM); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_HIPAGENO", ELF_DT_MIPS_HIPAGENO); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_MAP", ELF_DT_MIPS_RLD_MAP); + dynTagEnumBuilder.AddMemberWithValue("DT_MIPS_RLD_MAP_REL", ELF_DT_MIPS_RLD_MAP_REL); + + uint64_t entrySize = m_elf32 ? 8 : 16; + Ref<Enumeration> dynTagEnum = dynTagEnumBuilder.Finalize(); + Ref<Type> dynTagEnumType = Type::EnumerationType(GetParentView()->GetDefaultArchitecture(), dynTagEnum, entrySize / 2, false); + const string dynTagEnumName = "e_dyn_tag"; + const string dynTagEnumId = Type::GenerateAutoTypeId("elf", dynTagEnumName); + QualifiedName elfdynTagEnumName = DefineType(dynTagEnumId, dynTagEnumName, dynTagEnumType); + + StructureBuilder dynamicEntryBuilder; + dynamicEntryBuilder.AddMember(Type::NamedType(this, elfdynTagEnumName), "d_tag"); + dynamicEntryBuilder.AddMember(Type::IntegerType(entrySize / 2, false), "d_val"); + Ref<Structure> dynEntryStruct = dynamicEntryBuilder.Finalize(); + Ref<Type> dynEntryType = Type::StructureType(dynEntryStruct); + QualifiedName dynEntryName = m_elf32 ? string("Elf32_Dyn"): string("Elf64_Dyn"); + const string dynEntryTypeId = Type::GenerateAutoTypeId("elf", dynEntryName); + QualifiedName dynEntryTypeName = DefineType(dynEntryTypeId, dynEntryName, dynEntryType); + uint64_t adjustedVirtualAddr = m_dynamicTable.virtualAddress + imageBaseAdjustment; + DefineDataVariable(adjustedVirtualAddr, Type::ArrayType(Type::NamedType(this, dynEntryTypeName), m_numDynamicTableEntries)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_dynamic_table", adjustedVirtualAddr, NoBinding)); + } + + // Add types for the dynamic symbol table + if (m_auxSymbolTable.size) + { + StructureBuilder symTableBuilder; + if (m_elf32) + { + symTableBuilder.AddMember(Type::IntegerType(4, false), "st_name"); + symTableBuilder.AddMember(Type::IntegerType(4, false), "st_value"); + symTableBuilder.AddMember(Type::IntegerType(4, false), "st_size"); + symTableBuilder.AddMember(Type::IntegerType(1, false), "st_info"); + symTableBuilder.AddMember(Type::IntegerType(1, false), "st_other"); + symTableBuilder.AddMember(Type::IntegerType(2, false), "st_shndx"); + } + else + { + symTableBuilder.AddMember(Type::IntegerType(4, false), "st_name"); + symTableBuilder.AddMember(Type::IntegerType(1, false), "st_info"); + symTableBuilder.AddMember(Type::IntegerType(1, false), "st_other"); + symTableBuilder.AddMember(Type::IntegerType(2, false), "st_shndx"); + symTableBuilder.AddMember(Type::IntegerType(8, false), "st_value"); + symTableBuilder.AddMember(Type::IntegerType(8, false), "st_size"); + } + Ref<Structure> symTableStruct = symTableBuilder.Finalize(); + Ref<Type> symTableType = Type::StructureType(symTableStruct); + QualifiedName symTableName = m_elf32 ? string("Elf32_Sym") : string("Elf64_Sym"); + const string symTableTypeId = Type::GenerateAutoTypeId("elf", symTableName); + QualifiedName symTableTypeName = DefineType(symTableTypeId, symTableName, symTableType); + DefineDataVariable(m_auxSymbolTable.offset, Type::ArrayType(Type::NamedType(this, symTableTypeName), m_auxSymbolTable.size / m_auxSymbolTableEntrySize)); + DefineAutoSymbol(new Symbol(DataSymbol, "__elf_symbol_table", m_auxSymbolTable.offset, NoBinding)); + } + + // In 32-bit mips with .got, add .extern symbol "RTL_Resolve" + if (gotStart && In(m_arch->GetName(), {"mips32", "mipsel32", "mips64", "nanomips"})) + { + const char *name = "RTL_Resolve"; + + /* create symbol for RTL_Resolve(), address will be auto-assigned after placement in .extern */ + Ref<Symbol> symbol = new Symbol( + ExternalSymbol, /* type */ + name, /* shortName */ + name, /* fullName */ + name, /* rawName */ + 0, /* byAddr */ + GlobalBinding, /* binding */ + GetExternalNameSpace() /* namespace */ + ); + + /* create type, associate it with RTL_Resolve */ + Ref<Type> ptr_type = Type::PointerType(m_arch, Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE); + + Ref<CallingConvention> cc = m_arch->GetCallingConventionByName("linux-rtlresolve"); + + Ref<Type> type = Type::FunctionType( + Type::VoidType(), /* returnValue */ + cc, /* callingConvention */ + { /* params */ + FunctionParameter("caller_ret_addr", ptr_type), + FunctionParameter("sym_idx", Type::IntegerType(4, true)), + }, + false, /* hasVariableArguments */ + false, /* canReturn */ + 0 + ); + + /* This BinaryView helper does: + 1) DefineAutoSymbol(symbol); + 2) m_externalTypes[name] = type; + ...so that upon BinaryView finalization, data variables are made. */ + DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), symbol, type); + + /* Create relocation entry associated with this symbol so that reloc + servicing will overwrite GOT[0] with symbol's address. */ + BNRelocationInfo relocInfo; + memset(&relocInfo, 0, sizeof(BNRelocationInfo)); + relocInfo.base = gotStart; + relocInfo.address = gotStart; + relocInfo.size = m_arch->GetAddressSize(); + relocInfo.nativeType = m_arch->GetAddressSize() == 4 ? 2 /* R_MIPS_32 */ : 18 /* R_MIPS_64 */; + + DefineRelocation(m_arch, relocInfo, symbol, relocInfo.address); + } + + // Add type, data variables for TLS entries + for (auto offset : tlsModuleStarts) + { + /* All module ID's are set to 0. */ + DefineDataVariable(offset, Type::IntegerType(4, false)->WithConfidence(BN_FULL_CONFIDENCE)); + } + for (auto offset : tlsOffsets) + { + /* In runtime reality, these become the offsets of the variables within TLS data structures. + In static listing, we place a pointer to the variable for user convenience. */ + DefineDataVariable(offset, + Type::PointerType(m_arch, Type::VoidType())); + } + std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now(); + double t = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count() / 1000.0; + m_logger->LogInfo("ELF parsing took %.3f seconds\n", t); + m_stringTableCache.clear(); + return true; +} + + +void ElfView::DefineElfSymbol(BNSymbolType type, const string& incomingName, uint64_t addr, bool gotEntry, + BNSymbolBinding binding, size_t size, Ref<Type> typeObj) +{ + // Ensure symbol is within the executable + if (type != ExternalSymbol && !IsValidOffset(addr)) + return; + + string name = incomingName; + Ref<Type> symbolTypeRef; + if ((type == ExternalSymbol) || (type == ImportAddressSymbol) || (type == ImportedDataSymbol)) + { + QualifiedName n(name); + Ref<TypeLibrary> lib = nullptr; + symbolTypeRef = ImportTypeLibraryObject(lib, n); + if (symbolTypeRef) + { + m_logger->LogDebug("elf: type Library '%s' found hit for '%s'", lib->GetName().c_str(), name.c_str()); + if (type != ExternalSymbol || addr != 0) + { + RecordImportedObjectLibrary(GetDefaultPlatform(), addr, lib, n); + } + } + } + + auto pos = name.rfind("@@"); + if (type == ExternalSymbol && pos != string::npos) + { + name = name.substr(0, pos); + } + + pos = name.rfind("@GLIBC"); + if (type == ExternalSymbol && pos != string::npos) + { + name = name.substr(0, pos); + } + + // Deprioritize local label symbol names + if (type == DataSymbol && binding == LocalBinding && !name.empty() && name[0] == '.') + { + type = LocalLabelSymbol; + } + + // If name is empty, symbol is not valid + if (name.size() == 0) + return; + + if (!symbolTypeRef) + symbolTypeRef = typeObj; + + if (gotEntry) + m_gotEntryLocations.emplace(addr); + + auto process = [=]() { + NameSpace nameSpace = GetInternalNameSpace(); + if (type == ExternalSymbol) + { + nameSpace = GetExternalNameSpace(); + } + + // If name does not start with alphabetic character or symbol, prepend an underscore + string rawName = name; + if (!(((name[0] >= 'A') && (name[0] <= 'Z')) || ((name[0] >= 'a') && (name[0] <= 'z')) || (name[0] == '_') + || (name[0] == '?') || (name[0] == '$') || (name[0] == '@') || (name[0] == '.'))) + rawName = "_" + name; + + // Try to demangle any C++ symbols + string shortName = rawName; + string fullName = rawName; + Ref<Type> typeRef = symbolTypeRef; + if (m_arch && IsGNU3MangledString(rawName)) + { + QualifiedName varName; + Ref<Type> demangledType; + if (DemangleGNU3(m_arch, rawName, demangledType, varName, m_simplifyTemplates)) + { + shortName = varName.GetString(); + fullName = shortName; + if (demangledType) + fullName += demangledType->GetStringAfterName(); + if (!typeRef && m_extractMangledTypes && !GetDefaultPlatform()->GetFunctionByName(rawName)) + typeRef = demangledType; + } + else + { + m_logger->LogDebug("Failed to demangle name: '%s'\n", rawName.c_str()); + } + } + + if (!typeRef && (size > 0 && size <= 8)) + { + typeRef = Type::IntegerType(size, false); + } + + return std::pair<Ref<Symbol>, Ref<Type>>( + new Symbol(type, shortName, fullName, rawName, addr, binding, nameSpace), typeRef); + }; + + if (m_symbolQueue) + { + m_symbolQueue->Append(process, [this](Symbol* symbol, Type* type) { + DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), symbol, type); + }); + } + else + { + auto result = process(); + DefineAutoSymbolAndVariableOrFunction(GetDefaultPlatform(), result.first, result.second); + } +} + + +void ElfView::ApplyTypesToParentStringTable(const Elf64SectionHeader& section, const bool offset) +{ + m_logger->LogInfo("Found string table of size %p at offset %p", section.size, section.offset); + DataBuffer buffer = GetParentView()->ReadBuffer(section.offset, section.size); + if (buffer.GetLength() != section.size) + return; + unordered_map<size_t, Ref<Type>> cachedTypes; + for (size_t start_address = (offset ? 1 : 0); start_address < section.size; ++start_address) + { + size_t len; + char ch = 0; + for (len = 0; len < BN_MAX_STRING_LENGTH * 3 && start_address + len < section.size; ++len) + { + ch = buffer[start_address + len]; + if (ch == 0) + break; + } + + if (len != 0 && ch == 0) + { + auto i = cachedTypes.find(len); + Ref<Type> type; + if (i == cachedTypes.end()) + { + type = Type::ArrayType(Type::IntegerType(1, true), len + 1); + cachedTypes[len] = type; + } + else + { + type = i->second; + } + + GetParentView()->DefineDataVariable(section.offset + start_address, type); + } + + start_address += len; + } +} + + +void ElfView::ApplyTypesToStringTable(const Elf64SectionHeader& section, const int64_t imageBaseAdjustment, const bool offset) +{ + m_logger->LogInfo("Found string table of size %p at address %p", section.size, section.address); + DataVariable existing_var; + unordered_map<uint64_t, Ref<Type>> cachedTypes; + for (size_t start_address = section.offset + (offset ? 1 : 0); start_address < section.offset + section.size;) + { + if (!GetParentView()->GetDataVariableAtAddress(start_address, existing_var) || (existing_var.address != start_address)) + return; + + const uint64_t len = existing_var.type->GetElementCount(); + + auto i = cachedTypes.find(len); + Ref<Type> type; + if (i == cachedTypes.end()) + { + type = Type::ArrayType(Type::IntegerType(1, true), len); + cachedTypes[len] = type; + } + else + { + type = i->second; + } + DefineDataVariable(start_address - section.offset + section.address + imageBaseAdjustment, type); + + start_address += len; + } +} + + +string ElfView::ReadStringTable(BinaryReader& reader, const Elf64SectionHeader& section, uint64_t offset) +{ + if (offset == 0 || offset > section.size) + return ""; + + auto itr = m_stringTableCache.find(section.offset); + if (itr == m_stringTableCache.end()) + { + if (section.size > GetParentView()->GetLength()) + { + m_logger->LogError("Unable to read string table with section offset: 0x%" PRIx64 " size: 0x%" PRIx64, section.offset, section.size); + return ""; + } + + std::vector<char>& tableCache = m_stringTableCache[section.offset]; + tableCache.resize(section.size); + reader.Seek(section.offset); + reader.Read(tableCache.data(), section.size); + itr = m_stringTableCache.find(section.offset); + } + + const std::vector<char>& tableCache = itr->second; + return std::string(&tableCache[offset], strlen(tableCache.data() + offset)); +} + + +// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES +bool ElfView::DerefPpc64Descriptor(BinaryReader& reader, uint64_t addr, uint64_t& result) +{ + /* must be 64-bit ELF, arch PPC64 */ + if (m_elf32 || m_commonHeader.arch != EM_PPC64) + return false; + + /* .opd section must exist */ + if (!m_sectionOpd.size) + return false; + + /* addr must be within .opd section */ + if (addr < m_sectionOpd.address || addr >= m_sectionOpd.address + m_sectionOpd.size) + return false; + + /* dereference descriptor to get function entry */ + uint64_t saved = reader.GetOffset(); + reader.Seek(m_sectionOpd.offset + (addr - m_sectionOpd.address)); + bool read_success = reader.TryRead64(result);; + reader.Seek(saved); + return read_success; +} + + +vector<ElfSymbolTableEntry> ElfView::ParseSymbolTable(BinaryReader& reader, const Elf64SectionHeader& symbolSection, + const Elf64SectionHeader& stringSection, bool dynamic, size_t startEntry) +{ + size_t size = (size_t)symbolSection.size / (m_elf32 ? 16 : 24); + vector<ElfSymbolTableEntry> result; + for (size_t i = startEntry; i < size; i++) + { + ElfSymbolTableEntry entry; + if (!ParseSymbolTableEntry(reader, entry, i, symbolSection, stringSection, dynamic)) + break; + + /* TODO: PPC64 specific symbol handling to be moved to architecture extension for ELF */ + if (m_commonHeader.arch == EM_PPC64 && entry.type == ELF_STT_FUNC) + { + uint64_t func_start; + if (DerefPpc64Descriptor(reader, entry.value, func_start)) + { + if (entry.name[0] != '.') + { + /* new symbol with function entry as address */ + ElfSymbolTableEntry entry2 = entry; + entry2.name = "." + entry2.name; + entry2.value = func_start; + result.push_back(entry2); + + m_logger->LogDebug("PPC64 symbol %s=%016x to %s=%016x\n", entry.name.c_str(), entry.value, + entry2.name.c_str(), entry2.value); + + /* force the descriptor to a data symbol */ + entry.type = ELF_STT_OBJECT; + } + } + } + + result.push_back(entry); + } + + return result; +} + + +uint64_t ElfView::PerformGetEntryPoint() const +{ + return m_entryPoint; +} + + +BNEndianness ElfView::PerformGetDefaultEndianness() const +{ + return m_endian; +} + + +bool ElfView::PerformIsRelocatable() const +{ + return m_relocatable; +} + + +size_t ElfView::PerformGetAddressSize() const +{ + return m_addressSize; +} + + +ElfViewType::ElfViewType(): BinaryViewType("ELF", "ELF") +{ + m_logger = LogRegistry::CreateLogger("BinaryView.ElfViewType"); +} + + +Ref<BinaryView> ElfViewType::Create(BinaryView* data) +{ + try + { + return new ElfView(data); + } + catch (std::exception& e) + { + m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + return nullptr; + } +} + + +Ref<BinaryView> ElfViewType::Parse(BinaryView* data) +{ + try + { + return new ElfView(data, true); + } + catch (std::exception& e) + { + m_logger->LogError("%s<BinaryViewType> failed to create view! '%s'", GetName().c_str(), e.what()); + return nullptr; + } +} + + +bool ElfViewType::IsTypeValidForData(BinaryView* data) +{ + DataBuffer sig = data->ReadBuffer(0, 4); + if (sig.GetLength() != 4) + return false; + if (memcmp(sig.GetData(), "\x7f" "ELF", 4) == 0) + return true; + + // Cyber Grand Challenge DECREE executables can be parsed as ELF + if (memcmp(sig.GetData(), "\x7f" "CGC", 4) == 0) + return true; + + return false; +} + + +uint64_t ElfViewType::ParseHeaders(BinaryView* data, ElfIdent& ident, ElfCommonHeader& commonHeader, Elf64Header& header, Ref<Architecture>* arch, Ref<Platform>* plat, string& errorMsg, BNEndianness& endianness) +{ + if (!IsTypeValidForData(data)) + { + errorMsg = "invalid signature"; + return 0; + } + + // parse ElfIdent + if (data->Read(&ident, 0, sizeof(ident)) != sizeof(ident)) + { + errorMsg = "unable to read header"; + return 0; + } + + BinaryReader reader(data); + if (ident.encoding <= 1) + endianness = LittleEndian; + else if (ident.encoding == 2) + endianness = BigEndian; + else + { + errorMsg = "invalid encoding"; + return 0; + } + + // parse ElfCommonHeader + reader.SetEndianness(endianness); + reader.Seek(sizeof(ident)); + commonHeader.type = reader.Read16(); + commonHeader.arch = reader.Read16(); + commonHeader.version = reader.Read32(); + + // Promote the file class to 64-bit + // TODO potentially add a setting to allow the user to override header interpretation + if ((commonHeader.type == ET_EXEC) && (commonHeader.arch == EM_X86_64) && (ident.fileClass == 1)) + { + ident.fileClass = 2; + m_logger->LogWarn( + "Executable file claims to be 32-bit but specifies a 64-bit architecture. It is likely malformed or " + "malicious. Treating it as 64-bit."); + } + + // parse Elf64Header + if (ident.fileClass == 1) // 32-bit ELF + { + header.entry = reader.Read32(); + header.programHeaderOffset = reader.Read32(); + header.sectionHeaderOffset = reader.Read32(); + header.flags = reader.Read32(); + header.headerSize = reader.Read16(); + header.programHeaderSize = reader.Read16(); + header.programHeaderCount = reader.Read16(); + header.sectionHeaderSize = reader.Read16(); + header.sectionHeaderCount = reader.Read16(); + header.stringTable = reader.Read16(); + } + else if (ident.fileClass == 2) // 64-bit ELF + { + header.entry = reader.Read64(); + header.programHeaderOffset = reader.Read64(); + header.sectionHeaderOffset = reader.Read64(); + header.flags = reader.Read32(); + header.headerSize = reader.Read16(); + header.programHeaderSize = reader.Read16(); + header.programHeaderCount = reader.Read16(); + header.sectionHeaderSize = reader.Read16(); + header.sectionHeaderCount = reader.Read16(); + header.stringTable = reader.Read16(); + } + else + { + errorMsg = "invalid file class"; + return 0; + } + + map<string, Ref<Metadata>> metadataMap = { + {"EI_CLASS", new Metadata((uint64_t) ident.fileClass)}, + {"EI_DATA", new Metadata((uint64_t) ident.encoding)}, + {"EI_OSABI", new Metadata((uint64_t) ident.os)}, + {"e_type", new Metadata((uint64_t) commonHeader.type)}, + {"e_machine", new Metadata((uint64_t) commonHeader.arch)}, + {"e_flags", new Metadata((uint64_t) header.flags)}, + }; + + Ref<Metadata> metadata = new Metadata(metadataMap); + // retrieve architecture + // FIXME: Architecture registration methods should perhaps be virtual and take the raw data, or some additional opaque information. + + endianness = header.flags & EF_ARM_BE8 ? BigEndian : endianness; + + /* for architectures where .e_machine field doesn't disambiguate between 32/64 (like MIPS), + form the conventional alternative id, including the .e_ident[EI_CLASS] field */ + uint32_t altArchId = (ident.fileClass << 16) | commonHeader.arch; + + Ref<Platform> recognizedPlatform = g_elfViewType->RecognizePlatform(commonHeader.arch, endianness, data, metadata); + + if (!recognizedPlatform) + { + /* second try with the alternative architecture identifier */ + recognizedPlatform = g_elfViewType->RecognizePlatform(altArchId, endianness, data, metadata); + } + + if (recognizedPlatform) + { + if (plat) + *plat = recognizedPlatform; + if (arch) + *arch = recognizedPlatform->GetArchitecture(); + } + else + { + BNEndianness codeEndianness = endianness; + if ((commonHeader.arch == EM_ARM) && (header.flags & EF_ARM_BE8)) + codeEndianness = LittleEndian; + + if (arch) + { + *arch = g_elfViewType->GetArchitecture(commonHeader.arch, codeEndianness); + + if (!*arch) + { + /* second try with the alternative architecture identifier */ + *arch = g_elfViewType->GetArchitecture(altArchId, codeEndianness); + } + } + } + + return reader.GetOffset(); +} + + +Ref<Settings> ElfViewType::GetLoadSettingsForData(BinaryView* data) +{ + Ref<BinaryView> viewRef = Parse(data); + if (!viewRef || !viewRef->Init()) + { + m_logger->LogError("View type '%s' could not be created", GetName().c_str()); + return nullptr; + } + + Ref<Settings> settings = GetDefaultLoadSettingsForData(viewRef); + + // specify default load settings that can be overridden + vector<string> overrides = {"loader.architecture", "loader.imageBase", "loader.platform"}; + if (!viewRef->IsRelocatable()) + settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable."); + + for (const auto& override : overrides) + { + if (settings->Contains(override)) + settings->UpdateProperty(override, "readOnly", false); + } + + + return settings; +} + + +extern "C" +{ + BN_DECLARE_CORE_ABI_VERSION + +#ifdef DEMO_VERSION + bool ElfPluginInit() +#else + BINARYNINJAPLUGIN bool CorePluginInit() +#endif + { + InitElfViewType(); + return true; + } +} |
