summaryrefslogtreecommitdiff
path: root/source/Plugins/ObjectFile
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 18:01:57 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 18:01:57 +0000
commit88c643b6fec27eec436c8d138fee6346e92337d6 (patch)
tree82cd13b2f3cde1c9e5f79689ba4e6ba67694843f /source/Plugins/ObjectFile
parent94994d372d014ce4c8758b9605d63fae651bd8aa (diff)
Notes
Diffstat (limited to 'source/Plugins/ObjectFile')
-rw-r--r--source/Plugins/ObjectFile/Breakpad/CMakeLists.txt11
-rw-r--r--source/Plugins/ObjectFile/CMakeLists.txt5
-rw-r--r--source/Plugins/ObjectFile/ELF/CMakeLists.txt14
-rw-r--r--source/Plugins/ObjectFile/JIT/CMakeLists.txt11
-rw-r--r--source/Plugins/ObjectFile/Mach-O/CMakeLists.txt13
-rw-r--r--source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp6380
-rw-r--r--source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h220
-rw-r--r--source/Plugins/ObjectFile/PECOFF/CMakeLists.txt13
-rw-r--r--source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp1183
-rw-r--r--source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h294
-rw-r--r--source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp59
-rw-r--r--source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h23
12 files changed, 0 insertions, 8226 deletions
diff --git a/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt b/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt
deleted file mode 100644
index 2f51b2c8719a7..0000000000000
--- a/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-add_lldb_library(lldbPluginObjectFileBreakpad PLUGIN
- ObjectFileBreakpad.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbUtility
- LINK_COMPONENTS
- Support
- )
diff --git a/source/Plugins/ObjectFile/CMakeLists.txt b/source/Plugins/ObjectFile/CMakeLists.txt
deleted file mode 100644
index 4edd667b9723d..0000000000000
--- a/source/Plugins/ObjectFile/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-add_subdirectory(Breakpad)
-add_subdirectory(ELF)
-add_subdirectory(Mach-O)
-add_subdirectory(PECOFF)
-add_subdirectory(JIT)
diff --git a/source/Plugins/ObjectFile/ELF/CMakeLists.txt b/source/Plugins/ObjectFile/ELF/CMakeLists.txt
deleted file mode 100644
index 45a4edcbb1c9e..0000000000000
--- a/source/Plugins/ObjectFile/ELF/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-add_lldb_library(lldbPluginObjectFileELF PLUGIN
- ELFHeader.cpp
- ObjectFileELF.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbTarget
- LINK_COMPONENTS
- BinaryFormat
- Object
- Support
- )
diff --git a/source/Plugins/ObjectFile/JIT/CMakeLists.txt b/source/Plugins/ObjectFile/JIT/CMakeLists.txt
deleted file mode 100644
index fd575532db4c7..0000000000000
--- a/source/Plugins/ObjectFile/JIT/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-add_lldb_library(lldbPluginObjectFileJIT PLUGIN
- ObjectFileJIT.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbTarget
- LINK_COMPONENTS
- Support
- )
diff --git a/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt b/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt
deleted file mode 100644
index d39b93768ae7d..0000000000000
--- a/source/Plugins/ObjectFile/Mach-O/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-add_lldb_library(lldbPluginObjectFileMachO PLUGIN
- ObjectFileMachO.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbTarget
- lldbUtility
- lldbPluginProcessUtility
- LINK_COMPONENTS
- Support
- )
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
deleted file mode 100644
index 06908fecf9841..0000000000000
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ /dev/null
@@ -1,6380 +0,0 @@
-//===-- ObjectFileMachO.cpp -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/StringRef.h"
-
-#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
-#include "lldb/Core/Debugger.h"
-#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/RangeMap.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Symbol/DWARFCallFrameInfo.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Target/DynamicLoader.h"
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Target/Platform.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/SectionLoadList.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/Thread.h"
-#include "lldb/Target/ThreadList.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBuffer.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/RegisterValue.h"
-#include "lldb/Utility/Status.h"
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/Timer.h"
-#include "lldb/Utility/UUID.h"
-
-#include "lldb/Host/SafeMachO.h"
-
-#include "llvm/Support/MemoryBuffer.h"
-
-#include "ObjectFileMachO.h"
-
-#if defined(__APPLE__) && \
- (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
-// GetLLDBSharedCacheUUID() needs to call dlsym()
-#include <dlfcn.h>
-#endif
-
-#ifndef __APPLE__
-#include "Utility/UuidCompatibility.h"
-#else
-#include <uuid/uuid.h>
-#endif
-
-#define THUMB_ADDRESS_BIT_MASK 0xfffffffffffffffeull
-using namespace lldb;
-using namespace lldb_private;
-using namespace llvm::MachO;
-
-// Some structure definitions needed for parsing the dyld shared cache files
-// found on iOS devices.
-
-struct lldb_copy_dyld_cache_header_v1 {
- char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
- uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
- uint32_t mappingCount; // number of dyld_cache_mapping_info entries
- uint32_t imagesOffset;
- uint32_t imagesCount;
- uint64_t dyldBaseAddress;
- uint64_t codeSignatureOffset;
- uint64_t codeSignatureSize;
- uint64_t slideInfoOffset;
- uint64_t slideInfoSize;
- uint64_t localSymbolsOffset;
- uint64_t localSymbolsSize;
- uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13
- // and later
-};
-
-struct lldb_copy_dyld_cache_mapping_info {
- uint64_t address;
- uint64_t size;
- uint64_t fileOffset;
- uint32_t maxProt;
- uint32_t initProt;
-};
-
-struct lldb_copy_dyld_cache_local_symbols_info {
- uint32_t nlistOffset;
- uint32_t nlistCount;
- uint32_t stringsOffset;
- uint32_t stringsSize;
- uint32_t entriesOffset;
- uint32_t entriesCount;
-};
-struct lldb_copy_dyld_cache_local_symbols_entry {
- uint32_t dylibOffset;
- uint32_t nlistStartIndex;
- uint32_t nlistCount;
-};
-
-class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64 {
-public:
- RegisterContextDarwin_x86_64_Mach(lldb_private::Thread &thread,
- const DataExtractor &data)
- : RegisterContextDarwin_x86_64(thread, 0) {
- SetRegisterDataFrom_LC_THREAD(data);
- }
-
- void InvalidateAllRegisters() override {
- // Do nothing... registers are always valid...
- }
-
- void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
- lldb::offset_t offset = 0;
- SetError(GPRRegSet, Read, -1);
- SetError(FPURegSet, Read, -1);
- SetError(EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done) {
- int flavor = data.GetU32(&offset);
- if (flavor == 0)
- done = true;
- else {
- uint32_t i;
- uint32_t count = data.GetU32(&offset);
- switch (flavor) {
- case GPRRegSet:
- for (i = 0; i < count; ++i)
- (&gpr.rax)[i] = data.GetU64(&offset);
- SetError(GPRRegSet, Read, 0);
- done = true;
-
- break;
- case FPURegSet:
- // TODO: fill in FPU regs....
- // SetError (FPURegSet, Read, -1);
- done = true;
-
- break;
- case EXCRegSet:
- exc.trapno = data.GetU32(&offset);
- exc.err = data.GetU32(&offset);
- exc.faultvaddr = data.GetU64(&offset);
- SetError(EXCRegSet, Read, 0);
- done = true;
- break;
- case 7:
- case 8:
- case 9:
- // fancy flavors that encapsulate of the above flavors...
- break;
-
- default:
- done = true;
- break;
- }
- }
- }
- }
-
- static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
- const char *alt_name, size_t reg_byte_size,
- Stream &data) {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info) {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value)) {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
- ++i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i = 0; i < reg_byte_size; ++i)
- data.PutChar(0);
- return reg_byte_size;
- }
-
- static bool Create_LC_THREAD(Thread *thread, Stream &data) {
- RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
- if (reg_ctx_sp) {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32(GPRRegSet); // Flavor
- data.PutHex32(GPRWordCount);
- WriteRegister(reg_ctx, "rax", NULL, 8, data);
- WriteRegister(reg_ctx, "rbx", NULL, 8, data);
- WriteRegister(reg_ctx, "rcx", NULL, 8, data);
- WriteRegister(reg_ctx, "rdx", NULL, 8, data);
- WriteRegister(reg_ctx, "rdi", NULL, 8, data);
- WriteRegister(reg_ctx, "rsi", NULL, 8, data);
- WriteRegister(reg_ctx, "rbp", NULL, 8, data);
- WriteRegister(reg_ctx, "rsp", NULL, 8, data);
- WriteRegister(reg_ctx, "r8", NULL, 8, data);
- WriteRegister(reg_ctx, "r9", NULL, 8, data);
- WriteRegister(reg_ctx, "r10", NULL, 8, data);
- WriteRegister(reg_ctx, "r11", NULL, 8, data);
- WriteRegister(reg_ctx, "r12", NULL, 8, data);
- WriteRegister(reg_ctx, "r13", NULL, 8, data);
- WriteRegister(reg_ctx, "r14", NULL, 8, data);
- WriteRegister(reg_ctx, "r15", NULL, 8, data);
- WriteRegister(reg_ctx, "rip", NULL, 8, data);
- WriteRegister(reg_ctx, "rflags", NULL, 8, data);
- WriteRegister(reg_ctx, "cs", NULL, 8, data);
- WriteRegister(reg_ctx, "fs", NULL, 8, data);
- WriteRegister(reg_ctx, "gs", NULL, 8, data);
-
- // // Write out the FPU registers
- // const size_t fpu_byte_size = sizeof(FPU);
- // size_t bytes_written = 0;
- // data.PutHex32 (FPURegSet);
- // data.PutHex32 (fpu_byte_size/sizeof(uint64_t));
- // bytes_written += data.PutHex32(0); // uint32_t pad[0]
- // bytes_written += data.PutHex32(0); // uint32_t pad[1]
- // bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2,
- // data); // uint16_t fcw; // "fctrl"
- // bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2,
- // data); // uint16_t fsw; // "fstat"
- // bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1,
- // data); // uint8_t ftw; // "ftag"
- // bytes_written += data.PutHex8 (0); // uint8_t pad1;
- // bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2,
- // data); // uint16_t fop; // "fop"
- // bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4,
- // data); // uint32_t ip; // "fioff"
- // bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2,
- // data); // uint16_t cs; // "fiseg"
- // bytes_written += data.PutHex16 (0); // uint16_t pad2;
- // bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4,
- // data); // uint32_t dp; // "fooff"
- // bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2,
- // data); // uint16_t ds; // "foseg"
- // bytes_written += data.PutHex16 (0); // uint16_t pad3;
- // bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4,
- // data); // uint32_t mxcsr;
- // bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL,
- // 4, data);// uint32_t mxcsrmask;
- // bytes_written += WriteRegister (reg_ctx, "stmm0", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm1", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm2", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm3", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm4", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm5", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm6", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "stmm7", NULL,
- // sizeof(MMSReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm10", NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm11", NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm12", NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm13", NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm14", NULL,
- // sizeof(XMMReg), data);
- // bytes_written += WriteRegister (reg_ctx, "xmm15", NULL,
- // sizeof(XMMReg), data);
- //
- // // Fill rest with zeros
- // for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++
- // i)
- // data.PutChar(0);
-
- // Write out the EXC registers
- data.PutHex32(EXCRegSet);
- data.PutHex32(EXCWordCount);
- WriteRegister(reg_ctx, "trapno", NULL, 4, data);
- WriteRegister(reg_ctx, "err", NULL, 4, data);
- WriteRegister(reg_ctx, "faultvaddr", NULL, 8, data);
- return true;
- }
- return false;
- }
-
-protected:
- int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; }
-
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; }
-
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; }
-
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
- return 0;
- }
-
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
- return 0;
- }
-
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
- return 0;
- }
-};
-
-class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386 {
-public:
- RegisterContextDarwin_i386_Mach(lldb_private::Thread &thread,
- const DataExtractor &data)
- : RegisterContextDarwin_i386(thread, 0) {
- SetRegisterDataFrom_LC_THREAD(data);
- }
-
- void InvalidateAllRegisters() override {
- // Do nothing... registers are always valid...
- }
-
- void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
- lldb::offset_t offset = 0;
- SetError(GPRRegSet, Read, -1);
- SetError(FPURegSet, Read, -1);
- SetError(EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done) {
- int flavor = data.GetU32(&offset);
- if (flavor == 0)
- done = true;
- else {
- uint32_t i;
- uint32_t count = data.GetU32(&offset);
- switch (flavor) {
- case GPRRegSet:
- for (i = 0; i < count; ++i)
- (&gpr.eax)[i] = data.GetU32(&offset);
- SetError(GPRRegSet, Read, 0);
- done = true;
-
- break;
- case FPURegSet:
- // TODO: fill in FPU regs....
- // SetError (FPURegSet, Read, -1);
- done = true;
-
- break;
- case EXCRegSet:
- exc.trapno = data.GetU32(&offset);
- exc.err = data.GetU32(&offset);
- exc.faultvaddr = data.GetU32(&offset);
- SetError(EXCRegSet, Read, 0);
- done = true;
- break;
- case 7:
- case 8:
- case 9:
- // fancy flavors that encapsulate of the above flavors...
- break;
-
- default:
- done = true;
- break;
- }
- }
- }
- }
-
- static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
- const char *alt_name, size_t reg_byte_size,
- Stream &data) {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info) {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value)) {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
- ++i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i = 0; i < reg_byte_size; ++i)
- data.PutChar(0);
- return reg_byte_size;
- }
-
- static bool Create_LC_THREAD(Thread *thread, Stream &data) {
- RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
- if (reg_ctx_sp) {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32(GPRRegSet); // Flavor
- data.PutHex32(GPRWordCount);
- WriteRegister(reg_ctx, "eax", NULL, 4, data);
- WriteRegister(reg_ctx, "ebx", NULL, 4, data);
- WriteRegister(reg_ctx, "ecx", NULL, 4, data);
- WriteRegister(reg_ctx, "edx", NULL, 4, data);
- WriteRegister(reg_ctx, "edi", NULL, 4, data);
- WriteRegister(reg_ctx, "esi", NULL, 4, data);
- WriteRegister(reg_ctx, "ebp", NULL, 4, data);
- WriteRegister(reg_ctx, "esp", NULL, 4, data);
- WriteRegister(reg_ctx, "ss", NULL, 4, data);
- WriteRegister(reg_ctx, "eflags", NULL, 4, data);
- WriteRegister(reg_ctx, "eip", NULL, 4, data);
- WriteRegister(reg_ctx, "cs", NULL, 4, data);
- WriteRegister(reg_ctx, "ds", NULL, 4, data);
- WriteRegister(reg_ctx, "es", NULL, 4, data);
- WriteRegister(reg_ctx, "fs", NULL, 4, data);
- WriteRegister(reg_ctx, "gs", NULL, 4, data);
-
- // Write out the EXC registers
- data.PutHex32(EXCRegSet);
- data.PutHex32(EXCWordCount);
- WriteRegister(reg_ctx, "trapno", NULL, 4, data);
- WriteRegister(reg_ctx, "err", NULL, 4, data);
- WriteRegister(reg_ctx, "faultvaddr", NULL, 4, data);
- return true;
- }
- return false;
- }
-
-protected:
- int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; }
-
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; }
-
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; }
-
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
- return 0;
- }
-
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
- return 0;
- }
-
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
- return 0;
- }
-};
-
-class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm {
-public:
- RegisterContextDarwin_arm_Mach(lldb_private::Thread &thread,
- const DataExtractor &data)
- : RegisterContextDarwin_arm(thread, 0) {
- SetRegisterDataFrom_LC_THREAD(data);
- }
-
- void InvalidateAllRegisters() override {
- // Do nothing... registers are always valid...
- }
-
- void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
- lldb::offset_t offset = 0;
- SetError(GPRRegSet, Read, -1);
- SetError(FPURegSet, Read, -1);
- SetError(EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done) {
- int flavor = data.GetU32(&offset);
- uint32_t count = data.GetU32(&offset);
- lldb::offset_t next_thread_state = offset + (count * 4);
- switch (flavor) {
- case GPRAltRegSet:
- case GPRRegSet:
- for (uint32_t i = 0; i < count; ++i) {
- gpr.r[i] = data.GetU32(&offset);
- }
-
- // Note that gpr.cpsr is also copied by the above loop; this loop
- // technically extends one element past the end of the gpr.r[] array.
-
- SetError(GPRRegSet, Read, 0);
- offset = next_thread_state;
- break;
-
- case FPURegSet: {
- uint8_t *fpu_reg_buf = (uint8_t *)&fpu.floats.s[0];
- const int fpu_reg_buf_size = sizeof(fpu.floats);
- if (data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle,
- fpu_reg_buf) == fpu_reg_buf_size) {
- offset += fpu_reg_buf_size;
- fpu.fpscr = data.GetU32(&offset);
- SetError(FPURegSet, Read, 0);
- } else {
- done = true;
- }
- }
- offset = next_thread_state;
- break;
-
- case EXCRegSet:
- if (count == 3) {
- exc.exception = data.GetU32(&offset);
- exc.fsr = data.GetU32(&offset);
- exc.far = data.GetU32(&offset);
- SetError(EXCRegSet, Read, 0);
- }
- done = true;
- offset = next_thread_state;
- break;
-
- // Unknown register set flavor, stop trying to parse.
- default:
- done = true;
- }
- }
- }
-
- static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
- const char *alt_name, size_t reg_byte_size,
- Stream &data) {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info) {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value)) {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
- ++i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i = 0; i < reg_byte_size; ++i)
- data.PutChar(0);
- return reg_byte_size;
- }
-
- static bool Create_LC_THREAD(Thread *thread, Stream &data) {
- RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
- if (reg_ctx_sp) {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32(GPRRegSet); // Flavor
- data.PutHex32(GPRWordCount);
- WriteRegister(reg_ctx, "r0", NULL, 4, data);
- WriteRegister(reg_ctx, "r1", NULL, 4, data);
- WriteRegister(reg_ctx, "r2", NULL, 4, data);
- WriteRegister(reg_ctx, "r3", NULL, 4, data);
- WriteRegister(reg_ctx, "r4", NULL, 4, data);
- WriteRegister(reg_ctx, "r5", NULL, 4, data);
- WriteRegister(reg_ctx, "r6", NULL, 4, data);
- WriteRegister(reg_ctx, "r7", NULL, 4, data);
- WriteRegister(reg_ctx, "r8", NULL, 4, data);
- WriteRegister(reg_ctx, "r9", NULL, 4, data);
- WriteRegister(reg_ctx, "r10", NULL, 4, data);
- WriteRegister(reg_ctx, "r11", NULL, 4, data);
- WriteRegister(reg_ctx, "r12", NULL, 4, data);
- WriteRegister(reg_ctx, "sp", NULL, 4, data);
- WriteRegister(reg_ctx, "lr", NULL, 4, data);
- WriteRegister(reg_ctx, "pc", NULL, 4, data);
- WriteRegister(reg_ctx, "cpsr", NULL, 4, data);
-
- // Write out the EXC registers
- // data.PutHex32 (EXCRegSet);
- // data.PutHex32 (EXCWordCount);
- // WriteRegister (reg_ctx, "exception", NULL, 4, data);
- // WriteRegister (reg_ctx, "fsr", NULL, 4, data);
- // WriteRegister (reg_ctx, "far", NULL, 4, data);
- return true;
- }
- return false;
- }
-
-protected:
- int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
-
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
-
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
-
- int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; }
-
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
- return 0;
- }
-
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
- return 0;
- }
-
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
- return 0;
- }
-
- int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override {
- return -1;
- }
-};
-
-class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 {
-public:
- RegisterContextDarwin_arm64_Mach(lldb_private::Thread &thread,
- const DataExtractor &data)
- : RegisterContextDarwin_arm64(thread, 0) {
- SetRegisterDataFrom_LC_THREAD(data);
- }
-
- void InvalidateAllRegisters() override {
- // Do nothing... registers are always valid...
- }
-
- void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
- lldb::offset_t offset = 0;
- SetError(GPRRegSet, Read, -1);
- SetError(FPURegSet, Read, -1);
- SetError(EXCRegSet, Read, -1);
- bool done = false;
- while (!done) {
- int flavor = data.GetU32(&offset);
- uint32_t count = data.GetU32(&offset);
- lldb::offset_t next_thread_state = offset + (count * 4);
- switch (flavor) {
- case GPRRegSet:
- // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1
- // 32-bit register)
- if (count >= (33 * 2) + 1) {
- for (uint32_t i = 0; i < 29; ++i)
- gpr.x[i] = data.GetU64(&offset);
- gpr.fp = data.GetU64(&offset);
- gpr.lr = data.GetU64(&offset);
- gpr.sp = data.GetU64(&offset);
- gpr.pc = data.GetU64(&offset);
- gpr.cpsr = data.GetU32(&offset);
- SetError(GPRRegSet, Read, 0);
- }
- offset = next_thread_state;
- break;
- case FPURegSet: {
- uint8_t *fpu_reg_buf = (uint8_t *)&fpu.v[0];
- const int fpu_reg_buf_size = sizeof(fpu);
- if (fpu_reg_buf_size == count * sizeof(uint32_t) &&
- data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle,
- fpu_reg_buf) == fpu_reg_buf_size) {
- SetError(FPURegSet, Read, 0);
- } else {
- done = true;
- }
- }
- offset = next_thread_state;
- break;
- case EXCRegSet:
- if (count == 4) {
- exc.far = data.GetU64(&offset);
- exc.esr = data.GetU32(&offset);
- exc.exception = data.GetU32(&offset);
- SetError(EXCRegSet, Read, 0);
- }
- offset = next_thread_state;
- break;
- default:
- done = true;
- break;
- }
- }
- }
-
- static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
- const char *alt_name, size_t reg_byte_size,
- Stream &data) {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info) {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value)) {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
- ++i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i = 0; i < reg_byte_size; ++i)
- data.PutChar(0);
- return reg_byte_size;
- }
-
- static bool Create_LC_THREAD(Thread *thread, Stream &data) {
- RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
- if (reg_ctx_sp) {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32(GPRRegSet); // Flavor
- data.PutHex32(GPRWordCount);
- WriteRegister(reg_ctx, "x0", NULL, 8, data);
- WriteRegister(reg_ctx, "x1", NULL, 8, data);
- WriteRegister(reg_ctx, "x2", NULL, 8, data);
- WriteRegister(reg_ctx, "x3", NULL, 8, data);
- WriteRegister(reg_ctx, "x4", NULL, 8, data);
- WriteRegister(reg_ctx, "x5", NULL, 8, data);
- WriteRegister(reg_ctx, "x6", NULL, 8, data);
- WriteRegister(reg_ctx, "x7", NULL, 8, data);
- WriteRegister(reg_ctx, "x8", NULL, 8, data);
- WriteRegister(reg_ctx, "x9", NULL, 8, data);
- WriteRegister(reg_ctx, "x10", NULL, 8, data);
- WriteRegister(reg_ctx, "x11", NULL, 8, data);
- WriteRegister(reg_ctx, "x12", NULL, 8, data);
- WriteRegister(reg_ctx, "x13", NULL, 8, data);
- WriteRegister(reg_ctx, "x14", NULL, 8, data);
- WriteRegister(reg_ctx, "x15", NULL, 8, data);
- WriteRegister(reg_ctx, "x16", NULL, 8, data);
- WriteRegister(reg_ctx, "x17", NULL, 8, data);
- WriteRegister(reg_ctx, "x18", NULL, 8, data);
- WriteRegister(reg_ctx, "x19", NULL, 8, data);
- WriteRegister(reg_ctx, "x20", NULL, 8, data);
- WriteRegister(reg_ctx, "x21", NULL, 8, data);
- WriteRegister(reg_ctx, "x22", NULL, 8, data);
- WriteRegister(reg_ctx, "x23", NULL, 8, data);
- WriteRegister(reg_ctx, "x24", NULL, 8, data);
- WriteRegister(reg_ctx, "x25", NULL, 8, data);
- WriteRegister(reg_ctx, "x26", NULL, 8, data);
- WriteRegister(reg_ctx, "x27", NULL, 8, data);
- WriteRegister(reg_ctx, "x28", NULL, 8, data);
- WriteRegister(reg_ctx, "fp", NULL, 8, data);
- WriteRegister(reg_ctx, "lr", NULL, 8, data);
- WriteRegister(reg_ctx, "sp", NULL, 8, data);
- WriteRegister(reg_ctx, "pc", NULL, 8, data);
- WriteRegister(reg_ctx, "cpsr", NULL, 4, data);
-
- // Write out the EXC registers
- // data.PutHex32 (EXCRegSet);
- // data.PutHex32 (EXCWordCount);
- // WriteRegister (reg_ctx, "far", NULL, 8, data);
- // WriteRegister (reg_ctx, "esr", NULL, 4, data);
- // WriteRegister (reg_ctx, "exception", NULL, 4, data);
- return true;
- }
- return false;
- }
-
-protected:
- int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
-
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
-
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
-
- int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; }
-
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
- return 0;
- }
-
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
- return 0;
- }
-
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
- return 0;
- }
-
- int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override {
- return -1;
- }
-};
-
-static uint32_t MachHeaderSizeFromMagic(uint32_t magic) {
- switch (magic) {
- case MH_MAGIC:
- case MH_CIGAM:
- return sizeof(struct mach_header);
-
- case MH_MAGIC_64:
- case MH_CIGAM_64:
- return sizeof(struct mach_header_64);
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-#define MACHO_NLIST_ARM_SYMBOL_IS_THUMB 0x0008
-
-void ObjectFileMachO::Initialize() {
- PluginManager::RegisterPlugin(
- GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
- CreateMemoryInstance, GetModuleSpecifications, SaveCore);
-}
-
-void ObjectFileMachO::Terminate() {
- PluginManager::UnregisterPlugin(CreateInstance);
-}
-
-lldb_private::ConstString ObjectFileMachO::GetPluginNameStatic() {
- static ConstString g_name("mach-o");
- return g_name;
-}
-
-const char *ObjectFileMachO::GetPluginDescriptionStatic() {
- return "Mach-o object file reader (32 and 64 bit)";
-}
-
-ObjectFile *ObjectFileMachO::CreateInstance(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const FileSpec *file,
- lldb::offset_t file_offset,
- lldb::offset_t length) {
- if (!data_sp) {
- data_sp = MapFileData(*file, length, file_offset);
- if (!data_sp)
- return nullptr;
- data_offset = 0;
- }
-
- if (!ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length))
- return nullptr;
-
- // Update the data to contain the entire file if it doesn't already
- if (data_sp->GetByteSize() < length) {
- data_sp = MapFileData(*file, length, file_offset);
- if (!data_sp)
- return nullptr;
- data_offset = 0;
- }
- auto objfile_ap = llvm::make_unique<ObjectFileMachO>(
- module_sp, data_sp, data_offset, file, file_offset, length);
- if (!objfile_ap || !objfile_ap->ParseHeader())
- return nullptr;
-
- return objfile_ap.release();
-}
-
-ObjectFile *ObjectFileMachO::CreateMemoryInstance(
- const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
- const ProcessSP &process_sp, lldb::addr_t header_addr) {
- if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
- std::unique_ptr<ObjectFile> objfile_ap(
- new ObjectFileMachO(module_sp, data_sp, process_sp, header_addr));
- if (objfile_ap.get() && objfile_ap->ParseHeader())
- return objfile_ap.release();
- }
- return NULL;
-}
-
-size_t ObjectFileMachO::GetModuleSpecifications(
- const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset, lldb::offset_t file_offset,
- lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
- const size_t initial_count = specs.GetSize();
-
- if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
- DataExtractor data;
- data.SetData(data_sp);
- llvm::MachO::mach_header header;
- if (ParseHeader(data, &data_offset, header)) {
- size_t header_and_load_cmds =
- header.sizeofcmds + MachHeaderSizeFromMagic(header.magic);
- if (header_and_load_cmds >= data_sp->GetByteSize()) {
- data_sp = MapFileData(file, header_and_load_cmds, file_offset);
- data.SetData(data_sp);
- data_offset = MachHeaderSizeFromMagic(header.magic);
- }
- if (data_sp) {
- ModuleSpec spec;
- spec.GetFileSpec() = file;
- spec.SetObjectOffset(file_offset);
- spec.SetObjectSize(length);
-
- spec.GetArchitecture() = GetArchitecture(header, data, data_offset);
- if (spec.GetArchitecture().IsValid()) {
- GetUUID(header, data, data_offset, spec.GetUUID());
- specs.Append(spec);
- }
- }
- }
- }
- return specs.GetSize() - initial_count;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameTEXT() {
- static ConstString g_segment_name_TEXT("__TEXT");
- return g_segment_name_TEXT;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameDATA() {
- static ConstString g_segment_name_DATA("__DATA");
- return g_segment_name_DATA;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameDATA_DIRTY() {
- static ConstString g_segment_name("__DATA_DIRTY");
- return g_segment_name;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameDATA_CONST() {
- static ConstString g_segment_name("__DATA_CONST");
- return g_segment_name;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameOBJC() {
- static ConstString g_segment_name_OBJC("__OBJC");
- return g_segment_name_OBJC;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameLINKEDIT() {
- static ConstString g_section_name_LINKEDIT("__LINKEDIT");
- return g_section_name_LINKEDIT;
-}
-
-const ConstString &ObjectFileMachO::GetSegmentNameDWARF() {
- static ConstString g_section_name("__DWARF");
- return g_section_name;
-}
-
-const ConstString &ObjectFileMachO::GetSectionNameEHFrame() {
- static ConstString g_section_name_eh_frame("__eh_frame");
- return g_section_name_eh_frame;
-}
-
-bool ObjectFileMachO::MagicBytesMatch(DataBufferSP &data_sp,
- lldb::addr_t data_offset,
- lldb::addr_t data_length) {
- DataExtractor data;
- data.SetData(data_sp, data_offset, data_length);
- lldb::offset_t offset = 0;
- uint32_t magic = data.GetU32(&offset);
- return MachHeaderSizeFromMagic(magic) != 0;
-}
-
-ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const FileSpec *file,
- lldb::offset_t file_offset,
- lldb::offset_t length)
- : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
- m_mach_segments(), m_mach_sections(), m_entry_point_address(),
- m_thread_context_offsets(), m_thread_context_offsets_valid(false),
- m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) {
- ::memset(&m_header, 0, sizeof(m_header));
- ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
-}
-
-ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
- lldb::DataBufferSP &header_data_sp,
- const lldb::ProcessSP &process_sp,
- lldb::addr_t header_addr)
- : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
- m_mach_segments(), m_mach_sections(), m_entry_point_address(),
- m_thread_context_offsets(), m_thread_context_offsets_valid(false),
- m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) {
- ::memset(&m_header, 0, sizeof(m_header));
- ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
-}
-
-bool ObjectFileMachO::ParseHeader(DataExtractor &data,
- lldb::offset_t *data_offset_ptr,
- llvm::MachO::mach_header &header) {
- data.SetByteOrder(endian::InlHostByteOrder());
- // Leave magic in the original byte order
- header.magic = data.GetU32(data_offset_ptr);
- bool can_parse = false;
- bool is_64_bit = false;
- switch (header.magic) {
- case MH_MAGIC:
- data.SetByteOrder(endian::InlHostByteOrder());
- data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_MAGIC_64:
- data.SetByteOrder(endian::InlHostByteOrder());
- data.SetAddressByteSize(8);
- can_parse = true;
- is_64_bit = true;
- break;
-
- case MH_CIGAM:
- data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_CIGAM_64:
- data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- data.SetAddressByteSize(8);
- is_64_bit = true;
- can_parse = true;
- break;
-
- default:
- break;
- }
-
- if (can_parse) {
- data.GetU32(data_offset_ptr, &header.cputype, 6);
- if (is_64_bit)
- *data_offset_ptr += 4;
- return true;
- } else {
- memset(&header, 0, sizeof(header));
- }
- return false;
-}
-
-bool ObjectFileMachO::ParseHeader() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- bool can_parse = false;
- lldb::offset_t offset = 0;
- m_data.SetByteOrder(endian::InlHostByteOrder());
- // Leave magic in the original byte order
- m_header.magic = m_data.GetU32(&offset);
- switch (m_header.magic) {
- case MH_MAGIC:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_MAGIC_64:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(8);
- can_parse = true;
- break;
-
- case MH_CIGAM:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_CIGAM_64:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(8);
- can_parse = true;
- break;
-
- default:
- break;
- }
-
- if (can_parse) {
- m_data.GetU32(&offset, &m_header.cputype, 6);
-
- if (ArchSpec mach_arch = GetArchitecture()) {
- // Check if the module has a required architecture
- const ArchSpec &module_arch = module_sp->GetArchitecture();
- if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch))
- return false;
-
- if (SetModulesArchitecture(mach_arch)) {
- const size_t header_and_lc_size =
- m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
- if (m_data.GetByteSize() < header_and_lc_size) {
- DataBufferSP data_sp;
- ProcessSP process_sp(m_process_wp.lock());
- if (process_sp) {
- data_sp =
- ReadMemory(process_sp, m_memory_addr, header_and_lc_size);
- } else {
- // Read in all only the load command data from the file on disk
- data_sp = MapFileData(m_file, header_and_lc_size, m_file_offset);
- if (data_sp->GetByteSize() != header_and_lc_size)
- return false;
- }
- if (data_sp)
- m_data.SetData(data_sp);
- }
- }
- return true;
- }
- } else {
- memset(&m_header, 0, sizeof(struct mach_header));
- }
- }
- return false;
-}
-
-ByteOrder ObjectFileMachO::GetByteOrder() const {
- return m_data.GetByteOrder();
-}
-
-bool ObjectFileMachO::IsExecutable() const {
- return m_header.filetype == MH_EXECUTE;
-}
-
-uint32_t ObjectFileMachO::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
-}
-
-AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
- Symtab *symtab = GetSymtab();
- if (symtab) {
- Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr);
- if (symbol) {
- if (symbol->ValueIsAddress()) {
- SectionSP section_sp(symbol->GetAddressRef().GetSection());
- if (section_sp) {
- const lldb::SectionType section_type = section_sp->GetType();
- switch (section_type) {
- case eSectionTypeInvalid:
- return AddressClass::eUnknown;
-
- case eSectionTypeCode:
- if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) {
- // For ARM we have a bit in the n_desc field of the symbol that
- // tells us ARM/Thumb which is bit 0x0008.
- if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
- return AddressClass::eCodeAlternateISA;
- }
- return AddressClass::eCode;
-
- case eSectionTypeContainer:
- return AddressClass::eUnknown;
-
- case eSectionTypeData:
- case eSectionTypeDataCString:
- case eSectionTypeDataCStringPointers:
- case eSectionTypeDataSymbolAddress:
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- case eSectionTypeDataPointers:
- case eSectionTypeZeroFill:
- case eSectionTypeDataObjCMessageRefs:
- case eSectionTypeDataObjCCFStrings:
- case eSectionTypeGoSymtab:
- return AddressClass::eData;
-
- case eSectionTypeDebug:
- case eSectionTypeDWARFDebugAbbrev:
- case eSectionTypeDWARFDebugAbbrevDwo:
- case eSectionTypeDWARFDebugAddr:
- case eSectionTypeDWARFDebugAranges:
- case eSectionTypeDWARFDebugCuIndex:
- case eSectionTypeDWARFDebugFrame:
- case eSectionTypeDWARFDebugInfo:
- case eSectionTypeDWARFDebugInfoDwo:
- case eSectionTypeDWARFDebugLine:
- case eSectionTypeDWARFDebugLineStr:
- case eSectionTypeDWARFDebugLoc:
- case eSectionTypeDWARFDebugLocLists:
- case eSectionTypeDWARFDebugMacInfo:
- case eSectionTypeDWARFDebugMacro:
- case eSectionTypeDWARFDebugNames:
- case eSectionTypeDWARFDebugPubNames:
- case eSectionTypeDWARFDebugPubTypes:
- case eSectionTypeDWARFDebugRanges:
- case eSectionTypeDWARFDebugRngLists:
- case eSectionTypeDWARFDebugStr:
- case eSectionTypeDWARFDebugStrDwo:
- case eSectionTypeDWARFDebugStrOffsets:
- case eSectionTypeDWARFDebugStrOffsetsDwo:
- case eSectionTypeDWARFDebugTypes:
- case eSectionTypeDWARFAppleNames:
- case eSectionTypeDWARFAppleTypes:
- case eSectionTypeDWARFAppleNamespaces:
- case eSectionTypeDWARFAppleObjC:
- case eSectionTypeDWARFGNUDebugAltLink:
- return AddressClass::eDebug;
-
- case eSectionTypeEHFrame:
- case eSectionTypeARMexidx:
- case eSectionTypeARMextab:
- case eSectionTypeCompactUnwind:
- return AddressClass::eRuntime;
-
- case eSectionTypeAbsoluteAddress:
- case eSectionTypeELFSymbolTable:
- case eSectionTypeELFDynamicSymbols:
- case eSectionTypeELFRelocationEntries:
- case eSectionTypeELFDynamicLinkInfo:
- case eSectionTypeOther:
- return AddressClass::eUnknown;
- }
- }
- }
-
- const SymbolType symbol_type = symbol->GetType();
- switch (symbol_type) {
- case eSymbolTypeAny:
- return AddressClass::eUnknown;
- case eSymbolTypeAbsolute:
- return AddressClass::eUnknown;
-
- case eSymbolTypeCode:
- case eSymbolTypeTrampoline:
- case eSymbolTypeResolver:
- if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) {
- // For ARM we have a bit in the n_desc field of the symbol that tells
- // us ARM/Thumb which is bit 0x0008.
- if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
- return AddressClass::eCodeAlternateISA;
- }
- return AddressClass::eCode;
-
- case eSymbolTypeData:
- return AddressClass::eData;
- case eSymbolTypeRuntime:
- return AddressClass::eRuntime;
- case eSymbolTypeException:
- return AddressClass::eRuntime;
- case eSymbolTypeSourceFile:
- return AddressClass::eDebug;
- case eSymbolTypeHeaderFile:
- return AddressClass::eDebug;
- case eSymbolTypeObjectFile:
- return AddressClass::eDebug;
- case eSymbolTypeCommonBlock:
- return AddressClass::eDebug;
- case eSymbolTypeBlock:
- return AddressClass::eDebug;
- case eSymbolTypeLocal:
- return AddressClass::eData;
- case eSymbolTypeParam:
- return AddressClass::eData;
- case eSymbolTypeVariable:
- return AddressClass::eData;
- case eSymbolTypeVariableType:
- return AddressClass::eDebug;
- case eSymbolTypeLineEntry:
- return AddressClass::eDebug;
- case eSymbolTypeLineHeader:
- return AddressClass::eDebug;
- case eSymbolTypeScopeBegin:
- return AddressClass::eDebug;
- case eSymbolTypeScopeEnd:
- return AddressClass::eDebug;
- case eSymbolTypeAdditional:
- return AddressClass::eUnknown;
- case eSymbolTypeCompiler:
- return AddressClass::eDebug;
- case eSymbolTypeInstrumentation:
- return AddressClass::eDebug;
- case eSymbolTypeUndefined:
- return AddressClass::eUnknown;
- case eSymbolTypeObjCClass:
- return AddressClass::eRuntime;
- case eSymbolTypeObjCMetaClass:
- return AddressClass::eRuntime;
- case eSymbolTypeObjCIVar:
- return AddressClass::eRuntime;
- case eSymbolTypeReExported:
- return AddressClass::eRuntime;
- }
- }
- }
- return AddressClass::eUnknown;
-}
-
-Symtab *ObjectFileMachO::GetSymtab() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (m_symtab_ap.get() == NULL) {
- m_symtab_ap.reset(new Symtab(this));
- std::lock_guard<std::recursive_mutex> symtab_guard(
- m_symtab_ap->GetMutex());
- ParseSymtab();
- m_symtab_ap->Finalize();
- }
- }
- return m_symtab_ap.get();
-}
-
-bool ObjectFileMachO::IsStripped() {
- if (m_dysymtab.cmd == 0) {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
-
- load_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == LC_DYSYMTAB) {
- m_dysymtab.cmd = lc.cmd;
- m_dysymtab.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
- NULL) {
- // Clear m_dysymtab if we were unable to read all items from the
- // load command
- ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
- }
- }
- if (m_dysymtab.cmd)
- return m_dysymtab.nlocalsym <= 1;
- return false;
-}
-
-ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() {
- EncryptedFileRanges result;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
-
- encryption_info_command encryption_cmd;
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL)
- break;
-
- // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for the
- // 3 fields we care about, so treat them the same.
- if (encryption_cmd.cmd == LC_ENCRYPTION_INFO ||
- encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) {
- if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
- if (encryption_cmd.cryptid != 0) {
- EncryptedFileRanges::Entry entry;
- entry.SetRangeBase(encryption_cmd.cryptoff);
- entry.SetByteSize(encryption_cmd.cryptsize);
- result.Append(entry);
- }
- }
- }
- offset = load_cmd_offset + encryption_cmd.cmdsize;
- }
-
- return result;
-}
-
-void ObjectFileMachO::SanitizeSegmentCommand(segment_command_64 &seg_cmd,
- uint32_t cmd_idx) {
- if (m_length == 0 || seg_cmd.filesize == 0)
- return;
-
- if (seg_cmd.fileoff > m_length) {
- // We have a load command that says it extends past the end of the file.
- // This is likely a corrupt file. We don't have any way to return an error
- // condition here (this method was likely invoked from something like
- // ObjectFile::GetSectionList()), so we just null out the section contents,
- // and dump a message to stdout. The most common case here is core file
- // debugging with a truncated file.
- const char *lc_segment_name =
- seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
- GetModule()->ReportWarning(
- "load command %u %s has a fileoff (0x%" PRIx64
- ") that extends beyond the end of the file (0x%" PRIx64
- "), ignoring this section",
- cmd_idx, lc_segment_name, seg_cmd.fileoff, m_length);
-
- seg_cmd.fileoff = 0;
- seg_cmd.filesize = 0;
- }
-
- if (seg_cmd.fileoff + seg_cmd.filesize > m_length) {
- // We have a load command that says it extends past the end of the file.
- // This is likely a corrupt file. We don't have any way to return an error
- // condition here (this method was likely invoked from something like
- // ObjectFile::GetSectionList()), so we just null out the section contents,
- // and dump a message to stdout. The most common case here is core file
- // debugging with a truncated file.
- const char *lc_segment_name =
- seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
- GetModule()->ReportWarning(
- "load command %u %s has a fileoff + filesize (0x%" PRIx64
- ") that extends beyond the end of the file (0x%" PRIx64
- "), the segment will be truncated to match",
- cmd_idx, lc_segment_name, seg_cmd.fileoff + seg_cmd.filesize, m_length);
-
- // Truncate the length
- seg_cmd.filesize = m_length - seg_cmd.fileoff;
- }
-}
-
-static uint32_t GetSegmentPermissions(const segment_command_64 &seg_cmd) {
- uint32_t result = 0;
- if (seg_cmd.initprot & VM_PROT_READ)
- result |= ePermissionsReadable;
- if (seg_cmd.initprot & VM_PROT_WRITE)
- result |= ePermissionsWritable;
- if (seg_cmd.initprot & VM_PROT_EXECUTE)
- result |= ePermissionsExecutable;
- return result;
-}
-
-static lldb::SectionType GetSectionType(uint32_t flags,
- ConstString section_name) {
-
- if (flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS))
- return eSectionTypeCode;
-
- uint32_t mach_sect_type = flags & SECTION_TYPE;
- static ConstString g_sect_name_objc_data("__objc_data");
- static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs");
- static ConstString g_sect_name_objc_selrefs("__objc_selrefs");
- static ConstString g_sect_name_objc_classrefs("__objc_classrefs");
- static ConstString g_sect_name_objc_superrefs("__objc_superrefs");
- static ConstString g_sect_name_objc_const("__objc_const");
- static ConstString g_sect_name_objc_classlist("__objc_classlist");
- static ConstString g_sect_name_cfstring("__cfstring");
-
- static ConstString g_sect_name_dwarf_debug_abbrev("__debug_abbrev");
- static ConstString g_sect_name_dwarf_debug_aranges("__debug_aranges");
- static ConstString g_sect_name_dwarf_debug_frame("__debug_frame");
- static ConstString g_sect_name_dwarf_debug_info("__debug_info");
- static ConstString g_sect_name_dwarf_debug_line("__debug_line");
- static ConstString g_sect_name_dwarf_debug_loc("__debug_loc");
- static ConstString g_sect_name_dwarf_debug_loclists("__debug_loclists");
- static ConstString g_sect_name_dwarf_debug_macinfo("__debug_macinfo");
- static ConstString g_sect_name_dwarf_debug_names("__debug_names");
- static ConstString g_sect_name_dwarf_debug_pubnames("__debug_pubnames");
- static ConstString g_sect_name_dwarf_debug_pubtypes("__debug_pubtypes");
- static ConstString g_sect_name_dwarf_debug_ranges("__debug_ranges");
- static ConstString g_sect_name_dwarf_debug_str("__debug_str");
- static ConstString g_sect_name_dwarf_debug_types("__debug_types");
- static ConstString g_sect_name_dwarf_apple_names("__apple_names");
- static ConstString g_sect_name_dwarf_apple_types("__apple_types");
- static ConstString g_sect_name_dwarf_apple_namespaces("__apple_namespac");
- static ConstString g_sect_name_dwarf_apple_objc("__apple_objc");
- static ConstString g_sect_name_eh_frame("__eh_frame");
- static ConstString g_sect_name_compact_unwind("__unwind_info");
- static ConstString g_sect_name_text("__text");
- static ConstString g_sect_name_data("__data");
- static ConstString g_sect_name_go_symtab("__gosymtab");
-
- if (section_name == g_sect_name_dwarf_debug_abbrev)
- return eSectionTypeDWARFDebugAbbrev;
- if (section_name == g_sect_name_dwarf_debug_aranges)
- return eSectionTypeDWARFDebugAranges;
- if (section_name == g_sect_name_dwarf_debug_frame)
- return eSectionTypeDWARFDebugFrame;
- if (section_name == g_sect_name_dwarf_debug_info)
- return eSectionTypeDWARFDebugInfo;
- if (section_name == g_sect_name_dwarf_debug_line)
- return eSectionTypeDWARFDebugLine;
- if (section_name == g_sect_name_dwarf_debug_loc)
- return eSectionTypeDWARFDebugLoc;
- if (section_name == g_sect_name_dwarf_debug_loclists)
- return eSectionTypeDWARFDebugLocLists;
- if (section_name == g_sect_name_dwarf_debug_macinfo)
- return eSectionTypeDWARFDebugMacInfo;
- if (section_name == g_sect_name_dwarf_debug_names)
- return eSectionTypeDWARFDebugNames;
- if (section_name == g_sect_name_dwarf_debug_pubnames)
- return eSectionTypeDWARFDebugPubNames;
- if (section_name == g_sect_name_dwarf_debug_pubtypes)
- return eSectionTypeDWARFDebugPubTypes;
- if (section_name == g_sect_name_dwarf_debug_ranges)
- return eSectionTypeDWARFDebugRanges;
- if (section_name == g_sect_name_dwarf_debug_str)
- return eSectionTypeDWARFDebugStr;
- if (section_name == g_sect_name_dwarf_debug_types)
- return eSectionTypeDWARFDebugTypes;
- if (section_name == g_sect_name_dwarf_apple_names)
- return eSectionTypeDWARFAppleNames;
- if (section_name == g_sect_name_dwarf_apple_types)
- return eSectionTypeDWARFAppleTypes;
- if (section_name == g_sect_name_dwarf_apple_namespaces)
- return eSectionTypeDWARFAppleNamespaces;
- if (section_name == g_sect_name_dwarf_apple_objc)
- return eSectionTypeDWARFAppleObjC;
- if (section_name == g_sect_name_objc_selrefs)
- return eSectionTypeDataCStringPointers;
- if (section_name == g_sect_name_objc_msgrefs)
- return eSectionTypeDataObjCMessageRefs;
- if (section_name == g_sect_name_eh_frame)
- return eSectionTypeEHFrame;
- if (section_name == g_sect_name_compact_unwind)
- return eSectionTypeCompactUnwind;
- if (section_name == g_sect_name_cfstring)
- return eSectionTypeDataObjCCFStrings;
- if (section_name == g_sect_name_go_symtab)
- return eSectionTypeGoSymtab;
- if (section_name == g_sect_name_objc_data ||
- section_name == g_sect_name_objc_classrefs ||
- section_name == g_sect_name_objc_superrefs ||
- section_name == g_sect_name_objc_const ||
- section_name == g_sect_name_objc_classlist) {
- return eSectionTypeDataPointers;
- }
-
- switch (mach_sect_type) {
- // TODO: categorize sections by other flags for regular sections
- case S_REGULAR:
- if (section_name == g_sect_name_text)
- return eSectionTypeCode;
- if (section_name == g_sect_name_data)
- return eSectionTypeData;
- return eSectionTypeOther;
- case S_ZEROFILL:
- return eSectionTypeZeroFill;
- case S_CSTRING_LITERALS: // section with only literal C strings
- return eSectionTypeDataCString;
- case S_4BYTE_LITERALS: // section with only 4 byte literals
- return eSectionTypeData4;
- case S_8BYTE_LITERALS: // section with only 8 byte literals
- return eSectionTypeData8;
- case S_LITERAL_POINTERS: // section with only pointers to literals
- return eSectionTypeDataPointers;
- case S_NON_LAZY_SYMBOL_POINTERS: // section with only non-lazy symbol pointers
- return eSectionTypeDataPointers;
- case S_LAZY_SYMBOL_POINTERS: // section with only lazy symbol pointers
- return eSectionTypeDataPointers;
- case S_SYMBOL_STUBS: // section with only symbol stubs, byte size of stub in
- // the reserved2 field
- return eSectionTypeCode;
- case S_MOD_INIT_FUNC_POINTERS: // section with only function pointers for
- // initialization
- return eSectionTypeDataPointers;
- case S_MOD_TERM_FUNC_POINTERS: // section with only function pointers for
- // termination
- return eSectionTypeDataPointers;
- case S_COALESCED:
- return eSectionTypeOther;
- case S_GB_ZEROFILL:
- return eSectionTypeZeroFill;
- case S_INTERPOSING: // section with only pairs of function pointers for
- // interposing
- return eSectionTypeCode;
- case S_16BYTE_LITERALS: // section with only 16 byte literals
- return eSectionTypeData16;
- case S_DTRACE_DOF:
- return eSectionTypeDebug;
- case S_LAZY_DYLIB_SYMBOL_POINTERS:
- return eSectionTypeDataPointers;
- default:
- return eSectionTypeOther;
- }
-}
-
-struct ObjectFileMachO::SegmentParsingContext {
- const EncryptedFileRanges EncryptedRanges;
- lldb_private::SectionList &UnifiedList;
- uint32_t NextSegmentIdx = 0;
- uint32_t NextSectionIdx = 0;
- bool FileAddressesChanged = false;
-
- SegmentParsingContext(EncryptedFileRanges EncryptedRanges,
- lldb_private::SectionList &UnifiedList)
- : EncryptedRanges(std::move(EncryptedRanges)), UnifiedList(UnifiedList) {}
-};
-
-void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_,
- lldb::offset_t offset,
- uint32_t cmd_idx,
- SegmentParsingContext &context) {
- segment_command_64 load_cmd;
- memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_));
-
- if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16))
- return;
-
- ModuleSP module_sp = GetModule();
- const bool is_core = GetType() == eTypeCoreFile;
- const bool is_dsym = (m_header.filetype == MH_DSYM);
- bool add_section = true;
- bool add_to_unified = true;
- ConstString const_segname(
- load_cmd.segname,
- std::min<size_t>(strlen(load_cmd.segname), sizeof(load_cmd.segname)));
-
- SectionSP unified_section_sp(
- context.UnifiedList.FindSectionByName(const_segname));
- if (is_dsym && unified_section_sp) {
- if (const_segname == GetSegmentNameLINKEDIT()) {
- // We need to keep the __LINKEDIT segment private to this object file
- // only
- add_to_unified = false;
- } else {
- // This is the dSYM file and this section has already been created by the
- // object file, no need to create it.
- add_section = false;
- }
- }
- load_cmd.vmaddr = m_data.GetAddress(&offset);
- load_cmd.vmsize = m_data.GetAddress(&offset);
- load_cmd.fileoff = m_data.GetAddress(&offset);
- load_cmd.filesize = m_data.GetAddress(&offset);
- if (!m_data.GetU32(&offset, &load_cmd.maxprot, 4))
- return;
-
- SanitizeSegmentCommand(load_cmd, cmd_idx);
-
- const uint32_t segment_permissions = GetSegmentPermissions(load_cmd);
- const bool segment_is_encrypted =
- (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0;
-
- // Keep a list of mach segments around in case we need to get at data that
- // isn't stored in the abstracted Sections.
- m_mach_segments.push_back(load_cmd);
-
- // Use a segment ID of the segment index shifted left by 8 so they never
- // conflict with any of the sections.
- SectionSP segment_sp;
- if (add_section && (const_segname || is_core)) {
- segment_sp.reset(new Section(
- module_sp, // Module to which this section belongs
- this, // Object file to which this sections belongs
- ++context.NextSegmentIdx
- << 8, // Section ID is the 1 based segment index
- // shifted right by 8 bits as not to collide with any of the 256
- // section IDs that are possible
- const_segname, // Name of this section
- eSectionTypeContainer, // This section is a container of other
- // sections.
- load_cmd.vmaddr, // File VM address == addresses as they are
- // found in the object file
- load_cmd.vmsize, // VM size in bytes of this section
- load_cmd.fileoff, // Offset to the data for this section in
- // the file
- load_cmd.filesize, // Size in bytes of this section as found
- // in the file
- 0, // Segments have no alignment information
- load_cmd.flags)); // Flags for this section
-
- segment_sp->SetIsEncrypted(segment_is_encrypted);
- m_sections_ap->AddSection(segment_sp);
- segment_sp->SetPermissions(segment_permissions);
- if (add_to_unified)
- context.UnifiedList.AddSection(segment_sp);
- } else if (unified_section_sp) {
- if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) {
- // Check to see if the module was read from memory?
- if (module_sp->GetObjectFile()->GetBaseAddress().IsValid()) {
- // We have a module that is in memory and needs to have its file
- // address adjusted. We need to do this because when we load a file
- // from memory, its addresses will be slid already, yet the addresses
- // in the new symbol file will still be unslid. Since everything is
- // stored as section offset, this shouldn't cause any problems.
-
- // Make sure we've parsed the symbol table from the ObjectFile before
- // we go around changing its Sections.
- module_sp->GetObjectFile()->GetSymtab();
- // eh_frame would present the same problems but we parse that on a per-
- // function basis as-needed so it's more difficult to remove its use of
- // the Sections. Realistically, the environments where this code path
- // will be taken will not have eh_frame sections.
-
- unified_section_sp->SetFileAddress(load_cmd.vmaddr);
-
- // Notify the module that the section addresses have been changed once
- // we're done so any file-address caches can be updated.
- context.FileAddressesChanged = true;
- }
- }
- m_sections_ap->AddSection(unified_section_sp);
- }
-
- struct section_64 sect64;
- ::memset(&sect64, 0, sizeof(sect64));
- // Push a section into our mach sections for the section at index zero
- // (NO_SECT) if we don't have any mach sections yet...
- if (m_mach_sections.empty())
- m_mach_sections.push_back(sect64);
- uint32_t segment_sect_idx;
- const lldb::user_id_t first_segment_sectID = context.NextSectionIdx + 1;
-
- const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
- for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects;
- ++segment_sect_idx) {
- if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname,
- sizeof(sect64.sectname)) == NULL)
- break;
- if (m_data.GetU8(&offset, (uint8_t *)sect64.segname,
- sizeof(sect64.segname)) == NULL)
- break;
- sect64.addr = m_data.GetAddress(&offset);
- sect64.size = m_data.GetAddress(&offset);
-
- if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == NULL)
- break;
-
- // Keep a list of mach sections around in case we need to get at data that
- // isn't stored in the abstracted Sections.
- m_mach_sections.push_back(sect64);
-
- if (add_section) {
- ConstString section_name(
- sect64.sectname,
- std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname)));
- if (!const_segname) {
- // We have a segment with no name so we need to conjure up segments
- // that correspond to the section's segname if there isn't already such
- // a section. If there is such a section, we resize the section so that
- // it spans all sections. We also mark these sections as fake so
- // address matches don't hit if they land in the gaps between the child
- // sections.
- const_segname.SetTrimmedCStringWithLength(sect64.segname,
- sizeof(sect64.segname));
- segment_sp = context.UnifiedList.FindSectionByName(const_segname);
- if (segment_sp.get()) {
- Section *segment = segment_sp.get();
- // Grow the section size as needed.
- const lldb::addr_t sect64_min_addr = sect64.addr;
- const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size;
- const lldb::addr_t curr_seg_byte_size = segment->GetByteSize();
- const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress();
- const lldb::addr_t curr_seg_max_addr =
- curr_seg_min_addr + curr_seg_byte_size;
- if (sect64_min_addr >= curr_seg_min_addr) {
- const lldb::addr_t new_seg_byte_size =
- sect64_max_addr - curr_seg_min_addr;
- // Only grow the section size if needed
- if (new_seg_byte_size > curr_seg_byte_size)
- segment->SetByteSize(new_seg_byte_size);
- } else {
- // We need to change the base address of the segment and adjust the
- // child section offsets for all existing children.
- const lldb::addr_t slide_amount =
- sect64_min_addr - curr_seg_min_addr;
- segment->Slide(slide_amount, false);
- segment->GetChildren().Slide(-slide_amount, false);
- segment->SetByteSize(curr_seg_max_addr - sect64_min_addr);
- }
-
- // Grow the section size as needed.
- if (sect64.offset) {
- const lldb::addr_t segment_min_file_offset =
- segment->GetFileOffset();
- const lldb::addr_t segment_max_file_offset =
- segment_min_file_offset + segment->GetFileSize();
-
- const lldb::addr_t section_min_file_offset = sect64.offset;
- const lldb::addr_t section_max_file_offset =
- section_min_file_offset + sect64.size;
- const lldb::addr_t new_file_offset =
- std::min(section_min_file_offset, segment_min_file_offset);
- const lldb::addr_t new_file_size =
- std::max(section_max_file_offset, segment_max_file_offset) -
- new_file_offset;
- segment->SetFileOffset(new_file_offset);
- segment->SetFileSize(new_file_size);
- }
- } else {
- // Create a fake section for the section's named segment
- segment_sp.reset(new Section(
- segment_sp, // Parent section
- module_sp, // Module to which this section belongs
- this, // Object file to which this section belongs
- ++context.NextSegmentIdx
- << 8, // Section ID is the 1 based segment index
- // shifted right by 8 bits as not to
- // collide with any of the 256 section IDs
- // that are possible
- const_segname, // Name of this section
- eSectionTypeContainer, // This section is a container of
- // other sections.
- sect64.addr, // File VM address == addresses as they are
- // found in the object file
- sect64.size, // VM size in bytes of this section
- sect64.offset, // Offset to the data for this section in
- // the file
- sect64.offset ? sect64.size : 0, // Size in bytes of
- // this section as
- // found in the file
- sect64.align,
- load_cmd.flags)); // Flags for this section
- segment_sp->SetIsFake(true);
- segment_sp->SetPermissions(segment_permissions);
- m_sections_ap->AddSection(segment_sp);
- if (add_to_unified)
- context.UnifiedList.AddSection(segment_sp);
- segment_sp->SetIsEncrypted(segment_is_encrypted);
- }
- }
- assert(segment_sp.get());
-
- lldb::SectionType sect_type = GetSectionType(sect64.flags, section_name);
-
- SectionSP section_sp(new Section(
- segment_sp, module_sp, this, ++context.NextSectionIdx, section_name,
- sect_type, sect64.addr - segment_sp->GetFileAddress(), sect64.size,
- sect64.offset, sect64.offset == 0 ? 0 : sect64.size, sect64.align,
- sect64.flags));
- // Set the section to be encrypted to match the segment
-
- bool section_is_encrypted = false;
- if (!segment_is_encrypted && load_cmd.filesize != 0)
- section_is_encrypted = context.EncryptedRanges.FindEntryThatContains(
- sect64.offset) != NULL;
-
- section_sp->SetIsEncrypted(segment_is_encrypted || section_is_encrypted);
- section_sp->SetPermissions(segment_permissions);
- segment_sp->GetChildren().AddSection(section_sp);
-
- if (segment_sp->IsFake()) {
- segment_sp.reset();
- const_segname.Clear();
- }
- }
- }
- if (segment_sp && is_dsym) {
- if (first_segment_sectID <= context.NextSectionIdx) {
- lldb::user_id_t sect_uid;
- for (sect_uid = first_segment_sectID; sect_uid <= context.NextSectionIdx;
- ++sect_uid) {
- SectionSP curr_section_sp(
- segment_sp->GetChildren().FindSectionByID(sect_uid));
- SectionSP next_section_sp;
- if (sect_uid + 1 <= context.NextSectionIdx)
- next_section_sp =
- segment_sp->GetChildren().FindSectionByID(sect_uid + 1);
-
- if (curr_section_sp.get()) {
- if (curr_section_sp->GetByteSize() == 0) {
- if (next_section_sp.get() != NULL)
- curr_section_sp->SetByteSize(next_section_sp->GetFileAddress() -
- curr_section_sp->GetFileAddress());
- else
- curr_section_sp->SetByteSize(load_cmd.vmsize);
- }
- }
- }
- }
- }
-}
-
-void ObjectFileMachO::ProcessDysymtabCommand(const load_command &load_cmd,
- lldb::offset_t offset) {
- m_dysymtab.cmd = load_cmd.cmd;
- m_dysymtab.cmdsize = load_cmd.cmdsize;
- m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
-}
-
-void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
- if (m_sections_ap)
- return;
-
- m_sections_ap.reset(new SectionList());
-
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- // bool dump_sections = false;
- ModuleSP module_sp(GetModule());
-
- offset = MachHeaderSizeFromMagic(m_header.magic);
-
- SegmentParsingContext context(GetEncryptedFileRanges(), unified_section_list);
- struct load_command load_cmd;
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
- ProcessSegmentCommand(load_cmd, offset, i, context);
- else if (load_cmd.cmd == LC_DYSYMTAB)
- ProcessDysymtabCommand(load_cmd, offset);
-
- offset = load_cmd_offset + load_cmd.cmdsize;
- }
-
- if (context.FileAddressesChanged && module_sp)
- module_sp->SectionFileAddressesChanged();
-}
-
-class MachSymtabSectionInfo {
-public:
- MachSymtabSectionInfo(SectionList *section_list)
- : m_section_list(section_list), m_section_infos() {
- // Get the number of sections down to a depth of 1 to include all segments
- // and their sections, but no other sections that may be added for debug
- // map or
- m_section_infos.resize(section_list->GetNumSections(1));
- }
-
- SectionSP GetSection(uint8_t n_sect, addr_t file_addr) {
- if (n_sect == 0)
- return SectionSP();
- if (n_sect < m_section_infos.size()) {
- if (!m_section_infos[n_sect].section_sp) {
- SectionSP section_sp(m_section_list->FindSectionByID(n_sect));
- m_section_infos[n_sect].section_sp = section_sp;
- if (section_sp) {
- m_section_infos[n_sect].vm_range.SetBaseAddress(
- section_sp->GetFileAddress());
- m_section_infos[n_sect].vm_range.SetByteSize(
- section_sp->GetByteSize());
- } else {
- Host::SystemLog(Host::eSystemLogError,
- "error: unable to find section for section %u\n",
- n_sect);
- }
- }
- if (m_section_infos[n_sect].vm_range.Contains(file_addr)) {
- // Symbol is in section.
- return m_section_infos[n_sect].section_sp;
- } else if (m_section_infos[n_sect].vm_range.GetByteSize() == 0 &&
- m_section_infos[n_sect].vm_range.GetBaseAddress() ==
- file_addr) {
- // Symbol is in section with zero size, but has the same start address
- // as the section. This can happen with linker symbols (symbols that
- // start with the letter 'l' or 'L'.
- return m_section_infos[n_sect].section_sp;
- }
- }
- return m_section_list->FindSectionContainingFileAddress(file_addr);
- }
-
-protected:
- struct SectionInfo {
- SectionInfo() : vm_range(), section_sp() {}
-
- VMRange vm_range;
- SectionSP section_sp;
- };
- SectionList *m_section_list;
- std::vector<SectionInfo> m_section_infos;
-};
-
-struct TrieEntry {
- TrieEntry()
- : name(), address(LLDB_INVALID_ADDRESS), flags(0), other(0),
- import_name() {}
-
- void Clear() {
- name.Clear();
- address = LLDB_INVALID_ADDRESS;
- flags = 0;
- other = 0;
- import_name.Clear();
- }
-
- void Dump() const {
- printf("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"",
- static_cast<unsigned long long>(address),
- static_cast<unsigned long long>(flags),
- static_cast<unsigned long long>(other), name.GetCString());
- if (import_name)
- printf(" -> \"%s\"\n", import_name.GetCString());
- else
- printf("\n");
- }
- ConstString name;
- uint64_t address;
- uint64_t flags;
- uint64_t other;
- ConstString import_name;
-};
-
-struct TrieEntryWithOffset {
- lldb::offset_t nodeOffset;
- TrieEntry entry;
-
- TrieEntryWithOffset(lldb::offset_t offset) : nodeOffset(offset), entry() {}
-
- void Dump(uint32_t idx) const {
- printf("[%3u] 0x%16.16llx: ", idx,
- static_cast<unsigned long long>(nodeOffset));
- entry.Dump();
- }
-
- bool operator<(const TrieEntryWithOffset &other) const {
- return (nodeOffset < other.nodeOffset);
- }
-};
-
-static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset,
- const bool is_arm,
- std::vector<llvm::StringRef> &nameSlices,
- std::set<lldb::addr_t> &resolver_addresses,
- std::vector<TrieEntryWithOffset> &output) {
- if (!data.ValidOffset(offset))
- return true;
-
- const uint64_t terminalSize = data.GetULEB128(&offset);
- lldb::offset_t children_offset = offset + terminalSize;
- if (terminalSize != 0) {
- TrieEntryWithOffset e(offset);
- e.entry.flags = data.GetULEB128(&offset);
- const char *import_name = NULL;
- if (e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
- e.entry.address = 0;
- e.entry.other = data.GetULEB128(&offset); // dylib ordinal
- import_name = data.GetCStr(&offset);
- } else {
- e.entry.address = data.GetULEB128(&offset);
- if (e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
- e.entry.other = data.GetULEB128(&offset);
- uint64_t resolver_addr = e.entry.other;
- if (is_arm)
- resolver_addr &= THUMB_ADDRESS_BIT_MASK;
- resolver_addresses.insert(resolver_addr);
- } else
- e.entry.other = 0;
- }
- // Only add symbols that are reexport symbols with a valid import name
- if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name &&
- import_name[0]) {
- std::string name;
- if (!nameSlices.empty()) {
- for (auto name_slice : nameSlices)
- name.append(name_slice.data(), name_slice.size());
- }
- if (name.size() > 1) {
- // Skip the leading '_'
- e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1);
- }
- if (import_name) {
- // Skip the leading '_'
- e.entry.import_name.SetCString(import_name + 1);
- }
- output.push_back(e);
- }
- }
-
- const uint8_t childrenCount = data.GetU8(&children_offset);
- for (uint8_t i = 0; i < childrenCount; ++i) {
- const char *cstr = data.GetCStr(&children_offset);
- if (cstr)
- nameSlices.push_back(llvm::StringRef(cstr));
- else
- return false; // Corrupt data
- lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
- if (childNodeOffset) {
- if (!ParseTrieEntries(data, childNodeOffset, is_arm, nameSlices,
- resolver_addresses, output)) {
- return false;
- }
- }
- nameSlices.pop_back();
- }
- return true;
-}
-
-// Read the UUID out of a dyld_shared_cache file on-disk.
-UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache,
- const ByteOrder byte_order,
- const uint32_t addr_byte_size) {
- UUID dsc_uuid;
- DataBufferSP DscData = MapFileData(
- dyld_shared_cache, sizeof(struct lldb_copy_dyld_cache_header_v1), 0);
- if (!DscData)
- return dsc_uuid;
- DataExtractor dsc_header_data(DscData, byte_order, addr_byte_size);
-
- char version_str[7];
- lldb::offset_t offset = 0;
- memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6);
- version_str[6] = '\0';
- if (strcmp(version_str, "dyld_v") == 0) {
- offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid);
- dsc_uuid = UUID::fromOptionalData(
- dsc_header_data.GetData(&offset, sizeof(uuid_t)), sizeof(uuid_t));
- }
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS));
- if (log && dsc_uuid.IsValid()) {
- log->Printf("Shared cache %s has UUID %s", dyld_shared_cache.GetPath().c_str(),
- dsc_uuid.GetAsString().c_str());
- }
- return dsc_uuid;
-}
-
-size_t ObjectFileMachO::ParseSymtab() {
- static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
- Timer scoped_timer(func_cat, "ObjectFileMachO::ParseSymtab () module = %s",
- m_file.GetFilename().AsCString(""));
- ModuleSP module_sp(GetModule());
- if (!module_sp)
- return 0;
-
- struct symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0};
- struct linkedit_data_command function_starts_load_command = {0, 0, 0, 0};
- struct dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts;
- FunctionStarts function_starts;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t i;
- FileSpecList dylib_files;
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS));
- static const llvm::StringRef g_objc_v2_prefix_class("_OBJC_CLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_metaclass("_OBJC_METACLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_ivar("_OBJC_IVAR_$_");
-
- for (i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- // Read in the load command and load command size
- struct load_command lc;
- if (m_data.GetU32(&offset, &lc, 2) == NULL)
- break;
- // Watch for the symbol table load command
- switch (lc.cmd) {
- case LC_SYMTAB:
- symtab_load_command.cmd = lc.cmd;
- symtab_load_command.cmdsize = lc.cmdsize;
- // Read in the rest of the symtab load command
- if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) ==
- 0) // fill in symoff, nsyms, stroff, strsize fields
- return 0;
- if (symtab_load_command.symoff == 0) {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0");
- return 0;
- }
-
- if (symtab_load_command.stroff == 0) {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0");
- return 0;
- }
-
- if (symtab_load_command.nsyms == 0) {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0");
- return 0;
- }
-
- if (symtab_load_command.strsize == 0) {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0");
- return 0;
- }
- break;
-
- case LC_DYLD_INFO:
- case LC_DYLD_INFO_ONLY:
- if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) {
- dyld_info.cmd = lc.cmd;
- dyld_info.cmdsize = lc.cmdsize;
- } else {
- memset(&dyld_info, 0, sizeof(dyld_info));
- }
- break;
-
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- case LC_REEXPORT_DYLIB:
- case LC_LOADFVMLIB:
- case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
- if (path) {
- FileSpec file_spec(path);
- // Strip the path if there is @rpath, @executable, etc so we just use
- // the basename
- if (path[0] == '@')
- file_spec.GetDirectory().Clear();
-
- if (lc.cmd == LC_REEXPORT_DYLIB) {
- m_reexported_dylibs.AppendIfUnique(file_spec);
- }
-
- dylib_files.Append(file_spec);
- }
- } break;
-
- case LC_FUNCTION_STARTS:
- function_starts_load_command.cmd = lc.cmd;
- function_starts_load_command.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) ==
- NULL) // fill in symoff, nsyms, stroff, strsize fields
- memset(&function_starts_load_command, 0,
- sizeof(function_starts_load_command));
- break;
-
- default:
- break;
- }
- offset = cmd_offset + lc.cmdsize;
- }
-
- if (symtab_load_command.cmd) {
- Symtab *symtab = m_symtab_ap.get();
- SectionList *section_list = GetSectionList();
- if (section_list == NULL)
- return 0;
-
- const uint32_t addr_byte_size = m_data.GetAddressByteSize();
- const ByteOrder byte_order = m_data.GetByteOrder();
- bool bit_width_32 = addr_byte_size == 4;
- const size_t nlist_byte_size =
- bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
-
- DataExtractor nlist_data(NULL, 0, byte_order, addr_byte_size);
- DataExtractor strtab_data(NULL, 0, byte_order, addr_byte_size);
- DataExtractor function_starts_data(NULL, 0, byte_order, addr_byte_size);
- DataExtractor indirect_symbol_index_data(NULL, 0, byte_order,
- addr_byte_size);
- DataExtractor dyld_trie_data(NULL, 0, byte_order, addr_byte_size);
-
- const addr_t nlist_data_byte_size =
- symtab_load_command.nsyms * nlist_byte_size;
- const addr_t strtab_data_byte_size = symtab_load_command.strsize;
- addr_t strtab_addr = LLDB_INVALID_ADDRESS;
-
- ProcessSP process_sp(m_process_wp.lock());
- Process *process = process_sp.get();
-
- uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
-
- if (process && m_header.filetype != llvm::MachO::MH_OBJECT) {
- Target &target = process->GetTarget();
-
- memory_module_load_level = target.GetMemoryModuleLoadLevel();
-
- SectionSP linkedit_section_sp(
- section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
- // Reading mach file from memory in a process or core file...
-
- if (linkedit_section_sp) {
- addr_t linkedit_load_addr =
- linkedit_section_sp->GetLoadBaseAddress(&target);
- if (linkedit_load_addr == LLDB_INVALID_ADDRESS) {
- // We might be trying to access the symbol table before the
- // __LINKEDIT's load address has been set in the target. We can't
- // fail to read the symbol table, so calculate the right address
- // manually
- linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage(
- m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get());
- }
-
- const addr_t linkedit_file_offset =
- linkedit_section_sp->GetFileOffset();
- const addr_t symoff_addr = linkedit_load_addr +
- symtab_load_command.symoff -
- linkedit_file_offset;
- strtab_addr = linkedit_load_addr + symtab_load_command.stroff -
- linkedit_file_offset;
-
- bool data_was_read = false;
-
-#if defined(__APPLE__) && \
- (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
- if (m_header.flags & 0x80000000u &&
- process->GetAddressByteSize() == sizeof(void *)) {
- // This mach-o memory file is in the dyld shared cache. If this
- // program is not remote and this is iOS, then this process will
- // share the same shared cache as the process we are debugging and we
- // can read the entire __LINKEDIT from the address space in this
- // process. This is a needed optimization that is used for local iOS
- // debugging only since all shared libraries in the shared cache do
- // not have corresponding files that exist in the file system of the
- // device. They have been combined into a single file. This means we
- // always have to load these files from memory. All of the symbol and
- // string tables from all of the __LINKEDIT sections from the shared
- // libraries in the shared cache have been merged into a single large
- // symbol and string table. Reading all of this symbol and string
- // table data across can slow down debug launch times, so we optimize
- // this by reading the memory for the __LINKEDIT section from this
- // process.
-
- UUID lldb_shared_cache;
- addr_t lldb_shared_cache_addr;
- GetLLDBSharedCacheUUID (lldb_shared_cache_addr, lldb_shared_cache);
- UUID process_shared_cache;
- addr_t process_shared_cache_addr;
- GetProcessSharedCacheUUID(process, process_shared_cache_addr, process_shared_cache);
- bool use_lldb_cache = true;
- if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() &&
- (lldb_shared_cache != process_shared_cache
- || process_shared_cache_addr != lldb_shared_cache_addr)) {
- use_lldb_cache = false;
- }
-
- PlatformSP platform_sp(target.GetPlatform());
- if (platform_sp && platform_sp->IsHost() && use_lldb_cache) {
- data_was_read = true;
- nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size,
- eByteOrderLittle);
- strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size,
- eByteOrderLittle);
- if (function_starts_load_command.cmd) {
- const addr_t func_start_addr =
- linkedit_load_addr + function_starts_load_command.dataoff -
- linkedit_file_offset;
- function_starts_data.SetData(
- (void *)func_start_addr,
- function_starts_load_command.datasize, eByteOrderLittle);
- }
- }
- }
-#endif
-
- if (!data_was_read) {
- // Always load dyld - the dynamic linker - from memory if we didn't
- // find a binary anywhere else. lldb will not register
- // dylib/framework/bundle loads/unloads if we don't have the dyld
- // symbols, we force dyld to load from memory despite the user's
- // target.memory-module-load-level setting.
- if (memory_module_load_level == eMemoryModuleLoadLevelComplete ||
- m_header.filetype == llvm::MachO::MH_DYLINKER) {
- DataBufferSP nlist_data_sp(
- ReadMemory(process_sp, symoff_addr, nlist_data_byte_size));
- if (nlist_data_sp)
- nlist_data.SetData(nlist_data_sp, 0,
- nlist_data_sp->GetByteSize());
- if (m_dysymtab.nindirectsyms != 0) {
- const addr_t indirect_syms_addr = linkedit_load_addr +
- m_dysymtab.indirectsymoff -
- linkedit_file_offset;
- DataBufferSP indirect_syms_data_sp(
- ReadMemory(process_sp, indirect_syms_addr,
- m_dysymtab.nindirectsyms * 4));
- if (indirect_syms_data_sp)
- indirect_symbol_index_data.SetData(
- indirect_syms_data_sp, 0,
- indirect_syms_data_sp->GetByteSize());
- // If this binary is outside the shared cache,
- // cache the string table.
- // Binaries in the shared cache all share a giant string table, and
- // we can't share the string tables across multiple ObjectFileMachO's,
- // so we'd end up re-reading this mega-strtab for every binary
- // in the shared cache - it would be a big perf problem.
- // For binaries outside the shared cache, it's faster to read the
- // entire strtab at once instead of piece-by-piece as we process
- // the nlist records.
- if ((m_header.flags & 0x80000000u) == 0) {
- DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr,
- strtab_data_byte_size));
- if (strtab_data_sp) {
- strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize());
- }
- }
- }
- }
- if (memory_module_load_level >=
- eMemoryModuleLoadLevelPartial) {
- if (function_starts_load_command.cmd) {
- const addr_t func_start_addr =
- linkedit_load_addr + function_starts_load_command.dataoff -
- linkedit_file_offset;
- DataBufferSP func_start_data_sp(
- ReadMemory(process_sp, func_start_addr,
- function_starts_load_command.datasize));
- if (func_start_data_sp)
- function_starts_data.SetData(func_start_data_sp, 0,
- func_start_data_sp->GetByteSize());
- }
- }
- }
- }
- } else {
- nlist_data.SetData(m_data, symtab_load_command.symoff,
- nlist_data_byte_size);
- strtab_data.SetData(m_data, symtab_load_command.stroff,
- strtab_data_byte_size);
-
- if (dyld_info.export_size > 0) {
- dyld_trie_data.SetData(m_data, dyld_info.export_off,
- dyld_info.export_size);
- }
-
- if (m_dysymtab.nindirectsyms != 0) {
- indirect_symbol_index_data.SetData(m_data, m_dysymtab.indirectsymoff,
- m_dysymtab.nindirectsyms * 4);
- }
- if (function_starts_load_command.cmd) {
- function_starts_data.SetData(m_data,
- function_starts_load_command.dataoff,
- function_starts_load_command.datasize);
- }
- }
-
- if (nlist_data.GetByteSize() == 0 &&
- memory_module_load_level == eMemoryModuleLoadLevelComplete) {
- if (log)
- module_sp->LogMessage(log, "failed to read nlist data");
- return 0;
- }
-
- const bool have_strtab_data = strtab_data.GetByteSize() > 0;
- if (!have_strtab_data) {
- if (process) {
- if (strtab_addr == LLDB_INVALID_ADDRESS) {
- if (log)
- module_sp->LogMessage(log, "failed to locate the strtab in memory");
- return 0;
- }
- } else {
- if (log)
- module_sp->LogMessage(log, "failed to read strtab data");
- return 0;
- }
- }
-
- const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT();
- const ConstString &g_segment_name_DATA = GetSegmentNameDATA();
- const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
- const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
- const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC();
- const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame();
- SectionSP text_section_sp(
- section_list->FindSectionByName(g_segment_name_TEXT));
- SectionSP data_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA));
- SectionSP data_dirty_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
- SectionSP data_const_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA_CONST));
- SectionSP objc_section_sp(
- section_list->FindSectionByName(g_segment_name_OBJC));
- SectionSP eh_frame_section_sp;
- if (text_section_sp.get())
- eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName(
- g_section_name_eh_frame);
- else
- eh_frame_section_sp =
- section_list->FindSectionByName(g_section_name_eh_frame);
-
- const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM);
-
- // lldb works best if it knows the start address of all functions in a
- // module. Linker symbols or debug info are normally the best source of
- // information for start addr / size but they may be stripped in a released
- // binary. Two additional sources of information exist in Mach-O binaries:
- // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each
- // function's start address in the
- // binary, relative to the text section.
- // eh_frame - the eh_frame FDEs have the start addr & size of
- // each function
- // LC_FUNCTION_STARTS is the fastest source to read in, and is present on
- // all modern binaries.
- // Binaries built to run on older releases may need to use eh_frame
- // information.
-
- if (text_section_sp && function_starts_data.GetByteSize()) {
- FunctionStarts::Entry function_start_entry;
- function_start_entry.data = false;
- lldb::offset_t function_start_offset = 0;
- function_start_entry.addr = text_section_sp->GetFileAddress();
- uint64_t delta;
- while ((delta = function_starts_data.GetULEB128(&function_start_offset)) >
- 0) {
- // Now append the current entry
- function_start_entry.addr += delta;
- function_starts.Append(function_start_entry);
- }
- } else {
- // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the
- // load command claiming an eh_frame but it doesn't actually have the
- // eh_frame content. And if we have a dSYM, we don't need to do any of
- // this fill-in-the-missing-symbols works anyway - the debug info should
- // give us all the functions in the module.
- if (text_section_sp.get() && eh_frame_section_sp.get() &&
- m_type != eTypeDebugInfo) {
- DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp,
- DWARFCallFrameInfo::EH);
- DWARFCallFrameInfo::FunctionAddressAndSizeVector functions;
- eh_frame.GetFunctionAddressAndSizeVector(functions);
- addr_t text_base_addr = text_section_sp->GetFileAddress();
- size_t count = functions.GetSize();
- for (size_t i = 0; i < count; ++i) {
- const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func =
- functions.GetEntryAtIndex(i);
- if (func) {
- FunctionStarts::Entry function_start_entry;
- function_start_entry.addr = func->base - text_base_addr;
- function_starts.Append(function_start_entry);
- }
- }
- }
- }
-
- const size_t function_starts_count = function_starts.GetSize();
-
- // For user process binaries (executables, dylibs, frameworks, bundles), if
- // we don't have LC_FUNCTION_STARTS/eh_frame section in this binary, we're
- // going to assume the binary has been stripped. Don't allow assembly
- // language instruction emulation because we don't know proper function
- // start boundaries.
- //
- // For all other types of binaries (kernels, stand-alone bare board
- // binaries, kexts), they may not have LC_FUNCTION_STARTS / eh_frame
- // sections - we should not make any assumptions about them based on that.
- if (function_starts_count == 0 && CalculateStrata() == eStrataUser) {
- m_allow_assembly_emulation_unwind_plans = false;
- Log *unwind_or_symbol_log(lldb_private::GetLogIfAnyCategoriesSet(
- LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND));
-
- if (unwind_or_symbol_log)
- module_sp->LogMessage(
- unwind_or_symbol_log,
- "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds");
- }
-
- const user_id_t TEXT_eh_frame_sectID =
- eh_frame_section_sp.get() ? eh_frame_section_sp->GetID()
- : static_cast<user_id_t>(NO_SECT);
-
- lldb::offset_t nlist_data_offset = 0;
-
- uint32_t N_SO_index = UINT32_MAX;
-
- MachSymtabSectionInfo section_info(section_list);
- std::vector<uint32_t> N_FUN_indexes;
- std::vector<uint32_t> N_NSYM_indexes;
- std::vector<uint32_t> N_INCL_indexes;
- std::vector<uint32_t> N_BRAC_indexes;
- std::vector<uint32_t> N_COMM_indexes;
- typedef std::multimap<uint64_t, uint32_t> ValueToSymbolIndexMap;
- typedef std::map<uint32_t, uint32_t> NListIndexToSymbolIndexMap;
- typedef std::map<const char *, uint32_t> ConstNameToSymbolIndexMap;
- ValueToSymbolIndexMap N_FUN_addr_to_sym_idx;
- ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx;
- ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx;
- // Any symbols that get merged into another will get an entry in this map
- // so we know
- NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx;
- uint32_t nlist_idx = 0;
- Symbol *symbol_ptr = NULL;
-
- uint32_t sym_idx = 0;
- Symbol *sym = NULL;
- size_t num_syms = 0;
- std::string memory_symbol_name;
- uint32_t unmapped_local_symbols_found = 0;
-
- std::vector<TrieEntryWithOffset> trie_entries;
- std::set<lldb::addr_t> resolver_addresses;
-
- if (dyld_trie_data.GetByteSize() > 0) {
- std::vector<llvm::StringRef> nameSlices;
- ParseTrieEntries(dyld_trie_data, 0, is_arm, nameSlices,
- resolver_addresses, trie_entries);
-
- ConstString text_segment_name("__TEXT");
- SectionSP text_segment_sp =
- GetSectionList()->FindSectionByName(text_segment_name);
- if (text_segment_sp) {
- const lldb::addr_t text_segment_file_addr =
- text_segment_sp->GetFileAddress();
- if (text_segment_file_addr != LLDB_INVALID_ADDRESS) {
- for (auto &e : trie_entries)
- e.entry.address += text_segment_file_addr;
- }
- }
- }
-
- typedef std::set<ConstString> IndirectSymbols;
- IndirectSymbols indirect_symbol_names;
-
-#if defined(__APPLE__) && \
- (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
-
- // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been
- // optimized by moving LOCAL symbols out of the memory mapped portion of
- // the DSC. The symbol information has all been retained, but it isn't
- // available in the normal nlist data. However, there *are* duplicate
- // entries of *some*
- // LOCAL symbols in the normal nlist data. To handle this situation
- // correctly, we must first attempt
- // to parse any DSC unmapped symbol information. If we find any, we set a
- // flag that tells the normal nlist parser to ignore all LOCAL symbols.
-
- if (m_header.flags & 0x80000000u) {
- // Before we can start mapping the DSC, we need to make certain the
- // target process is actually using the cache we can find.
-
- // Next we need to determine the correct path for the dyld shared cache.
-
- ArchSpec header_arch;
- GetArchitecture(header_arch);
- char dsc_path[PATH_MAX];
- char dsc_path_development[PATH_MAX];
-
- snprintf(
- dsc_path, sizeof(dsc_path), "%s%s%s",
- "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR
- */
- "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
- header_arch.GetArchitectureName());
-
- snprintf(
- dsc_path_development, sizeof(dsc_path), "%s%s%s%s",
- "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR
- */
- "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
- header_arch.GetArchitectureName(), ".development");
-
- FileSpec dsc_nondevelopment_filespec(dsc_path, false);
- FileSpec dsc_development_filespec(dsc_path_development, false);
- FileSpec dsc_filespec;
-
- UUID dsc_uuid;
- UUID process_shared_cache_uuid;
- addr_t process_shared_cache_base_addr;
-
- if (process) {
- GetProcessSharedCacheUUID(process, process_shared_cache_base_addr, process_shared_cache_uuid);
- }
-
- // First see if we can find an exact match for the inferior process
- // shared cache UUID in the development or non-development shared caches
- // on disk.
- if (process_shared_cache_uuid.IsValid()) {
- if (FileSystem::Instance().Exists(dsc_development_filespec)) {
- UUID dsc_development_uuid = GetSharedCacheUUID(
- dsc_development_filespec, byte_order, addr_byte_size);
- if (dsc_development_uuid.IsValid() &&
- dsc_development_uuid == process_shared_cache_uuid) {
- dsc_filespec = dsc_development_filespec;
- dsc_uuid = dsc_development_uuid;
- }
- }
- if (!dsc_uuid.IsValid() &&
- FileSystem::Instance().Exists(dsc_nondevelopment_filespec)) {
- UUID dsc_nondevelopment_uuid = GetSharedCacheUUID(
- dsc_nondevelopment_filespec, byte_order, addr_byte_size);
- if (dsc_nondevelopment_uuid.IsValid() &&
- dsc_nondevelopment_uuid == process_shared_cache_uuid) {
- dsc_filespec = dsc_nondevelopment_filespec;
- dsc_uuid = dsc_nondevelopment_uuid;
- }
- }
- }
-
- // Failing a UUID match, prefer the development dyld_shared cache if both
- // are present.
- if (!FileSystem::Instance().Exists(dsc_filespec)) {
- if (FileSystem::Instance().Exists(dsc_development_filespec)) {
- dsc_filespec = dsc_development_filespec;
- } else {
- dsc_filespec = dsc_nondevelopment_filespec;
- }
- }
-
- /* The dyld_cache_header has a pointer to the
- dyld_cache_local_symbols_info structure (localSymbolsOffset).
- The dyld_cache_local_symbols_info structure gives us three things:
- 1. The start and count of the nlist records in the dyld_shared_cache
- file
- 2. The start and size of the strings for these nlist records
- 3. The start and count of dyld_cache_local_symbols_entry entries
-
- There is one dyld_cache_local_symbols_entry per dylib/framework in the
- dyld shared cache.
- The "dylibOffset" field is the Mach-O header of this dylib/framework in
- the dyld shared cache.
- The dyld_cache_local_symbols_entry also lists the start of this
- dylib/framework's nlist records
- and the count of how many nlist records there are for this
- dylib/framework.
- */
-
- // Process the dyld shared cache header to find the unmapped symbols
-
- DataBufferSP dsc_data_sp = MapFileData(
- dsc_filespec, sizeof(struct lldb_copy_dyld_cache_header_v1), 0);
- if (!dsc_uuid.IsValid()) {
- dsc_uuid = GetSharedCacheUUID(dsc_filespec, byte_order, addr_byte_size);
- }
- if (dsc_data_sp) {
- DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size);
-
- bool uuid_match = true;
- if (dsc_uuid.IsValid() && process) {
- if (process_shared_cache_uuid.IsValid() &&
- dsc_uuid != process_shared_cache_uuid) {
- // The on-disk dyld_shared_cache file is not the same as the one in
- // this process' memory, don't use it.
- uuid_match = false;
- ModuleSP module_sp(GetModule());
- if (module_sp)
- module_sp->ReportWarning("process shared cache does not match "
- "on-disk dyld_shared_cache file, some "
- "symbol names will be missing.");
- }
- }
-
- offset = offsetof(struct lldb_copy_dyld_cache_header_v1, mappingOffset);
-
- uint32_t mappingOffset = dsc_header_data.GetU32(&offset);
-
- // If the mappingOffset points to a location inside the header, we've
- // opened an old dyld shared cache, and should not proceed further.
- if (uuid_match &&
- mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) {
-
- DataBufferSP dsc_mapping_info_data_sp = MapFileData(
- dsc_filespec, sizeof(struct lldb_copy_dyld_cache_mapping_info),
- mappingOffset);
-
- DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp,
- byte_order, addr_byte_size);
- offset = 0;
-
- // The File addresses (from the in-memory Mach-O load commands) for
- // the shared libraries in the shared library cache need to be
- // adjusted by an offset to match up with the dylibOffset identifying
- // field in the dyld_cache_local_symbol_entry's. This offset is
- // recorded in mapping_offset_value.
- const uint64_t mapping_offset_value =
- dsc_mapping_info_data.GetU64(&offset);
-
- offset = offsetof(struct lldb_copy_dyld_cache_header_v1,
- localSymbolsOffset);
- uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset);
- uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset);
-
- if (localSymbolsOffset && localSymbolsSize) {
- // Map the local symbols
- DataBufferSP dsc_local_symbols_data_sp =
- MapFileData(dsc_filespec, localSymbolsSize, localSymbolsOffset);
-
- if (dsc_local_symbols_data_sp) {
- DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp,
- byte_order, addr_byte_size);
-
- offset = 0;
-
- typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
- typedef std::map<uint32_t, ConstString> SymbolIndexToName;
- UndefinedNameToDescMap undefined_name_to_desc;
- SymbolIndexToName reexport_shlib_needs_fixup;
-
- // Read the local_symbols_infos struct in one shot
- struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info;
- dsc_local_symbols_data.GetU32(&offset,
- &local_symbols_info.nlistOffset, 6);
-
- SectionSP text_section_sp(
- section_list->FindSectionByName(GetSegmentNameTEXT()));
-
- uint32_t header_file_offset =
- (text_section_sp->GetFileAddress() - mapping_offset_value);
-
- offset = local_symbols_info.entriesOffset;
- for (uint32_t entry_index = 0;
- entry_index < local_symbols_info.entriesCount;
- entry_index++) {
- struct lldb_copy_dyld_cache_local_symbols_entry
- local_symbols_entry;
- local_symbols_entry.dylibOffset =
- dsc_local_symbols_data.GetU32(&offset);
- local_symbols_entry.nlistStartIndex =
- dsc_local_symbols_data.GetU32(&offset);
- local_symbols_entry.nlistCount =
- dsc_local_symbols_data.GetU32(&offset);
-
- if (header_file_offset == local_symbols_entry.dylibOffset) {
- unmapped_local_symbols_found = local_symbols_entry.nlistCount;
-
- // The normal nlist code cannot correctly size the Symbols
- // array, we need to allocate it here.
- sym = symtab->Resize(
- symtab_load_command.nsyms + m_dysymtab.nindirectsyms +
- unmapped_local_symbols_found - m_dysymtab.nlocalsym);
- num_syms = symtab->GetNumSymbols();
-
- nlist_data_offset =
- local_symbols_info.nlistOffset +
- (nlist_byte_size * local_symbols_entry.nlistStartIndex);
- uint32_t string_table_offset =
- local_symbols_info.stringsOffset;
-
- for (uint32_t nlist_index = 0;
- nlist_index < local_symbols_entry.nlistCount;
- nlist_index++) {
- /////////////////////////////
- {
- struct nlist_64 nlist;
- if (!dsc_local_symbols_data.ValidOffsetForDataOfSize(
- nlist_data_offset, nlist_byte_size))
- break;
-
- nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked(
- &nlist_data_offset);
- nlist.n_type = dsc_local_symbols_data.GetU8_unchecked(
- &nlist_data_offset);
- nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked(
- &nlist_data_offset);
- nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked(
- &nlist_data_offset);
- nlist.n_value =
- dsc_local_symbols_data.GetAddress_unchecked(
- &nlist_data_offset);
-
- SymbolType type = eSymbolTypeInvalid;
- const char *symbol_name = dsc_local_symbols_data.PeekCStr(
- string_table_offset + nlist.n_strx);
-
- if (symbol_name == NULL) {
- // No symbol should be NULL, even the symbols with no
- // string values should have an offset zero which
- // points to an empty C-string
- Host::SystemLog(
- Host::eSystemLogError,
- "error: DSC unmapped local symbol[%u] has invalid "
- "string table offset 0x%x in %s, ignoring symbol\n",
- entry_index, nlist.n_strx,
- module_sp->GetFileSpec().GetPath().c_str());
- continue;
- }
- if (symbol_name[0] == '\0')
- symbol_name = NULL;
-
- const char *symbol_name_non_abi_mangled = NULL;
-
- SectionSP symbol_section;
- uint32_t symbol_byte_size = 0;
- bool add_nlist = true;
- bool is_debug = ((nlist.n_type & N_STAB) != 0);
- bool demangled_is_synthesized = false;
- bool is_gsym = false;
- bool set_value = true;
-
- assert(sym_idx < num_syms);
-
- sym[sym_idx].SetDebug(is_debug);
-
- if (is_debug) {
- switch (nlist.n_type) {
- case N_GSYM:
- // global symbol: name,,NO_SECT,type,0
- // Sometimes the N_GSYM value contains the address.
-
- // FIXME: In the .o files, we have a GSYM and a debug
- // symbol for all the ObjC data. They
- // have the same address, but we want to ensure that
- // we always find only the real symbol, 'cause we
- // don't currently correctly attribute the
- // GSYM one to the ObjCClass/Ivar/MetaClass
- // symbol type. This is a temporary hack to make
- // sure the ObjectiveC symbols get treated correctly.
- // To do this right, we should coalesce all the GSYM
- // & global symbols that have the same address.
-
- is_gsym = true;
- sym[sym_idx].SetExternal(true);
-
- if (symbol_name && symbol_name[0] == '_' &&
- symbol_name[1] == 'O') {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith(
- g_objc_v2_prefix_class)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name =
- symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
-
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_metaclass)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name +
- g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_ivar)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name =
- symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- } else {
- if (nlist.n_value != 0)
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- type = eSymbolTypeData;
- }
- break;
-
- case N_FNAME:
- // procedure name (f77 kludge): name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_FUN:
- // procedure: name,,n_sect,linenumber,address
- if (symbol_name) {
- type = eSymbolTypeCode;
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
-
- N_FUN_addr_to_sym_idx.insert(
- std::make_pair(nlist.n_value, sym_idx));
- // We use the current number of symbols in the
- // symbol table in lieu of using nlist_idx in case
- // we ever start trimming entries out
- N_FUN_indexes.push_back(sym_idx);
- } else {
- type = eSymbolTypeCompiler;
-
- if (!N_FUN_indexes.empty()) {
- // Copy the size of the function into the
- // original
- // STAB entry so we don't have
- // to hunt for it later
- symtab->SymbolAtIndex(N_FUN_indexes.back())
- ->SetByteSize(nlist.n_value);
- N_FUN_indexes.pop_back();
- // We don't really need the end function STAB as
- // it contains the size which we already placed
- // with the original symbol, so don't add it if
- // we want a minimal symbol table
- add_nlist = false;
- }
- }
- break;
-
- case N_STSYM:
- // static symbol: name,,n_sect,type,address
- N_STSYM_addr_to_sym_idx.insert(
- std::make_pair(nlist.n_value, sym_idx));
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- if (symbol_name && symbol_name[0]) {
- type = ObjectFile::GetSymbolTypeFromName(
- symbol_name + 1, eSymbolTypeData);
- }
- break;
-
- case N_LCSYM:
- // .lcomm symbol: name,,n_sect,type,address
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- type = eSymbolTypeCommonBlock;
- break;
-
- case N_BNSYM:
- // We use the current number of symbols in the symbol
- // table in lieu of using nlist_idx in case we ever
- // start trimming entries out Skip these if we want
- // minimal symbol tables
- add_nlist = false;
- break;
-
- case N_ENSYM:
- // Set the size of the N_BNSYM to the terminating
- // index of this N_ENSYM so that we can always skip
- // the entire symbol if we need to navigate more
- // quickly at the source level when parsing STABS
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_OPT:
- // emitted with gcc2_compiled and in gcc source
- type = eSymbolTypeCompiler;
- break;
-
- case N_RSYM:
- // register sym: name,,NO_SECT,type,register
- type = eSymbolTypeVariable;
- break;
-
- case N_SLINE:
- // src line: 0,,n_sect,linenumber,address
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- case N_SSYM:
- // structure elt: name,,NO_SECT,type,struct_offset
- type = eSymbolTypeVariableType;
- break;
-
- case N_SO:
- // source file name
- type = eSymbolTypeSourceFile;
- if (symbol_name == NULL) {
- add_nlist = false;
- if (N_SO_index != UINT32_MAX) {
- // Set the size of the N_SO to the terminating
- // index of this N_SO so that we can always skip
- // the entire N_SO if we need to navigate more
- // quickly at the source level when parsing STABS
- symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
- symbol_ptr->SetByteSize(sym_idx);
- symbol_ptr->SetSizeIsSibling(true);
- }
- N_NSYM_indexes.clear();
- N_INCL_indexes.clear();
- N_BRAC_indexes.clear();
- N_COMM_indexes.clear();
- N_FUN_indexes.clear();
- N_SO_index = UINT32_MAX;
- } else {
- // We use the current number of symbols in the
- // symbol table in lieu of using nlist_idx in case
- // we ever start trimming entries out
- const bool N_SO_has_full_path =
- symbol_name[0] == '/';
- if (N_SO_has_full_path) {
- if ((N_SO_index == sym_idx - 1) &&
- ((sym_idx - 1) < num_syms)) {
- // We have two consecutive N_SO entries where
- // the first contains a directory and the
- // second contains a full path.
- sym[sym_idx - 1].GetMangled().SetValue(
- ConstString(symbol_name), false);
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- add_nlist = false;
- } else {
- // This is the first entry in a N_SO that
- // contains a directory or
- // a full path to the source file
- N_SO_index = sym_idx;
- }
- } else if ((N_SO_index == sym_idx - 1) &&
- ((sym_idx - 1) < num_syms)) {
- // This is usually the second N_SO entry that
- // contains just the filename, so here we combine
- // it with the first one if we are minimizing the
- // symbol table
- const char *so_path =
- sym[sym_idx - 1]
- .GetMangled()
- .GetDemangledName(
- lldb::eLanguageTypeUnknown)
- .AsCString();
- if (so_path && so_path[0]) {
- std::string full_so_path(so_path);
- const size_t double_slash_pos =
- full_so_path.find("//");
- if (double_slash_pos != std::string::npos) {
- // The linker has been generating bad N_SO
- // entries with doubled up paths
- // in the format "%s%s" where the first
- // string in the DW_AT_comp_dir, and the
- // second is the directory for the source
- // file so you end up with a path that looks
- // like "/tmp/src//tmp/src/"
- FileSpec so_dir(so_path, false);
- if (!FileSystem::Instance().Exists(so_dir)) {
- so_dir.SetFile(
- &full_so_path[double_slash_pos + 1],
- false);
- if (FileSystem::Instance().Exists(so_dir)) {
- // Trim off the incorrect path
- full_so_path.erase(0,
- double_slash_pos + 1);
- }
- }
- }
- if (*full_so_path.rbegin() != '/')
- full_so_path += '/';
- full_so_path += symbol_name;
- sym[sym_idx - 1].GetMangled().SetValue(
- ConstString(full_so_path.c_str()), false);
- add_nlist = false;
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- }
- } else {
- // This could be a relative path to a N_SO
- N_SO_index = sym_idx;
- }
- }
- break;
-
- case N_OSO:
- // object file name: name,,0,0,st_mtime
- type = eSymbolTypeObjectFile;
- break;
-
- case N_LSYM:
- // local sym: name,,NO_SECT,type,offset
- type = eSymbolTypeLocal;
- break;
-
- //----------------------------------------------------------------------
- // INCL scopes
- //----------------------------------------------------------------------
- case N_BINCL:
- // include file beginning: name,,NO_SECT,0,sum We use
- // the current number of symbols in the symbol table
- // in lieu of using nlist_idx in case we ever start
- // trimming entries out
- N_INCL_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_EINCL:
- // include file end: name,,NO_SECT,0,0
- // Set the size of the N_BINCL to the terminating
- // index of this N_EINCL so that we can always skip
- // the entire symbol if we need to navigate more
- // quickly at the source level when parsing STABS
- if (!N_INCL_indexes.empty()) {
- symbol_ptr =
- symtab->SymbolAtIndex(N_INCL_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_INCL_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_SOL:
- // #included file name: name,,n_sect,0,address
- type = eSymbolTypeHeaderFile;
-
- // We currently don't use the header files on darwin
- add_nlist = false;
- break;
-
- case N_PARAMS:
- // compiler parameters: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_VERSION:
- // compiler version: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_OLEVEL:
- // compiler -O level: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_PSYM:
- // parameter: name,,NO_SECT,type,offset
- type = eSymbolTypeVariable;
- break;
-
- case N_ENTRY:
- // alternate entry: name,,n_sect,linenumber,address
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- //----------------------------------------------------------------------
- // Left and Right Braces
- //----------------------------------------------------------------------
- case N_LBRAC:
- // left bracket: 0,,NO_SECT,nesting level,address We
- // use the current number of symbols in the symbol
- // table in lieu of using nlist_idx in case we ever
- // start trimming entries out
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- N_BRAC_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_RBRAC:
- // right bracket: 0,,NO_SECT,nesting level,address
- // Set the size of the N_LBRAC to the terminating
- // index of this N_RBRAC so that we can always skip
- // the entire symbol if we need to navigate more
- // quickly at the source level when parsing STABS
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- if (!N_BRAC_indexes.empty()) {
- symbol_ptr =
- symtab->SymbolAtIndex(N_BRAC_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_BRAC_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_EXCL:
- // deleted include file: name,,NO_SECT,0,sum
- type = eSymbolTypeHeaderFile;
- break;
-
- //----------------------------------------------------------------------
- // COMM scopes
- //----------------------------------------------------------------------
- case N_BCOMM:
- // begin common: name,,NO_SECT,0,0
- // We use the current number of symbols in the symbol
- // table in lieu of using nlist_idx in case we ever
- // start trimming entries out
- type = eSymbolTypeScopeBegin;
- N_COMM_indexes.push_back(sym_idx);
- break;
-
- case N_ECOML:
- // end common (local name): 0,,n_sect,0,address
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
- // Fall through
-
- case N_ECOMM:
- // end common: name,,n_sect,0,0
- // Set the size of the N_BCOMM to the terminating
- // index of this N_ECOMM/N_ECOML so that we can
- // always skip the entire symbol if we need to
- // navigate more quickly at the source level when
- // parsing STABS
- if (!N_COMM_indexes.empty()) {
- symbol_ptr =
- symtab->SymbolAtIndex(N_COMM_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_COMM_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_LENG:
- // second stab entry with length information
- type = eSymbolTypeAdditional;
- break;
-
- default:
- break;
- }
- } else {
- // uint8_t n_pext = N_PEXT & nlist.n_type;
- uint8_t n_type = N_TYPE & nlist.n_type;
- sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
-
- switch (n_type) {
- case N_INDR: {
- const char *reexport_name_cstr =
- strtab_data.PeekCStr(nlist.n_value);
- if (reexport_name_cstr && reexport_name_cstr[0]) {
- type = eSymbolTypeReExported;
- ConstString reexport_name(
- reexport_name_cstr +
- ((reexport_name_cstr[0] == '_') ? 1 : 0));
- sym[sym_idx].SetReExportedSymbolName(reexport_name);
- set_value = false;
- reexport_shlib_needs_fixup[sym_idx] = reexport_name;
- indirect_symbol_names.insert(
- ConstString(symbol_name +
- ((symbol_name[0] == '_') ? 1 : 0)));
- } else
- type = eSymbolTypeUndefined;
- } break;
-
- case N_UNDF:
- if (symbol_name && symbol_name[0]) {
- ConstString undefined_name(
- symbol_name +
- ((symbol_name[0] == '_') ? 1 : 0));
- undefined_name_to_desc[undefined_name] =
- nlist.n_desc;
- }
- // Fall through
- case N_PBUD:
- type = eSymbolTypeUndefined;
- break;
-
- case N_ABS:
- type = eSymbolTypeAbsolute;
- break;
-
- case N_SECT: {
- symbol_section = section_info.GetSection(
- nlist.n_sect, nlist.n_value);
-
- if (symbol_section == NULL) {
- // TODO: warn about this?
- add_nlist = false;
- break;
- }
-
- if (TEXT_eh_frame_sectID == nlist.n_sect) {
- type = eSymbolTypeException;
- } else {
- uint32_t section_type =
- symbol_section->Get() & SECTION_TYPE;
-
- switch (section_type) {
- case S_CSTRING_LITERALS:
- type = eSymbolTypeData;
- break; // section with only literal C strings
- case S_4BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 4 byte literals
- case S_8BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 8 byte literals
- case S_LITERAL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only pointers to literals
- case S_NON_LAZY_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only non-lazy symbol
- // pointers
- case S_LAZY_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only lazy symbol pointers
- case S_SYMBOL_STUBS:
- type = eSymbolTypeTrampoline;
- break; // section with only symbol stubs, byte
- // size of stub in the reserved2 field
- case S_MOD_INIT_FUNC_POINTERS:
- type = eSymbolTypeCode;
- break; // section with only function pointers for
- // initialization
- case S_MOD_TERM_FUNC_POINTERS:
- type = eSymbolTypeCode;
- break; // section with only function pointers for
- // termination
- case S_INTERPOSING:
- type = eSymbolTypeTrampoline;
- break; // section with only pairs of function
- // pointers for interposing
- case S_16BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 16 byte literals
- case S_DTRACE_DOF:
- type = eSymbolTypeInstrumentation;
- break;
- case S_LAZY_DYLIB_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break;
- default:
- switch (symbol_section->GetType()) {
- case lldb::eSectionTypeCode:
- type = eSymbolTypeCode;
- break;
- case eSectionTypeData:
- case eSectionTypeDataCString: // Inlined C string
- // data
- case eSectionTypeDataCStringPointers: // Pointers
- // to C
- // string
- // data
- case eSectionTypeDataSymbolAddress: // Address of
- // a symbol in
- // the symbol
- // table
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- type = eSymbolTypeData;
- break;
- default:
- break;
- }
- break;
- }
-
- if (type == eSymbolTypeInvalid) {
- const char *symbol_sect_name =
- symbol_section->GetName().AsCString();
- if (symbol_section->IsDescendant(
- text_section_sp.get())) {
- if (symbol_section->IsClear(
- S_ATTR_PURE_INSTRUCTIONS |
- S_ATTR_SELF_MODIFYING_CODE |
- S_ATTR_SOME_INSTRUCTIONS))
- type = eSymbolTypeData;
- else
- type = eSymbolTypeCode;
- } else if (symbol_section->IsDescendant(
- data_section_sp.get()) ||
- symbol_section->IsDescendant(
- data_dirty_section_sp.get()) ||
- symbol_section->IsDescendant(
- data_const_section_sp.get())) {
- if (symbol_sect_name &&
- ::strstr(symbol_sect_name, "__objc") ==
- symbol_sect_name) {
- type = eSymbolTypeRuntime;
-
- if (symbol_name) {
- llvm::StringRef symbol_name_ref(
- symbol_name);
- if (symbol_name_ref.startswith("_OBJC_")) {
- static const llvm::StringRef
- g_objc_v2_prefix_class(
- "_OBJC_CLASS_$_");
- static const llvm::StringRef
- g_objc_v2_prefix_metaclass(
- "_OBJC_METACLASS_$_");
- static const llvm::StringRef
- g_objc_v2_prefix_ivar(
- "_OBJC_IVAR_$_");
- if (symbol_name_ref.startswith(
- g_objc_v2_prefix_class)) {
- symbol_name_non_abi_mangled =
- symbol_name + 1;
- symbol_name =
- symbol_name +
- g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- } else if (
- symbol_name_ref.startswith(
- g_objc_v2_prefix_metaclass)) {
- symbol_name_non_abi_mangled =
- symbol_name + 1;
- symbol_name =
- symbol_name +
- g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_ivar)) {
- symbol_name_non_abi_mangled =
- symbol_name + 1;
- symbol_name =
- symbol_name +
- g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- }
- } else if (symbol_sect_name &&
- ::strstr(symbol_sect_name,
- "__gcc_except_tab") ==
- symbol_sect_name) {
- type = eSymbolTypeException;
- } else {
- type = eSymbolTypeData;
- }
- } else if (symbol_sect_name &&
- ::strstr(symbol_sect_name,
- "__IMPORT") ==
- symbol_sect_name) {
- type = eSymbolTypeTrampoline;
- } else if (symbol_section->IsDescendant(
- objc_section_sp.get())) {
- type = eSymbolTypeRuntime;
- if (symbol_name && symbol_name[0] == '.') {
- llvm::StringRef symbol_name_ref(symbol_name);
- static const llvm::StringRef
- g_objc_v1_prefix_class(
- ".objc_class_name_");
- if (symbol_name_ref.startswith(
- g_objc_v1_prefix_class)) {
- symbol_name_non_abi_mangled = symbol_name;
- symbol_name = symbol_name +
- g_objc_v1_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- }
- }
- }
- }
- } break;
- }
- }
-
- if (add_nlist) {
- uint64_t symbol_value = nlist.n_value;
- if (symbol_name_non_abi_mangled) {
- sym[sym_idx].GetMangled().SetMangledName(
- ConstString(symbol_name_non_abi_mangled));
- sym[sym_idx].GetMangled().SetDemangledName(
- ConstString(symbol_name));
- } else {
- bool symbol_name_is_mangled = false;
-
- if (symbol_name && symbol_name[0] == '_') {
- symbol_name_is_mangled = symbol_name[1] == '_';
- symbol_name++; // Skip the leading underscore
- }
-
- if (symbol_name) {
- ConstString const_symbol_name(symbol_name);
- sym[sym_idx].GetMangled().SetValue(
- const_symbol_name, symbol_name_is_mangled);
- if (is_gsym && is_debug) {
- const char *gsym_name =
- sym[sym_idx]
- .GetMangled()
- .GetName(lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)
- .GetCString();
- if (gsym_name)
- N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
- }
- }
- }
- if (symbol_section) {
- const addr_t section_file_addr =
- symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 &&
- function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses,
- // else get the closest since the symbol might be a
- // thumb symbol which has an address with bit zero
- // set
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(
- symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the
- // symbol address (ARM) or the symbol address + 1
- // (thumb)
- if (func_start_entry->addr !=
- symbol_lookup_file_addr &&
- func_start_entry->addr !=
- (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm) {
- if (symbol_file_addr & 1)
- symbol_flags =
- MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
-
- const FunctionStarts::Entry
- *next_func_start_entry =
- function_starts.FindNextEntry(
- func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr +
- symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr =
- next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when
- // we calculate the size from the current and
- // next address
- if (is_arm)
- next_symbol_file_addr &=
- THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size =
- section_end_file_addr - symbol_file_addr;
- }
- }
- }
- symbol_value -= section_file_addr;
- }
-
- if (is_debug == false) {
- if (type == eSymbolTypeCode) {
- // See if we can find a N_FUN entry for any code
- // symbols. If we do find a match, and the name
- // matches, then we can merge the two into just the
- // function symbol to avoid duplicate entries in
- // the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator,
- ValueToSymbolIndexMap::const_iterator>
- range;
- range = N_FUN_addr_to_sym_idx.equal_range(
- nlist.n_value);
- if (range.first != range.second) {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos =
- range.first;
- pos != range.second; ++pos) {
- if (sym[sym_idx].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled) ==
- sym[pos->second].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)) {
- m_nlist_idx_to_sym_idx[nlist_idx] =
- pos->second;
- // We just need the flags from the linker
- // symbol, so put these flags
- // into the N_FUN flags to avoid duplicate
- // symbols in the symbol table
- sym[pos->second].SetExternal(
- sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
- if (resolver_addresses.find(nlist.n_value) !=
- resolver_addresses.end())
- sym[pos->second].SetType(
- eSymbolTypeResolver);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- } else {
- if (resolver_addresses.find(nlist.n_value) !=
- resolver_addresses.end())
- type = eSymbolTypeResolver;
- }
- } else if (type == eSymbolTypeData ||
- type == eSymbolTypeObjCClass ||
- type == eSymbolTypeObjCMetaClass ||
- type == eSymbolTypeObjCIVar) {
- // See if we can find a N_STSYM entry for any data
- // symbols. If we do find a match, and the name
- // matches, then we can merge the two into just the
- // Static symbol to avoid duplicate entries in the
- // symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator,
- ValueToSymbolIndexMap::const_iterator>
- range;
- range = N_STSYM_addr_to_sym_idx.equal_range(
- nlist.n_value);
- if (range.first != range.second) {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos =
- range.first;
- pos != range.second; ++pos) {
- if (sym[sym_idx].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled) ==
- sym[pos->second].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)) {
- m_nlist_idx_to_sym_idx[nlist_idx] =
- pos->second;
- // We just need the flags from the linker
- // symbol, so put these flags
- // into the N_STSYM flags to avoid duplicate
- // symbols in the symbol table
- sym[pos->second].SetExternal(
- sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- } else {
- const char *gsym_name =
- sym[sym_idx]
- .GetMangled()
- .GetName(lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)
- .GetCString();
- if (gsym_name) {
- // Combine N_GSYM stab entries with the non
- // stab symbol
- ConstNameToSymbolIndexMap::const_iterator pos =
- N_GSYM_name_to_sym_idx.find(gsym_name);
- if (pos != N_GSYM_name_to_sym_idx.end()) {
- const uint32_t GSYM_sym_idx = pos->second;
- m_nlist_idx_to_sym_idx[nlist_idx] =
- GSYM_sym_idx;
- // Copy the address, because often the N_GSYM
- // address has an invalid address of zero
- // when the global is a common symbol
- sym[GSYM_sym_idx].GetAddressRef().SetSection(
- symbol_section);
- sym[GSYM_sym_idx].GetAddressRef().SetOffset(
- symbol_value);
- // We just need the flags from the linker
- // symbol, so put these flags
- // into the N_GSYM flags to avoid duplicate
- // symbols in the symbol table
- sym[GSYM_sym_idx].SetFlags(
- nlist.n_type << 16 | nlist.n_desc);
- sym[sym_idx].Clear();
- continue;
- }
- }
- }
- }
- }
-
- sym[sym_idx].SetID(nlist_idx);
- sym[sym_idx].SetType(type);
- if (set_value) {
- sym[sym_idx].GetAddressRef().SetSection(
- symbol_section);
- sym[sym_idx].GetAddressRef().SetOffset(symbol_value);
- }
- sym[sym_idx].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
-
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
- if (demangled_is_synthesized)
- sym[sym_idx].SetDemangledNameIsSynthesized(true);
- ++sym_idx;
- } else {
- sym[sym_idx].Clear();
- }
- }
- /////////////////////////////
- }
- break; // No more entries to consider
- }
- }
-
- for (const auto &pos : reexport_shlib_needs_fixup) {
- const auto undef_pos = undefined_name_to_desc.find(pos.second);
- if (undef_pos != undefined_name_to_desc.end()) {
- const uint8_t dylib_ordinal =
- llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
- if (dylib_ordinal > 0 &&
- dylib_ordinal < dylib_files.GetSize())
- sym[pos.first].SetReExportedSymbolSharedLibrary(
- dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1));
- }
- }
- }
- }
- }
- }
- }
-
- // Must reset this in case it was mutated above!
- nlist_data_offset = 0;
-#endif
-
- if (nlist_data.GetByteSize() > 0) {
-
- // If the sym array was not created while parsing the DSC unmapped
- // symbols, create it now.
- if (sym == NULL) {
- sym = symtab->Resize(symtab_load_command.nsyms +
- m_dysymtab.nindirectsyms);
- num_syms = symtab->GetNumSymbols();
- }
-
- if (unmapped_local_symbols_found) {
- assert(m_dysymtab.ilocalsym == 0);
- nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size);
- nlist_idx = m_dysymtab.nlocalsym;
- } else {
- nlist_idx = 0;
- }
-
- typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
- typedef std::map<uint32_t, ConstString> SymbolIndexToName;
- UndefinedNameToDescMap undefined_name_to_desc;
- SymbolIndexToName reexport_shlib_needs_fixup;
- for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx) {
- struct nlist_64 nlist;
- if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset,
- nlist_byte_size))
- break;
-
- nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset);
- nlist.n_type = nlist_data.GetU8_unchecked(&nlist_data_offset);
- nlist.n_sect = nlist_data.GetU8_unchecked(&nlist_data_offset);
- nlist.n_desc = nlist_data.GetU16_unchecked(&nlist_data_offset);
- nlist.n_value = nlist_data.GetAddress_unchecked(&nlist_data_offset);
-
- SymbolType type = eSymbolTypeInvalid;
- const char *symbol_name = NULL;
-
- if (have_strtab_data) {
- symbol_name = strtab_data.PeekCStr(nlist.n_strx);
-
- if (symbol_name == NULL) {
- // No symbol should be NULL, even the symbols with no string values
- // should have an offset zero which points to an empty C-string
- Host::SystemLog(Host::eSystemLogError,
- "error: symbol[%u] has invalid string table offset "
- "0x%x in %s, ignoring symbol\n",
- nlist_idx, nlist.n_strx,
- module_sp->GetFileSpec().GetPath().c_str());
- continue;
- }
- if (symbol_name[0] == '\0')
- symbol_name = NULL;
- } else {
- const addr_t str_addr = strtab_addr + nlist.n_strx;
- Status str_error;
- if (process->ReadCStringFromMemory(str_addr, memory_symbol_name,
- str_error))
- symbol_name = memory_symbol_name.c_str();
- }
- const char *symbol_name_non_abi_mangled = NULL;
-
- SectionSP symbol_section;
- lldb::addr_t symbol_byte_size = 0;
- bool add_nlist = true;
- bool is_gsym = false;
- bool is_debug = ((nlist.n_type & N_STAB) != 0);
- bool demangled_is_synthesized = false;
- bool set_value = true;
- assert(sym_idx < num_syms);
-
- sym[sym_idx].SetDebug(is_debug);
-
- if (is_debug) {
- switch (nlist.n_type) {
- case N_GSYM:
- // global symbol: name,,NO_SECT,type,0
- // Sometimes the N_GSYM value contains the address.
-
- // FIXME: In the .o files, we have a GSYM and a debug symbol for all
- // the ObjC data. They
- // have the same address, but we want to ensure that we always find
- // only the real symbol, 'cause we don't currently correctly
- // attribute the GSYM one to the ObjCClass/Ivar/MetaClass symbol
- // type. This is a temporary hack to make sure the ObjectiveC
- // symbols get treated correctly. To do this right, we should
- // coalesce all the GSYM & global symbols that have the same
- // address.
- is_gsym = true;
- sym[sym_idx].SetExternal(true);
-
- if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
-
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_metaclass)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- } else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- } else {
- if (nlist.n_value != 0)
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- type = eSymbolTypeData;
- }
- break;
-
- case N_FNAME:
- // procedure name (f77 kludge): name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_FUN:
- // procedure: name,,n_sect,linenumber,address
- if (symbol_name) {
- type = eSymbolTypeCode;
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
-
- N_FUN_addr_to_sym_idx.insert(
- std::make_pair(nlist.n_value, sym_idx));
- // We use the current number of symbols in the symbol table in
- // lieu of using nlist_idx in case we ever start trimming entries
- // out
- N_FUN_indexes.push_back(sym_idx);
- } else {
- type = eSymbolTypeCompiler;
-
- if (!N_FUN_indexes.empty()) {
- // Copy the size of the function into the original STAB entry
- // so we don't have to hunt for it later
- symtab->SymbolAtIndex(N_FUN_indexes.back())
- ->SetByteSize(nlist.n_value);
- N_FUN_indexes.pop_back();
- // We don't really need the end function STAB as it contains
- // the size which we already placed with the original symbol,
- // so don't add it if we want a minimal symbol table
- add_nlist = false;
- }
- }
- break;
-
- case N_STSYM:
- // static symbol: name,,n_sect,type,address
- N_STSYM_addr_to_sym_idx.insert(
- std::make_pair(nlist.n_value, sym_idx));
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- if (symbol_name && symbol_name[0]) {
- type = ObjectFile::GetSymbolTypeFromName(symbol_name + 1,
- eSymbolTypeData);
- }
- break;
-
- case N_LCSYM:
- // .lcomm symbol: name,,n_sect,type,address
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- type = eSymbolTypeCommonBlock;
- break;
-
- case N_BNSYM:
- // We use the current number of symbols in the symbol table in lieu
- // of using nlist_idx in case we ever start trimming entries out
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_ENSYM:
- // Set the size of the N_BNSYM to the terminating index of this
- // N_ENSYM so that we can always skip the entire symbol if we need
- // to navigate more quickly at the source level when parsing STABS
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_OPT:
- // emitted with gcc2_compiled and in gcc source
- type = eSymbolTypeCompiler;
- break;
-
- case N_RSYM:
- // register sym: name,,NO_SECT,type,register
- type = eSymbolTypeVariable;
- break;
-
- case N_SLINE:
- // src line: 0,,n_sect,linenumber,address
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- case N_SSYM:
- // structure elt: name,,NO_SECT,type,struct_offset
- type = eSymbolTypeVariableType;
- break;
-
- case N_SO:
- // source file name
- type = eSymbolTypeSourceFile;
- if (symbol_name == NULL) {
- add_nlist = false;
- if (N_SO_index != UINT32_MAX) {
- // Set the size of the N_SO to the terminating index of this
- // N_SO so that we can always skip the entire N_SO if we need
- // to navigate more quickly at the source level when parsing
- // STABS
- symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
- symbol_ptr->SetByteSize(sym_idx);
- symbol_ptr->SetSizeIsSibling(true);
- }
- N_NSYM_indexes.clear();
- N_INCL_indexes.clear();
- N_BRAC_indexes.clear();
- N_COMM_indexes.clear();
- N_FUN_indexes.clear();
- N_SO_index = UINT32_MAX;
- } else {
- // We use the current number of symbols in the symbol table in
- // lieu of using nlist_idx in case we ever start trimming entries
- // out
- const bool N_SO_has_full_path = symbol_name[0] == '/';
- if (N_SO_has_full_path) {
- if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) {
- // We have two consecutive N_SO entries where the first
- // contains a directory and the second contains a full path.
- sym[sym_idx - 1].GetMangled().SetValue(
- ConstString(symbol_name), false);
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- add_nlist = false;
- } else {
- // This is the first entry in a N_SO that contains a
- // directory or a full path to the source file
- N_SO_index = sym_idx;
- }
- } else if ((N_SO_index == sym_idx - 1) &&
- ((sym_idx - 1) < num_syms)) {
- // This is usually the second N_SO entry that contains just the
- // filename, so here we combine it with the first one if we are
- // minimizing the symbol table
- const char *so_path =
- sym[sym_idx - 1]
- .GetMangled()
- .GetDemangledName(lldb::eLanguageTypeUnknown)
- .AsCString();
- if (so_path && so_path[0]) {
- std::string full_so_path(so_path);
- const size_t double_slash_pos = full_so_path.find("//");
- if (double_slash_pos != std::string::npos) {
- // The linker has been generating bad N_SO entries with
- // doubled up paths in the format "%s%s" where the first
- // string in the DW_AT_comp_dir, and the second is the
- // directory for the source file so you end up with a path
- // that looks like "/tmp/src//tmp/src/"
- FileSpec so_dir(so_path);
- if (!FileSystem::Instance().Exists(so_dir)) {
- so_dir.SetFile(&full_so_path[double_slash_pos + 1],
- FileSpec::Style::native);
- if (FileSystem::Instance().Exists(so_dir)) {
- // Trim off the incorrect path
- full_so_path.erase(0, double_slash_pos + 1);
- }
- }
- }
- if (*full_so_path.rbegin() != '/')
- full_so_path += '/';
- full_so_path += symbol_name;
- sym[sym_idx - 1].GetMangled().SetValue(
- ConstString(full_so_path.c_str()), false);
- add_nlist = false;
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- }
- } else {
- // This could be a relative path to a N_SO
- N_SO_index = sym_idx;
- }
- }
- break;
-
- case N_OSO:
- // object file name: name,,0,0,st_mtime
- type = eSymbolTypeObjectFile;
- break;
-
- case N_LSYM:
- // local sym: name,,NO_SECT,type,offset
- type = eSymbolTypeLocal;
- break;
-
- //----------------------------------------------------------------------
- // INCL scopes
- //----------------------------------------------------------------------
- case N_BINCL:
- // include file beginning: name,,NO_SECT,0,sum We use the current
- // number of symbols in the symbol table in lieu of using nlist_idx
- // in case we ever start trimming entries out
- N_INCL_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_EINCL:
- // include file end: name,,NO_SECT,0,0
- // Set the size of the N_BINCL to the terminating index of this
- // N_EINCL so that we can always skip the entire symbol if we need
- // to navigate more quickly at the source level when parsing STABS
- if (!N_INCL_indexes.empty()) {
- symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_INCL_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_SOL:
- // #included file name: name,,n_sect,0,address
- type = eSymbolTypeHeaderFile;
-
- // We currently don't use the header files on darwin
- add_nlist = false;
- break;
-
- case N_PARAMS:
- // compiler parameters: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_VERSION:
- // compiler version: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_OLEVEL:
- // compiler -O level: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_PSYM:
- // parameter: name,,NO_SECT,type,offset
- type = eSymbolTypeVariable;
- break;
-
- case N_ENTRY:
- // alternate entry: name,,n_sect,linenumber,address
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- //----------------------------------------------------------------------
- // Left and Right Braces
- //----------------------------------------------------------------------
- case N_LBRAC:
- // left bracket: 0,,NO_SECT,nesting level,address We use the
- // current number of symbols in the symbol table in lieu of using
- // nlist_idx in case we ever start trimming entries out
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- N_BRAC_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_RBRAC:
- // right bracket: 0,,NO_SECT,nesting level,address Set the size of
- // the N_LBRAC to the terminating index of this N_RBRAC so that we
- // can always skip the entire symbol if we need to navigate more
- // quickly at the source level when parsing STABS
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- if (!N_BRAC_indexes.empty()) {
- symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_BRAC_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_EXCL:
- // deleted include file: name,,NO_SECT,0,sum
- type = eSymbolTypeHeaderFile;
- break;
-
- //----------------------------------------------------------------------
- // COMM scopes
- //----------------------------------------------------------------------
- case N_BCOMM:
- // begin common: name,,NO_SECT,0,0
- // We use the current number of symbols in the symbol table in lieu
- // of using nlist_idx in case we ever start trimming entries out
- type = eSymbolTypeScopeBegin;
- N_COMM_indexes.push_back(sym_idx);
- break;
-
- case N_ECOML:
- // end common (local name): 0,,n_sect,0,address
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
- LLVM_FALLTHROUGH;
-
- case N_ECOMM:
- // end common: name,,n_sect,0,0
- // Set the size of the N_BCOMM to the terminating index of this
- // N_ECOMM/N_ECOML so that we can always skip the entire symbol if
- // we need to navigate more quickly at the source level when
- // parsing STABS
- if (!N_COMM_indexes.empty()) {
- symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_COMM_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_LENG:
- // second stab entry with length information
- type = eSymbolTypeAdditional;
- break;
-
- default:
- break;
- }
- } else {
- // uint8_t n_pext = N_PEXT & nlist.n_type;
- uint8_t n_type = N_TYPE & nlist.n_type;
- sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
-
- switch (n_type) {
- case N_INDR: {
- const char *reexport_name_cstr =
- strtab_data.PeekCStr(nlist.n_value);
- if (reexport_name_cstr && reexport_name_cstr[0]) {
- type = eSymbolTypeReExported;
- ConstString reexport_name(
- reexport_name_cstr +
- ((reexport_name_cstr[0] == '_') ? 1 : 0));
- sym[sym_idx].SetReExportedSymbolName(reexport_name);
- set_value = false;
- reexport_shlib_needs_fixup[sym_idx] = reexport_name;
- indirect_symbol_names.insert(
- ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
- } else
- type = eSymbolTypeUndefined;
- } break;
-
- case N_UNDF:
- if (symbol_name && symbol_name[0]) {
- ConstString undefined_name(symbol_name +
- ((symbol_name[0] == '_') ? 1 : 0));
- undefined_name_to_desc[undefined_name] = nlist.n_desc;
- }
- LLVM_FALLTHROUGH;
-
- case N_PBUD:
- type = eSymbolTypeUndefined;
- break;
-
- case N_ABS:
- type = eSymbolTypeAbsolute;
- break;
-
- case N_SECT: {
- symbol_section =
- section_info.GetSection(nlist.n_sect, nlist.n_value);
-
- if (!symbol_section) {
- // TODO: warn about this?
- add_nlist = false;
- break;
- }
-
- if (TEXT_eh_frame_sectID == nlist.n_sect) {
- type = eSymbolTypeException;
- } else {
- uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
-
- switch (section_type) {
- case S_CSTRING_LITERALS:
- type = eSymbolTypeData;
- break; // section with only literal C strings
- case S_4BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 4 byte literals
- case S_8BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 8 byte literals
- case S_LITERAL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only pointers to literals
- case S_NON_LAZY_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only non-lazy symbol pointers
- case S_LAZY_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break; // section with only lazy symbol pointers
- case S_SYMBOL_STUBS:
- type = eSymbolTypeTrampoline;
- break; // section with only symbol stubs, byte size of stub in
- // the reserved2 field
- case S_MOD_INIT_FUNC_POINTERS:
- type = eSymbolTypeCode;
- break; // section with only function pointers for initialization
- case S_MOD_TERM_FUNC_POINTERS:
- type = eSymbolTypeCode;
- break; // section with only function pointers for termination
- case S_INTERPOSING:
- type = eSymbolTypeTrampoline;
- break; // section with only pairs of function pointers for
- // interposing
- case S_16BYTE_LITERALS:
- type = eSymbolTypeData;
- break; // section with only 16 byte literals
- case S_DTRACE_DOF:
- type = eSymbolTypeInstrumentation;
- break;
- case S_LAZY_DYLIB_SYMBOL_POINTERS:
- type = eSymbolTypeTrampoline;
- break;
- default:
- switch (symbol_section->GetType()) {
- case lldb::eSectionTypeCode:
- type = eSymbolTypeCode;
- break;
- case eSectionTypeData:
- case eSectionTypeDataCString: // Inlined C string data
- case eSectionTypeDataCStringPointers: // Pointers to C string
- // data
- case eSectionTypeDataSymbolAddress: // Address of a symbol in
- // the symbol table
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- type = eSymbolTypeData;
- break;
- default:
- break;
- }
- break;
- }
-
- if (type == eSymbolTypeInvalid) {
- const char *symbol_sect_name =
- symbol_section->GetName().AsCString();
- if (symbol_section->IsDescendant(text_section_sp.get())) {
- if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
- S_ATTR_SELF_MODIFYING_CODE |
- S_ATTR_SOME_INSTRUCTIONS))
- type = eSymbolTypeData;
- else
- type = eSymbolTypeCode;
- } else if (symbol_section->IsDescendant(
- data_section_sp.get()) ||
- symbol_section->IsDescendant(
- data_dirty_section_sp.get()) ||
- symbol_section->IsDescendant(
- data_const_section_sp.get())) {
- if (symbol_sect_name &&
- ::strstr(symbol_sect_name, "__objc") ==
- symbol_sect_name) {
- type = eSymbolTypeRuntime;
-
- if (symbol_name) {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith("_OBJC_")) {
- static const llvm::StringRef g_objc_v2_prefix_class(
- "_OBJC_CLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_metaclass(
- "_OBJC_METACLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_ivar(
- "_OBJC_IVAR_$_");
- if (symbol_name_ref.startswith(
- g_objc_v2_prefix_class)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name =
- symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_metaclass)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name =
- symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- } else if (symbol_name_ref.startswith(
- g_objc_v2_prefix_ivar)) {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name =
- symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- }
- } else if (symbol_sect_name &&
- ::strstr(symbol_sect_name, "__gcc_except_tab") ==
- symbol_sect_name) {
- type = eSymbolTypeException;
- } else {
- type = eSymbolTypeData;
- }
- } else if (symbol_sect_name &&
- ::strstr(symbol_sect_name, "__IMPORT") ==
- symbol_sect_name) {
- type = eSymbolTypeTrampoline;
- } else if (symbol_section->IsDescendant(
- objc_section_sp.get())) {
- type = eSymbolTypeRuntime;
- if (symbol_name && symbol_name[0] == '.') {
- llvm::StringRef symbol_name_ref(symbol_name);
- static const llvm::StringRef g_objc_v1_prefix_class(
- ".objc_class_name_");
- if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) {
- symbol_name_non_abi_mangled = symbol_name;
- symbol_name = symbol_name + g_objc_v1_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- }
- }
- }
- }
- } break;
- }
- }
-
- if (add_nlist) {
- uint64_t symbol_value = nlist.n_value;
-
- if (symbol_name_non_abi_mangled) {
- sym[sym_idx].GetMangled().SetMangledName(
- ConstString(symbol_name_non_abi_mangled));
- sym[sym_idx].GetMangled().SetDemangledName(
- ConstString(symbol_name));
- } else {
- bool symbol_name_is_mangled = false;
-
- if (symbol_name && symbol_name[0] == '_') {
- symbol_name_is_mangled = symbol_name[1] == '_';
- symbol_name++; // Skip the leading underscore
- }
-
- if (symbol_name) {
- ConstString const_symbol_name(symbol_name);
- sym[sym_idx].GetMangled().SetValue(const_symbol_name,
- symbol_name_is_mangled);
- }
- }
-
- if (is_gsym) {
- const char *gsym_name = sym[sym_idx]
- .GetMangled()
- .GetName(lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)
- .GetCString();
- if (gsym_name)
- N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
- }
-
- if (symbol_section) {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 && function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses, else get the
- // closest since the symbol might be a thumb symbol which has an
- // address with bit zero set
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the symbol address
- // (ARM) or the symbol address + 1 (thumb)
- if (func_start_entry->addr != symbol_lookup_file_addr &&
- func_start_entry->addr != (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- if (is_arm)
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
-
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when we calculate
- // the size from the current and next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- }
- }
- symbol_value -= section_file_addr;
- }
-
- if (!is_debug) {
- if (type == eSymbolTypeCode) {
- // See if we can find a N_FUN entry for any code symbols. If we
- // do find a match, and the name matches, then we can merge the
- // two into just the function symbol to avoid duplicate entries
- // in the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator,
- ValueToSymbolIndexMap::const_iterator>
- range;
- range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second) {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first;
- pos != range.second; ++pos) {
- if (sym[sym_idx].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled) ==
- sym[pos->second].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)) {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put
- // these flags into the N_FUN flags to avoid duplicate
- // symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
- if (resolver_addresses.find(nlist.n_value) !=
- resolver_addresses.end())
- sym[pos->second].SetType(eSymbolTypeResolver);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- } else {
- if (resolver_addresses.find(nlist.n_value) !=
- resolver_addresses.end())
- type = eSymbolTypeResolver;
- }
- } else if (type == eSymbolTypeData ||
- type == eSymbolTypeObjCClass ||
- type == eSymbolTypeObjCMetaClass ||
- type == eSymbolTypeObjCIVar) {
- // See if we can find a N_STSYM entry for any data symbols. If we
- // do find a match, and the name matches, then we can merge the
- // two into just the Static symbol to avoid duplicate entries in
- // the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator,
- ValueToSymbolIndexMap::const_iterator>
- range;
- range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second) {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first;
- pos != range.second; ++pos) {
- if (sym[sym_idx].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled) ==
- sym[pos->second].GetMangled().GetName(
- lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)) {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put
- // these flags into the N_STSYM flags to avoid duplicate
- // symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- } else {
- // Combine N_GSYM stab entries with the non stab symbol
- const char *gsym_name = sym[sym_idx]
- .GetMangled()
- .GetName(lldb::eLanguageTypeUnknown,
- Mangled::ePreferMangled)
- .GetCString();
- if (gsym_name) {
- ConstNameToSymbolIndexMap::const_iterator pos =
- N_GSYM_name_to_sym_idx.find(gsym_name);
- if (pos != N_GSYM_name_to_sym_idx.end()) {
- const uint32_t GSYM_sym_idx = pos->second;
- m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
- // Copy the address, because often the N_GSYM address has
- // an invalid address of zero when the global is a common
- // symbol
- sym[GSYM_sym_idx].GetAddressRef().SetSection(
- symbol_section);
- sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value);
- // We just need the flags from the linker symbol, so put
- // these flags into the N_GSYM flags to avoid duplicate
- // symbols in the symbol table
- sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 |
- nlist.n_desc);
- sym[sym_idx].Clear();
- continue;
- }
- }
- }
- }
- }
-
- sym[sym_idx].SetID(nlist_idx);
- sym[sym_idx].SetType(type);
- if (set_value) {
- sym[sym_idx].GetAddressRef().SetSection(symbol_section);
- sym[sym_idx].GetAddressRef().SetOffset(symbol_value);
- }
- sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc);
-
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
- if (demangled_is_synthesized)
- sym[sym_idx].SetDemangledNameIsSynthesized(true);
-
- ++sym_idx;
- } else {
- sym[sym_idx].Clear();
- }
- }
-
- for (const auto &pos : reexport_shlib_needs_fixup) {
- const auto undef_pos = undefined_name_to_desc.find(pos.second);
- if (undef_pos != undefined_name_to_desc.end()) {
- const uint8_t dylib_ordinal =
- llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
- if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
- sym[pos.first].SetReExportedSymbolSharedLibrary(
- dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1));
- }
- }
- }
-
- uint32_t synthetic_sym_id = symtab_load_command.nsyms;
-
- if (function_starts_count > 0) {
- uint32_t num_synthetic_function_symbols = 0;
- for (i = 0; i < function_starts_count; ++i) {
- if (!function_starts.GetEntryRef(i).data)
- ++num_synthetic_function_symbols;
- }
-
- if (num_synthetic_function_symbols > 0) {
- if (num_syms < sym_idx + num_synthetic_function_symbols) {
- num_syms = sym_idx + num_synthetic_function_symbols;
- sym = symtab->Resize(num_syms);
- }
- for (i = 0; i < function_starts_count; ++i) {
- const FunctionStarts::Entry *func_start_entry =
- function_starts.GetEntryAtIndex(i);
- if (!func_start_entry->data) {
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm) {
- if (symbol_file_addr & 1)
- symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
- Address symbol_addr;
- if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) {
- SectionSP symbol_section(symbol_addr.GetSection());
- uint32_t symbol_byte_size = 0;
- if (symbol_section) {
- const addr_t section_file_addr =
- symbol_section->GetFileAddress();
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- sym[sym_idx].SetID(synthetic_sym_id++);
- sym[sym_idx].GetMangled().SetDemangledName(
- GetNextSyntheticSymbolName());
- sym[sym_idx].SetType(eSymbolTypeCode);
- sym[sym_idx].SetIsSynthetic(true);
- sym[sym_idx].GetAddressRef() = symbol_addr;
- if (symbol_flags)
- sym[sym_idx].SetFlags(symbol_flags);
- if (symbol_byte_size)
- sym[sym_idx].SetByteSize(symbol_byte_size);
- ++sym_idx;
- }
- }
- }
- }
- }
- }
-
- // Trim our symbols down to just what we ended up with after removing any
- // symbols.
- if (sym_idx < num_syms) {
- num_syms = sym_idx;
- sym = symtab->Resize(num_syms);
- }
-
- // Now synthesize indirect symbols
- if (m_dysymtab.nindirectsyms != 0) {
- if (indirect_symbol_index_data.GetByteSize()) {
- NListIndexToSymbolIndexMap::const_iterator end_index_pos =
- m_nlist_idx_to_sym_idx.end();
-
- for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size();
- ++sect_idx) {
- if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) ==
- S_SYMBOL_STUBS) {
- uint32_t symbol_stub_byte_size =
- m_mach_sections[sect_idx].reserved2;
- if (symbol_stub_byte_size == 0)
- continue;
-
- const uint32_t num_symbol_stubs =
- m_mach_sections[sect_idx].size / symbol_stub_byte_size;
-
- if (num_symbol_stubs == 0)
- continue;
-
- const uint32_t symbol_stub_index_offset =
- m_mach_sections[sect_idx].reserved1;
- for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs;
- ++stub_idx) {
- const uint32_t symbol_stub_index =
- symbol_stub_index_offset + stub_idx;
- const lldb::addr_t symbol_stub_addr =
- m_mach_sections[sect_idx].addr +
- (stub_idx * symbol_stub_byte_size);
- lldb::offset_t symbol_stub_offset = symbol_stub_index * 4;
- if (indirect_symbol_index_data.ValidOffsetForDataOfSize(
- symbol_stub_offset, 4)) {
- const uint32_t stub_sym_id =
- indirect_symbol_index_data.GetU32(&symbol_stub_offset);
- if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL))
- continue;
-
- NListIndexToSymbolIndexMap::const_iterator index_pos =
- m_nlist_idx_to_sym_idx.find(stub_sym_id);
- Symbol *stub_symbol = NULL;
- if (index_pos != end_index_pos) {
- // We have a remapping from the original nlist index to a
- // current symbol index, so just look this up by index
- stub_symbol = symtab->SymbolAtIndex(index_pos->second);
- } else {
- // We need to lookup a symbol using the original nlist symbol
- // index since this index is coming from the S_SYMBOL_STUBS
- stub_symbol = symtab->FindSymbolByID(stub_sym_id);
- }
-
- if (stub_symbol) {
- Address so_addr(symbol_stub_addr, section_list);
-
- if (stub_symbol->GetType() == eSymbolTypeUndefined) {
- // Change the external symbol into a trampoline that makes
- // sense These symbols were N_UNDF N_EXT, and are useless
- // to us, so we can re-use them so we don't have to make up
- // a synthetic symbol for no good reason.
- if (resolver_addresses.find(symbol_stub_addr) ==
- resolver_addresses.end())
- stub_symbol->SetType(eSymbolTypeTrampoline);
- else
- stub_symbol->SetType(eSymbolTypeResolver);
- stub_symbol->SetExternal(false);
- stub_symbol->GetAddressRef() = so_addr;
- stub_symbol->SetByteSize(symbol_stub_byte_size);
- } else {
- // Make a synthetic symbol to describe the trampoline stub
- Mangled stub_symbol_mangled_name(stub_symbol->GetMangled());
- if (sym_idx >= num_syms) {
- sym = symtab->Resize(++num_syms);
- stub_symbol = NULL; // this pointer no longer valid
- }
- sym[sym_idx].SetID(synthetic_sym_id++);
- sym[sym_idx].GetMangled() = stub_symbol_mangled_name;
- if (resolver_addresses.find(symbol_stub_addr) ==
- resolver_addresses.end())
- sym[sym_idx].SetType(eSymbolTypeTrampoline);
- else
- sym[sym_idx].SetType(eSymbolTypeResolver);
- sym[sym_idx].SetIsSynthetic(true);
- sym[sym_idx].GetAddressRef() = so_addr;
- sym[sym_idx].SetByteSize(symbol_stub_byte_size);
- ++sym_idx;
- }
- } else {
- if (log)
- log->Warning("symbol stub referencing symbol table symbol "
- "%u that isn't in our minimal symbol table, "
- "fix this!!!",
- stub_sym_id);
- }
- }
- }
- }
- }
- }
- }
-
- if (!trie_entries.empty()) {
- for (const auto &e : trie_entries) {
- if (e.entry.import_name) {
- // Only add indirect symbols from the Trie entries if we didn't have
- // a N_INDR nlist entry for this already
- if (indirect_symbol_names.find(e.entry.name) ==
- indirect_symbol_names.end()) {
- // Make a synthetic symbol to describe re-exported symbol.
- if (sym_idx >= num_syms)
- sym = symtab->Resize(++num_syms);
- sym[sym_idx].SetID(synthetic_sym_id++);
- sym[sym_idx].GetMangled() = Mangled(e.entry.name);
- sym[sym_idx].SetType(eSymbolTypeReExported);
- sym[sym_idx].SetIsSynthetic(true);
- sym[sym_idx].SetReExportedSymbolName(e.entry.import_name);
- if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) {
- sym[sym_idx].SetReExportedSymbolSharedLibrary(
- dylib_files.GetFileSpecAtIndex(e.entry.other - 1));
- }
- ++sym_idx;
- }
- }
- }
- }
-
- // StreamFile s(stdout, false);
- // s.Printf ("Symbol table before CalculateSymbolSizes():\n");
- // symtab->Dump(&s, NULL, eSortOrderNone);
- // Set symbol byte sizes correctly since mach-o nlist entries don't have
- // sizes
- symtab->CalculateSymbolSizes();
-
- // s.Printf ("Symbol table after CalculateSymbolSizes():\n");
- // symtab->Dump(&s, NULL, eSortOrderNone);
-
- return symtab->GetNumSymbols();
- }
- return 0;
-}
-
-void ObjectFileMachO::Dump(Stream *s) {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- s->Printf("%p: ", static_cast<void *>(this));
- s->Indent();
- if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
- s->PutCString("ObjectFileMachO64");
- else
- s->PutCString("ObjectFileMachO32");
-
- ArchSpec header_arch = GetArchitecture();
-
- *s << ", file = '" << m_file
- << "', triple = " << header_arch.GetTriple().getTriple() << "\n";
-
- SectionList *sections = GetSectionList();
- if (sections)
- sections->Dump(s, NULL, true, UINT32_MAX);
-
- if (m_symtab_ap.get())
- m_symtab_ap->Dump(s, NULL, eSortOrderNone);
- }
-}
-
-bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset,
- lldb_private::UUID &uuid) {
- uint32_t i;
- struct uuid_command load_cmd;
-
- lldb::offset_t offset = lc_offset;
- for (i = 0; i < header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- if (data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- if (load_cmd.cmd == LC_UUID) {
- const uint8_t *uuid_bytes = data.PeekData(offset, 16);
-
- if (uuid_bytes) {
- // OpenCL on Mac OS X uses the same UUID for each of its object files.
- // We pretend these object files have no UUID to prevent crashing.
-
- const uint8_t opencl_uuid[] = {0x8c, 0x8e, 0xb3, 0x9b, 0x3b, 0xa8,
- 0x4b, 0x16, 0xb6, 0xa4, 0x27, 0x63,
- 0xbb, 0x14, 0xf0, 0x0d};
-
- if (!memcmp(uuid_bytes, opencl_uuid, 16))
- return false;
-
- uuid = UUID::fromOptionalData(uuid_bytes, 16);
- return true;
- }
- return false;
- }
- offset = cmd_offset + load_cmd.cmdsize;
- }
- return false;
-}
-
-static llvm::StringRef GetOSName(uint32_t cmd) {
- switch (cmd) {
- case llvm::MachO::LC_VERSION_MIN_IPHONEOS:
- return llvm::Triple::getOSTypeName(llvm::Triple::IOS);
- case llvm::MachO::LC_VERSION_MIN_MACOSX:
- return llvm::Triple::getOSTypeName(llvm::Triple::MacOSX);
- case llvm::MachO::LC_VERSION_MIN_TVOS:
- return llvm::Triple::getOSTypeName(llvm::Triple::TvOS);
- case llvm::MachO::LC_VERSION_MIN_WATCHOS:
- return llvm::Triple::getOSTypeName(llvm::Triple::WatchOS);
- default:
- llvm_unreachable("unexpected LC_VERSION load command");
- }
-}
-
-namespace {
- struct OSEnv {
- llvm::StringRef os_type;
- llvm::StringRef environment;
- OSEnv(uint32_t cmd) {
- switch (cmd) {
- case PLATFORM_MACOS:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::MacOSX);
- return;
- case PLATFORM_IOS:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS);
- return;
- case PLATFORM_TVOS:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS);
- return;
- case PLATFORM_WATCHOS:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS);
- return;
-// NEED_BRIDGEOS_TRIPLE case PLATFORM_BRIDGEOS:
-// NEED_BRIDGEOS_TRIPLE os_type = llvm::Triple::getOSTypeName(llvm::Triple::BridgeOS);
-// NEED_BRIDGEOS_TRIPLE return;
-#if defined (PLATFORM_IOSSIMULATOR) && defined (PLATFORM_TVOSSIMULATOR) && defined (PLATFORM_WATCHOSSIMULATOR)
- case PLATFORM_IOSSIMULATOR:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS);
- environment =
- llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator);
- return;
- case PLATFORM_TVOSSIMULATOR:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS);
- environment =
- llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator);
- return;
- case PLATFORM_WATCHOSSIMULATOR:
- os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS);
- environment =
- llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator);
- return;
-#endif
- default: {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS |
- LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("unsupported platform in LC_BUILD_VERSION");
- }
- }
- }
- };
-
- struct MinOS {
- uint32_t major_version, minor_version, patch_version;
- MinOS(uint32_t version)
- : major_version(version >> 16),
- minor_version((version >> 8) & 0xffu),
- patch_version(version & 0xffu) {}
- };
-} // namespace
-
-ArchSpec
-ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset) {
- ArchSpec arch;
- arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype);
-
- if (arch.IsValid()) {
- llvm::Triple &triple = arch.GetTriple();
-
- // Set OS to an unspecified unknown or a "*" so it can match any OS
- triple.setOS(llvm::Triple::UnknownOS);
- triple.setOSName(llvm::StringRef());
-
- if (header.filetype == MH_PRELOAD) {
- if (header.cputype == CPU_TYPE_ARM) {
- // If this is a 32-bit arm binary, and it's a standalone binary, force
- // the Vendor to Apple so we don't accidentally pick up the generic
- // armv7 ABI at runtime. Apple's armv7 ABI always uses r7 for the
- // frame pointer register; most other armv7 ABIs use a combination of
- // r7 and r11.
- triple.setVendor(llvm::Triple::Apple);
- } else {
- // Set vendor to an unspecified unknown or a "*" so it can match any
- // vendor This is required for correct behavior of EFI debugging on
- // x86_64
- triple.setVendor(llvm::Triple::UnknownVendor);
- triple.setVendorName(llvm::StringRef());
- }
- return arch;
- } else {
- struct load_command load_cmd;
- llvm::SmallString<16> os_name;
- llvm::raw_svector_ostream os(os_name);
-
- // See if there is an LC_VERSION_MIN_* load command that can give
- // us the OS type.
- lldb::offset_t offset = lc_offset;
- for (uint32_t i = 0; i < header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- if (data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- struct version_min_command version_min;
- switch (load_cmd.cmd) {
- case llvm::MachO::LC_VERSION_MIN_IPHONEOS:
- case llvm::MachO::LC_VERSION_MIN_MACOSX:
- case llvm::MachO::LC_VERSION_MIN_TVOS:
- case llvm::MachO::LC_VERSION_MIN_WATCHOS: {
- if (load_cmd.cmdsize != sizeof(version_min))
- break;
- if (data.ExtractBytes(cmd_offset, sizeof(version_min),
- data.GetByteOrder(), &version_min) == 0)
- break;
- MinOS min_os(version_min.version);
- os << GetOSName(load_cmd.cmd) << min_os.major_version << '.'
- << min_os.minor_version << '.' << min_os.patch_version;
- triple.setOSName(os.str());
- return arch;
- }
- default:
- break;
- }
-
- offset = cmd_offset + load_cmd.cmdsize;
- }
-
- // See if there is an LC_BUILD_VERSION load command that can give
- // us the OS type.
-
- offset = lc_offset;
- for (uint32_t i = 0; i < header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- if (data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
- do {
- if (load_cmd.cmd == llvm::MachO::LC_BUILD_VERSION) {
- struct build_version_command build_version;
- if (load_cmd.cmdsize < sizeof(build_version)) {
- // Malformed load command.
- break;
- }
- if (data.ExtractBytes(cmd_offset, sizeof(build_version),
- data.GetByteOrder(), &build_version) == 0)
- break;
- MinOS min_os(build_version.minos);
- OSEnv os_env(build_version.platform);
- if (os_env.os_type.empty())
- break;
- os << os_env.os_type << min_os.major_version << '.'
- << min_os.minor_version << '.' << min_os.patch_version;
- triple.setOSName(os.str());
- if (!os_env.environment.empty())
- triple.setEnvironmentName(os_env.environment);
- return arch;
- }
- } while (0);
- offset = cmd_offset + load_cmd.cmdsize;
- }
-
- if (header.filetype != MH_KEXT_BUNDLE) {
- // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT
- // so lets not say our Vendor is Apple, leave it as an unspecified
- // unknown
- triple.setVendor(llvm::Triple::UnknownVendor);
- triple.setVendorName(llvm::StringRef());
- }
- }
- }
- return arch;
-}
-
-bool ObjectFileMachO::GetUUID(lldb_private::UUID *uuid) {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- return GetUUID(m_header, m_data, offset, *uuid);
- }
- return false;
-}
-
-uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
- uint32_t count = 0;
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct load_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- std::vector<std::string> rpath_paths;
- std::vector<std::string> rpath_relative_paths;
- std::vector<std::string> at_exec_relative_paths;
- uint32_t i;
- for (i = 0; i < m_header.ncmds; ++i) {
- const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- switch (load_cmd.cmd) {
- case LC_RPATH:
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- case LC_REEXPORT_DYLIB:
- case LC_LOAD_DYLINKER:
- case LC_LOADFVMLIB:
- case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
- if (path) {
- if (load_cmd.cmd == LC_RPATH)
- rpath_paths.push_back(path);
- else {
- if (path[0] == '@') {
- if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
- rpath_relative_paths.push_back(path + strlen("@rpath"));
- else if (strncmp(path, "@executable_path",
- strlen("@executable_path")) == 0)
- at_exec_relative_paths.push_back(path
- + strlen("@executable_path"));
- } else {
- FileSpec file_spec(path);
- if (files.AppendIfUnique(file_spec))
- count++;
- }
- }
- }
- } break;
-
- default:
- break;
- }
- offset = cmd_offset + load_cmd.cmdsize;
- }
-
- FileSpec this_file_spec(m_file);
- FileSystem::Instance().Resolve(this_file_spec);
-
- if (!rpath_paths.empty()) {
- // Fixup all LC_RPATH values to be absolute paths
- std::string loader_path("@loader_path");
- std::string executable_path("@executable_path");
- for (auto &rpath : rpath_paths) {
- if (rpath.find(loader_path) == 0) {
- rpath.erase(0, loader_path.size());
- rpath.insert(0, this_file_spec.GetDirectory().GetCString());
- } else if (rpath.find(executable_path) == 0) {
- rpath.erase(0, executable_path.size());
- rpath.insert(0, this_file_spec.GetDirectory().GetCString());
- }
- }
-
- for (const auto &rpath_relative_path : rpath_relative_paths) {
- for (const auto &rpath : rpath_paths) {
- std::string path = rpath;
- path += rpath_relative_path;
- // It is OK to resolve this path because we must find a file on disk
- // for us to accept it anyway if it is rpath relative.
- FileSpec file_spec(path);
- FileSystem::Instance().Resolve(file_spec);
- if (FileSystem::Instance().Exists(file_spec) &&
- files.AppendIfUnique(file_spec)) {
- count++;
- break;
- }
- }
- }
- }
-
- // We may have @executable_paths but no RPATHS. Figure those out here.
- // Only do this if this object file is the executable. We have no way to
- // get back to the actual executable otherwise, so we won't get the right
- // path.
- if (!at_exec_relative_paths.empty() && CalculateType() == eTypeExecutable) {
- FileSpec exec_dir = this_file_spec.CopyByRemovingLastPathComponent();
- for (const auto &at_exec_relative_path : at_exec_relative_paths) {
- FileSpec file_spec =
- exec_dir.CopyByAppendingPathComponent(at_exec_relative_path);
- if (FileSystem::Instance().Exists(file_spec) &&
- files.AppendIfUnique(file_spec))
- count++;
- }
- }
- }
- return count;
-}
-
-lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
- // If the object file is not an executable it can't hold the entry point.
- // m_entry_point_address is initialized to an invalid address, so we can just
- // return that. If m_entry_point_address is valid it means we've found it
- // already, so return the cached value.
-
- if (!IsExecutable() || m_entry_point_address.IsValid())
- return m_entry_point_address;
-
- // Otherwise, look for the UnixThread or Thread command. The data for the
- // Thread command is given in /usr/include/mach-o.h, but it is basically:
- //
- // uint32_t flavor - this is the flavor argument you would pass to
- // thread_get_state
- // uint32_t count - this is the count of longs in the thread state data
- // struct XXX_thread_state state - this is the structure from
- // <machine/thread_status.h> corresponding to the flavor.
- // <repeat this trio>
- //
- // So we just keep reading the various register flavors till we find the GPR
- // one, then read the PC out of there.
- // FIXME: We will need to have a "RegisterContext data provider" class at some
- // point that can get all the registers
- // out of data in this form & attach them to a given thread. That should
- // underlie the MacOS X User process plugin, and we'll also need it for the
- // MacOS X Core File process plugin. When we have that we can also use it
- // here.
- //
- // For now we hard-code the offsets and flavors we need:
- //
- //
-
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct load_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t i;
- lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
- bool done = false;
-
- for (i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- switch (load_cmd.cmd) {
- case LC_UNIXTHREAD:
- case LC_THREAD: {
- while (offset < cmd_offset + load_cmd.cmdsize) {
- uint32_t flavor = m_data.GetU32(&offset);
- uint32_t count = m_data.GetU32(&offset);
- if (count == 0) {
- // We've gotten off somehow, log and exit;
- return m_entry_point_address;
- }
-
- switch (m_header.cputype) {
- case llvm::MachO::CPU_TYPE_ARM:
- if (flavor == 1 ||
- flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 from
- // mach/arm/thread_status.h
- {
- offset += 60; // This is the offset of pc in the GPR thread state
- // data structure.
- start_address = m_data.GetU32(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_ARM64:
- if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h
- {
- offset += 256; // This is the offset of pc in the GPR thread state
- // data structure.
- start_address = m_data.GetU64(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_I386:
- if (flavor ==
- 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
- {
- offset += 40; // This is the offset of eip in the GPR thread state
- // data structure.
- start_address = m_data.GetU32(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_X86_64:
- if (flavor ==
- 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
- {
- offset += 16 * 8; // This is the offset of rip in the GPR thread
- // state data structure.
- start_address = m_data.GetU64(&offset);
- done = true;
- }
- break;
- default:
- return m_entry_point_address;
- }
- // Haven't found the GPR flavor yet, skip over the data for this
- // flavor:
- if (done)
- break;
- offset += count * 4;
- }
- } break;
- case LC_MAIN: {
- ConstString text_segment_name("__TEXT");
- uint64_t entryoffset = m_data.GetU64(&offset);
- SectionSP text_segment_sp =
- GetSectionList()->FindSectionByName(text_segment_name);
- if (text_segment_sp) {
- done = true;
- start_address = text_segment_sp->GetFileAddress() + entryoffset;
- }
- } break;
-
- default:
- break;
- }
- if (done)
- break;
-
- // Go to the next load command:
- offset = cmd_offset + load_cmd.cmdsize;
- }
-
- if (start_address != LLDB_INVALID_ADDRESS) {
- // We got the start address from the load commands, so now resolve that
- // address in the sections of this ObjectFile:
- if (!m_entry_point_address.ResolveAddressUsingFileSections(
- start_address, GetSectionList())) {
- m_entry_point_address.Clear();
- }
- } else {
- // We couldn't read the UnixThread load command - maybe it wasn't there.
- // As a fallback look for the "start" symbol in the main executable.
-
- ModuleSP module_sp(GetModule());
-
- if (module_sp) {
- SymbolContextList contexts;
- SymbolContext context;
- if (module_sp->FindSymbolsWithNameAndType(ConstString("start"),
- eSymbolTypeCode, contexts)) {
- if (contexts.GetContextAtIndex(0, context))
- m_entry_point_address = context.symbol->GetAddress();
- }
- }
- }
- }
-
- return m_entry_point_address;
-}
-
-lldb_private::Address ObjectFileMachO::GetBaseAddress() {
- lldb_private::Address header_addr;
- SectionList *section_list = GetSectionList();
- if (section_list) {
- SectionSP text_segment_sp(
- section_list->FindSectionByName(GetSegmentNameTEXT()));
- if (text_segment_sp) {
- header_addr.SetSection(text_segment_sp);
- header_addr.SetOffset(0);
- }
- }
- return header_addr;
-}
-
-uint32_t ObjectFileMachO::GetNumThreadContexts() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (!m_thread_context_offsets_valid) {
- m_thread_context_offsets_valid = true;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- FileRangeArray::Entry file_range;
- thread_command thread_cmd;
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL)
- break;
-
- if (thread_cmd.cmd == LC_THREAD) {
- file_range.SetRangeBase(offset);
- file_range.SetByteSize(thread_cmd.cmdsize - 8);
- m_thread_context_offsets.Append(file_range);
- }
- offset = cmd_offset + thread_cmd.cmdsize;
- }
- }
- }
- return m_thread_context_offsets.GetSize();
-}
-
-std::string ObjectFileMachO::GetIdentifierString() {
- std::string result;
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
-
- // First, look over the load commands for an LC_NOTE load command with
- // data_owner string "kern ver str" & use that if found.
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const uint32_t cmd_offset = offset;
- load_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == LC_NOTE)
- {
- char data_owner[17];
- m_data.CopyData (offset, 16, data_owner);
- data_owner[16] = '\0';
- offset += 16;
- uint64_t fileoff = m_data.GetU64_unchecked (&offset);
- uint64_t size = m_data.GetU64_unchecked (&offset);
-
- // "kern ver str" has a uint32_t version and then a nul terminated
- // c-string.
- if (strcmp ("kern ver str", data_owner) == 0)
- {
- offset = fileoff;
- uint32_t version;
- if (m_data.GetU32 (&offset, &version, 1) != nullptr)
- {
- if (version == 1)
- {
- uint32_t strsize = size - sizeof (uint32_t);
- char *buf = (char*) malloc (strsize);
- if (buf)
- {
- m_data.CopyData (offset, strsize, buf);
- buf[strsize - 1] = '\0';
- result = buf;
- if (buf)
- free (buf);
- return result;
- }
- }
- }
- }
- }
- offset = cmd_offset + lc.cmdsize;
- }
-
- // Second, make a pass over the load commands looking for an obsolete
- // LC_IDENT load command.
- offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const uint32_t cmd_offset = offset;
- struct ident_command ident_command;
- if (m_data.GetU32(&offset, &ident_command, 2) == NULL)
- break;
- if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) {
- char *buf = (char *) malloc (ident_command.cmdsize);
- if (buf != nullptr
- && m_data.CopyData (offset, ident_command.cmdsize, buf) == ident_command.cmdsize) {
- buf[ident_command.cmdsize - 1] = '\0';
- result = buf;
- }
- if (buf)
- free (buf);
- }
- offset = cmd_offset + ident_command.cmdsize;
- }
-
- }
- return result;
-}
-
-bool ObjectFileMachO::GetCorefileMainBinaryInfo (addr_t &address, UUID &uuid) {
- address = LLDB_INVALID_ADDRESS;
- uuid.Clear();
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const uint32_t cmd_offset = offset;
- load_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == LC_NOTE)
- {
- char data_owner[17];
- memset (data_owner, 0, sizeof (data_owner));
- m_data.CopyData (offset, 16, data_owner);
- offset += 16;
- uint64_t fileoff = m_data.GetU64_unchecked (&offset);
- uint64_t size = m_data.GetU64_unchecked (&offset);
-
- // "main bin spec" (main binary specification) data payload is
- // formatted:
- // uint32_t version [currently 1]
- // uint32_t type [0 == unspecified, 1 == kernel, 2 == user process]
- // uint64_t address [ UINT64_MAX if address not specified ]
- // uuid_t uuid [ all zero's if uuid not specified ]
- // uint32_t log2_pagesize [ process page size in log base 2, e.g. 4k pages are 12. 0 for unspecified ]
-
- if (strcmp ("main bin spec", data_owner) == 0 && size >= 32)
- {
- offset = fileoff;
- uint32_t version;
- if (m_data.GetU32 (&offset, &version, 1) != nullptr && version == 1)
- {
- uint32_t type = 0;
- uuid_t raw_uuid;
- memset (raw_uuid, 0, sizeof (uuid_t));
-
- if (m_data.GetU32(&offset, &type, 1) &&
- m_data.GetU64(&offset, &address, 1) &&
- m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
- uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t));
- return true;
- }
- }
- }
- }
- offset = cmd_offset + lc.cmdsize;
- }
- }
- return false;
-}
-
-lldb::RegisterContextSP
-ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
- lldb_private::Thread &thread) {
- lldb::RegisterContextSP reg_ctx_sp;
-
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (!m_thread_context_offsets_valid)
- GetNumThreadContexts();
-
- const FileRangeArray::Entry *thread_context_file_range =
- m_thread_context_offsets.GetEntryAtIndex(idx);
- if (thread_context_file_range) {
-
- DataExtractor data(m_data, thread_context_file_range->GetRangeBase(),
- thread_context_file_range->GetByteSize());
-
- switch (m_header.cputype) {
- case llvm::MachO::CPU_TYPE_ARM64:
- reg_ctx_sp.reset(new RegisterContextDarwin_arm64_Mach(thread, data));
- break;
-
- case llvm::MachO::CPU_TYPE_ARM:
- reg_ctx_sp.reset(new RegisterContextDarwin_arm_Mach(thread, data));
- break;
-
- case llvm::MachO::CPU_TYPE_I386:
- reg_ctx_sp.reset(new RegisterContextDarwin_i386_Mach(thread, data));
- break;
-
- case llvm::MachO::CPU_TYPE_X86_64:
- reg_ctx_sp.reset(new RegisterContextDarwin_x86_64_Mach(thread, data));
- break;
- }
- }
- }
- return reg_ctx_sp;
-}
-
-ObjectFile::Type ObjectFileMachO::CalculateType() {
- switch (m_header.filetype) {
- case MH_OBJECT: // 0x1u
- if (GetAddressByteSize() == 4) {
- // 32 bit kexts are just object files, but they do have a valid
- // UUID load command.
- UUID uuid;
- if (GetUUID(&uuid)) {
- // this checking for the UUID load command is not enough we could
- // eventually look for the symbol named "OSKextGetCurrentIdentifier" as
- // this is required of kexts
- if (m_strata == eStrataInvalid)
- m_strata = eStrataKernel;
- return eTypeSharedLibrary;
- }
- }
- return eTypeObjectFile;
-
- case MH_EXECUTE:
- return eTypeExecutable; // 0x2u
- case MH_FVMLIB:
- return eTypeSharedLibrary; // 0x3u
- case MH_CORE:
- return eTypeCoreFile; // 0x4u
- case MH_PRELOAD:
- return eTypeSharedLibrary; // 0x5u
- case MH_DYLIB:
- return eTypeSharedLibrary; // 0x6u
- case MH_DYLINKER:
- return eTypeDynamicLinker; // 0x7u
- case MH_BUNDLE:
- return eTypeSharedLibrary; // 0x8u
- case MH_DYLIB_STUB:
- return eTypeStubLibrary; // 0x9u
- case MH_DSYM:
- return eTypeDebugInfo; // 0xAu
- case MH_KEXT_BUNDLE:
- return eTypeSharedLibrary; // 0xBu
- default:
- break;
- }
- return eTypeUnknown;
-}
-
-ObjectFile::Strata ObjectFileMachO::CalculateStrata() {
- switch (m_header.filetype) {
- case MH_OBJECT: // 0x1u
- {
- // 32 bit kexts are just object files, but they do have a valid
- // UUID load command.
- UUID uuid;
- if (GetUUID(&uuid)) {
- // this checking for the UUID load command is not enough we could
- // eventually look for the symbol named "OSKextGetCurrentIdentifier" as
- // this is required of kexts
- if (m_type == eTypeInvalid)
- m_type = eTypeSharedLibrary;
-
- return eStrataKernel;
- }
- }
- return eStrataUnknown;
-
- case MH_EXECUTE: // 0x2u
- // Check for the MH_DYLDLINK bit in the flags
- if (m_header.flags & MH_DYLDLINK) {
- return eStrataUser;
- } else {
- SectionList *section_list = GetSectionList();
- if (section_list) {
- static ConstString g_kld_section_name("__KLD");
- if (section_list->FindSectionByName(g_kld_section_name))
- return eStrataKernel;
- }
- }
- return eStrataRawImage;
-
- case MH_FVMLIB:
- return eStrataUser; // 0x3u
- case MH_CORE:
- return eStrataUnknown; // 0x4u
- case MH_PRELOAD:
- return eStrataRawImage; // 0x5u
- case MH_DYLIB:
- return eStrataUser; // 0x6u
- case MH_DYLINKER:
- return eStrataUser; // 0x7u
- case MH_BUNDLE:
- return eStrataUser; // 0x8u
- case MH_DYLIB_STUB:
- return eStrataUser; // 0x9u
- case MH_DSYM:
- return eStrataUnknown; // 0xAu
- case MH_KEXT_BUNDLE:
- return eStrataKernel; // 0xBu
- default:
- break;
- }
- return eStrataUnknown;
-}
-
-llvm::VersionTuple ObjectFileMachO::GetVersion() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct dylib_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t version_cmd = 0;
- uint64_t version = 0;
- uint32_t i;
- for (i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- if (load_cmd.cmd == LC_ID_DYLIB) {
- if (version_cmd == 0) {
- version_cmd = load_cmd.cmd;
- if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL)
- break;
- version = load_cmd.dylib.current_version;
- }
- break; // Break for now unless there is another more complete version
- // number load command in the future.
- }
- offset = cmd_offset + load_cmd.cmdsize;
- }
-
- if (version_cmd == LC_ID_DYLIB) {
- unsigned major = (version & 0xFFFF0000ull) >> 16;
- unsigned minor = (version & 0x0000FF00ull) >> 8;
- unsigned subminor = (version & 0x000000FFull);
- return llvm::VersionTuple(major, minor, subminor);
- }
- }
- return llvm::VersionTuple();
-}
-
-ArchSpec ObjectFileMachO::GetArchitecture() {
- ModuleSP module_sp(GetModule());
- ArchSpec arch;
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
-
- return GetArchitecture(m_header, m_data,
- MachHeaderSizeFromMagic(m_header.magic));
- }
- return arch;
-}
-
-void ObjectFileMachO::GetProcessSharedCacheUUID(Process *process, addr_t &base_addr, UUID &uuid) {
- uuid.Clear();
- base_addr = LLDB_INVALID_ADDRESS;
- if (process && process->GetDynamicLoader()) {
- DynamicLoader *dl = process->GetDynamicLoader();
- LazyBool using_shared_cache;
- LazyBool private_shared_cache;
- dl->GetSharedCacheInformation(base_addr, uuid, using_shared_cache,
- private_shared_cache);
- }
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("inferior process shared cache has a UUID of %s, base address 0x%" PRIx64 , uuid.GetAsString().c_str(), base_addr);
-}
-
-// From dyld SPI header dyld_process_info.h
-typedef void *dyld_process_info;
-struct lldb_copy__dyld_process_cache_info {
- uuid_t cacheUUID; // UUID of cache used by process
- uint64_t cacheBaseAddress; // load address of dyld shared cache
- bool noCache; // process is running without a dyld cache
- bool privateCache; // process is using a private copy of its dyld cache
-};
-
-// #including mach/mach.h pulls in machine.h & CPU_TYPE_ARM etc conflicts with llvm
-// enum definitions llvm::MachO::CPU_TYPE_ARM turning them into compile errors.
-// So we need to use the actual underlying types of task_t and kern_return_t
-// below.
-extern "C" unsigned int /*task_t*/ mach_task_self();
-
-void ObjectFileMachO::GetLLDBSharedCacheUUID(addr_t &base_addr, UUID &uuid) {
- uuid.Clear();
- base_addr = LLDB_INVALID_ADDRESS;
-
-#if defined(__APPLE__) && \
- (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
- uint8_t *(*dyld_get_all_image_infos)(void);
- dyld_get_all_image_infos =
- (uint8_t * (*)())dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos");
- if (dyld_get_all_image_infos) {
- uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos();
- if (dyld_all_image_infos_address) {
- uint32_t *version = (uint32_t *)
- dyld_all_image_infos_address; // version <mach-o/dyld_images.h>
- if (*version >= 13) {
- uuid_t *sharedCacheUUID_address = 0;
- int wordsize = sizeof(uint8_t *);
- if (wordsize == 8) {
- sharedCacheUUID_address =
- (uuid_t *)((uint8_t *)dyld_all_image_infos_address +
- 160); // sharedCacheUUID <mach-o/dyld_images.h>
- if (*version >= 15)
- base_addr = *(uint64_t *) ((uint8_t *) dyld_all_image_infos_address
- + 176); // sharedCacheBaseAddress <mach-o/dyld_images.h>
- } else {
- sharedCacheUUID_address =
- (uuid_t *)((uint8_t *)dyld_all_image_infos_address +
- 84); // sharedCacheUUID <mach-o/dyld_images.h>
- if (*version >= 15) {
- base_addr = 0;
- base_addr = *(uint32_t *) ((uint8_t *) dyld_all_image_infos_address
- + 100); // sharedCacheBaseAddress <mach-o/dyld_images.h>
- }
- }
- uuid = UUID::fromOptionalData(sharedCacheUUID_address, sizeof(uuid_t));
- }
- }
- } else {
- // Exists in macOS 10.12 and later, iOS 10.0 and later - dyld SPI
- dyld_process_info (*dyld_process_info_create)(unsigned int /* task_t */ task, uint64_t timestamp, unsigned int /*kern_return_t*/ *kernelError);
- void (*dyld_process_info_get_cache)(void *info, void *cacheInfo);
- void (*dyld_process_info_release)(dyld_process_info info);
-
- dyld_process_info_create = (void *(*)(unsigned int /* task_t */, uint64_t, unsigned int /*kern_return_t*/ *))
- dlsym (RTLD_DEFAULT, "_dyld_process_info_create");
- dyld_process_info_get_cache = (void (*)(void *, void *))
- dlsym (RTLD_DEFAULT, "_dyld_process_info_get_cache");
- dyld_process_info_release = (void (*)(void *))
- dlsym (RTLD_DEFAULT, "_dyld_process_info_release");
-
- if (dyld_process_info_create && dyld_process_info_get_cache) {
- unsigned int /*kern_return_t */ kern_ret;
- dyld_process_info process_info = dyld_process_info_create(::mach_task_self(), 0, &kern_ret);
- if (process_info) {
- struct lldb_copy__dyld_process_cache_info sc_info;
- memset (&sc_info, 0, sizeof (struct lldb_copy__dyld_process_cache_info));
- dyld_process_info_get_cache (process_info, &sc_info);
- if (sc_info.cacheBaseAddress != 0) {
- base_addr = sc_info.cacheBaseAddress;
- uuid = UUID::fromOptionalData(sc_info.cacheUUID, sizeof(uuid_t));
- }
- dyld_process_info_release (process_info);
- }
- }
- }
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_PROCESS));
- if (log && uuid.IsValid())
- log->Printf("lldb's in-memory shared cache has a UUID of %s base address of 0x%" PRIx64, uuid.GetAsString().c_str(), base_addr);
-#endif
-}
-
-llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() {
- if (!m_min_os_version) {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
-
- version_min_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) {
- if (m_data.GetU32(&offset, &lc.version,
- (sizeof(lc) / sizeof(uint32_t)) - 2)) {
- const uint32_t xxxx = lc.version >> 16;
- const uint32_t yy = (lc.version >> 8) & 0xffu;
- const uint32_t zz = lc.version & 0xffu;
- if (xxxx) {
- m_min_os_version = llvm::VersionTuple(xxxx, yy, zz);
- break;
- }
- }
- } else if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) {
- // struct build_version_command {
- // uint32_t cmd; /* LC_BUILD_VERSION */
- // uint32_t cmdsize; /* sizeof(struct build_version_command) plus */
- // /* ntools * sizeof(struct build_tool_version) */
- // uint32_t platform; /* platform */
- // uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
- // uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
- // uint32_t ntools; /* number of tool entries following this */
- // };
-
- offset += 4; // skip platform
- uint32_t minos = m_data.GetU32(&offset);
-
- const uint32_t xxxx = minos >> 16;
- const uint32_t yy = (minos >> 8) & 0xffu;
- const uint32_t zz = minos & 0xffu;
- if (xxxx) {
- m_min_os_version = llvm::VersionTuple(xxxx, yy, zz);
- break;
- }
- }
-
- offset = load_cmd_offset + lc.cmdsize;
- }
-
- if (!m_min_os_version) {
- // Set version to an empty value so we don't keep trying to
- m_min_os_version = llvm::VersionTuple();
- }
- }
-
- return *m_min_os_version;
-}
-
-uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions,
- uint32_t num_versions) {
- if (m_sdk_versions.empty()) {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- bool success = false;
- for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
-
- version_min_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS ||
- lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) {
- if (m_data.GetU32(&offset, &lc.version,
- (sizeof(lc) / sizeof(uint32_t)) - 2)) {
- const uint32_t xxxx = lc.sdk >> 16;
- const uint32_t yy = (lc.sdk >> 8) & 0xffu;
- const uint32_t zz = lc.sdk & 0xffu;
- if (xxxx) {
- m_sdk_versions.push_back(xxxx);
- m_sdk_versions.push_back(yy);
- m_sdk_versions.push_back(zz);
- success = true;
- } else {
- GetModule()->ReportWarning(
- "minimum OS version load command with invalid (0) version found.");
- }
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
-
- if (!success) {
- offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i = 0; !success && i < m_header.ncmds; ++i) {
- const lldb::offset_t load_cmd_offset = offset;
-
- version_min_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) {
- // struct build_version_command {
- // uint32_t cmd; /* LC_BUILD_VERSION */
- // uint32_t cmdsize; /* sizeof(struct
- // build_version_command) plus */
- // /* ntools * sizeof(struct
- // build_tool_version) */
- // uint32_t platform; /* platform */
- // uint32_t minos; /* X.Y.Z is encoded in nibbles
- // xxxx.yy.zz */ uint32_t sdk; /* X.Y.Z is encoded
- // in nibbles xxxx.yy.zz */ uint32_t ntools; /* number
- // of tool entries following this */
- // };
-
- offset += 4; // skip platform
- uint32_t minos = m_data.GetU32(&offset);
-
- const uint32_t xxxx = minos >> 16;
- const uint32_t yy = (minos >> 8) & 0xffu;
- const uint32_t zz = minos & 0xffu;
- if (xxxx) {
- m_sdk_versions.push_back(xxxx);
- m_sdk_versions.push_back(yy);
- m_sdk_versions.push_back(zz);
- success = true;
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
- }
-
- if (!success) {
- // Push an invalid value so we don't try to find
- // the version # again on the next call to this
- // method.
- m_sdk_versions.push_back(UINT32_MAX);
- }
- }
-
- // Legitimate version numbers will have 3 entries pushed
- // on to m_sdk_versions. If we only have one value, it's
- // the sentinel value indicating that this object file
- // does not have a valid minimum os version #.
- if (m_sdk_versions.size() > 1) {
- if (versions != NULL && num_versions > 0) {
- for (size_t i = 0; i < num_versions; ++i) {
- if (i < m_sdk_versions.size())
- versions[i] = m_sdk_versions[i];
- else
- versions[i] = 0;
- }
- }
- return m_sdk_versions.size();
- }
- // Call the superclasses version that will empty out the data
- return ObjectFile::GetSDKVersion(versions, num_versions);
-}
-
-bool ObjectFileMachO::GetIsDynamicLinkEditor() {
- return m_header.filetype == llvm::MachO::MH_DYLINKER;
-}
-
-bool ObjectFileMachO::AllowAssemblyEmulationUnwindPlans() {
- return m_allow_assembly_emulation_unwind_plans;
-}
-
-//------------------------------------------------------------------
-// PluginInterface protocol
-//------------------------------------------------------------------
-lldb_private::ConstString ObjectFileMachO::GetPluginName() {
- return GetPluginNameStatic();
-}
-
-uint32_t ObjectFileMachO::GetPluginVersion() { return 1; }
-
-Section *ObjectFileMachO::GetMachHeaderSection() {
- // Find the first address of the mach header which is the first non-zero file
- // sized section whose file offset is zero. This is the base file address of
- // the mach-o file which can be subtracted from the vmaddr of the other
- // segments found in memory and added to the load address
- ModuleSP module_sp = GetModule();
- if (!module_sp)
- return nullptr;
- SectionList *section_list = GetSectionList();
- if (!section_list)
- return nullptr;
- const size_t num_sections = section_list->GetSize();
- for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
- Section *section = section_list->GetSectionAtIndex(sect_idx).get();
- if (section->GetFileOffset() == 0 && SectionIsLoadable(section))
- return section;
- }
- return nullptr;
-}
-
-bool ObjectFileMachO::SectionIsLoadable(const Section *section) {
- if (!section)
- return false;
- const bool is_dsym = (m_header.filetype == MH_DSYM);
- if (section->GetFileSize() == 0 && !is_dsym)
- return false;
- if (section->IsThreadSpecific())
- return false;
- if (GetModule().get() != section->GetModule().get())
- return false;
- // Be careful with __LINKEDIT and __DWARF segments
- if (section->GetName() == GetSegmentNameLINKEDIT() ||
- section->GetName() == GetSegmentNameDWARF()) {
- // Only map __LINKEDIT and __DWARF if we have an in memory image and
- // this isn't a kernel binary like a kext or mach_kernel.
- const bool is_memory_image = (bool)m_process_wp.lock();
- const Strata strata = GetStrata();
- if (is_memory_image == false || strata == eStrataKernel)
- return false;
- }
- return true;
-}
-
-lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage(
- lldb::addr_t header_load_address, const Section *header_section,
- const Section *section) {
- ModuleSP module_sp = GetModule();
- if (module_sp && header_section && section &&
- header_load_address != LLDB_INVALID_ADDRESS) {
- lldb::addr_t file_addr = header_section->GetFileAddress();
- if (file_addr != LLDB_INVALID_ADDRESS && SectionIsLoadable(section))
- return section->GetFileAddress() - file_addr + header_load_address;
- }
- return LLDB_INVALID_ADDRESS;
-}
-
-bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value,
- bool value_is_offset) {
- ModuleSP module_sp = GetModule();
- if (module_sp) {
- size_t num_loaded_sections = 0;
- SectionList *section_list = GetSectionList();
- if (section_list) {
- const size_t num_sections = section_list->GetSize();
-
- if (value_is_offset) {
- // "value" is an offset to apply to each top level segment
- for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
- // Iterate through the object file sections to find all of the
- // sections that size on disk (to avoid __PAGEZERO) and load them
- SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
- if (SectionIsLoadable(section_sp.get()))
- if (target.GetSectionLoadList().SetSectionLoadAddress(
- section_sp, section_sp->GetFileAddress() + value))
- ++num_loaded_sections;
- }
- } else {
- // "value" is the new base address of the mach_header, adjust each
- // section accordingly
-
- Section *mach_header_section = GetMachHeaderSection();
- if (mach_header_section) {
- for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
- SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
-
- lldb::addr_t section_load_addr =
- CalculateSectionLoadAddressForMemoryImage(
- value, mach_header_section, section_sp.get());
- if (section_load_addr != LLDB_INVALID_ADDRESS) {
- if (target.GetSectionLoadList().SetSectionLoadAddress(
- section_sp, section_load_addr))
- ++num_loaded_sections;
- }
- }
- }
- }
- }
- return num_loaded_sections > 0;
- }
- return false;
-}
-
-bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
- const FileSpec &outfile, Status &error) {
- if (process_sp) {
- Target &target = process_sp->GetTarget();
- const ArchSpec target_arch = target.GetArchitecture();
- const llvm::Triple &target_triple = target_arch.GetTriple();
- if (target_triple.getVendor() == llvm::Triple::Apple &&
- (target_triple.getOS() == llvm::Triple::MacOSX ||
- target_triple.getOS() == llvm::Triple::IOS ||
- target_triple.getOS() == llvm::Triple::WatchOS ||
- target_triple.getOS() == llvm::Triple::TvOS)) {
- // NEED_BRIDGEOS_TRIPLE target_triple.getOS() == llvm::Triple::BridgeOS)) {
- bool make_core = false;
- switch (target_arch.GetMachine()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- make_core = true;
- break;
- default:
- error.SetErrorStringWithFormat("unsupported core architecture: %s",
- target_triple.str().c_str());
- break;
- }
-
- if (make_core) {
- std::vector<segment_command_64> segment_load_commands;
- // uint32_t range_info_idx = 0;
- MemoryRegionInfo range_info;
- Status range_error = process_sp->GetMemoryRegionInfo(0, range_info);
- const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
- const ByteOrder byte_order = target_arch.GetByteOrder();
- if (range_error.Success()) {
- while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) {
- const addr_t addr = range_info.GetRange().GetRangeBase();
- const addr_t size = range_info.GetRange().GetByteSize();
-
- if (size == 0)
- break;
-
- // Calculate correct protections
- uint32_t prot = 0;
- if (range_info.GetReadable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_READ;
- if (range_info.GetWritable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_WRITE;
- if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_EXECUTE;
-
- // printf ("[%3u] [0x%16.16" PRIx64 " -
- // 0x%16.16" PRIx64 ") %c%c%c\n",
- // range_info_idx,
- // addr,
- // size,
- // (prot & VM_PROT_READ ) ? 'r' :
- // '-',
- // (prot & VM_PROT_WRITE ) ? 'w' :
- // '-',
- // (prot & VM_PROT_EXECUTE) ? 'x' :
- // '-');
-
- if (prot != 0) {
- uint32_t cmd_type = LC_SEGMENT_64;
- uint32_t segment_size = sizeof(segment_command_64);
- if (addr_byte_size == 4) {
- cmd_type = LC_SEGMENT;
- segment_size = sizeof(segment_command);
- }
- segment_command_64 segment = {
- cmd_type, // uint32_t cmd;
- segment_size, // uint32_t cmdsize;
- {0}, // char segname[16];
- addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O
- size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O
- 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
- size, // uint64_t filesize; // uint32_t for 32-bit Mach-O
- prot, // uint32_t maxprot;
- prot, // uint32_t initprot;
- 0, // uint32_t nsects;
- 0}; // uint32_t flags;
- segment_load_commands.push_back(segment);
- } else {
- // No protections and a size of 1 used to be returned from old
- // debugservers when we asked about a region that was past the
- // last memory region and it indicates the end...
- if (size == 1)
- break;
- }
-
- range_error = process_sp->GetMemoryRegionInfo(
- range_info.GetRange().GetRangeEnd(), range_info);
- if (range_error.Fail())
- break;
- }
-
- StreamString buffer(Stream::eBinary, addr_byte_size, byte_order);
-
- mach_header_64 mach_header;
- if (addr_byte_size == 8) {
- mach_header.magic = MH_MAGIC_64;
- } else {
- mach_header.magic = MH_MAGIC;
- }
- mach_header.cputype = target_arch.GetMachOCPUType();
- mach_header.cpusubtype = target_arch.GetMachOCPUSubType();
- mach_header.filetype = MH_CORE;
- mach_header.ncmds = segment_load_commands.size();
- mach_header.flags = 0;
- mach_header.reserved = 0;
- ThreadList &thread_list = process_sp->GetThreadList();
- const uint32_t num_threads = thread_list.GetSize();
-
- // Make an array of LC_THREAD data items. Each one contains the
- // contents of the LC_THREAD load command. The data doesn't contain
- // the load command + load command size, we will add the load command
- // and load command size as we emit the data.
- std::vector<StreamString> LC_THREAD_datas(num_threads);
- for (auto &LC_THREAD_data : LC_THREAD_datas) {
- LC_THREAD_data.GetFlags().Set(Stream::eBinary);
- LC_THREAD_data.SetAddressByteSize(addr_byte_size);
- LC_THREAD_data.SetByteOrder(byte_order);
- }
- for (uint32_t thread_idx = 0; thread_idx < num_threads;
- ++thread_idx) {
- ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
- if (thread_sp) {
- switch (mach_header.cputype) {
- case llvm::MachO::CPU_TYPE_ARM64:
- RegisterContextDarwin_arm64_Mach::Create_LC_THREAD(
- thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_ARM:
- RegisterContextDarwin_arm_Mach::Create_LC_THREAD(
- thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_I386:
- RegisterContextDarwin_i386_Mach::Create_LC_THREAD(
- thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_X86_64:
- RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD(
- thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
- }
- }
- }
-
- // The size of the load command is the size of the segments...
- if (addr_byte_size == 8) {
- mach_header.sizeofcmds = segment_load_commands.size() *
- sizeof(struct segment_command_64);
- } else {
- mach_header.sizeofcmds =
- segment_load_commands.size() * sizeof(struct segment_command);
- }
-
- // and the size of all LC_THREAD load command
- for (const auto &LC_THREAD_data : LC_THREAD_datas) {
- ++mach_header.ncmds;
- mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize();
- }
-
- printf("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x "
- "0x%8.8x 0x%8.8x\n",
- mach_header.magic, mach_header.cputype, mach_header.cpusubtype,
- mach_header.filetype, mach_header.ncmds,
- mach_header.sizeofcmds, mach_header.flags,
- mach_header.reserved);
-
- // Write the mach header
- buffer.PutHex32(mach_header.magic);
- buffer.PutHex32(mach_header.cputype);
- buffer.PutHex32(mach_header.cpusubtype);
- buffer.PutHex32(mach_header.filetype);
- buffer.PutHex32(mach_header.ncmds);
- buffer.PutHex32(mach_header.sizeofcmds);
- buffer.PutHex32(mach_header.flags);
- if (addr_byte_size == 8) {
- buffer.PutHex32(mach_header.reserved);
- }
-
- // Skip the mach header and all load commands and align to the next
- // 0x1000 byte boundary
- addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds;
- if (file_offset & 0x00000fff) {
- file_offset += 0x00001000ull;
- file_offset &= (~0x00001000ull + 1);
- }
-
- for (auto &segment : segment_load_commands) {
- segment.fileoff = file_offset;
- file_offset += segment.filesize;
- }
-
- // Write out all of the LC_THREAD load commands
- for (const auto &LC_THREAD_data : LC_THREAD_datas) {
- const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize();
- buffer.PutHex32(LC_THREAD);
- buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data
- buffer.Write(LC_THREAD_data.GetString().data(),
- LC_THREAD_data_size);
- }
-
- // Write out all of the segment load commands
- for (const auto &segment : segment_load_commands) {
- printf("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64
- ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64
- ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n",
- segment.cmd, segment.cmdsize, segment.vmaddr,
- segment.vmaddr + segment.vmsize, segment.fileoff,
- segment.filesize, segment.maxprot, segment.initprot,
- segment.nsects, segment.flags);
-
- buffer.PutHex32(segment.cmd);
- buffer.PutHex32(segment.cmdsize);
- buffer.PutRawBytes(segment.segname, sizeof(segment.segname));
- if (addr_byte_size == 8) {
- buffer.PutHex64(segment.vmaddr);
- buffer.PutHex64(segment.vmsize);
- buffer.PutHex64(segment.fileoff);
- buffer.PutHex64(segment.filesize);
- } else {
- buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr));
- buffer.PutHex32(static_cast<uint32_t>(segment.vmsize));
- buffer.PutHex32(static_cast<uint32_t>(segment.fileoff));
- buffer.PutHex32(static_cast<uint32_t>(segment.filesize));
- }
- buffer.PutHex32(segment.maxprot);
- buffer.PutHex32(segment.initprot);
- buffer.PutHex32(segment.nsects);
- buffer.PutHex32(segment.flags);
- }
-
- File core_file;
- std::string core_file_path(outfile.GetPath());
- error = FileSystem::Instance().Open(core_file, outfile,
- File::eOpenOptionWrite |
- File::eOpenOptionTruncate |
- File::eOpenOptionCanCreate);
- if (error.Success()) {
- // Read 1 page at a time
- uint8_t bytes[0x1000];
- // Write the mach header and load commands out to the core file
- size_t bytes_written = buffer.GetString().size();
- error = core_file.Write(buffer.GetString().data(), bytes_written);
- if (error.Success()) {
- // Now write the file data for all memory segments in the process
- for (const auto &segment : segment_load_commands) {
- if (core_file.SeekFromStart(segment.fileoff) == -1) {
- error.SetErrorStringWithFormat(
- "unable to seek to offset 0x%" PRIx64 " in '%s'",
- segment.fileoff, core_file_path.c_str());
- break;
- }
-
- printf("Saving %" PRId64
- " bytes of data for memory region at 0x%" PRIx64 "\n",
- segment.vmsize, segment.vmaddr);
- addr_t bytes_left = segment.vmsize;
- addr_t addr = segment.vmaddr;
- Status memory_read_error;
- while (bytes_left > 0 && error.Success()) {
- const size_t bytes_to_read =
- bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left;
- const size_t bytes_read = process_sp->ReadMemory(
- addr, bytes, bytes_to_read, memory_read_error);
- if (bytes_read == bytes_to_read) {
- size_t bytes_written = bytes_read;
- error = core_file.Write(bytes, bytes_written);
- bytes_left -= bytes_read;
- addr += bytes_read;
- } else {
- // Some pages within regions are not readable, those should
- // be zero filled
- memset(bytes, 0, bytes_to_read);
- size_t bytes_written = bytes_to_read;
- error = core_file.Write(bytes, bytes_written);
- bytes_left -= bytes_to_read;
- addr += bytes_to_read;
- }
- }
- }
- }
- }
- } else {
- error.SetErrorString(
- "process doesn't support getting memory region info");
- }
- }
- return true; // This is the right plug to handle saving core files for
- // this process
- }
- }
- return false;
-}
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
deleted file mode 100644
index 196abae807e90..0000000000000
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ /dev/null
@@ -1,220 +0,0 @@
-//===-- ObjectFileMachO.h ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_ObjectFileMachO_h_
-#define liblldb_ObjectFileMachO_h_
-
-#include "lldb/Core/Address.h"
-#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/RangeMap.h"
-#include "lldb/Host/SafeMachO.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/UUID.h"
-
-//----------------------------------------------------------------------
-// This class needs to be hidden as eventually belongs in a plugin that
-// will export the ObjectFile protocol
-//----------------------------------------------------------------------
-class ObjectFileMachO : public lldb_private::ObjectFile {
-public:
- ObjectFileMachO(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const lldb_private::FileSpec *file, lldb::offset_t offset,
- lldb::offset_t length);
-
- ObjectFileMachO(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
-
- ~ObjectFileMachO() override = default;
-
- //------------------------------------------------------------------
- // Static Functions
- //------------------------------------------------------------------
- static void Initialize();
-
- static void Terminate();
-
- static lldb_private::ConstString GetPluginNameStatic();
-
- static const char *GetPluginDescriptionStatic();
-
- static lldb_private::ObjectFile *
- CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset, const lldb_private::FileSpec *file,
- lldb::offset_t file_offset, lldb::offset_t length);
-
- static lldb_private::ObjectFile *CreateMemoryInstance(
- const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
-
- static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
- lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- lldb::offset_t file_offset,
- lldb::offset_t length,
- lldb_private::ModuleSpecList &specs);
-
- static bool SaveCore(const lldb::ProcessSP &process_sp,
- const lldb_private::FileSpec &outfile,
- lldb_private::Status &error);
-
- static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset,
- lldb::addr_t length);
-
- //------------------------------------------------------------------
- // Member Functions
- //------------------------------------------------------------------
- bool ParseHeader() override;
-
- bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value,
- bool value_is_offset) override;
-
- lldb::ByteOrder GetByteOrder() const override;
-
- bool IsExecutable() const override;
-
- uint32_t GetAddressByteSize() const override;
-
- lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override;
-
- lldb_private::Symtab *GetSymtab() override;
-
- bool IsStripped() override;
-
- void CreateSections(lldb_private::SectionList &unified_section_list) override;
-
- void Dump(lldb_private::Stream *s) override;
-
- lldb_private::ArchSpec GetArchitecture() override;
-
- bool GetUUID(lldb_private::UUID *uuid) override;
-
- uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
-
- lldb_private::FileSpecList GetReExportedLibraries() override {
- return m_reexported_dylibs;
- }
-
- lldb_private::Address GetEntryPointAddress() override;
-
- lldb_private::Address GetBaseAddress() override;
-
- uint32_t GetNumThreadContexts() override;
-
- std::string GetIdentifierString() override;
-
- bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override;
-
- lldb::RegisterContextSP
- GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override;
-
- ObjectFile::Type CalculateType() override;
-
- ObjectFile::Strata CalculateStrata() override;
-
- llvm::VersionTuple GetVersion() override;
-
- llvm::VersionTuple GetMinimumOSVersion() override;
-
- uint32_t GetSDKVersion(uint32_t *versions, uint32_t num_versions) override;
-
- bool GetIsDynamicLinkEditor() override;
-
- static bool ParseHeader(lldb_private::DataExtractor &data,
- lldb::offset_t *data_offset_ptr,
- llvm::MachO::mach_header &header);
-
- bool AllowAssemblyEmulationUnwindPlans() override;
-
- //------------------------------------------------------------------
- // PluginInterface protocol
- //------------------------------------------------------------------
- lldb_private::ConstString GetPluginName() override;
-
- uint32_t GetPluginVersion() override;
-
-protected:
- static bool
- GetUUID(const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset, // Offset to the first load command
- lldb_private::UUID &uuid);
-
- static lldb_private::ArchSpec
- GetArchitecture(const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset);
-
- // Intended for same-host arm device debugging where lldb needs to
- // detect libraries in the shared cache and augment the nlist entries
- // with an on-disk dyld_shared_cache file. The process will record
- // the shared cache UUID so the on-disk cache can be matched or rejected
- // correctly.
- void GetProcessSharedCacheUUID(lldb_private::Process *, lldb::addr_t &base_addr, lldb_private::UUID &uuid);
-
- // Intended for same-host arm device debugging where lldb will read
- // shared cache libraries out of its own memory instead of the remote
- // process' memory as an optimization. If lldb's shared cache UUID
- // does not match the process' shared cache UUID, this optimization
- // should not be used.
- void GetLLDBSharedCacheUUID(lldb::addr_t &base_addir, lldb_private::UUID &uuid);
-
- lldb_private::Section *GetMachHeaderSection();
-
- lldb::addr_t CalculateSectionLoadAddressForMemoryImage(
- lldb::addr_t mach_header_load_address,
- const lldb_private::Section *mach_header_section,
- const lldb_private::Section *section);
-
- lldb_private::UUID
- GetSharedCacheUUID(lldb_private::FileSpec dyld_shared_cache,
- const lldb::ByteOrder byte_order,
- const uint32_t addr_byte_size);
-
- size_t ParseSymtab();
-
- typedef lldb_private::RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges;
- EncryptedFileRanges GetEncryptedFileRanges();
-
- struct SegmentParsingContext;
- void ProcessDysymtabCommand(const llvm::MachO::load_command &load_cmd,
- lldb::offset_t offset);
- void ProcessSegmentCommand(const llvm::MachO::load_command &load_cmd,
- lldb::offset_t offset, uint32_t cmd_idx,
- SegmentParsingContext &context);
- void SanitizeSegmentCommand(llvm::MachO::segment_command_64 &seg_cmd,
- uint32_t cmd_idx);
-
- bool SectionIsLoadable(const lldb_private::Section *section);
-
- llvm::MachO::mach_header m_header;
- static const lldb_private::ConstString &GetSegmentNameTEXT();
- static const lldb_private::ConstString &GetSegmentNameDATA();
- static const lldb_private::ConstString &GetSegmentNameDATA_DIRTY();
- static const lldb_private::ConstString &GetSegmentNameDATA_CONST();
- static const lldb_private::ConstString &GetSegmentNameOBJC();
- static const lldb_private::ConstString &GetSegmentNameLINKEDIT();
- static const lldb_private::ConstString &GetSegmentNameDWARF();
- static const lldb_private::ConstString &GetSectionNameEHFrame();
-
- llvm::MachO::dysymtab_command m_dysymtab;
- std::vector<llvm::MachO::segment_command_64> m_mach_segments;
- std::vector<llvm::MachO::section_64> m_mach_sections;
- llvm::Optional<llvm::VersionTuple> m_min_os_version;
- std::vector<uint32_t> m_sdk_versions;
- typedef lldb_private::RangeVector<uint32_t, uint32_t> FileRangeArray;
- lldb_private::Address m_entry_point_address;
- FileRangeArray m_thread_context_offsets;
- bool m_thread_context_offsets_valid;
- lldb_private::FileSpecList m_reexported_dylibs;
- bool m_allow_assembly_emulation_unwind_plans;
-};
-
-#endif // liblldb_ObjectFileMachO_h_
diff --git a/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt b/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
deleted file mode 100644
index 04321f2765510..0000000000000
--- a/source/Plugins/ObjectFile/PECOFF/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-add_lldb_library(lldbPluginObjectFilePECOFF PLUGIN
- ObjectFilePECOFF.cpp
- WindowsMiniDump.cpp
-
- LINK_LIBS
- lldbCore
- lldbHost
- lldbSymbol
- lldbTarget
- LINK_COMPONENTS
- BinaryFormat
- Support
- )
diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
deleted file mode 100644
index d18ff617521f5..0000000000000
--- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ /dev/null
@@ -1,1183 +0,0 @@
-//===-- ObjectFilePECOFF.cpp ------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ObjectFilePECOFF.h"
-#include "WindowsMiniDump.h"
-
-#include "lldb/Core/FileSpecList.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/SectionLoadList.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/Timer.h"
-#include "lldb/Utility/UUID.h"
-#include "llvm/BinaryFormat/COFF.h"
-
-#include "llvm/Object/COFFImportFile.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
-#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
-#define OPT_HEADER_MAGIC_PE32 0x010b
-#define OPT_HEADER_MAGIC_PE32_PLUS 0x020b
-
-using namespace lldb;
-using namespace lldb_private;
-
-void ObjectFilePECOFF::Initialize() {
- PluginManager::RegisterPlugin(
- GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
- CreateMemoryInstance, GetModuleSpecifications, SaveCore);
-}
-
-void ObjectFilePECOFF::Terminate() {
- PluginManager::UnregisterPlugin(CreateInstance);
-}
-
-lldb_private::ConstString ObjectFilePECOFF::GetPluginNameStatic() {
- static ConstString g_name("pe-coff");
- return g_name;
-}
-
-const char *ObjectFilePECOFF::GetPluginDescriptionStatic() {
- return "Portable Executable and Common Object File Format object file reader "
- "(32 and 64 bit)";
-}
-
-ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const lldb_private::FileSpec *file,
- lldb::offset_t file_offset,
- lldb::offset_t length) {
- if (!data_sp) {
- data_sp = MapFileData(file, length, file_offset);
- if (!data_sp)
- return nullptr;
- data_offset = 0;
- }
-
- if (!ObjectFilePECOFF::MagicBytesMatch(data_sp))
- return nullptr;
-
- // Update the data to contain the entire file if it doesn't already
- if (data_sp->GetByteSize() < length) {
- data_sp = MapFileData(file, length, file_offset);
- if (!data_sp)
- return nullptr;
- }
-
- auto objfile_ap = llvm::make_unique<ObjectFilePECOFF>(
- module_sp, data_sp, data_offset, file, file_offset, length);
- if (!objfile_ap || !objfile_ap->ParseHeader())
- return nullptr;
-
- // Cache coff binary.
- if (!objfile_ap->CreateBinary())
- return nullptr;
-
- return objfile_ap.release();
-}
-
-ObjectFile *ObjectFilePECOFF::CreateMemoryInstance(
- const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) {
- if (!data_sp || !ObjectFilePECOFF::MagicBytesMatch(data_sp))
- return nullptr;
- auto objfile_ap = llvm::make_unique<ObjectFilePECOFF>(
- module_sp, data_sp, process_sp, header_addr);
- if (objfile_ap.get() && objfile_ap->ParseHeader()) {
- return objfile_ap.release();
- }
- return nullptr;
-}
-
-size_t ObjectFilePECOFF::GetModuleSpecifications(
- const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset, lldb::offset_t file_offset,
- lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
- const size_t initial_count = specs.GetSize();
-
- if (ObjectFilePECOFF::MagicBytesMatch(data_sp)) {
- DataExtractor data;
- data.SetData(data_sp, data_offset, length);
- data.SetByteOrder(eByteOrderLittle);
-
- dos_header_t dos_header;
- coff_header_t coff_header;
-
- if (ParseDOSHeader(data, dos_header)) {
- lldb::offset_t offset = dos_header.e_lfanew;
- uint32_t pe_signature = data.GetU32(&offset);
- if (pe_signature != IMAGE_NT_SIGNATURE)
- return false;
- if (ParseCOFFHeader(data, &offset, coff_header)) {
- ArchSpec spec;
- if (coff_header.machine == MachineAmd64) {
- spec.SetTriple("x86_64-pc-windows");
- specs.Append(ModuleSpec(file, spec));
- } else if (coff_header.machine == MachineX86) {
- spec.SetTriple("i386-pc-windows");
- specs.Append(ModuleSpec(file, spec));
- spec.SetTriple("i686-pc-windows");
- specs.Append(ModuleSpec(file, spec));
- } else if (coff_header.machine == MachineArmNt) {
- spec.SetTriple("arm-pc-windows");
- specs.Append(ModuleSpec(file, spec));
- }
- }
- }
- }
-
- return specs.GetSize() - initial_count;
-}
-
-bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp,
- const lldb_private::FileSpec &outfile,
- lldb_private::Status &error) {
- return SaveMiniDump(process_sp, outfile, error);
-}
-
-bool ObjectFilePECOFF::MagicBytesMatch(DataBufferSP &data_sp) {
- DataExtractor data(data_sp, eByteOrderLittle, 4);
- lldb::offset_t offset = 0;
- uint16_t magic = data.GetU16(&offset);
- return magic == IMAGE_DOS_SIGNATURE;
-}
-
-lldb::SymbolType ObjectFilePECOFF::MapSymbolType(uint16_t coff_symbol_type) {
- // TODO: We need to complete this mapping of COFF symbol types to LLDB ones.
- // For now, here's a hack to make sure our function have types.
- const auto complex_type =
- coff_symbol_type >> llvm::COFF::SCT_COMPLEX_TYPE_SHIFT;
- if (complex_type == llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) {
- return lldb::eSymbolTypeCode;
- }
- return lldb::eSymbolTypeInvalid;
-}
-
-bool ObjectFilePECOFF::CreateBinary() {
- if (m_owningbin)
- return true;
-
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
-
- auto binary = llvm::object::createBinary(m_file.GetPath());
- if (!binary) {
- if (log)
- log->Printf("ObjectFilePECOFF::CreateBinary() - failed to create binary "
- "for file (%s): %s",
- m_file ? m_file.GetPath().c_str() : "<NULL>",
- errorToErrorCode(binary.takeError()).message().c_str());
- return false;
- }
-
- // Make sure we only handle COFF format.
- if (!binary->getBinary()->isCOFF() &&
- !binary->getBinary()->isCOFFImportFile())
- return false;
-
- m_owningbin = OWNBINType(std::move(*binary));
- if (log)
- log->Printf("%p ObjectFilePECOFF::CreateBinary() module = %p (%s), file = "
- "%s, binary = %p (Bin = %p)",
- static_cast<void *>(this),
- static_cast<void *>(GetModule().get()),
- GetModule()->GetSpecificationDescription().c_str(),
- m_file ? m_file.GetPath().c_str() : "<NULL>",
- static_cast<void *>(m_owningbin.getPointer()),
- static_cast<void *>(m_owningbin->getBinary()));
- return true;
-}
-
-ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
- DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const FileSpec *file,
- lldb::offset_t file_offset,
- lldb::offset_t length)
- : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
- m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
- m_entry_point_address(), m_deps_filespec(), m_owningbin() {
- ::memset(&m_dos_header, 0, sizeof(m_dos_header));
- ::memset(&m_coff_header, 0, sizeof(m_coff_header));
- ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt));
-}
-
-ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
- DataBufferSP &header_data_sp,
- const lldb::ProcessSP &process_sp,
- addr_t header_addr)
- : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
- m_dos_header(), m_coff_header(), m_coff_header_opt(), m_sect_headers(),
- m_entry_point_address(), m_deps_filespec(), m_owningbin() {
- ::memset(&m_dos_header, 0, sizeof(m_dos_header));
- ::memset(&m_coff_header, 0, sizeof(m_coff_header));
- ::memset(&m_coff_header_opt, 0, sizeof(m_coff_header_opt));
-}
-
-ObjectFilePECOFF::~ObjectFilePECOFF() {}
-
-bool ObjectFilePECOFF::ParseHeader() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- m_sect_headers.clear();
- m_data.SetByteOrder(eByteOrderLittle);
- lldb::offset_t offset = 0;
-
- if (ParseDOSHeader(m_data, m_dos_header)) {
- offset = m_dos_header.e_lfanew;
- uint32_t pe_signature = m_data.GetU32(&offset);
- if (pe_signature != IMAGE_NT_SIGNATURE)
- return false;
- if (ParseCOFFHeader(m_data, &offset, m_coff_header)) {
- if (m_coff_header.hdrsize > 0)
- ParseCOFFOptionalHeader(&offset);
- ParseSectionHeaders(offset);
- }
- return true;
- }
- }
- return false;
-}
-
-bool ObjectFilePECOFF::SetLoadAddress(Target &target, addr_t value,
- bool value_is_offset) {
- bool changed = false;
- ModuleSP module_sp = GetModule();
- if (module_sp) {
- size_t num_loaded_sections = 0;
- SectionList *section_list = GetSectionList();
- if (section_list) {
- if (!value_is_offset) {
- value -= m_image_base;
- }
-
- const size_t num_sections = section_list->GetSize();
- size_t sect_idx = 0;
-
- for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
- // Iterate through the object file sections to find all of the sections
- // that have SHF_ALLOC in their flag bits.
- SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
- if (section_sp && !section_sp->IsThreadSpecific()) {
- if (target.GetSectionLoadList().SetSectionLoadAddress(
- section_sp, section_sp->GetFileAddress() + value))
- ++num_loaded_sections;
- }
- }
- changed = num_loaded_sections > 0;
- }
- }
- return changed;
-}
-
-ByteOrder ObjectFilePECOFF::GetByteOrder() const { return eByteOrderLittle; }
-
-bool ObjectFilePECOFF::IsExecutable() const {
- return (m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0;
-}
-
-uint32_t ObjectFilePECOFF::GetAddressByteSize() const {
- if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32_PLUS)
- return 8;
- else if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32)
- return 4;
- return 4;
-}
-
-//----------------------------------------------------------------------
-// NeedsEndianSwap
-//
-// Return true if an endian swap needs to occur when extracting data from this
-// file.
-//----------------------------------------------------------------------
-bool ObjectFilePECOFF::NeedsEndianSwap() const {
-#if defined(__LITTLE_ENDIAN__)
- return false;
-#else
- return true;
-#endif
-}
-//----------------------------------------------------------------------
-// ParseDOSHeader
-//----------------------------------------------------------------------
-bool ObjectFilePECOFF::ParseDOSHeader(DataExtractor &data,
- dos_header_t &dos_header) {
- bool success = false;
- lldb::offset_t offset = 0;
- success = data.ValidOffsetForDataOfSize(0, sizeof(dos_header));
-
- if (success) {
- dos_header.e_magic = data.GetU16(&offset); // Magic number
- success = dos_header.e_magic == IMAGE_DOS_SIGNATURE;
-
- if (success) {
- dos_header.e_cblp = data.GetU16(&offset); // Bytes on last page of file
- dos_header.e_cp = data.GetU16(&offset); // Pages in file
- dos_header.e_crlc = data.GetU16(&offset); // Relocations
- dos_header.e_cparhdr =
- data.GetU16(&offset); // Size of header in paragraphs
- dos_header.e_minalloc =
- data.GetU16(&offset); // Minimum extra paragraphs needed
- dos_header.e_maxalloc =
- data.GetU16(&offset); // Maximum extra paragraphs needed
- dos_header.e_ss = data.GetU16(&offset); // Initial (relative) SS value
- dos_header.e_sp = data.GetU16(&offset); // Initial SP value
- dos_header.e_csum = data.GetU16(&offset); // Checksum
- dos_header.e_ip = data.GetU16(&offset); // Initial IP value
- dos_header.e_cs = data.GetU16(&offset); // Initial (relative) CS value
- dos_header.e_lfarlc =
- data.GetU16(&offset); // File address of relocation table
- dos_header.e_ovno = data.GetU16(&offset); // Overlay number
-
- dos_header.e_res[0] = data.GetU16(&offset); // Reserved words
- dos_header.e_res[1] = data.GetU16(&offset); // Reserved words
- dos_header.e_res[2] = data.GetU16(&offset); // Reserved words
- dos_header.e_res[3] = data.GetU16(&offset); // Reserved words
-
- dos_header.e_oemid =
- data.GetU16(&offset); // OEM identifier (for e_oeminfo)
- dos_header.e_oeminfo =
- data.GetU16(&offset); // OEM information; e_oemid specific
- dos_header.e_res2[0] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[1] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[2] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[3] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[4] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[5] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[6] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[7] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[8] = data.GetU16(&offset); // Reserved words
- dos_header.e_res2[9] = data.GetU16(&offset); // Reserved words
-
- dos_header.e_lfanew =
- data.GetU32(&offset); // File address of new exe header
- }
- }
- if (!success)
- memset(&dos_header, 0, sizeof(dos_header));
- return success;
-}
-
-//----------------------------------------------------------------------
-// ParserCOFFHeader
-//----------------------------------------------------------------------
-bool ObjectFilePECOFF::ParseCOFFHeader(DataExtractor &data,
- lldb::offset_t *offset_ptr,
- coff_header_t &coff_header) {
- bool success =
- data.ValidOffsetForDataOfSize(*offset_ptr, sizeof(coff_header));
- if (success) {
- coff_header.machine = data.GetU16(offset_ptr);
- coff_header.nsects = data.GetU16(offset_ptr);
- coff_header.modtime = data.GetU32(offset_ptr);
- coff_header.symoff = data.GetU32(offset_ptr);
- coff_header.nsyms = data.GetU32(offset_ptr);
- coff_header.hdrsize = data.GetU16(offset_ptr);
- coff_header.flags = data.GetU16(offset_ptr);
- }
- if (!success)
- memset(&coff_header, 0, sizeof(coff_header));
- return success;
-}
-
-bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) {
- bool success = false;
- const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize;
- if (*offset_ptr < end_offset) {
- success = true;
- m_coff_header_opt.magic = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.code_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.entry = m_data.GetU32(offset_ptr);
- m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr);
-
- const uint32_t addr_byte_size = GetAddressByteSize();
-
- if (*offset_ptr < end_offset) {
- if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) {
- // PE32 only
- m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr);
- } else
- m_coff_header_opt.data_offset = 0;
-
- if (*offset_ptr < end_offset) {
- m_coff_header_opt.image_base =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr);
- m_coff_header_opt.image_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.header_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.checksum = m_data.GetU32(offset_ptr);
- m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr);
- m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr);
- m_coff_header_opt.stack_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.stack_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.heap_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.heap_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr);
- uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_dirs.clear();
- m_coff_header_opt.data_dirs.resize(num_data_dir_entries);
- uint32_t i;
- for (i = 0; i < num_data_dir_entries; i++) {
- m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr);
- }
-
- m_file_offset = m_coff_header_opt.image_base;
- m_image_base = m_coff_header_opt.image_base;
- }
- }
- }
- // Make sure we are on track for section data which follows
- *offset_ptr = end_offset;
- return success;
-}
-
-DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
- if (m_file) {
- // A bit of a hack, but we intend to write to this buffer, so we can't
- // mmap it.
- auto buffer_sp = MapFileData(m_file, size, offset);
- return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
- }
- ProcessSP process_sp(m_process_wp.lock());
- DataExtractor data;
- if (process_sp) {
- auto data_ap = llvm::make_unique<DataBufferHeap>(size, 0);
- Status readmem_error;
- size_t bytes_read =
- process_sp->ReadMemory(m_image_base + offset, data_ap->GetBytes(),
- data_ap->GetByteSize(), readmem_error);
- if (bytes_read == size) {
- DataBufferSP buffer_sp(data_ap.release());
- data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
- }
- }
- return data;
-}
-
-//----------------------------------------------------------------------
-// ParseSectionHeaders
-//----------------------------------------------------------------------
-bool ObjectFilePECOFF::ParseSectionHeaders(
- uint32_t section_header_data_offset) {
- const uint32_t nsects = m_coff_header.nsects;
- m_sect_headers.clear();
-
- if (nsects > 0) {
- const size_t section_header_byte_size = nsects * sizeof(section_header_t);
- DataExtractor section_header_data =
- ReadImageData(section_header_data_offset, section_header_byte_size);
-
- lldb::offset_t offset = 0;
- if (section_header_data.ValidOffsetForDataOfSize(
- offset, section_header_byte_size)) {
- m_sect_headers.resize(nsects);
-
- for (uint32_t idx = 0; idx < nsects; ++idx) {
- const void *name_data = section_header_data.GetData(&offset, 8);
- if (name_data) {
- memcpy(m_sect_headers[idx].name, name_data, 8);
- m_sect_headers[idx].vmsize = section_header_data.GetU32(&offset);
- m_sect_headers[idx].vmaddr = section_header_data.GetU32(&offset);
- m_sect_headers[idx].size = section_header_data.GetU32(&offset);
- m_sect_headers[idx].offset = section_header_data.GetU32(&offset);
- m_sect_headers[idx].reloff = section_header_data.GetU32(&offset);
- m_sect_headers[idx].lineoff = section_header_data.GetU32(&offset);
- m_sect_headers[idx].nreloc = section_header_data.GetU16(&offset);
- m_sect_headers[idx].nline = section_header_data.GetU16(&offset);
- m_sect_headers[idx].flags = section_header_data.GetU32(&offset);
- }
- }
- }
- }
-
- return !m_sect_headers.empty();
-}
-
-llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t &sect) {
- llvm::StringRef hdr_name(sect.name, llvm::array_lengthof(sect.name));
- hdr_name = hdr_name.split('\0').first;
- if (hdr_name.consume_front("/")) {
- lldb::offset_t stroff;
- if (!to_integer(hdr_name, stroff, 10))
- return "";
- lldb::offset_t string_file_offset =
- m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff;
- if (const char *name = m_data.GetCStr(&string_file_offset))
- return name;
- return "";
- }
- return hdr_name;
-}
-
-//----------------------------------------------------------------------
-// GetNListSymtab
-//----------------------------------------------------------------------
-Symtab *ObjectFilePECOFF::GetSymtab() {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (m_symtab_ap.get() == NULL) {
- SectionList *sect_list = GetSectionList();
- m_symtab_ap.reset(new Symtab(this));
- std::lock_guard<std::recursive_mutex> guard(m_symtab_ap->GetMutex());
-
- const uint32_t num_syms = m_coff_header.nsyms;
-
- if (m_file && num_syms > 0 && m_coff_header.symoff > 0) {
- const uint32_t symbol_size = 18;
- const size_t symbol_data_size = num_syms * symbol_size;
- // Include the 4-byte string table size at the end of the symbols
- DataExtractor symtab_data =
- ReadImageData(m_coff_header.symoff, symbol_data_size + 4);
- lldb::offset_t offset = symbol_data_size;
- const uint32_t strtab_size = symtab_data.GetU32(&offset);
- if (strtab_size > 0) {
- DataExtractor strtab_data = ReadImageData(
- m_coff_header.symoff + symbol_data_size, strtab_size);
-
- // First 4 bytes should be zeroed after strtab_size has been read,
- // because it is used as offset 0 to encode a NULL string.
- uint32_t *strtab_data_start = const_cast<uint32_t *>(
- reinterpret_cast<const uint32_t *>(strtab_data.GetDataStart()));
- strtab_data_start[0] = 0;
-
- offset = 0;
- std::string symbol_name;
- Symbol *symbols = m_symtab_ap->Resize(num_syms);
- for (uint32_t i = 0; i < num_syms; ++i) {
- coff_symbol_t symbol;
- const uint32_t symbol_offset = offset;
- const char *symbol_name_cstr = NULL;
- // If the first 4 bytes of the symbol string are zero, then they
- // are followed by a 4-byte string table offset. Else these
- // 8 bytes contain the symbol name
- if (symtab_data.GetU32(&offset) == 0) {
- // Long string that doesn't fit into the symbol table name, so
- // now we must read the 4 byte string table offset
- uint32_t strtab_offset = symtab_data.GetU32(&offset);
- symbol_name_cstr = strtab_data.PeekCStr(strtab_offset);
- symbol_name.assign(symbol_name_cstr);
- } else {
- // Short string that fits into the symbol table name which is 8
- // bytes
- offset += sizeof(symbol.name) - 4; // Skip remaining
- symbol_name_cstr = symtab_data.PeekCStr(symbol_offset);
- if (symbol_name_cstr == NULL)
- break;
- symbol_name.assign(symbol_name_cstr, sizeof(symbol.name));
- }
- symbol.value = symtab_data.GetU32(&offset);
- symbol.sect = symtab_data.GetU16(&offset);
- symbol.type = symtab_data.GetU16(&offset);
- symbol.storage = symtab_data.GetU8(&offset);
- symbol.naux = symtab_data.GetU8(&offset);
- symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
- if ((int16_t)symbol.sect >= 1) {
- Address symbol_addr(sect_list->GetSectionAtIndex(symbol.sect - 1),
- symbol.value);
- symbols[i].GetAddressRef() = symbol_addr;
- symbols[i].SetType(MapSymbolType(symbol.type));
- }
-
- if (symbol.naux > 0) {
- i += symbol.naux;
- offset += symbol_size;
- }
- }
- }
- }
-
- // Read export header
- if (coff_data_dir_export_table < m_coff_header_opt.data_dirs.size() &&
- m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmsize > 0 &&
- m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr > 0) {
- export_directory_entry export_table;
- uint32_t data_start =
- m_coff_header_opt.data_dirs[coff_data_dir_export_table].vmaddr;
-
- uint32_t address_rva = data_start;
- if (m_file) {
- Address address(m_coff_header_opt.image_base + data_start, sect_list);
- address_rva =
- address.GetSection()->GetFileOffset() + address.GetOffset();
- }
- DataExtractor symtab_data =
- ReadImageData(address_rva, m_coff_header_opt.data_dirs[0].vmsize);
- lldb::offset_t offset = 0;
-
- // Read export_table header
- export_table.characteristics = symtab_data.GetU32(&offset);
- export_table.time_date_stamp = symtab_data.GetU32(&offset);
- export_table.major_version = symtab_data.GetU16(&offset);
- export_table.minor_version = symtab_data.GetU16(&offset);
- export_table.name = symtab_data.GetU32(&offset);
- export_table.base = symtab_data.GetU32(&offset);
- export_table.number_of_functions = symtab_data.GetU32(&offset);
- export_table.number_of_names = symtab_data.GetU32(&offset);
- export_table.address_of_functions = symtab_data.GetU32(&offset);
- export_table.address_of_names = symtab_data.GetU32(&offset);
- export_table.address_of_name_ordinals = symtab_data.GetU32(&offset);
-
- bool has_ordinal = export_table.address_of_name_ordinals != 0;
-
- lldb::offset_t name_offset = export_table.address_of_names - data_start;
- lldb::offset_t name_ordinal_offset =
- export_table.address_of_name_ordinals - data_start;
-
- Symbol *symbols = m_symtab_ap->Resize(export_table.number_of_names);
-
- std::string symbol_name;
-
- // Read each export table entry
- for (size_t i = 0; i < export_table.number_of_names; ++i) {
- uint32_t name_ordinal =
- has_ordinal ? symtab_data.GetU16(&name_ordinal_offset) : i;
- uint32_t name_address = symtab_data.GetU32(&name_offset);
-
- const char *symbol_name_cstr =
- symtab_data.PeekCStr(name_address - data_start);
- symbol_name.assign(symbol_name_cstr);
-
- lldb::offset_t function_offset = export_table.address_of_functions -
- data_start +
- sizeof(uint32_t) * name_ordinal;
- uint32_t function_rva = symtab_data.GetU32(&function_offset);
-
- Address symbol_addr(m_coff_header_opt.image_base + function_rva,
- sect_list);
- symbols[i].GetMangled().SetValue(ConstString(symbol_name.c_str()));
- symbols[i].GetAddressRef() = symbol_addr;
- symbols[i].SetType(lldb::eSymbolTypeCode);
- symbols[i].SetDebug(true);
- }
- }
- m_symtab_ap->CalculateSymbolSizes();
- }
- }
- return m_symtab_ap.get();
-}
-
-bool ObjectFilePECOFF::IsStripped() {
- // TODO: determine this for COFF
- return false;
-}
-
-void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) {
- if (m_sections_ap)
- return;
- m_sections_ap.reset(new SectionList());
-
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- const uint32_t nsects = m_sect_headers.size();
- ModuleSP module_sp(GetModule());
- for (uint32_t idx = 0; idx < nsects; ++idx) {
- ConstString const_sect_name(GetSectionName(m_sect_headers[idx]));
- static ConstString g_code_sect_name(".code");
- static ConstString g_CODE_sect_name("CODE");
- static ConstString g_data_sect_name(".data");
- static ConstString g_DATA_sect_name("DATA");
- static ConstString g_bss_sect_name(".bss");
- static ConstString g_BSS_sect_name("BSS");
- static ConstString g_debug_sect_name(".debug");
- static ConstString g_reloc_sect_name(".reloc");
- static ConstString g_stab_sect_name(".stab");
- static ConstString g_stabstr_sect_name(".stabstr");
- static ConstString g_sect_name_dwarf_debug_abbrev(".debug_abbrev");
- static ConstString g_sect_name_dwarf_debug_aranges(".debug_aranges");
- static ConstString g_sect_name_dwarf_debug_frame(".debug_frame");
- static ConstString g_sect_name_dwarf_debug_info(".debug_info");
- static ConstString g_sect_name_dwarf_debug_line(".debug_line");
- static ConstString g_sect_name_dwarf_debug_loc(".debug_loc");
- static ConstString g_sect_name_dwarf_debug_loclists(".debug_loclists");
- static ConstString g_sect_name_dwarf_debug_macinfo(".debug_macinfo");
- static ConstString g_sect_name_dwarf_debug_names(".debug_names");
- static ConstString g_sect_name_dwarf_debug_pubnames(".debug_pubnames");
- static ConstString g_sect_name_dwarf_debug_pubtypes(".debug_pubtypes");
- static ConstString g_sect_name_dwarf_debug_ranges(".debug_ranges");
- static ConstString g_sect_name_dwarf_debug_str(".debug_str");
- static ConstString g_sect_name_dwarf_debug_types(".debug_types");
- static ConstString g_sect_name_eh_frame(".eh_frame");
- static ConstString g_sect_name_go_symtab(".gosymtab");
- SectionType section_type = eSectionTypeOther;
- if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE &&
- ((const_sect_name == g_code_sect_name) ||
- (const_sect_name == g_CODE_sect_name))) {
- section_type = eSectionTypeCode;
- } else if (m_sect_headers[idx].flags &
- llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA &&
- ((const_sect_name == g_data_sect_name) ||
- (const_sect_name == g_DATA_sect_name))) {
- if (m_sect_headers[idx].size == 0 && m_sect_headers[idx].offset == 0)
- section_type = eSectionTypeZeroFill;
- else
- section_type = eSectionTypeData;
- } else if (m_sect_headers[idx].flags &
- llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA &&
- ((const_sect_name == g_bss_sect_name) ||
- (const_sect_name == g_BSS_sect_name))) {
- if (m_sect_headers[idx].size == 0)
- section_type = eSectionTypeZeroFill;
- else
- section_type = eSectionTypeData;
- } else if (const_sect_name == g_debug_sect_name) {
- section_type = eSectionTypeDebug;
- } else if (const_sect_name == g_stabstr_sect_name) {
- section_type = eSectionTypeDataCString;
- } else if (const_sect_name == g_reloc_sect_name) {
- section_type = eSectionTypeOther;
- } else if (const_sect_name == g_sect_name_dwarf_debug_abbrev)
- section_type = eSectionTypeDWARFDebugAbbrev;
- else if (const_sect_name == g_sect_name_dwarf_debug_aranges)
- section_type = eSectionTypeDWARFDebugAranges;
- else if (const_sect_name == g_sect_name_dwarf_debug_frame)
- section_type = eSectionTypeDWARFDebugFrame;
- else if (const_sect_name == g_sect_name_dwarf_debug_info)
- section_type = eSectionTypeDWARFDebugInfo;
- else if (const_sect_name == g_sect_name_dwarf_debug_line)
- section_type = eSectionTypeDWARFDebugLine;
- else if (const_sect_name == g_sect_name_dwarf_debug_loc)
- section_type = eSectionTypeDWARFDebugLoc;
- else if (const_sect_name == g_sect_name_dwarf_debug_loclists)
- section_type = eSectionTypeDWARFDebugLocLists;
- else if (const_sect_name == g_sect_name_dwarf_debug_macinfo)
- section_type = eSectionTypeDWARFDebugMacInfo;
- else if (const_sect_name == g_sect_name_dwarf_debug_names)
- section_type = eSectionTypeDWARFDebugNames;
- else if (const_sect_name == g_sect_name_dwarf_debug_pubnames)
- section_type = eSectionTypeDWARFDebugPubNames;
- else if (const_sect_name == g_sect_name_dwarf_debug_pubtypes)
- section_type = eSectionTypeDWARFDebugPubTypes;
- else if (const_sect_name == g_sect_name_dwarf_debug_ranges)
- section_type = eSectionTypeDWARFDebugRanges;
- else if (const_sect_name == g_sect_name_dwarf_debug_str)
- section_type = eSectionTypeDWARFDebugStr;
- else if (const_sect_name == g_sect_name_dwarf_debug_types)
- section_type = eSectionTypeDWARFDebugTypes;
- else if (const_sect_name == g_sect_name_eh_frame)
- section_type = eSectionTypeEHFrame;
- else if (const_sect_name == g_sect_name_go_symtab)
- section_type = eSectionTypeGoSymtab;
- else if (m_sect_headers[idx].flags & llvm::COFF::IMAGE_SCN_CNT_CODE) {
- section_type = eSectionTypeCode;
- } else if (m_sect_headers[idx].flags &
- llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) {
- section_type = eSectionTypeData;
- } else if (m_sect_headers[idx].flags &
- llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
- if (m_sect_headers[idx].size == 0)
- section_type = eSectionTypeZeroFill;
- else
- section_type = eSectionTypeData;
- }
-
- // Use a segment ID of the segment index shifted left by 8 so they
- // never conflict with any of the sections.
- SectionSP section_sp(new Section(
- module_sp, // Module to which this section belongs
- this, // Object file to which this section belongs
- idx + 1, // Section ID is the 1 based segment index shifted right by
- // 8 bits as not to collide with any of the 256 section IDs
- // that are possible
- const_sect_name, // Name of this section
- section_type, // This section is a container of other sections.
- m_coff_header_opt.image_base +
- m_sect_headers[idx].vmaddr, // File VM address == addresses as
- // they are found in the object file
- m_sect_headers[idx].vmsize, // VM size in bytes of this section
- m_sect_headers[idx]
- .offset, // Offset to the data for this section in the file
- m_sect_headers[idx]
- .size, // Size in bytes of this section as found in the file
- m_coff_header_opt.sect_alignment, // Section alignment
- m_sect_headers[idx].flags)); // Flags for this section
-
- // section_sp->SetIsEncrypted (segment_is_encrypted);
-
- unified_section_list.AddSection(section_sp);
- m_sections_ap->AddSection(section_sp);
- }
- }
-}
-
-bool ObjectFilePECOFF::GetUUID(UUID *uuid) { return false; }
-
-uint32_t ObjectFilePECOFF::ParseDependentModules() {
- ModuleSP module_sp(GetModule());
- if (!module_sp)
- return 0;
-
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (m_deps_filespec)
- return m_deps_filespec->GetSize();
-
- // Cache coff binary if it is not done yet.
- if (!CreateBinary())
- return 0;
-
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf("%p ObjectFilePECOFF::ParseDependentModules() module = %p "
- "(%s), binary = %p (Bin = %p)",
- static_cast<void *>(this), static_cast<void *>(module_sp.get()),
- module_sp->GetSpecificationDescription().c_str(),
- static_cast<void *>(m_owningbin.getPointer()),
- m_owningbin ? static_cast<void *>(m_owningbin->getBinary())
- : nullptr);
-
- auto COFFObj =
- llvm::dyn_cast<llvm::object::COFFObjectFile>(m_owningbin->getBinary());
- if (!COFFObj)
- return 0;
-
- m_deps_filespec = FileSpecList();
-
- for (const auto &entry : COFFObj->import_directories()) {
- llvm::StringRef dll_name;
- auto ec = entry.getName(dll_name);
- // Report a bogus entry.
- if (ec != std::error_code()) {
- if (log)
- log->Printf("ObjectFilePECOFF::ParseDependentModules() - failed to get "
- "import directory entry name: %s",
- ec.message().c_str());
- continue;
- }
-
- // At this moment we only have the base name of the DLL. The full path can
- // only be seen after the dynamic loading. Our best guess is Try to get it
- // with the help of the object file's directory.
- llvm::SmallString<128> dll_fullpath;
- FileSpec dll_specs(dll_name);
- dll_specs.GetDirectory().SetString(m_file.GetDirectory().GetCString());
-
- if (!llvm::sys::fs::real_path(dll_specs.GetPath(), dll_fullpath))
- m_deps_filespec->Append(FileSpec(dll_fullpath));
- else {
- // Known DLLs or DLL not found in the object file directory.
- m_deps_filespec->Append(FileSpec(dll_name));
- }
- }
- return m_deps_filespec->GetSize();
-}
-
-uint32_t ObjectFilePECOFF::GetDependentModules(FileSpecList &files) {
- auto num_modules = ParseDependentModules();
- auto original_size = files.GetSize();
-
- for (unsigned i = 0; i < num_modules; ++i)
- files.AppendIfUnique(m_deps_filespec->GetFileSpecAtIndex(i));
-
- return files.GetSize() - original_size;
-}
-
-lldb_private::Address ObjectFilePECOFF::GetEntryPointAddress() {
- if (m_entry_point_address.IsValid())
- return m_entry_point_address;
-
- if (!ParseHeader() || !IsExecutable())
- return m_entry_point_address;
-
- SectionList *section_list = GetSectionList();
- addr_t file_addr = m_coff_header_opt.entry + m_coff_header_opt.image_base;
-
- if (!section_list)
- m_entry_point_address.SetOffset(file_addr);
- else
- m_entry_point_address.ResolveAddressUsingFileSections(file_addr, section_list);
- return m_entry_point_address;
-}
-
-//----------------------------------------------------------------------
-// Dump
-//
-// Dump the specifics of the runtime file container (such as any headers
-// segments, sections, etc).
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::Dump(Stream *s) {
- ModuleSP module_sp(GetModule());
- if (module_sp) {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- s->Printf("%p: ", static_cast<void *>(this));
- s->Indent();
- s->PutCString("ObjectFilePECOFF");
-
- ArchSpec header_arch = GetArchitecture();
-
- *s << ", file = '" << m_file
- << "', arch = " << header_arch.GetArchitectureName() << "\n";
-
- SectionList *sections = GetSectionList();
- if (sections)
- sections->Dump(s, NULL, true, UINT32_MAX);
-
- if (m_symtab_ap.get())
- m_symtab_ap->Dump(s, NULL, eSortOrderNone);
-
- if (m_dos_header.e_magic)
- DumpDOSHeader(s, m_dos_header);
- if (m_coff_header.machine) {
- DumpCOFFHeader(s, m_coff_header);
- if (m_coff_header.hdrsize)
- DumpOptCOFFHeader(s, m_coff_header_opt);
- }
- s->EOL();
- DumpSectionHeaders(s);
- s->EOL();
-
- DumpDependentModules(s);
- s->EOL();
- }
-}
-
-//----------------------------------------------------------------------
-// DumpDOSHeader
-//
-// Dump the MS-DOS header to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpDOSHeader(Stream *s, const dos_header_t &header) {
- s->PutCString("MSDOS Header\n");
- s->Printf(" e_magic = 0x%4.4x\n", header.e_magic);
- s->Printf(" e_cblp = 0x%4.4x\n", header.e_cblp);
- s->Printf(" e_cp = 0x%4.4x\n", header.e_cp);
- s->Printf(" e_crlc = 0x%4.4x\n", header.e_crlc);
- s->Printf(" e_cparhdr = 0x%4.4x\n", header.e_cparhdr);
- s->Printf(" e_minalloc = 0x%4.4x\n", header.e_minalloc);
- s->Printf(" e_maxalloc = 0x%4.4x\n", header.e_maxalloc);
- s->Printf(" e_ss = 0x%4.4x\n", header.e_ss);
- s->Printf(" e_sp = 0x%4.4x\n", header.e_sp);
- s->Printf(" e_csum = 0x%4.4x\n", header.e_csum);
- s->Printf(" e_ip = 0x%4.4x\n", header.e_ip);
- s->Printf(" e_cs = 0x%4.4x\n", header.e_cs);
- s->Printf(" e_lfarlc = 0x%4.4x\n", header.e_lfarlc);
- s->Printf(" e_ovno = 0x%4.4x\n", header.e_ovno);
- s->Printf(" e_res[4] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
- header.e_res[0], header.e_res[1], header.e_res[2], header.e_res[3]);
- s->Printf(" e_oemid = 0x%4.4x\n", header.e_oemid);
- s->Printf(" e_oeminfo = 0x%4.4x\n", header.e_oeminfo);
- s->Printf(" e_res2[10] = { 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, "
- "0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x, 0x%4.4x }\n",
- header.e_res2[0], header.e_res2[1], header.e_res2[2],
- header.e_res2[3], header.e_res2[4], header.e_res2[5],
- header.e_res2[6], header.e_res2[7], header.e_res2[8],
- header.e_res2[9]);
- s->Printf(" e_lfanew = 0x%8.8x\n", header.e_lfanew);
-}
-
-//----------------------------------------------------------------------
-// DumpCOFFHeader
-//
-// Dump the COFF header to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpCOFFHeader(Stream *s, const coff_header_t &header) {
- s->PutCString("COFF Header\n");
- s->Printf(" machine = 0x%4.4x\n", header.machine);
- s->Printf(" nsects = 0x%4.4x\n", header.nsects);
- s->Printf(" modtime = 0x%8.8x\n", header.modtime);
- s->Printf(" symoff = 0x%8.8x\n", header.symoff);
- s->Printf(" nsyms = 0x%8.8x\n", header.nsyms);
- s->Printf(" hdrsize = 0x%4.4x\n", header.hdrsize);
-}
-
-//----------------------------------------------------------------------
-// DumpOptCOFFHeader
-//
-// Dump the optional COFF header to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpOptCOFFHeader(Stream *s,
- const coff_opt_header_t &header) {
- s->PutCString("Optional COFF Header\n");
- s->Printf(" magic = 0x%4.4x\n", header.magic);
- s->Printf(" major_linker_version = 0x%2.2x\n",
- header.major_linker_version);
- s->Printf(" minor_linker_version = 0x%2.2x\n",
- header.minor_linker_version);
- s->Printf(" code_size = 0x%8.8x\n", header.code_size);
- s->Printf(" data_size = 0x%8.8x\n", header.data_size);
- s->Printf(" bss_size = 0x%8.8x\n", header.bss_size);
- s->Printf(" entry = 0x%8.8x\n", header.entry);
- s->Printf(" code_offset = 0x%8.8x\n", header.code_offset);
- s->Printf(" data_offset = 0x%8.8x\n", header.data_offset);
- s->Printf(" image_base = 0x%16.16" PRIx64 "\n",
- header.image_base);
- s->Printf(" sect_alignment = 0x%8.8x\n", header.sect_alignment);
- s->Printf(" file_alignment = 0x%8.8x\n", header.file_alignment);
- s->Printf(" major_os_system_version = 0x%4.4x\n",
- header.major_os_system_version);
- s->Printf(" minor_os_system_version = 0x%4.4x\n",
- header.minor_os_system_version);
- s->Printf(" major_image_version = 0x%4.4x\n",
- header.major_image_version);
- s->Printf(" minor_image_version = 0x%4.4x\n",
- header.minor_image_version);
- s->Printf(" major_subsystem_version = 0x%4.4x\n",
- header.major_subsystem_version);
- s->Printf(" minor_subsystem_version = 0x%4.4x\n",
- header.minor_subsystem_version);
- s->Printf(" reserved1 = 0x%8.8x\n", header.reserved1);
- s->Printf(" image_size = 0x%8.8x\n", header.image_size);
- s->Printf(" header_size = 0x%8.8x\n", header.header_size);
- s->Printf(" checksum = 0x%8.8x\n", header.checksum);
- s->Printf(" subsystem = 0x%4.4x\n", header.subsystem);
- s->Printf(" dll_flags = 0x%4.4x\n", header.dll_flags);
- s->Printf(" stack_reserve_size = 0x%16.16" PRIx64 "\n",
- header.stack_reserve_size);
- s->Printf(" stack_commit_size = 0x%16.16" PRIx64 "\n",
- header.stack_commit_size);
- s->Printf(" heap_reserve_size = 0x%16.16" PRIx64 "\n",
- header.heap_reserve_size);
- s->Printf(" heap_commit_size = 0x%16.16" PRIx64 "\n",
- header.heap_commit_size);
- s->Printf(" loader_flags = 0x%8.8x\n", header.loader_flags);
- s->Printf(" num_data_dir_entries = 0x%8.8x\n",
- (uint32_t)header.data_dirs.size());
- uint32_t i;
- for (i = 0; i < header.data_dirs.size(); i++) {
- s->Printf(" data_dirs[%2u] vmaddr = 0x%8.8x, vmsize = 0x%8.8x\n", i,
- header.data_dirs[i].vmaddr, header.data_dirs[i].vmsize);
- }
-}
-//----------------------------------------------------------------------
-// DumpSectionHeader
-//
-// Dump a single ELF section header to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpSectionHeader(Stream *s,
- const section_header_t &sh) {
- std::string name = GetSectionName(sh);
- s->Printf("%-16s 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%4.4x "
- "0x%4.4x 0x%8.8x\n",
- name.c_str(), sh.vmaddr, sh.vmsize, sh.offset, sh.size, sh.reloff,
- sh.lineoff, sh.nreloc, sh.nline, sh.flags);
-}
-
-//----------------------------------------------------------------------
-// DumpSectionHeaders
-//
-// Dump all of the ELF section header to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpSectionHeaders(Stream *s) {
-
- s->PutCString("Section Headers\n");
- s->PutCString("IDX name vm addr vm size file off file "
- "size reloc off line off nreloc nline flags\n");
- s->PutCString("==== ---------------- ---------- ---------- ---------- "
- "---------- ---------- ---------- ------ ------ ----------\n");
-
- uint32_t idx = 0;
- SectionHeaderCollIter pos, end = m_sect_headers.end();
-
- for (pos = m_sect_headers.begin(); pos != end; ++pos, ++idx) {
- s->Printf("[%2u] ", idx);
- ObjectFilePECOFF::DumpSectionHeader(s, *pos);
- }
-}
-
-//----------------------------------------------------------------------
-// DumpDependentModules
-//
-// Dump all of the dependent modules to the specified output stream
-//----------------------------------------------------------------------
-void ObjectFilePECOFF::DumpDependentModules(lldb_private::Stream *s) {
- auto num_modules = ParseDependentModules();
- if (num_modules > 0) {
- s->PutCString("Dependent Modules\n");
- for (unsigned i = 0; i < num_modules; ++i) {
- auto spec = m_deps_filespec->GetFileSpecAtIndex(i);
- s->Printf(" %s\n", spec.GetFilename().GetCString());
- }
- }
-}
-
-bool ObjectFilePECOFF::IsWindowsSubsystem() {
- switch (m_coff_header_opt.subsystem) {
- case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE:
- case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI:
- case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI:
- case llvm::COFF::IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
- case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
- case llvm::COFF::IMAGE_SUBSYSTEM_XBOX:
- case llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION:
- return true;
- default:
- return false;
- }
-}
-
-ArchSpec ObjectFilePECOFF::GetArchitecture() {
- uint16_t machine = m_coff_header.machine;
- switch (machine) {
- default:
- break;
- case llvm::COFF::IMAGE_FILE_MACHINE_AMD64:
- case llvm::COFF::IMAGE_FILE_MACHINE_I386:
- case llvm::COFF::IMAGE_FILE_MACHINE_POWERPC:
- case llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP:
- case llvm::COFF::IMAGE_FILE_MACHINE_ARM:
- case llvm::COFF::IMAGE_FILE_MACHINE_ARMNT:
- case llvm::COFF::IMAGE_FILE_MACHINE_THUMB:
- ArchSpec arch;
- arch.SetArchitecture(eArchTypeCOFF, machine, LLDB_INVALID_CPUTYPE,
- IsWindowsSubsystem() ? llvm::Triple::Win32
- : llvm::Triple::UnknownOS);
- return arch;
- }
- return ArchSpec();
-}
-
-ObjectFile::Type ObjectFilePECOFF::CalculateType() {
- if (m_coff_header.machine != 0) {
- if ((m_coff_header.flags & llvm::COFF::IMAGE_FILE_DLL) == 0)
- return eTypeExecutable;
- else
- return eTypeSharedLibrary;
- }
- return eTypeExecutable;
-}
-
-ObjectFile::Strata ObjectFilePECOFF::CalculateStrata() { return eStrataUser; }
-
-//------------------------------------------------------------------
-// PluginInterface protocol
-//------------------------------------------------------------------
-ConstString ObjectFilePECOFF::GetPluginName() { return GetPluginNameStatic(); }
-
-uint32_t ObjectFilePECOFF::GetPluginVersion() { return 1; }
diff --git a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
deleted file mode 100644
index 9fd313f26a0a2..0000000000000
--- a/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
+++ /dev/null
@@ -1,294 +0,0 @@
-//===-- ObjectFilePECOFF.h --------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_ObjectFilePECOFF_h_
-#define liblldb_ObjectFilePECOFF_h_
-
-#include <vector>
-
-#include "lldb/Symbol/ObjectFile.h"
-#include "llvm/Object/Binary.h"
-
-class ObjectFilePECOFF : public lldb_private::ObjectFile {
-public:
- typedef enum MachineType {
- MachineUnknown = 0x0,
- MachineAm33 = 0x1d3,
- MachineAmd64 = 0x8664,
- MachineArm = 0x1c0,
- MachineArmNt = 0x1c4,
- MachineArm64 = 0xaa64,
- MachineEbc = 0xebc,
- MachineX86 = 0x14c,
- MachineIA64 = 0x200,
- MachineM32R = 0x9041,
- MachineMips16 = 0x266,
- MachineMipsFpu = 0x366,
- MachineMipsFpu16 = 0x466,
- MachinePowerPc = 0x1f0,
- MachinePowerPcfp = 0x1f1,
- MachineR4000 = 0x166,
- MachineSh3 = 0x1a2,
- MachineSh3dsp = 0x1a3,
- MachineSh4 = 0x1a6,
- MachineSh5 = 0x1a8,
- MachineThumb = 0x1c2,
- MachineWcemIpsv2 = 0x169
- } MachineType;
-
- ObjectFilePECOFF(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- const lldb_private::FileSpec *file,
- lldb::offset_t file_offset, lldb::offset_t length);
-
- ObjectFilePECOFF(const lldb::ModuleSP &module_sp,
- lldb::DataBufferSP &header_data_sp,
- const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
-
- ~ObjectFilePECOFF() override;
-
- //------------------------------------------------------------------
- // Static Functions
- //------------------------------------------------------------------
- static void Initialize();
-
- static void Terminate();
-
- static lldb_private::ConstString GetPluginNameStatic();
-
- static const char *GetPluginDescriptionStatic();
-
- static ObjectFile *
- CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset, const lldb_private::FileSpec *file,
- lldb::offset_t offset, lldb::offset_t length);
-
- static lldb_private::ObjectFile *CreateMemoryInstance(
- const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp,
- const lldb::ProcessSP &process_sp, lldb::addr_t header_addr);
-
- static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
- lldb::DataBufferSP &data_sp,
- lldb::offset_t data_offset,
- lldb::offset_t file_offset,
- lldb::offset_t length,
- lldb_private::ModuleSpecList &specs);
-
- static bool SaveCore(const lldb::ProcessSP &process_sp,
- const lldb_private::FileSpec &outfile,
- lldb_private::Status &error);
-
- static bool MagicBytesMatch(lldb::DataBufferSP &data_sp);
-
- static lldb::SymbolType MapSymbolType(uint16_t coff_symbol_type);
-
- bool ParseHeader() override;
-
- bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value,
- bool value_is_offset) override;
-
- lldb::ByteOrder GetByteOrder() const override;
-
- bool IsExecutable() const override;
-
- uint32_t GetAddressByteSize() const override;
-
- // virtual lldb_private::AddressClass
- // GetAddressClass (lldb::addr_t file_addr);
-
- lldb_private::Symtab *GetSymtab() override;
-
- bool IsStripped() override;
-
- void CreateSections(lldb_private::SectionList &unified_section_list) override;
-
- void Dump(lldb_private::Stream *s) override;
-
- lldb_private::ArchSpec GetArchitecture() override;
-
- bool GetUUID(lldb_private::UUID *uuid) override;
-
- uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
-
- virtual lldb_private::Address GetEntryPointAddress() override;
-
- ObjectFile::Type CalculateType() override;
-
- ObjectFile::Strata CalculateStrata() override;
-
- //------------------------------------------------------------------
- // PluginInterface protocol
- //------------------------------------------------------------------
- lldb_private::ConstString GetPluginName() override;
-
- uint32_t GetPluginVersion() override;
-
- bool IsWindowsSubsystem();
-
- lldb_private::DataExtractor ReadImageData(uint32_t offset, size_t size);
-
-protected:
- bool NeedsEndianSwap() const;
-
- typedef struct dos_header { // DOS .EXE header
- uint16_t e_magic; // Magic number
- uint16_t e_cblp; // Bytes on last page of file
- uint16_t e_cp; // Pages in file
- uint16_t e_crlc; // Relocations
- uint16_t e_cparhdr; // Size of header in paragraphs
- uint16_t e_minalloc; // Minimum extra paragraphs needed
- uint16_t e_maxalloc; // Maximum extra paragraphs needed
- uint16_t e_ss; // Initial (relative) SS value
- uint16_t e_sp; // Initial SP value
- uint16_t e_csum; // Checksum
- uint16_t e_ip; // Initial IP value
- uint16_t e_cs; // Initial (relative) CS value
- uint16_t e_lfarlc; // File address of relocation table
- uint16_t e_ovno; // Overlay number
- uint16_t e_res[4]; // Reserved words
- uint16_t e_oemid; // OEM identifier (for e_oeminfo)
- uint16_t e_oeminfo; // OEM information; e_oemid specific
- uint16_t e_res2[10]; // Reserved words
- uint32_t e_lfanew; // File address of new exe header
- } dos_header_t;
-
- typedef struct coff_header {
- uint16_t machine;
- uint16_t nsects;
- uint32_t modtime;
- uint32_t symoff;
- uint32_t nsyms;
- uint16_t hdrsize;
- uint16_t flags;
- } coff_header_t;
-
- typedef struct data_directory {
- uint32_t vmaddr;
- uint32_t vmsize;
- } data_directory_t;
-
- typedef struct coff_opt_header {
- uint16_t magic;
- uint8_t major_linker_version;
- uint8_t minor_linker_version;
- uint32_t code_size;
- uint32_t data_size;
- uint32_t bss_size;
- uint32_t entry;
- uint32_t code_offset;
- uint32_t data_offset;
-
- uint64_t image_base;
- uint32_t sect_alignment;
- uint32_t file_alignment;
- uint16_t major_os_system_version;
- uint16_t minor_os_system_version;
- uint16_t major_image_version;
- uint16_t minor_image_version;
- uint16_t major_subsystem_version;
- uint16_t minor_subsystem_version;
- uint32_t reserved1;
- uint32_t image_size;
- uint32_t header_size;
- uint32_t checksum;
- uint16_t subsystem;
- uint16_t dll_flags;
- uint64_t stack_reserve_size;
- uint64_t stack_commit_size;
- uint64_t heap_reserve_size;
- uint64_t heap_commit_size;
- uint32_t loader_flags;
- // uint32_t num_data_dir_entries;
- std::vector<data_directory>
- data_dirs; // will contain num_data_dir_entries entries
- } coff_opt_header_t;
-
- typedef enum coff_data_dir_type {
- coff_data_dir_export_table = 0,
- coff_data_dir_import_table = 1,
- } coff_data_dir_type;
-
- typedef struct section_header {
- char name[8];
- uint32_t vmsize; // Virtual Size
- uint32_t vmaddr; // Virtual Addr
- uint32_t size; // File size
- uint32_t offset; // File offset
- uint32_t reloff; // Offset to relocations
- uint32_t lineoff; // Offset to line table entries
- uint16_t nreloc; // Number of relocation entries
- uint16_t nline; // Number of line table entries
- uint32_t flags;
- } section_header_t;
-
- typedef struct coff_symbol {
- char name[8];
- uint32_t value;
- uint16_t sect;
- uint16_t type;
- uint8_t storage;
- uint8_t naux;
- } coff_symbol_t;
-
- typedef struct export_directory_entry {
- uint32_t characteristics;
- uint32_t time_date_stamp;
- uint16_t major_version;
- uint16_t minor_version;
- uint32_t name;
- uint32_t base;
- uint32_t number_of_functions;
- uint32_t number_of_names;
- uint32_t address_of_functions;
- uint32_t address_of_names;
- uint32_t address_of_name_ordinals;
- } export_directory_entry;
-
- static bool ParseDOSHeader(lldb_private::DataExtractor &data,
- dos_header_t &dos_header);
- static bool ParseCOFFHeader(lldb_private::DataExtractor &data,
- lldb::offset_t *offset_ptr,
- coff_header_t &coff_header);
- bool ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr);
- bool ParseSectionHeaders(uint32_t offset);
-
- uint32_t ParseDependentModules();
-
- static void DumpDOSHeader(lldb_private::Stream *s,
- const dos_header_t &header);
- static void DumpCOFFHeader(lldb_private::Stream *s,
- const coff_header_t &header);
- static void DumpOptCOFFHeader(lldb_private::Stream *s,
- const coff_opt_header_t &header);
- void DumpSectionHeaders(lldb_private::Stream *s);
- void DumpSectionHeader(lldb_private::Stream *s, const section_header_t &sh);
- void DumpDependentModules(lldb_private::Stream *s);
-
- llvm::StringRef GetSectionName(const section_header_t &sect);
-
- typedef std::vector<section_header_t> SectionHeaderColl;
- typedef SectionHeaderColl::iterator SectionHeaderCollIter;
- typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
-
-private:
- bool CreateBinary();
-
-private:
- dos_header_t m_dos_header;
- coff_header_t m_coff_header;
- coff_opt_header_t m_coff_header_opt;
- SectionHeaderColl m_sect_headers;
- lldb::addr_t m_image_base;
- lldb_private::Address m_entry_point_address;
- llvm::Optional<lldb_private::FileSpecList> m_deps_filespec;
- typedef llvm::object::OwningBinary<llvm::object::Binary> OWNBINType;
- llvm::Optional<OWNBINType> m_owningbin;
-};
-
-#endif // liblldb_ObjectFilePECOFF_h_
diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp
deleted file mode 100644
index e77888c871b55..0000000000000
--- a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-//===-- WindowsMiniDump.cpp -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// This function is separated out from ObjectFilePECOFF.cpp to name avoid name
-// collisions with WinAPI preprocessor macros.
-
-#include "WindowsMiniDump.h"
-#include "lldb/Utility/FileSpec.h"
-#include "llvm/Support/ConvertUTF.h"
-
-#ifdef _WIN32
-#include "lldb/Host/windows/windows.h"
-#include <dbghelp.h>
-#endif
-
-namespace lldb_private {
-
-bool SaveMiniDump(const lldb::ProcessSP &process_sp,
- const lldb_private::FileSpec &outfile,
- lldb_private::Status &error) {
- if (!process_sp)
- return false;
-#ifdef _WIN32
- HANDLE process_handle = ::OpenProcess(
- PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID());
- const std::string file_name = outfile.GetCString();
- std::wstring wide_name;
- wide_name.resize(file_name.size() + 1);
- char *result_ptr = reinterpret_cast<char *>(&wide_name[0]);
- const llvm::UTF8 *error_ptr = nullptr;
- if (!llvm::ConvertUTF8toWide(sizeof(wchar_t), file_name, result_ptr,
- error_ptr)) {
- error.SetErrorString("cannot convert file name");
- return false;
- }
- HANDLE file_handle =
- ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- const auto result =
- ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle,
- MiniDumpWithFullMemoryInfo, NULL, NULL, NULL);
- ::CloseHandle(file_handle);
- ::CloseHandle(process_handle);
- if (!result) {
- error.SetError(::GetLastError(), lldb::eErrorTypeWin32);
- return false;
- }
- return true;
-#endif
- return false;
-}
-
-} // namesapce lldb_private
diff --git a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h b/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h
deleted file mode 100644
index 135d533873876..0000000000000
--- a/source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//===-- WindowsMiniDump.h ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_WindowsMiniDump_h_
-#define liblldb_WindowsMiniDump_h_
-
-#include "lldb/Target/Process.h"
-
-namespace lldb_private {
-
-bool SaveMiniDump(const lldb::ProcessSP &process_sp,
- const lldb_private::FileSpec &outfile,
- lldb_private::Status &error);
-
-} // namespace lldb_private
-
-#endif