diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 18:01:57 +0000 |
commit | 88c643b6fec27eec436c8d138fee6346e92337d6 (patch) | |
tree | 82cd13b2f3cde1c9e5f79689ba4e6ba67694843f /source/Plugins/ObjectFile | |
parent | 94994d372d014ce4c8758b9605d63fae651bd8aa (diff) |
Notes
Diffstat (limited to 'source/Plugins/ObjectFile')
-rw-r--r-- | source/Plugins/ObjectFile/Breakpad/CMakeLists.txt | 11 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/ELF/CMakeLists.txt | 14 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/JIT/CMakeLists.txt | 11 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Mach-O/CMakeLists.txt | 13 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 6380 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h | 220 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/CMakeLists.txt | 13 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 1183 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h | 294 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp | 59 | ||||
-rw-r--r-- | source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h | 23 |
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(§64, 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, §64.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 §) { - 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 §); - - 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 |