summaryrefslogtreecommitdiff
path: root/view/elf
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2024-03-06 19:20:34 -0500
commit828fff839f4e4de3e9582405dfec567531000ebc (patch)
treeee0db0607edb0c76c653078672201c85e8a96d19 /view/elf
parent47894a1ce20090849ad304c68e6c0b889665eda3 (diff)
Move view modules into the API repo
Diffstat (limited to 'view/elf')
-rw-r--r--view/elf/.gitignore8
-rw-r--r--view/elf/CMakeLists.txt33
-rw-r--r--view/elf/LICENSE13
-rw-r--r--view/elf/README.md27
-rw-r--r--view/elf/elfview.cpp2772
-rw-r--r--view/elf/elfview.h558
6 files changed, 3411 insertions, 0 deletions
diff --git a/view/elf/.gitignore b/view/elf/.gitignore
new file mode 100644
index 00000000..d4c4c4dc
--- /dev/null
+++ b/view/elf/.gitignore
@@ -0,0 +1,8 @@
+CMakeFiles
+CMakeCache.txt
+cmake_install.cmake
+Makefile
+api
+build
+libview_*
+view_*.dll
diff --git a/view/elf/CMakeLists.txt b/view/elf/CMakeLists.txt
new file mode 100644
index 00000000..dbd252d2
--- /dev/null
+++ b/view/elf/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+
+project(view_elf)
+
+if(NOT BN_INTERNAL_BUILD)
+ add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
+endif()
+
+file(GLOB SOURCES
+ *.cpp
+ *.h)
+
+if(DEMO)
+ add_library(view_elf STATIC ${SOURCES})
+else()
+ add_library(view_elf SHARED ${SOURCES})
+endif()
+
+target_link_libraries(view_elf binaryninjaapi)
+
+set_target_properties(view_elf PROPERTIES
+ CXX_STANDARD 17
+ CXX_VISIBILITY_PRESET hidden
+ CXX_STANDARD_REQUIRED ON
+ VISIBILITY_INLINES_HIDDEN ON
+ POSITION_INDEPENDENT_CODE ON)
+
+if(BN_INTERNAL_BUILD)
+ plugin_rpath(view_elf)
+ set_target_properties(view_elf PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
+ RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
+endif()
diff --git a/view/elf/LICENSE b/view/elf/LICENSE
new file mode 100644
index 00000000..265883c5
--- /dev/null
+++ b/view/elf/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2021 Vector 35 Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/view/elf/README.md b/view/elf/README.md
new file mode 100644
index 00000000..bb81d1da
--- /dev/null
+++ b/view/elf/README.md
@@ -0,0 +1,27 @@
+# view-elf
+This is the ELF view plugin that ships with Binary Ninja.
+
+## Issues
+
+Issues for this repository have been disabled. Please file an issue for this repository at https://github.com/Vector35/binaryninja-api/issues. All previously existing issues for this repository have been transferred there as well.
+
+## Building
+
+Building the architecture plugin requires `cmake` 3.9 or above. You will also need the
+[Binary Ninja API source](https://github.com/Vector35/binaryninja-api).
+
+Run `cmake`. This can be done either from a separate build directory or from the source
+directory. Once that is complete, run `make` in the build directory to compile the plugin.
+
+The plugin can be found in the root of the build directory as `libview_elf.so`,
+`libview_elf.dylib` or `view_elf.dll` depending on your platform.
+
+To install the plugin, first launch Binary Ninja and uncheck the "ELF view plugin"
+option in the "Core Plugins" section. This will cause Binary Ninja to stop loading the
+bundled plugin so that its replacement can be loaded. Once this is complete, you can copy
+the plugin into the user plugins directory (you can locate this by using the "Open Plugin Folder"
+option in the Binary Ninja UI).
+
+**Do not replace the view plugin in the Binary Ninja install directory. This will be overwritten
+every time there is a Binary Ninja update. Use the above process to ensure that updates do not
+automatically uninstall your custom build.**
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;
+ }
+}
diff --git a/view/elf/elfview.h b/view/elf/elfview.h
new file mode 100644
index 00000000..7df78d01
--- /dev/null
+++ b/view/elf/elfview.h
@@ -0,0 +1,558 @@
+#pragma once
+
+#include "binaryninjaapi.h"
+#include <exception>
+
+#define ELF_PT_NULL 0
+#define ELF_PT_LOAD 1
+#define ELF_PT_DYNAMIC 2
+#define ELF_PT_INTERP 3
+#define ELF_PT_NOTE 4
+#define ELF_PT_SHLIB 5
+#define ELF_PT_PHDR 6
+#define ELF_PT_TLS 7 /* Thread-local storage segment */
+#define ELF_PT_NUM 8 /* Number of defined types */
+#define ELF_PT_LOOS 0x60000000 /* Start of OS-specific */
+#define ELF_PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
+#define ELF_PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
+#define ELF_PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
+
+#define ELF_PT_LOSUNW 0x6ffffffa
+#define ELF_PT_SUNWBSS 0x6ffffffb
+#define ELF_PT_SUNWSTACK 0x6ffffffa
+#define ELF_PT_HISUNW 0x6fffffff
+#define ELF_PT_LOPROC 0x70000000
+#define ELF_PT_HIPROC 0x7fffffff
+
+#define ELF_PT_MIPS_REGINFO 0x70000000 /* Register usage information */
+#define ELF_PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table */
+#define ELF_PT_MIPS_OPTIONS 0x70000002
+#define ELF_PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement */
+
+// x86-64 program header types.
+// These all contain stack unwind tables.
+#define ELF_PT_GNU_EH_FRAME 0x6474e550
+#define ELF_PT_SUNW_EH_FRAME 0x6474e550
+#define ELF_PT_SUNW_UNWIND 0x6464e550
+#define ELF_PT_GNU_STACK 0x6474e551 // Indicates stack executability.
+#define ELF_PT_GNU_RELRO 0x6474e552 // Read-only after relocation.
+#define ELF_PT_OPENBSD_RANDOMIZE 0x65a3dbe6 // Fill with random data.
+#define ELF_PT_OPENBSD_WXNEEDED 0x65a3dbe7 // Program does W^X violations.
+#define ELF_PT_OPENBSD_BOOTDATA 0x65a41be6 // Section for boot arguments.
+ // ARM program header types.
+#define PT_ARM_ARCHEXT 0x70000000 // Platform architecture compatibility info
+ // These all contain stack unwind tables.
+#define PT_ARM_EXIDX 0x70000001
+#define PT_ARM_UNWIND 0x70000001
+
+ // MIPS program header types.
+#define PT_MIPS_REGINFO 0x70000000 // Register usage information.
+#define PT_MIPS_RTPROC 0x70000001 // Runtime procedure table.
+#define PT_MIPS_OPTIONS 0x70000002 // Options segment.
+#define PT_MIPS_ABIFLAGS 0x70000003 // Abiflags segment.
+
+ // WebAssembly program header types.
+ #define PT_WEBASSEMBLY_FUNCTIONS ELF_PT_LOPROC + 0 // Function definitions.
+
+#define ELF_DT_NULL 0
+#define ELF_DT_NEEDED 1
+#define ELF_DT_PLTRELSZ 2
+#define ELF_DT_PLTGOT 3
+#define ELF_DT_HASH 4
+#define ELF_DT_STRTAB 5
+#define ELF_DT_SYMTAB 6
+#define ELF_DT_RELA 7
+#define ELF_DT_RELASZ 8
+#define ELF_DT_RELAENT 9
+#define ELF_DT_STRSZ 10
+#define ELF_DT_DYNSYM 11
+#define ELF_DT_SYMENT 11
+#define ELF_DT_INIT 12
+#define ELF_DT_FINI 13
+#define ELF_DT_SONAME 14
+#define ELF_DT_RPATH 15
+#define ELF_DT_SYMBOLIC 16
+#define ELF_DT_REL 17
+#define ELF_DT_RELSZ 18
+#define ELF_DT_RELENT 19
+#define ELF_DT_PLTREL 20
+#define ELF_DT_DEBUG 21
+#define ELF_DT_TEXTREL 22
+#define ELF_DT_JMPREL 23
+#define ELF_DT_BIND_NOW 24
+#define ELF_DT_INIT_ARRAY 25
+#define ELF_DT_FINI_ARRAY 26
+#define ELF_DT_INIT_ARRAYSZ 27
+#define ELF_DT_FINI_ARRAYSZ 28
+#define ELF_DT_RUNPATH 29
+#define ELF_DT_FLAGS 30
+#define ELF_DT_ENCODING 31
+#define ELF_DT_PREINIT_ARRAY 32
+#define ELF_DT_PREINIT_ARRAYSZ 33
+
+#define ELF_DT_LOOS 0x6000000D
+#define ELF_DT_SUNW_RTLDINF 0x6000000E
+#define ELF_DT_HIOS 0x6FFFF000
+#define ELF_DT_VALRNGLO 0x6FFFFD00
+#define ELF_DT_CHECKSUM 0x6FFFFDF8
+#define ELF_DT_PLTPADSZ 0x6FFFFDF9
+#define ELF_DT_MOVEEN 0x6FFFFDFA
+#define ELF_DT_MOVES 0x6FFFFDFB
+#define ELF_DT_FEATURE_1 0x6FFFFDFC
+#define ELF_DT_POSFLAG_1 0x6FFFFDFD
+#define ELF_DT_SYMINSZ 0x6FFFFDFE
+#define ELF_DT_SYMINENT 0x6FFFFDFF
+#define ELF_DT_VALRNGH 0x6FFFFDFF
+#define ELF_DT_ADDRRNGLO 0x6FFFFE00
+#define ELF_DT_GNU_HASH 0x6FFFFEF5
+#define ELF_DT_CONFIG 0x6FFFFEFA
+#define ELF_DT_DEPAUDIT 0x6FFFFEFB
+#define ELF_DT_AUDIT 0x6FFFFEFC
+#define ELF_DT_PLTPAD 0x6FFFFEFD
+#define ELF_DT_MOVETAB 0x6FFFFEFE
+#define ELF_DT_SYMINFO 0x6FFFFEFF
+#define ELF_DT_ADDRRNGHI 0x6FFFFEFF
+#define ELF_DT_RELACOUNT 0x6FFFFFF9
+#define ELF_DT_RELCOUNT 0x6FFFFFFA
+#define ELF_DT_FLAGS_1 0x6FFFFFFB
+#define ELF_DT_VERDEF 0x6FFFFFFC
+#define ELF_DT_VERDEFNUM 0x6FFFFFFD
+#define ELF_DT_VERNEED 0x6FFFFFFE
+#define ELF_DT_VERNEEDNUM 0x6FFFFFFF
+#define ELF_DT_VERSYM 0x6FFFFFF0
+
+#define ELF_DT_LOPROC 0x70000000
+
+#define ELF_DT_SPARC_REGISTER 0x70000001
+
+#define ELF_DT_MIPS_RLD_VERSION 0x70000001
+#define ELF_DT_MIPS_TIME_STAMP 0x70000002
+#define ELF_DT_MIPS_ICHECKSUM 0x70000003
+#define ELF_DT_MIPS_IVERSION 0x70000004
+#define ELF_DT_MIPS_FLAGS 0x70000005
+#define ELF_DT_MIPS_BASE_ADDRESS 0x70000006
+#define ELF_DT_MIPS_CONFLICT 0x70000008
+#define ELF_DT_MIPS_LIBLIST 0x70000009
+#define ELF_DT_MIPS_LOCAL_GOTNO 0x7000000A
+#define ELF_DT_MIPS_CONFLICTNO 0x7000000B
+#define ELF_DT_MIPS_LIBLISTNO 0x70000010
+#define ELF_DT_MIPS_SYMTABNO 0x70000011
+#define ELF_DT_MIPS_UNREFEXTNO 0x70000012
+#define ELF_DT_MIPS_GOTSYM 0x70000013
+#define ELF_DT_MIPS_HIPAGENO 0x70000014
+#define ELF_DT_MIPS_RLD_MAP 0x70000016
+#define ELF_DT_MIPS_RLD_MAP_REL 0x70000035
+
+#define ELF_DT_AUXILIARY 0x7FFFFFFD
+#define ELF_DT_USED 0x7FFFFFFE
+#define ELF_DT_FILTER 0x7FFFFFFF
+#define ELF_DT_HIPROC 0x7FFFFFFF
+
+#define ELF_STT_NOTYPE 0
+#define ELF_STT_OBJECT 1
+#define ELF_STT_FUNC 2
+#define ELF_STT_SECTION 3
+#define ELF_STT_FILE 4
+#define ELF_STT_COMMON 5
+#define ELF_STT_TLS 6
+// GNU/Linux specific
+#define ELF_STT_GNU_IFUNC 10
+
+#define ELF_STB_LOCAL 0
+#define ELF_STB_GLOBAL 1
+#define ELF_STB_WEAK 2
+#define ELF_STB_LOPROC 13
+#define ELF_STB_HIPROC 15
+
+#define ELF_ST_TYPE(t) ((t) & 0xf)
+#define ELF_ST_BIND(b) ((b) >> 4)
+
+#define ELF_RELOC_COPY 5
+#define ELF_RELOC_GLOBAL 6
+#define ELF_RELOC_JUMP_SLOT 7
+
+#define ET_NONE 0 // No file type
+#define ET_REL 1 // Relocatable file
+#define ET_EXEC 2 // Executable file
+#define ET_DYN 3 // Shared object file
+#define ET_CORE 4 // Core file
+#define ET_NUM 5 // Number of defined types
+
+#define EM_NONE 0 // No machine
+#define EM_M32 1 // AT&T WE 32100
+#define EM_SPARC 2 // SUN SPARC
+#define EM_386 3 // Intel 80386
+#define EM_68K 4 // Motorola m68k family
+#define EM_88K 5 // Motorola m88k family
+#define EM_860 7 // Intel 80860
+#define EM_MIPS 8 // MIPS R3000 big-endian
+#define EM_S370 9 // IBM System/370
+#define EM_MIPS_RS3_LE 10 // MIPS R3000 little-endian
+#define EM_PARISC 15 // HPPA
+#define EM_VPP500 17 // Fujitsu VPP500
+#define EM_SPARC32PLUS 18 // Sun's "v8plus"
+#define EM_960 19 // Intel 80960
+#define EM_PPC 20 // PowerPC
+#define EM_PPC64 21 // PowerPC 64-bit
+#define EM_S390 22 // IBM S390
+#define EM_V800 36 // NEC V800 series
+#define EM_FR20 37 // Fujitsu FR20
+#define EM_RH32 38 // TRW RH-32
+#define EM_RCE 39 // Motorola RCE
+#define EM_ARM 40 // ARM
+#define EM_FAKE_ALPHA 41 // Digital Alpha
+#define EM_SH 42 // Hitachi SH
+#define EM_SPARCV9 43 // SPARC v9 64-bit
+#define EM_TRICORE 44 // Siemens Tricore
+#define EM_ARC 45 // Argonaut RISC Core
+#define EM_H8_300 46 // Hitachi H8/300
+#define EM_H8_300H 47 // Hitachi H8/300H
+#define EM_H8S 48 // Hitachi H8S
+#define EM_H8_500 49 // Hitachi H8/500
+#define EM_IA_64 50 // Intel Merced
+#define EM_MIPS_X 51 // Stanford MIPS-X
+#define EM_COLDFIRE 52 // Motorola Coldfire
+#define EM_68HC12 53 // Motorola M68HC12
+#define EM_MMA 54 // Fujitsu MMA Multimedia Accelerator
+#define EM_PCP 55 // Siemens PCP
+#define EM_NCPU 56 // Sony nCPU embeeded RISC
+#define EM_NDR1 57 // Denso NDR1 microprocessor
+#define EM_STARCORE 58 // Motorola Start*Core processor
+#define EM_ME16 59 // Toyota ME16 processor
+#define EM_ST100 60 // STMicroelectronic ST100 processor
+#define EM_TINYJ 61 // Advanced Logic Corp. Tinyj emb.fam
+#define EM_X86_64 62 // AMD x86-64 architecture
+#define EM_PDSP 63 // Sony DSP Processor
+#define EM_FX66 66 // Siemens FX66 microcontroller
+#define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 mc
+#define EM_ST7 68 // STmicroelectronics ST7 8 bit mc
+#define EM_68HC16 69 // Motorola MC68HC16 microcontroller
+#define EM_68HC11 70 // Motorola MC68HC11 microcontroller
+#define EM_68HC08 71 // Motorola MC68HC08 microcontroller
+#define EM_68HC05 72 // Motorola MC68HC05 microcontroller
+#define EM_SVX 73 // Silicon Graphics SVx
+#define EM_ST19 74 // STMicroelectronics ST19 8 bit mc
+#define EM_VAX 75 // Digital VAX
+#define EM_CRIS 76 // Axis Communications 32-bit embedded processor
+#define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded processor
+#define EM_FIREPATH 78 // Element 14 64-bit DSP Processor
+#define EM_ZSP 79 // LSI Logic 16-bit DSP Processor
+#define EM_MMIX 80 // Donald Knuth's educational 64-bit processor
+#define EM_HUANY 81 // Harvard University machine-independent object files
+#define EM_PRISM 82 // SiTera Prism
+#define EM_AVR 83 // Atmel AVR 8-bit microcontroller
+#define EM_FR30 84 // Fujitsu FR30
+#define EM_D10V 85 // Mitsubishi D10V
+#define EM_D30V 86 // Mitsubishi D30V
+#define EM_V850 87 // NEC v850
+#define EM_M32R 88 // Mitsubishi M32R
+#define EM_MN10300 89 // Matsushita MN10300
+#define EM_MN10200 90 // Matsushita MN10200
+#define EM_PJ 91 // picoJava
+#define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor
+#define EM_ARC_A5 93 // ARC Cores Tangent-A5
+#define EM_XTENSA 94 // Tensilica Xtensa Architecture
+#define EM_ALTERA_NIOS2 113 // Altera Nios II
+#define EM_AARCH64 183 // ARM AARCH64
+#define EM_TILEPRO 188 // Tilera TILEPro
+#define EM_MICROBLAZE 189 // Xilinx MicroBlaze
+#define EM_TILEGX 191 // Tilera TILE-Gx
+#define EM_NUM 192
+
+// Section Header Types
+#define ELF_SHT_NULL 0
+#define ELF_SHT_PROGBITS 1
+#define ELF_SHT_SYMTAB 2
+#define ELF_SHT_STRTAB 3
+#define ELF_SHT_RELA 4
+#define ELF_SHT_HASH 5
+#define ELF_SHT_DYNAMIC 6
+#define ELF_SHT_NOTE 7
+#define ELF_SHT_NOBITS 8
+#define ELF_SHT_REL 9
+#define ELF_SHT_SHLIB 10
+#define ELF_SHT_DYNSYM 11
+#define ELF_SHT_LOPROC 0x70000000 // (take note that this only shows if none of the below are)
+#define ELF_SHT_HIPROC 0x7fffffff // (take note that this only shows if none of the below are)
+#define ELF_SHT_LOUSER 0x80000000
+#define ELF_SHT_HIUSER 0xffffffff
+
+#define ELF_SHT_EXT 0x70000000 // PA-RISC and Intel Itanium Only - Section contains product-specific extension bits
+#define ELF_SHT_UNWIND 0x70000001 // PA-RISC, Intel Itanium, and AMD64 Only - Section contains unwind function table entries for stack unwinding
+#define ELF_SHT_PARISC_DOC 0x70000002 // PA-RISC Only - Section contains debug information for optimized code
+#define ELF_SHT_PARISC_ANNOT 0x70000003 // PA-RISC Only - Section contains code annotations Name Value Meaning
+#define ELF_SHT_IA_64_LOPSREG 0x78000000 // Intel Itanium Only - Low section of operating system identification bits (and implimentation-specific types)
+#define ELF_SHT_IA_64_HIPSREG 0x7fffffff // Intel Itanium Only - High section of operating system identification bits (and implimentation-specific types)
+#define ELF_SHT_IA_64_PRIORITY_INIT 0x79000000 // Intel Itanium Only - Section contains priority initialization records
+
+// Section Header Flags
+#define ELF_SHF_WRITE 0x1 // Section is writable
+#define ELF_SHF_ALLOC 0x2 // Section occupies memory during execution (is a mapped segment)
+#define ELF_SHF_EXECINSTR 0x4 // Section is executable
+#define ELF_SHF_MASKOS 0x0ff00000 // OS-specific semantics
+#define ELF_SHF_MASKPROC 0xf0000000 // Processor specific (take note that this only shows if none of the below are)
+
+// LLVM and GoLang Specific
+#define ELF_SHF_MERGE 0x10 // Section may be merged
+#define ELF_SHF_STRINGS 0x20 // Section contains strings
+#define ELF_SHF_INFO_LINK 0x40 // sh_info holds section index
+#define ELF_SHF_LINK_ORDER 0x80 // Special ordering requirements
+#define ELF_SHF_OS_NONCONFORMING 0x100 // OS-specific processing required
+#define ELF_SHF_GROUP 0x200 // Member of section group
+#define ELF_SHF_TLS 0x400 // Section contains TLS data
+#define ELF_SHF_COMPRESSED 0x800 // Section is compressed
+
+// Arch Specific
+#define ELF_SHF_ENTRYSECT 0x10000000 // ARM only - Section contains an entrypoint
+#define ELF_SHF_COMDEF 0x80000000 // ARM only - Section may be multiply defined in the input to a link step
+#define ELF_SHF_AMD64_LARGE 0x10000000 // AMD64 Only - Section can be >2GB
+#define ELF_SHF_IA_64_SHORT 0x10000000 // Intel Itanium Only - Section contains objects referenced by gp, so must be position near gp
+#define ELF_SHF_IA_64_NORECOV 0x20000000 // Intel Itanium Only - Section contains speculative instructions without recovery code
+#define ELF_SHF_MIPS_GPREL 0x10000000 // MIPS Only - Section contains global data
+#define ELF_SHF_PARISC_SHORT 0x20000000 // PA-RISC Only - Section should be near gp
+#define ELF_SHF_PARISC_HUGE 0x40000000 // PA-RISC Only - Section should be allocated far from gp
+#define ELF_SHF_PARISC_SBP 0x80000000 // PA-RISC Only - Section contains code compiled for static branch prediction
+#define ELF_SHF_EXCLUDE 0x80000000 // PPC Only - Section is excluded from executable and SO's when they're not to be further relocated
+
+#define EV_NONE 0 // Invalid ELF version
+#define EV_CURRENT 1 // Current version
+#define EV_NUM 2
+
+#define EF_ARM_BE8 0x00800000 // ELF contains BE-8 code for ARMv6 processor
+
+#define PF_X (1 << 0) // Segment is executable
+#define PF_W (1 << 1) // Segment is writable
+#define PF_R (1 << 2) // Segment is readable
+
+#define ELF_SHN_UNDEF 0
+#define ELF_SHN_LORESERVE 0xff00
+#define ELF_SHN_LOPROC 0xff00
+#define ELF_SHN_HIPROC 0xff1f
+#define ELF_SHN_ABS 0xfff1
+#define ELF_SHN_COMMON 0xfff2
+#define ELF_SHN_HIRESERVE 0xffff
+
+// TODO : Add these (MIPs Only):
+// #define ELF_SHN_MIPS_ACOMMON 0xff00
+// #define ELF_SHN_MIPS_TEXT 0xff01
+// #define ELF_SHN_MIPS_DATA 0xff02
+// #define ELF_SHN_MIPS_SCOMMON 0xff03
+// #define ELF_SHN_MIPS_SUNDEFINED 0xff04
+
+// ARM ONLY
+#define R_ARM_TLS_DTPMOD32 0x11
+#define R_ARM_TLS_DTPOFF32 0x12
+
+namespace BinaryNinja
+{
+ class ElfFormatException: public std::exception
+ {
+ std::string m_message;
+
+ public:
+ ElfFormatException(const std::string& msg = "invalid format"): m_message(msg) {}
+ virtual const char* what() const NOEXCEPT { return m_message.c_str(); }
+ };
+
+ struct ElfIdent
+ {
+ char signature[4];
+ uint8_t fileClass;
+ uint8_t encoding;
+ uint8_t version;
+ uint8_t os;
+ uint8_t abiVersion;
+ uint8_t pad[7];
+ };
+
+ struct ElfCommonHeader
+ {
+ uint16_t type;
+ uint16_t arch;
+ uint32_t version;
+ };
+
+ struct Elf32Header
+ {
+ uint32_t entry;
+ uint32_t programHeaderOffset;
+ uint32_t sectionHeaderOffset;
+ uint32_t flags;
+ uint16_t headerSize;
+ uint16_t programHeaderSize;
+ uint16_t programHeaderCount;
+ uint16_t sectionHeaderSize;
+ uint16_t sectionHeaderCount;
+ uint16_t stringTable;
+ };
+
+ struct Elf32ProgramHeader
+ {
+ uint32_t type;
+ uint32_t offset;
+ uint32_t virtualAddress;
+ uint32_t physicalAddress;
+ uint32_t fileSize;
+ uint32_t memorySize;
+ uint32_t flags;
+ uint32_t align;
+ };
+
+ struct Elf32SectionHeader
+ {
+ uint32_t name;
+ uint32_t type;
+ uint32_t flags;
+ uint32_t address;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t link;
+ uint32_t info;
+ uint32_t align;
+ uint32_t entrySize;
+ };
+
+ struct Elf64Header
+ {
+ uint64_t entry;
+ uint64_t programHeaderOffset;
+ uint64_t sectionHeaderOffset;
+ uint32_t flags;
+ uint16_t headerSize;
+ uint16_t programHeaderSize;
+ uint16_t programHeaderCount;
+ uint16_t sectionHeaderSize;
+ uint16_t sectionHeaderCount;
+ uint16_t stringTable;
+ };
+
+ struct Elf64ProgramHeader
+ {
+ uint32_t type;
+ uint32_t flags;
+ uint64_t offset;
+ uint64_t virtualAddress;
+ uint64_t physicalAddress;
+ uint64_t fileSize;
+ uint64_t memorySize;
+ uint64_t align;
+ };
+
+ struct Elf64SectionHeader
+ {
+ uint32_t name;
+ uint32_t type;
+ uint64_t flags;
+ uint64_t address;
+ uint64_t offset;
+ uint64_t size;
+ uint32_t link;
+ uint32_t info;
+ uint64_t align;
+ uint64_t entrySize;
+ };
+
+ struct ElfSymbolTableEntry
+ {
+ uint32_t nameOffset;
+ uint8_t type;
+ BNSymbolBinding binding;
+ uint8_t other;
+ uint16_t section;
+ uint64_t value;
+ uint64_t size;
+ std::string name;
+ bool dynamic;
+ };
+
+ struct ELFRelocEntry
+ {
+ uint64_t offset, sym, relocType, addend;
+ size_t sectionIdx;
+ bool implicit;
+ ELFRelocEntry(uint64_t o, uint64_t s, uint64_t r, uint64_t a, size_t idx, bool imp): offset(o), sym(s), relocType(r),
+ addend(a), sectionIdx(idx), implicit(imp) {}
+ };
+
+ class ElfView: public BinaryView
+ {
+ bool m_parseOnly, m_backedByDatabase;
+ uint64_t m_entryPoint;
+ uint64_t m_sectionHeaderOffset, m_programHeaderOffset;
+ size_t m_sectionHeaderCount, m_programHeaderCount;
+ uint64_t m_fileSize;
+ BNEndianness m_endian;
+ size_t m_addressSize;
+ ElfIdent m_ident;
+ ElfCommonHeader m_commonHeader;
+ Ref<Architecture> m_arch;
+ Ref<Platform> m_plat = nullptr;
+ uint32_t m_headerFlags;
+ bool m_elf32;
+ bool m_objectFile;
+ Ref<Logger> m_logger;
+ bool m_extractMangledTypes;
+ bool m_simplifyTemplates;
+ bool m_relocatable = false;
+ std::map<uint64_t, std::vector<char>> m_stringTableCache;
+
+ // Section and program headers, internally use 64-bit form as it is a superset of 32-bit
+ std::vector<Elf64SectionHeader> m_elfSections;
+ std::vector<Elf64ProgramHeader> m_programHeaders;
+ Elf64SectionHeader m_symbolTableSection, m_dynamicSymbolTableSection;
+ Elf64SectionHeader m_auxSymbolTable, m_dynamicStringTable, m_sectionStringTable, m_sectionOpd;
+ Elf64ProgramHeader m_dynamicTable;
+ Elf64ProgramHeader m_tlsSegment;
+ std::map<uint64_t, uint64_t> m_localGotEntries;
+ std::set<uint64_t> m_gotEntryLocations;
+ std::vector<BNRelocationInfo> m_relocationInfo;
+
+ size_t m_auxSymbolTableEntrySize = 0;
+ size_t m_numDynamicTableEntries = 0;
+ uint64_t m_hashHeader = 0;
+ uint64_t m_gnuHashHeader = 0;
+
+ SymbolQueue* m_symbolQueue = nullptr;
+
+ void DefineElfSymbol(BNSymbolType type, const std::string& name, uint64_t addr, bool gotEntry,
+ BNSymbolBinding binding, size_t size, Ref<Type> typeObj=nullptr);
+
+ void ApplyTypesToParentStringTable(const Elf64SectionHeader& section, const bool offset = true);
+ void ApplyTypesToStringTable(const Elf64SectionHeader& section, const int64_t imageBaseAdjustment, const bool offset = true);
+ std::string ReadStringTable(BinaryReader& view, const Elf64SectionHeader& section, uint64_t offset);
+ bool ParseSymbolTableEntry(BinaryReader& reader, ElfSymbolTableEntry& entry, uint64_t sym,
+ const Elf64SectionHeader& symbolTable, const Elf64SectionHeader& stringTable, bool dynamic);
+
+ std::vector<ElfSymbolTableEntry> ParseSymbolTable(BinaryReader& reader, const Elf64SectionHeader& symbolTableSection,
+ const Elf64SectionHeader& section, bool dynamic, size_t startEntry=0);
+
+ virtual uint64_t PerformGetEntryPoint() const override;
+
+ virtual bool PerformIsExecutable() const override { return true; }
+ virtual BNEndianness PerformGetDefaultEndianness() const override;
+ virtual bool PerformIsRelocatable() const override;
+ virtual size_t PerformGetAddressSize() const override;
+ void GetRelocEntries(BinaryReader& reader, const std::vector<Elf64SectionHeader>& sections,
+ bool implicit, std::vector<ELFRelocEntry>& result);
+ bool DerefPpc64Descriptor(BinaryReader& reader, uint64_t addr, uint64_t& result);
+ public:
+ ElfView(BinaryView* data, bool parseOnly = false);
+ ~ElfView();
+
+ virtual bool Init() override;
+ };
+
+ class ElfViewType: public BinaryViewType
+ {
+ Ref<Logger> m_logger;
+ public:
+ ElfViewType();
+ virtual Ref<BinaryView> Create(BinaryView* data) override;
+ virtual Ref<BinaryView> Parse(BinaryView* data) override;
+ virtual bool IsTypeValidForData(BinaryView* data) override;
+ virtual uint64_t ParseHeaders(BinaryView* data, ElfIdent& ident, ElfCommonHeader& commonHeader, Elf64Header& header, Ref<Architecture>* arch, Ref<Platform>* plat, std::string& errorMsg, BNEndianness& endianness);
+ virtual Ref<Settings> GetLoadSettingsForData(BinaryView* data) override;
+ };
+
+ void InitElfViewType();
+}