diff options
Diffstat (limited to 'source/Plugins/DynamicLoader')
23 files changed, 7137 insertions, 7080 deletions
diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 4021b44c96a9..b7010303bcaa 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -1,4 +1,5 @@ -//===-- DynamicLoaderDarwinKernel.cpp -----------------------------*- C++ -*-===// +//===-- DynamicLoaderDarwinKernel.cpp -----------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -9,6 +10,7 @@ #include "lldb/Utility/SafeMachO.h" +#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/DataBufferHeap.h" @@ -28,14 +30,13 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" -#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" #include "DynamicLoaderDarwinKernel.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF #include <stdio.h> -#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) #endif @@ -44,89 +45,79 @@ using namespace lldb; using namespace lldb_private; // Progressively greater amounts of scanning we will allow -// For some targets very early in startup, we can't do any random reads of memory or we can crash the device +// For some targets very early in startup, we can't do any random reads of +// memory or we can crash the device // so a setting is needed that can completely disable the KASLR scans. -enum KASLRScanType -{ - eKASLRScanNone = 0, // No reading into the inferior at all - eKASLRScanLowgloAddresses, // Check one word of memory for a possible kernel addr, then see if a kernel is there - eKASLRScanNearPC, // Scan backwards from the current $pc looking for kernel; checking at 96 locations total - eKASLRScanExhaustiveScan // Scan through the entire possible kernel address range looking for a kernel -}; - -OptionEnumValueElement -g_kaslr_kernel_scan_enum_values[] = -{ - { eKASLRScanNone, "none", "Do not read memory looking for a Darwin kernel when attaching." }, - { eKASLRScanLowgloAddresses, "basic", "Check for the Darwin kernel's load addr in the lowglo page (boot-args=debug) only." }, - { eKASLRScanNearPC, "fast-scan", "Scan near the pc value on attach to find the Darwin kernel's load address."}, - { eKASLRScanExhaustiveScan, "exhaustive-scan", "Scan through the entire potential address range of Darwin kernel (only on 32-bit targets)."}, - { 0, NULL, NULL } -}; - -static PropertyDefinition -g_properties[] = -{ - { "load-kexts" , OptionValue::eTypeBoolean, true, true, NULL, NULL, "Automatically loads kext images when attaching to a kernel." }, - { "scan-type", OptionValue::eTypeEnum, true, eKASLRScanNearPC, NULL, g_kaslr_kernel_scan_enum_values, "Control how many reads lldb will make while searching for a Darwin kernel on attach." }, - { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL } -}; - -enum { - ePropertyLoadKexts, - ePropertyScanType +enum KASLRScanType { + eKASLRScanNone = 0, // No reading into the inferior at all + eKASLRScanLowgloAddresses, // Check one word of memory for a possible kernel + // addr, then see if a kernel is there + eKASLRScanNearPC, // Scan backwards from the current $pc looking for kernel; + // checking at 96 locations total + eKASLRScanExhaustiveScan // Scan through the entire possible kernel address + // range looking for a kernel }; -class DynamicLoaderDarwinKernelProperties : public Properties -{ +OptionEnumValueElement g_kaslr_kernel_scan_enum_values[] = { + {eKASLRScanNone, "none", + "Do not read memory looking for a Darwin kernel when attaching."}, + {eKASLRScanLowgloAddresses, "basic", "Check for the Darwin kernel's load " + "addr in the lowglo page " + "(boot-args=debug) only."}, + {eKASLRScanNearPC, "fast-scan", "Scan near the pc value on attach to find " + "the Darwin kernel's load address."}, + {eKASLRScanExhaustiveScan, "exhaustive-scan", + "Scan through the entire potential address range of Darwin kernel (only " + "on 32-bit targets)."}, + {0, NULL, NULL}}; + +static PropertyDefinition g_properties[] = { + {"load-kexts", OptionValue::eTypeBoolean, true, true, NULL, NULL, + "Automatically loads kext images when attaching to a kernel."}, + {"scan-type", OptionValue::eTypeEnum, true, eKASLRScanNearPC, NULL, + g_kaslr_kernel_scan_enum_values, "Control how many reads lldb will make " + "while searching for a Darwin kernel on " + "attach."}, + {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; + +enum { ePropertyLoadKexts, ePropertyScanType }; + +class DynamicLoaderDarwinKernelProperties : public Properties { public: - - static ConstString & - GetSettingName () - { - static ConstString g_setting_name("darwin-kernel"); - return g_setting_name; - } - - DynamicLoaderDarwinKernelProperties() : - Properties () - { - m_collection_sp.reset (new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - virtual - ~DynamicLoaderDarwinKernelProperties() - { - } - - bool - GetLoadKexts() const - { - const uint32_t idx = ePropertyLoadKexts; - return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); - } - - KASLRScanType - GetScanType() const - { - const uint32_t idx = ePropertyScanType; - return (KASLRScanType) m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value); - } - - + static ConstString &GetSettingName() { + static ConstString g_setting_name("darwin-kernel"); + return g_setting_name; + } + + DynamicLoaderDarwinKernelProperties() : Properties() { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + virtual ~DynamicLoaderDarwinKernelProperties() {} + + bool GetLoadKexts() const { + const uint32_t idx = ePropertyLoadKexts; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + NULL, idx, g_properties[idx].default_uint_value != 0); + } + + KASLRScanType GetScanType() const { + const uint32_t idx = ePropertyScanType; + return (KASLRScanType)m_collection_sp->GetPropertyAtIndexAsEnumeration( + NULL, idx, g_properties[idx].default_uint_value); + } }; -typedef std::shared_ptr<DynamicLoaderDarwinKernelProperties> DynamicLoaderDarwinKernelPropertiesSP; +typedef std::shared_ptr<DynamicLoaderDarwinKernelProperties> + DynamicLoaderDarwinKernelPropertiesSP; -static const DynamicLoaderDarwinKernelPropertiesSP & -GetGlobalProperties() -{ - static DynamicLoaderDarwinKernelPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset (new DynamicLoaderDarwinKernelProperties ()); - return g_settings_sp; +static const DynamicLoaderDarwinKernelPropertiesSP &GetGlobalProperties() { + static DynamicLoaderDarwinKernelPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp.reset(new DynamicLoaderDarwinKernelProperties()); + return g_settings_sp; } //---------------------------------------------------------------------- @@ -134,359 +125,382 @@ GetGlobalProperties() // the plugin info class that gets handed out by the plugin factory and // allows the lldb to instantiate an instance of this class. //---------------------------------------------------------------------- -DynamicLoader * -DynamicLoaderDarwinKernel::CreateInstance (Process* process, bool force) -{ - if (!force) - { - // If the user provided an executable binary and it is not a kernel, - // this plugin should not create an instance. - Module* exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - ObjectFile *object_file = exe_module->GetObjectFile(); - if (object_file) - { - if (object_file->GetStrata() != ObjectFile::eStrataKernel) - { - return NULL; - } - } - } - - // If the target's architecture does not look like an Apple environment, - // this plugin should not create an instance. - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - switch (triple_ref.getOS()) - { - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: - case llvm::Triple::IOS: - case llvm::Triple::TvOS: - case llvm::Triple::WatchOS: - if (triple_ref.getVendor() != llvm::Triple::Apple) - { - return NULL; - } - break; - // If we have triple like armv7-unknown-unknown, we should try looking for a Darwin kernel. - case llvm::Triple::UnknownOS: - break; - default: - return NULL; - break; +DynamicLoader *DynamicLoaderDarwinKernel::CreateInstance(Process *process, + bool force) { + if (!force) { + // If the user provided an executable binary and it is not a kernel, + // this plugin should not create an instance. + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + if (object_file->GetStrata() != ObjectFile::eStrataKernel) { + return NULL; } + } } - // At this point if there is an ExecutableModule, it is a kernel and the Target is some variant of an Apple system. - // If the Process hasn't provided the kernel load address, we need to look around in memory to find it. - - const addr_t kernel_load_address = SearchForDarwinKernel (process); - if (CheckForKernelImageAtAddress (kernel_load_address, process).IsValid()) - { - process->SetCanRunCode(false); - return new DynamicLoaderDarwinKernel (process, kernel_load_address); + // If the target's architecture does not look like an Apple environment, + // this plugin should not create an instance. + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + switch (triple_ref.getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + if (triple_ref.getVendor() != llvm::Triple::Apple) { + return NULL; + } + break; + // If we have triple like armv7-unknown-unknown, we should try looking for a + // Darwin kernel. + case llvm::Triple::UnknownOS: + break; + default: + return NULL; + break; } - return NULL; + } + + // At this point if there is an ExecutableModule, it is a kernel and the + // Target is some variant of an Apple system. + // If the Process hasn't provided the kernel load address, we need to look + // around in memory to find it. + + const addr_t kernel_load_address = SearchForDarwinKernel(process); + if (CheckForKernelImageAtAddress(kernel_load_address, process).IsValid()) { + process->SetCanRunCode(false); + return new DynamicLoaderDarwinKernel(process, kernel_load_address); + } + return NULL; } lldb::addr_t -DynamicLoaderDarwinKernel::SearchForDarwinKernel (Process *process) -{ - addr_t kernel_load_address = process->GetImageInfoAddress(); - if (kernel_load_address == LLDB_INVALID_ADDRESS) - { - kernel_load_address = SearchForKernelAtSameLoadAddr (process); - if (kernel_load_address == LLDB_INVALID_ADDRESS) - { - kernel_load_address = SearchForKernelWithDebugHints (process); - if (kernel_load_address == LLDB_INVALID_ADDRESS) - { - kernel_load_address = SearchForKernelNearPC (process); - if (kernel_load_address == LLDB_INVALID_ADDRESS) - { - kernel_load_address = SearchForKernelViaExhaustiveSearch (process); - } - } +DynamicLoaderDarwinKernel::SearchForDarwinKernel(Process *process) { + addr_t kernel_load_address = process->GetImageInfoAddress(); + if (kernel_load_address == LLDB_INVALID_ADDRESS) { + kernel_load_address = SearchForKernelAtSameLoadAddr(process); + if (kernel_load_address == LLDB_INVALID_ADDRESS) { + kernel_load_address = SearchForKernelWithDebugHints(process); + if (kernel_load_address == LLDB_INVALID_ADDRESS) { + kernel_load_address = SearchForKernelNearPC(process); + if (kernel_load_address == LLDB_INVALID_ADDRESS) { + kernel_load_address = SearchForKernelViaExhaustiveSearch(process); } + } } - return kernel_load_address; + } + return kernel_load_address; } //---------------------------------------------------------------------- // Check if the kernel binary is loaded in memory without a slide. // First verify that the ExecutableModule is a kernel before we proceed. -// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS. +// Returns the address of the kernel if one was found, else +// LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t -DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr (Process *process) -{ - Module *exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module == NULL) - return LLDB_INVALID_ADDRESS; +DynamicLoaderDarwinKernel::SearchForKernelAtSameLoadAddr(Process *process) { + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module == NULL) + return LLDB_INVALID_ADDRESS; - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - if (exe_objfile == NULL) - return LLDB_INVALID_ADDRESS; + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + if (exe_objfile == NULL) + return LLDB_INVALID_ADDRESS; - if (exe_objfile->GetType() != ObjectFile::eTypeExecutable || exe_objfile->GetStrata() != ObjectFile::eStrataKernel) - return LLDB_INVALID_ADDRESS; + if (exe_objfile->GetType() != ObjectFile::eTypeExecutable || + exe_objfile->GetStrata() != ObjectFile::eStrataKernel) + return LLDB_INVALID_ADDRESS; - if (!exe_objfile->GetHeaderAddress().IsValid()) - return LLDB_INVALID_ADDRESS; + if (!exe_objfile->GetHeaderAddress().IsValid()) + return LLDB_INVALID_ADDRESS; - if (CheckForKernelImageAtAddress (exe_objfile->GetHeaderAddress().GetFileAddress(), process) == exe_module->GetUUID()) - return exe_objfile->GetHeaderAddress().GetFileAddress(); + if (CheckForKernelImageAtAddress( + exe_objfile->GetHeaderAddress().GetFileAddress(), process) == + exe_module->GetUUID()) + return exe_objfile->GetHeaderAddress().GetFileAddress(); - return LLDB_INVALID_ADDRESS; + return LLDB_INVALID_ADDRESS; } //---------------------------------------------------------------------- -// If the debug flag is included in the boot-args nvram setting, the kernel's load address +// If the debug flag is included in the boot-args nvram setting, the kernel's +// load address // will be noted in the lowglo page at a fixed address -// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS. +// Returns the address of the kernel if one was found, else +// LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t -DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints (Process *process) -{ - if (GetGlobalProperties()->GetScanType() == eKASLRScanNone) - return LLDB_INVALID_ADDRESS; - - Error read_err; - addr_t addr = LLDB_INVALID_ADDRESS; - addr_t kernel_addresses_64[] = { 0xffffff8000002010ULL, 0xffffff8000004010ULL, - 0xfffffff000002010ULL, 0xfffffff000004010ULL, - LLDB_INVALID_ADDRESS }; - addr_t kernel_addresses_32[] = { 0xffff0110, - LLDB_INVALID_ADDRESS }; - for (size_t i = 0; kernel_addresses_64[i] != LLDB_INVALID_ADDRESS; i++) - { - addr = process->ReadUnsignedIntegerFromMemory (kernel_addresses_64[i], 8, LLDB_INVALID_ADDRESS, read_err); - if (CheckForKernelImageAtAddress (addr, process).IsValid()) - { - return addr; - } - } - - for (size_t i = 0; kernel_addresses_32[i] != LLDB_INVALID_ADDRESS; i++) - { - addr = process->ReadUnsignedIntegerFromMemory (kernel_addresses_32[i], 4, LLDB_INVALID_ADDRESS, read_err); - if (CheckForKernelImageAtAddress (addr, process).IsValid()) - { - return addr; - } - } - +DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { + if (GetGlobalProperties()->GetScanType() == eKASLRScanNone) return LLDB_INVALID_ADDRESS; + + Error read_err; + addr_t kernel_addresses_64[] = { + 0xfffffff000004010ULL, // newest arm64 devices + 0xffffff8000004010ULL, // 2014-2015-ish arm64 devices + 0xffffff8000002010ULL, // oldest arm64 devices + LLDB_INVALID_ADDRESS}; + addr_t kernel_addresses_32[] = {0xffff0110, // 2016 and earlier armv7 devices + 0xffff1010, + LLDB_INVALID_ADDRESS}; + + uint8_t uval[8]; + if (process->GetAddressByteSize() == 8) { + for (size_t i = 0; kernel_addresses_64[i] != LLDB_INVALID_ADDRESS; i++) { + if (process->ReadMemoryFromInferior (kernel_addresses_64[i], uval, 8, read_err) == 8) + { + DataExtractor data (&uval, 8, process->GetByteOrder(), process->GetAddressByteSize()); + offset_t offset = 0; + uint64_t addr = data.GetU64 (&offset); + if (CheckForKernelImageAtAddress(addr, process).IsValid()) { + return addr; + } + } + } + } + + if (process->GetAddressByteSize() == 4) { + for (size_t i = 0; kernel_addresses_32[i] != LLDB_INVALID_ADDRESS; i++) { + if (process->ReadMemoryFromInferior (kernel_addresses_32[i], uval, 4, read_err) == 4) + { + DataExtractor data (&uval, 4, process->GetByteOrder(), process->GetAddressByteSize()); + offset_t offset = 0; + uint32_t addr = data.GetU32 (&offset); + if (CheckForKernelImageAtAddress(addr, process).IsValid()) { + return addr; + } + } + } + } + + return LLDB_INVALID_ADDRESS; } //---------------------------------------------------------------------- // If the kernel is currently executing when lldb attaches, and we don't have // a better way of finding the kernel's load address, try searching backwards // from the current pc value looking for the kernel's Mach header in memory. -// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS. +// Returns the address of the kernel if one was found, else +// LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- lldb::addr_t -DynamicLoaderDarwinKernel::SearchForKernelNearPC (Process *process) -{ - if (GetGlobalProperties()->GetScanType() == eKASLRScanNone - || GetGlobalProperties()->GetScanType() == eKASLRScanLowgloAddresses) - { - return LLDB_INVALID_ADDRESS; - } +DynamicLoaderDarwinKernel::SearchForKernelNearPC(Process *process) { + if (GetGlobalProperties()->GetScanType() == eKASLRScanNone || + GetGlobalProperties()->GetScanType() == eKASLRScanLowgloAddresses) { + return LLDB_INVALID_ADDRESS; + } - ThreadSP thread = process->GetThreadList().GetSelectedThread (); - if (thread.get() == NULL) - return LLDB_INVALID_ADDRESS; - addr_t pc = thread->GetRegisterContext ()->GetPC(LLDB_INVALID_ADDRESS); - - if (pc == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - // The kernel will load at at one megabyte boundary (0x100000), or at that boundary plus - // an offset of one page (0x1000) or two, or four (0x4000), depending on the device. - - // Round the current pc down to the nearest one megabyte boundary - the place where we will start searching. - addr_t addr = pc & ~0xfffff; - - // Search backwards 32 megabytes, looking for the start of the kernel at each one-megabyte boundary. - for (int i = 0; i < 32; i++, addr -= 0x100000) - { - if (CheckForKernelImageAtAddress (addr, process).IsValid()) - return addr; - if (CheckForKernelImageAtAddress (addr + 0x1000, process).IsValid()) - return addr + 0x1000; - if (CheckForKernelImageAtAddress (addr + 0x2000, process).IsValid()) - return addr + 0x2000; - if (CheckForKernelImageAtAddress (addr + 0x4000, process).IsValid()) - return addr + 0x4000; - } + ThreadSP thread = process->GetThreadList().GetSelectedThread(); + if (thread.get() == NULL) + return LLDB_INVALID_ADDRESS; + addr_t pc = thread->GetRegisterContext()->GetPC(LLDB_INVALID_ADDRESS); + if (pc == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; + + // The kernel will load at at one megabyte boundary (0x100000), or at that + // boundary plus + // an offset of one page (0x1000) or two, or four (0x4000), depending on the + // device. + + // Round the current pc down to the nearest one megabyte boundary - the place + // where we will start searching. + addr_t addr = pc & ~0xfffff; + + // Search backwards 32 megabytes, looking for the start of the kernel at each + // one-megabyte boundary. + for (int i = 0; i < 32; i++, addr -= 0x100000) { + if (CheckForKernelImageAtAddress(addr, process).IsValid()) + return addr; + if (CheckForKernelImageAtAddress(addr + 0x1000, process).IsValid()) + return addr + 0x1000; + if (CheckForKernelImageAtAddress(addr + 0x2000, process).IsValid()) + return addr + 0x2000; + if (CheckForKernelImageAtAddress(addr + 0x4000, process).IsValid()) + return addr + 0x4000; + } + + return LLDB_INVALID_ADDRESS; } //---------------------------------------------------------------------- // Scan through the valid address range for a kernel binary. // This is uselessly slow in 64-bit environments so we don't even try it. // This scan is not enabled by default even for 32-bit targets. -// Returns the address of the kernel if one was found, else LLDB_INVALID_ADDRESS. +// Returns the address of the kernel if one was found, else +// LLDB_INVALID_ADDRESS. //---------------------------------------------------------------------- -lldb::addr_t -DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch (Process *process) -{ - if (GetGlobalProperties()->GetScanType() != eKASLRScanExhaustiveScan) - { - return LLDB_INVALID_ADDRESS; - } - - addr_t kernel_range_low, kernel_range_high; - if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8) - { - kernel_range_low = 1ULL << 63; - kernel_range_high = UINT64_MAX; - } - else - { - kernel_range_low = 1ULL << 31; - kernel_range_high = UINT32_MAX; - } - - // Stepping through memory at one-megabyte resolution looking for a kernel - // rarely works (fast enough) with a 64-bit address space -- for now, let's - // not even bother. We may be attaching to something which *isn't* a kernel - // and we don't want to spin for minutes on-end looking for a kernel. - if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8) - return LLDB_INVALID_ADDRESS; - - addr_t addr = kernel_range_low; - - while (addr >= kernel_range_low && addr < kernel_range_high) - { - if (CheckForKernelImageAtAddress (addr, process).IsValid()) - return addr; - if (CheckForKernelImageAtAddress (addr + 0x1000, process).IsValid()) - return addr + 0x1000; - if (CheckForKernelImageAtAddress (addr + 0x2000, process).IsValid()) - return addr + 0x2000; - if (CheckForKernelImageAtAddress (addr + 0x4000, process).IsValid()) - return addr + 0x4000; - addr += 0x100000; - } +lldb::addr_t DynamicLoaderDarwinKernel::SearchForKernelViaExhaustiveSearch( + Process *process) { + if (GetGlobalProperties()->GetScanType() != eKASLRScanExhaustiveScan) { + return LLDB_INVALID_ADDRESS; + } + + addr_t kernel_range_low, kernel_range_high; + if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8) { + kernel_range_low = 1ULL << 63; + kernel_range_high = UINT64_MAX; + } else { + kernel_range_low = 1ULL << 31; + kernel_range_high = UINT32_MAX; + } + + // Stepping through memory at one-megabyte resolution looking for a kernel + // rarely works (fast enough) with a 64-bit address space -- for now, let's + // not even bother. We may be attaching to something which *isn't* a kernel + // and we don't want to spin for minutes on-end looking for a kernel. + if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 8) return LLDB_INVALID_ADDRESS; + + addr_t addr = kernel_range_low; + + while (addr >= kernel_range_low && addr < kernel_range_high) { + if (CheckForKernelImageAtAddress(addr, process).IsValid()) + return addr; + if (CheckForKernelImageAtAddress(addr + 0x1000, process).IsValid()) + return addr + 0x1000; + if (CheckForKernelImageAtAddress(addr + 0x2000, process).IsValid()) + return addr + 0x2000; + if (CheckForKernelImageAtAddress(addr + 0x4000, process).IsValid()) + return addr + 0x4000; + addr += 0x100000; + } + return LLDB_INVALID_ADDRESS; } //---------------------------------------------------------------------- // Given an address in memory, look to see if there is a kernel image at that -// address. -// Returns a UUID; if a kernel was not found at that address, UUID.IsValid() will be false. +// address. +// Returns a UUID; if a kernel was not found at that address, UUID.IsValid() +// will be false. //---------------------------------------------------------------------- lldb_private::UUID -DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress (lldb::addr_t addr, Process *process) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - if (addr == LLDB_INVALID_ADDRESS) - return UUID(); +DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress(lldb::addr_t addr, + Process *process) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (addr == LLDB_INVALID_ADDRESS) + return UUID(); - if (log) - log->Printf ("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: looking for kernel binary at 0x%" PRIx64, addr); - - // First try a quick test -- read the first 4 bytes and see if there is a valid Mach-O magic field there - // (the first field of the mach_header/mach_header_64 struct). - - Error read_error; - uint64_t result = process->ReadUnsignedIntegerFromMemory (addr, 4, LLDB_INVALID_ADDRESS, read_error); - if (result != llvm::MachO::MH_MAGIC_64 - && result != llvm::MachO::MH_MAGIC - && result != llvm::MachO::MH_CIGAM - && result != llvm::MachO::MH_CIGAM_64) - { - return UUID(); - } + if (log) + log->Printf("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: " + "looking for kernel binary at 0x%" PRIx64, + addr); + + // First try a quick test -- read the first 4 bytes and see if there is a + // valid Mach-O magic field there + // (the first field of the mach_header/mach_header_64 struct). - // Read the mach header and see whether it looks like a kernel - llvm::MachO::mach_header header; - if (process->DoReadMemory (addr, &header, sizeof (header), read_error) != sizeof (header)) - return UUID(); - - if (header.magic == llvm::MachO::MH_CIGAM || - header.magic == llvm::MachO::MH_CIGAM_64) - { - header.magic = llvm::ByteSwap_32 (header.magic); - header.cputype = llvm::ByteSwap_32 (header.cputype); - header.cpusubtype = llvm::ByteSwap_32 (header.cpusubtype); - header.filetype = llvm::ByteSwap_32 (header.filetype); - header.ncmds = llvm::ByteSwap_32 (header.ncmds); - header.sizeofcmds = llvm::ByteSwap_32 (header.sizeofcmds); - header.flags = llvm::ByteSwap_32 (header.flags); + Error read_error; + uint8_t magicbuf[4]; + if (process->ReadMemoryFromInferior (addr, magicbuf, sizeof (magicbuf), read_error) != sizeof (magicbuf)) + return UUID(); + + const uint32_t magicks[] = { llvm::MachO::MH_MAGIC_64, llvm::MachO::MH_MAGIC, llvm::MachO::MH_CIGAM, llvm::MachO::MH_CIGAM_64}; + + bool found_matching_pattern = false; + for (size_t i = 0; i < llvm::array_lengthof (magicks); i++) + if (::memcmp (magicbuf, &magicks[i], sizeof (magicbuf)) == 0) + found_matching_pattern = true; + + if (found_matching_pattern == false) + return UUID(); + + // Read the mach header and see whether it looks like a kernel + llvm::MachO::mach_header header; + if (process->DoReadMemory(addr, &header, sizeof(header), read_error) != + sizeof(header)) + return UUID(); + + if (header.magic == llvm::MachO::MH_CIGAM || + header.magic == llvm::MachO::MH_CIGAM_64) { + header.magic = llvm::ByteSwap_32(header.magic); + header.cputype = llvm::ByteSwap_32(header.cputype); + header.cpusubtype = llvm::ByteSwap_32(header.cpusubtype); + header.filetype = llvm::ByteSwap_32(header.filetype); + header.ncmds = llvm::ByteSwap_32(header.ncmds); + header.sizeofcmds = llvm::ByteSwap_32(header.sizeofcmds); + header.flags = llvm::ByteSwap_32(header.flags); + } + + // A kernel is an executable which does not have the dynamic link object flag + // set. + if (header.filetype == llvm::MachO::MH_EXECUTE && + (header.flags & llvm::MachO::MH_DYLDLINK) == 0) { + // Create a full module to get the UUID + ModuleSP memory_module_sp = process->ReadModuleFromMemory( + FileSpec("temp_mach_kernel", false), addr); + if (!memory_module_sp.get()) + return UUID(); + + ObjectFile *exe_objfile = memory_module_sp->GetObjectFile(); + if (exe_objfile == NULL) { + if (log) + log->Printf("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress " + "found a binary at 0x%" PRIx64 + " but could not create an object file from memory", + addr); + return UUID(); } - // A kernel is an executable which does not have the dynamic link object flag set. - if (header.filetype == llvm::MachO::MH_EXECUTE - && (header.flags & llvm::MachO::MH_DYLDLINK) == 0) - { - // Create a full module to get the UUID - ModuleSP memory_module_sp = process->ReadModuleFromMemory (FileSpec ("temp_mach_kernel", false), addr); - if (!memory_module_sp.get()) - return UUID(); - - ObjectFile *exe_objfile = memory_module_sp->GetObjectFile(); - if (exe_objfile == NULL) - return UUID(); - - if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && exe_objfile->GetStrata() == ObjectFile::eStrataKernel) - { - ArchSpec kernel_arch (eArchTypeMachO, header.cputype, header.cpusubtype); - if (!process->GetTarget().GetArchitecture().IsCompatibleMatch(kernel_arch)) - { - process->GetTarget().SetArchitecture (kernel_arch); - } - if (log) - log->Printf ("DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: kernel binary image found at 0x%" PRIx64, addr); - return memory_module_sp->GetUUID(); + if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && + exe_objfile->GetStrata() == ObjectFile::eStrataKernel) { + ArchSpec kernel_arch(eArchTypeMachO, header.cputype, header.cpusubtype); + if (!process->GetTarget().GetArchitecture().IsCompatibleMatch( + kernel_arch)) { + process->GetTarget().SetArchitecture(kernel_arch); + } + if (log) { + std::string uuid_str; + if (memory_module_sp->GetUUID().IsValid()) { + uuid_str = "with UUID "; + uuid_str += memory_module_sp->GetUUID().GetAsString(); + } else { + uuid_str = "and no LC_UUID found in load commands "; } + log->Printf( + "DynamicLoaderDarwinKernel::CheckForKernelImageAtAddress: " + "kernel binary image found at 0x%" PRIx64 " with arch '%s' %s", + addr, kernel_arch.GetTriple().str().c_str(), uuid_str.c_str()); + } + return memory_module_sp->GetUUID(); } + } - return UUID(); + return UUID(); } //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel(Process *process, lldb::addr_t kernel_addr) - : DynamicLoader(process), - m_kernel_load_address(kernel_addr), - m_kernel(), - m_kext_summary_header_ptr_addr(), - m_kext_summary_header_addr(), - m_kext_summary_header(), - m_known_kexts(), - m_mutex(), - m_break_id(LLDB_INVALID_BREAK_ID) -{ - Error error; - PlatformSP platform_sp(Platform::Create(PlatformDarwinKernel::GetPluginNameStatic(), error)); - // Only select the darwin-kernel Platform if we've been asked to load kexts. - // It can take some time to scan over all of the kext info.plists and that - // shouldn't be done if kext loading is explicitly disabled. - if (platform_sp.get() && GetGlobalProperties()->GetLoadKexts()) - { - process->GetTarget().SetPlatform(platform_sp); - } +DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel(Process *process, + lldb::addr_t kernel_addr) + : DynamicLoader(process), m_kernel_load_address(kernel_addr), m_kernel(), + m_kext_summary_header_ptr_addr(), m_kext_summary_header_addr(), + m_kext_summary_header(), m_known_kexts(), m_mutex(), + m_break_id(LLDB_INVALID_BREAK_ID) { + Error error; + PlatformSP platform_sp( + Platform::Create(PlatformDarwinKernel::GetPluginNameStatic(), error)); + // Only select the darwin-kernel Platform if we've been asked to load kexts. + // It can take some time to scan over all of the kext info.plists and that + // shouldn't be done if kext loading is explicitly disabled. + if (platform_sp.get() && GetGlobalProperties()->GetLoadKexts()) { + process->GetTarget().SetPlatform(platform_sp); + } } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -DynamicLoaderDarwinKernel::~DynamicLoaderDarwinKernel() -{ - Clear(true); -} +DynamicLoaderDarwinKernel::~DynamicLoaderDarwinKernel() { Clear(true); } -void -DynamicLoaderDarwinKernel::UpdateIfNeeded() -{ - LoadKernelModuleIfNeeded(); - SetNotificationBreakpointIfNeeded (); +void DynamicLoaderDarwinKernel::UpdateIfNeeded() { + LoadKernelModuleIfNeeded(); + SetNotificationBreakpointIfNeeded(); } //------------------------------------------------------------------ /// Called after attaching a process. @@ -494,11 +508,9 @@ DynamicLoaderDarwinKernel::UpdateIfNeeded() /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderDarwinKernel::DidAttach () -{ - PrivateInitialize(m_process); - UpdateIfNeeded(); +void DynamicLoaderDarwinKernel::DidAttach() { + PrivateInitialize(m_process); + UpdateIfNeeded(); } //------------------------------------------------------------------ @@ -507,592 +519,528 @@ DynamicLoaderDarwinKernel::DidAttach () /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderDarwinKernel::DidLaunch () -{ - PrivateInitialize(m_process); - UpdateIfNeeded(); +void DynamicLoaderDarwinKernel::DidLaunch() { + PrivateInitialize(m_process); + UpdateIfNeeded(); } - //---------------------------------------------------------------------- // Clear out the state of this class. //---------------------------------------------------------------------- -void -DynamicLoaderDarwinKernel::Clear (bool clear_process) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id)) - m_process->ClearBreakpointSiteByID(m_break_id); - - if (clear_process) - m_process = NULL; - m_kernel.Clear(); - m_known_kexts.clear(); - m_kext_summary_header_ptr_addr.Clear(); - m_kext_summary_header_addr.Clear(); - m_break_id = LLDB_INVALID_BREAK_ID; +void DynamicLoaderDarwinKernel::Clear(bool clear_process) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id)) + m_process->ClearBreakpointSiteByID(m_break_id); + + if (clear_process) + m_process = NULL; + m_kernel.Clear(); + m_known_kexts.clear(); + m_kext_summary_header_ptr_addr.Clear(); + m_kext_summary_header_addr.Clear(); + m_break_id = LLDB_INVALID_BREAK_ID; } +bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageAtFileAddress( + Process *process) { + if (IsLoaded()) + return true; -bool -DynamicLoaderDarwinKernel::KextImageInfo::LoadImageAtFileAddress (Process *process) -{ - if (IsLoaded()) - return true; - - if (m_module_sp) - { - bool changed = false; - if (m_module_sp->SetLoadAddress (process->GetTarget(), 0, true, changed)) - m_load_process_stop_id = process->GetStopID(); - } - return false; + if (m_module_sp) { + bool changed = false; + if (m_module_sp->SetLoadAddress(process->GetTarget(), 0, true, changed)) + m_load_process_stop_id = process->GetStopID(); + } + return false; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetModule (ModuleSP module_sp) -{ - m_module_sp = module_sp; - if (module_sp.get() && module_sp->GetObjectFile()) - { - if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeExecutable - && module_sp->GetObjectFile()->GetStrata() == ObjectFile::eStrataKernel) - { - m_kernel_image = true; - } - else - { - m_kernel_image = false; - } +void DynamicLoaderDarwinKernel::KextImageInfo::SetModule(ModuleSP module_sp) { + m_module_sp = module_sp; + if (module_sp.get() && module_sp->GetObjectFile()) { + if (module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeExecutable && + module_sp->GetObjectFile()->GetStrata() == ObjectFile::eStrataKernel) { + m_kernel_image = true; + } else { + m_kernel_image = false; } + } } -ModuleSP -DynamicLoaderDarwinKernel::KextImageInfo::GetModule () -{ - return m_module_sp; +ModuleSP DynamicLoaderDarwinKernel::KextImageInfo::GetModule() { + return m_module_sp; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetLoadAddress (addr_t load_addr) -{ - m_load_address = load_addr; +void DynamicLoaderDarwinKernel::KextImageInfo::SetLoadAddress( + addr_t load_addr) { + m_load_address = load_addr; } -addr_t -DynamicLoaderDarwinKernel::KextImageInfo::GetLoadAddress () const -{ - return m_load_address; +addr_t DynamicLoaderDarwinKernel::KextImageInfo::GetLoadAddress() const { + return m_load_address; } -uint64_t -DynamicLoaderDarwinKernel::KextImageInfo::GetSize () const -{ - return m_size; +uint64_t DynamicLoaderDarwinKernel::KextImageInfo::GetSize() const { + return m_size; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetSize (uint64_t size) -{ - m_size = size; +void DynamicLoaderDarwinKernel::KextImageInfo::SetSize(uint64_t size) { + m_size = size; } -uint32_t -DynamicLoaderDarwinKernel::KextImageInfo::GetProcessStopId () const -{ - return m_load_process_stop_id; +uint32_t DynamicLoaderDarwinKernel::KextImageInfo::GetProcessStopId() const { + return m_load_process_stop_id; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetProcessStopId (uint32_t stop_id) -{ - m_load_process_stop_id = stop_id; +void DynamicLoaderDarwinKernel::KextImageInfo::SetProcessStopId( + uint32_t stop_id) { + m_load_process_stop_id = stop_id; } -bool -DynamicLoaderDarwinKernel::KextImageInfo::operator== (const KextImageInfo &rhs) -{ - if (m_uuid.IsValid() || rhs.GetUUID().IsValid()) - { - if (m_uuid == rhs.GetUUID()) - { - return true; - } - return false; +bool DynamicLoaderDarwinKernel::KextImageInfo:: +operator==(const KextImageInfo &rhs) { + if (m_uuid.IsValid() || rhs.GetUUID().IsValid()) { + if (m_uuid == rhs.GetUUID()) { + return true; } + return false; + } - if (m_name == rhs.GetName() && m_load_address == rhs.GetLoadAddress()) - return true; + if (m_name == rhs.GetName() && m_load_address == rhs.GetLoadAddress()) + return true; - return false; + return false; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetName (const char *name) -{ - m_name = name; +void DynamicLoaderDarwinKernel::KextImageInfo::SetName(const char *name) { + m_name = name; } -std::string -DynamicLoaderDarwinKernel::KextImageInfo::GetName () const -{ - return m_name; +std::string DynamicLoaderDarwinKernel::KextImageInfo::GetName() const { + return m_name; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetUUID (const UUID &uuid) -{ - m_uuid = uuid; +void DynamicLoaderDarwinKernel::KextImageInfo::SetUUID(const UUID &uuid) { + m_uuid = uuid; } -UUID -DynamicLoaderDarwinKernel::KextImageInfo::GetUUID () const -{ - return m_uuid; +UUID DynamicLoaderDarwinKernel::KextImageInfo::GetUUID() const { + return m_uuid; } -// Given the m_load_address from the kext summaries, and a UUID, try to create an in-memory -// Module at that address. Require that the MemoryModule have a matching UUID and detect +// Given the m_load_address from the kext summaries, and a UUID, try to create +// an in-memory +// Module at that address. Require that the MemoryModule have a matching UUID +// and detect // if this MemoryModule is a kernel or a kext. // -// Returns true if m_memory_module_sp is now set to a valid Module. - -bool -DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule (Process *process) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (m_memory_module_sp.get() != NULL) - return true; - if (m_load_address == LLDB_INVALID_ADDRESS) - return false; - - FileSpec file_spec; - file_spec.SetFile (m_name.c_str(), false); - - ModuleSP memory_module_sp = process->ReadModuleFromMemory (file_spec, m_load_address); - - if (memory_module_sp.get() == NULL) - return false; - - bool is_kernel = false; - if (memory_module_sp->GetObjectFile()) - { - if (memory_module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeExecutable - && memory_module_sp->GetObjectFile()->GetStrata() == ObjectFile::eStrataKernel) - { - is_kernel = true; - } - else if (memory_module_sp->GetObjectFile()->GetType() == ObjectFile::eTypeSharedLibrary) - { - is_kernel = false; - } - } +// Returns true if m_memory_module_sp is now set to a valid Module. - // If this is a kext, and the kernel specified what UUID we should find at this - // load address, require that the memory module have a matching UUID or something - // has gone wrong and we should discard it. - if (m_uuid.IsValid()) - { - if (m_uuid != memory_module_sp->GetUUID()) - { - if (log) - { - log->Printf ("KextImageInfo::ReadMemoryModule the kernel said to find uuid %s at 0x%" PRIx64 " but instead we found uuid %s, throwing it away", m_uuid.GetAsString().c_str(), m_load_address, memory_module_sp->GetUUID().GetAsString().c_str()); - } - return false; - } - } +bool DynamicLoaderDarwinKernel::KextImageInfo::ReadMemoryModule( + Process *process) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (m_memory_module_sp.get() != NULL) + return true; + if (m_load_address == LLDB_INVALID_ADDRESS) + return false; - // If the in-memory Module has a UUID, let's use that. - if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid()) - { - m_uuid = memory_module_sp->GetUUID(); - } + FileSpec file_spec; + file_spec.SetFile(m_name.c_str(), false); - m_memory_module_sp = memory_module_sp; - m_kernel_image = is_kernel; - if (is_kernel) - { - if (log) - { - // This is unusual and probably not intended - log->Printf ("KextImageInfo::ReadMemoryModule read the kernel binary out of memory"); - } - if (memory_module_sp->GetArchitecture().IsValid()) - { - process->GetTarget().SetArchitecture(memory_module_sp->GetArchitecture()); - } - if (m_uuid.IsValid()) - { - ModuleSP exe_module_sp = process->GetTarget().GetExecutableModule(); - if (exe_module_sp.get() && exe_module_sp->GetUUID().IsValid()) - { - if (m_uuid != exe_module_sp->GetUUID()) - { - // The user specified a kernel binary that has a different UUID than - // the kernel actually running in memory. This never ends well; - // clear the user specified kernel binary from the Target. - - m_module_sp.reset(); - - ModuleList user_specified_kernel_list; - user_specified_kernel_list.Append (exe_module_sp); - process->GetTarget().GetImages().Remove (user_specified_kernel_list); - } - } + ModuleSP memory_module_sp = + process->ReadModuleFromMemory(file_spec, m_load_address); + + if (memory_module_sp.get() == NULL) + return false; + + bool is_kernel = false; + if (memory_module_sp->GetObjectFile()) { + if (memory_module_sp->GetObjectFile()->GetType() == + ObjectFile::eTypeExecutable && + memory_module_sp->GetObjectFile()->GetStrata() == + ObjectFile::eStrataKernel) { + is_kernel = true; + } else if (memory_module_sp->GetObjectFile()->GetType() == + ObjectFile::eTypeSharedLibrary) { + is_kernel = false; + } + } + + // If this is a kext, and the kernel specified what UUID we should find at + // this + // load address, require that the memory module have a matching UUID or + // something + // has gone wrong and we should discard it. + if (m_uuid.IsValid()) { + if (m_uuid != memory_module_sp->GetUUID()) { + if (log) { + log->Printf("KextImageInfo::ReadMemoryModule the kernel said to find " + "uuid %s at 0x%" PRIx64 + " but instead we found uuid %s, throwing it away", + m_uuid.GetAsString().c_str(), m_load_address, + memory_module_sp->GetUUID().GetAsString().c_str()); + } + return false; + } + } + + // If the in-memory Module has a UUID, let's use that. + if (!m_uuid.IsValid() && memory_module_sp->GetUUID().IsValid()) { + m_uuid = memory_module_sp->GetUUID(); + } + + m_memory_module_sp = memory_module_sp; + m_kernel_image = is_kernel; + if (is_kernel) { + if (log) { + // This is unusual and probably not intended + log->Printf("KextImageInfo::ReadMemoryModule read the kernel binary out " + "of memory"); + } + if (memory_module_sp->GetArchitecture().IsValid()) { + process->GetTarget().SetArchitecture(memory_module_sp->GetArchitecture()); + } + if (m_uuid.IsValid()) { + ModuleSP exe_module_sp = process->GetTarget().GetExecutableModule(); + if (exe_module_sp.get() && exe_module_sp->GetUUID().IsValid()) { + if (m_uuid != exe_module_sp->GetUUID()) { + // The user specified a kernel binary that has a different UUID than + // the kernel actually running in memory. This never ends well; + // clear the user specified kernel binary from the Target. + + m_module_sp.reset(); + + ModuleList user_specified_kernel_list; + user_specified_kernel_list.Append(exe_module_sp); + process->GetTarget().GetImages().Remove(user_specified_kernel_list); } + } } + } - return true; + return true; } -bool -DynamicLoaderDarwinKernel::KextImageInfo::IsKernel () const -{ - return m_kernel_image == true; +bool DynamicLoaderDarwinKernel::KextImageInfo::IsKernel() const { + return m_kernel_image == true; } -void -DynamicLoaderDarwinKernel::KextImageInfo::SetIsKernel (bool is_kernel) -{ - m_kernel_image = is_kernel; +void DynamicLoaderDarwinKernel::KextImageInfo::SetIsKernel(bool is_kernel) { + m_kernel_image = is_kernel; } -bool -DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule (Process *process) -{ - if (IsLoaded()) - return true; - +bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( + Process *process) { + if (IsLoaded()) + return true; - Target &target = process->GetTarget(); + Target &target = process->GetTarget(); - // If we don't have / can't create a memory module for this kext, don't try to load it - we won't - // have the correct segment load addresses. - if (!ReadMemoryModule (process)) - { - return false; - } + // If we don't have / can't create a memory module for this kext, don't try to + // load it - we won't + // have the correct segment load addresses. + if (!ReadMemoryModule(process)) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("Unable to read '%s' from memory at address 0x%" PRIx64 + " to get the segment load addresses.", + m_name.c_str(), m_load_address); + return false; + } - bool uuid_is_valid = m_uuid.IsValid(); + bool uuid_is_valid = m_uuid.IsValid(); - if (IsKernel() && uuid_is_valid && m_memory_module_sp.get()) - { - Stream *s = target.GetDebugger().GetOutputFile().get(); - if (s) - { - s->Printf ("Kernel UUID: %s\n", m_memory_module_sp->GetUUID().GetAsString().c_str()); - s->Printf ("Load Address: 0x%" PRIx64 "\n", m_load_address); - } + if (IsKernel() && uuid_is_valid && m_memory_module_sp.get()) { + Stream *s = target.GetDebugger().GetOutputFile().get(); + if (s) { + s->Printf("Kernel UUID: %s\n", + m_memory_module_sp->GetUUID().GetAsString().c_str()); + s->Printf("Load Address: 0x%" PRIx64 "\n", m_load_address); } - - if (!m_module_sp) - { - // See if the kext has already been loaded into the target, probably by the user doing target modules add. - const ModuleList &target_images = target.GetImages(); - m_module_sp = target_images.FindModule(m_uuid); - - // Search for the kext on the local filesystem via the UUID - if (!m_module_sp && uuid_is_valid) - { - ModuleSpec module_spec; - module_spec.GetUUID() = m_uuid; - module_spec.GetArchitecture() = target.GetArchitecture(); - - // For the kernel, we really do need an on-disk file copy of the binary to do anything useful. - // This will force a clal to - if (IsKernel()) - { - if (Symbols::DownloadObjectAndSymbolFile (module_spec, true)) - { - if (module_spec.GetFileSpec().Exists()) - { - m_module_sp.reset(new Module (module_spec.GetFileSpec(), target.GetArchitecture())); - if (m_module_sp.get() && m_module_sp->MatchesModuleSpec (module_spec)) - { - ModuleList loaded_module_list; - loaded_module_list.Append (m_module_sp); - target.ModulesDidLoad (loaded_module_list); - } - } - } - } - - // If the current platform is PlatformDarwinKernel, create a ModuleSpec with the filename set - // to be the bundle ID for this kext, e.g. "com.apple.filesystems.msdosfs", and ask the platform - // to find it. - PlatformSP platform_sp (target.GetPlatform()); - if (!m_module_sp && platform_sp) - { - ConstString platform_name (platform_sp->GetPluginName()); - static ConstString g_platform_name (PlatformDarwinKernel::GetPluginNameStatic()); - if (platform_name == g_platform_name) - { - ModuleSpec kext_bundle_module_spec(module_spec); - FileSpec kext_filespec(m_name.c_str(), false); - kext_bundle_module_spec.GetFileSpec() = kext_filespec; - platform_sp->GetSharedModule (kext_bundle_module_spec, process, m_module_sp, &target.GetExecutableSearchPaths(), NULL, NULL); - } - } - - // Ask the Target to find this file on the local system, if possible. - // This will search in the list of currently-loaded files, look in the - // standard search paths on the system, and on a Mac it will try calling - // the DebugSymbols framework with the UUID to find the binary via its - // search methods. - if (!m_module_sp) - { - m_module_sp = target.GetSharedModule (module_spec); - } - - if (IsKernel() && !m_module_sp) - { - Stream *s = target.GetDebugger().GetOutputFile().get(); - if (s) - { - s->Printf ("WARNING: Unable to locate kernel binary on the debugger system.\n"); - } + } + + if (!m_module_sp) { + // See if the kext has already been loaded into the target, probably by the + // user doing target modules add. + const ModuleList &target_images = target.GetImages(); + m_module_sp = target_images.FindModule(m_uuid); + + // Search for the kext on the local filesystem via the UUID + if (!m_module_sp && uuid_is_valid) { + ModuleSpec module_spec; + module_spec.GetUUID() = m_uuid; + module_spec.GetArchitecture() = target.GetArchitecture(); + + // For the kernel, we really do need an on-disk file copy of the binary to + // do anything useful. + // This will force a clal to + if (IsKernel()) { + if (Symbols::DownloadObjectAndSymbolFile(module_spec, true)) { + if (module_spec.GetFileSpec().Exists()) { + m_module_sp.reset(new Module(module_spec.GetFileSpec(), + target.GetArchitecture())); + if (m_module_sp.get() && + m_module_sp->MatchesModuleSpec(module_spec)) { + ModuleList loaded_module_list; + loaded_module_list.Append(m_module_sp); + target.ModulesDidLoad(loaded_module_list); } + } } - - // If we managed to find a module, append it to the target's list of images. - // If we also have a memory module, require that they have matching UUIDs - if (m_module_sp) - { - bool uuid_match_ok = true; - if (m_memory_module_sp) - { - if (m_module_sp->GetUUID() != m_memory_module_sp->GetUUID()) - { - uuid_match_ok = false; - } - } - if (uuid_match_ok) - { - target.GetImages().AppendIfNeeded(m_module_sp); - if (IsKernel() && target.GetExecutableModulePointer() != m_module_sp.get()) - { - target.SetExecutableModule (m_module_sp, false); - } - } + } + + // If the current platform is PlatformDarwinKernel, create a ModuleSpec + // with the filename set + // to be the bundle ID for this kext, e.g. + // "com.apple.filesystems.msdosfs", and ask the platform + // to find it. + PlatformSP platform_sp(target.GetPlatform()); + if (!m_module_sp && platform_sp) { + ConstString platform_name(platform_sp->GetPluginName()); + static ConstString g_platform_name( + PlatformDarwinKernel::GetPluginNameStatic()); + if (platform_name == g_platform_name) { + ModuleSpec kext_bundle_module_spec(module_spec); + FileSpec kext_filespec(m_name.c_str(), false); + kext_bundle_module_spec.GetFileSpec() = kext_filespec; + platform_sp->GetSharedModule( + kext_bundle_module_spec, process, m_module_sp, + &target.GetExecutableSearchPaths(), NULL, NULL); } - } - - if (!m_module_sp && !IsKernel() && m_uuid.IsValid() && !m_name.empty()) - { + } + + // Ask the Target to find this file on the local system, if possible. + // This will search in the list of currently-loaded files, look in the + // standard search paths on the system, and on a Mac it will try calling + // the DebugSymbols framework with the UUID to find the binary via its + // search methods. + if (!m_module_sp) { + m_module_sp = target.GetSharedModule(module_spec); + } + + if (IsKernel() && !m_module_sp) { Stream *s = target.GetDebugger().GetOutputFile().get(); - if (s) - { - s->Printf ("warning: Can't find binary/dSYM for %s (%s)\n", - m_name.c_str(), m_uuid.GetAsString().c_str()); + if (s) { + s->Printf("WARNING: Unable to locate kernel binary on the debugger " + "system.\n"); } + } } - static ConstString g_section_name_LINKEDIT ("__LINKEDIT"); - - if (m_memory_module_sp && m_module_sp) - { - if (m_module_sp->GetUUID() == m_memory_module_sp->GetUUID()) - { - ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile(); - ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile(); - - if (memory_object_file && ondisk_object_file) - { - // The memory_module for kexts may have an invalid __LINKEDIT seg; skip it. - const bool ignore_linkedit = !IsKernel (); - - SectionList *ondisk_section_list = ondisk_object_file->GetSectionList (); - SectionList *memory_section_list = memory_object_file->GetSectionList (); - if (memory_section_list && ondisk_section_list) - { - const uint32_t num_ondisk_sections = ondisk_section_list->GetSize(); - // There may be CTF sections in the memory image so we can't - // always just compare the number of sections (which are actually - // segments in mach-o parlance) - uint32_t sect_idx = 0; - - // Use the memory_module's addresses for each section to set the - // file module's load address as appropriate. We don't want to use - // a single slide value for the entire kext - different segments may - // be slid different amounts by the kext loader. - - uint32_t num_sections_loaded = 0; - for (sect_idx=0; sect_idx<num_ondisk_sections; ++sect_idx) - { - SectionSP ondisk_section_sp(ondisk_section_list->GetSectionAtIndex(sect_idx)); - if (ondisk_section_sp) - { - // Don't ever load __LINKEDIT as it may or may not be actually - // mapped into memory and there is no current way to tell. - // I filed rdar://problem/12851706 to track being able to tell - // if the __LINKEDIT is actually mapped, but until then, we need - // to not load the __LINKEDIT - if (ignore_linkedit && ondisk_section_sp->GetName() == g_section_name_LINKEDIT) - continue; - - const Section *memory_section = memory_section_list->FindSectionByName(ondisk_section_sp->GetName()).get(); - if (memory_section) - { - target.SetSectionLoadAddress (ondisk_section_sp, memory_section->GetFileAddress()); - ++num_sections_loaded; - } - } - } - if (num_sections_loaded > 0) - m_load_process_stop_id = process->GetStopID(); - else - m_module_sp.reset(); // No sections were loaded - } - else - m_module_sp.reset(); // One or both section lists - } - else - m_module_sp.reset(); // One or both object files missing + // If we managed to find a module, append it to the target's list of images. + // If we also have a memory module, require that they have matching UUIDs + if (m_module_sp) { + bool uuid_match_ok = true; + if (m_memory_module_sp) { + if (m_module_sp->GetUUID() != m_memory_module_sp->GetUUID()) { + uuid_match_ok = false; } - else - m_module_sp.reset(); // UUID mismatch + } + if (uuid_match_ok) { + target.GetImages().AppendIfNeeded(m_module_sp); + if (IsKernel() && + target.GetExecutableModulePointer() != m_module_sp.get()) { + target.SetExecutableModule(m_module_sp, false); + } + } } + } - bool is_loaded = IsLoaded(); - - if (is_loaded && m_module_sp && IsKernel()) - { - Stream *s = target.GetDebugger().GetOutputFile().get(); - if (s) - { - ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); - if (kernel_object_file) - { - addr_t file_address = kernel_object_file->GetHeaderAddress().GetFileAddress(); - if (m_load_address != LLDB_INVALID_ADDRESS && file_address != LLDB_INVALID_ADDRESS) - { - s->Printf ("Kernel slid 0x%" PRIx64 " in memory.\n", m_load_address - file_address); - } - } - { - s->Printf ("Loaded kernel file %s\n", - m_module_sp->GetFileSpec().GetPath().c_str()); + if (!m_module_sp && !IsKernel() && m_uuid.IsValid() && !m_name.empty()) { + Stream *s = target.GetDebugger().GetOutputFile().get(); + if (s) { + s->Printf("warning: Can't find binary/dSYM for %s (%s)\n", m_name.c_str(), + m_uuid.GetAsString().c_str()); + } + } + + static ConstString g_section_name_LINKEDIT("__LINKEDIT"); + + if (m_memory_module_sp && m_module_sp) { + if (m_module_sp->GetUUID() == m_memory_module_sp->GetUUID()) { + ObjectFile *ondisk_object_file = m_module_sp->GetObjectFile(); + ObjectFile *memory_object_file = m_memory_module_sp->GetObjectFile(); + + if (memory_object_file && ondisk_object_file) { + // The memory_module for kexts may have an invalid __LINKEDIT seg; skip + // it. + const bool ignore_linkedit = !IsKernel(); + + SectionList *ondisk_section_list = ondisk_object_file->GetSectionList(); + SectionList *memory_section_list = memory_object_file->GetSectionList(); + if (memory_section_list && ondisk_section_list) { + const uint32_t num_ondisk_sections = ondisk_section_list->GetSize(); + // There may be CTF sections in the memory image so we can't + // always just compare the number of sections (which are actually + // segments in mach-o parlance) + uint32_t sect_idx = 0; + + // Use the memory_module's addresses for each section to set the + // file module's load address as appropriate. We don't want to use + // a single slide value for the entire kext - different segments may + // be slid different amounts by the kext loader. + + uint32_t num_sections_loaded = 0; + for (sect_idx = 0; sect_idx < num_ondisk_sections; ++sect_idx) { + SectionSP ondisk_section_sp( + ondisk_section_list->GetSectionAtIndex(sect_idx)); + if (ondisk_section_sp) { + // Don't ever load __LINKEDIT as it may or may not be actually + // mapped into memory and there is no current way to tell. + // I filed rdar://problem/12851706 to track being able to tell + // if the __LINKEDIT is actually mapped, but until then, we need + // to not load the __LINKEDIT + if (ignore_linkedit && + ondisk_section_sp->GetName() == g_section_name_LINKEDIT) + continue; + + const Section *memory_section = + memory_section_list + ->FindSectionByName(ondisk_section_sp->GetName()) + .get(); + if (memory_section) { + target.SetSectionLoadAddress(ondisk_section_sp, + memory_section->GetFileAddress()); + ++num_sections_loaded; + } } - s->Flush (); + } + if (num_sections_loaded > 0) + m_load_process_stop_id = process->GetStopID(); + else + m_module_sp.reset(); // No sections were loaded + } else + m_module_sp.reset(); // One or both section lists + } else + m_module_sp.reset(); // One or both object files missing + } else + m_module_sp.reset(); // UUID mismatch + } + + bool is_loaded = IsLoaded(); + + if (is_loaded && m_module_sp && IsKernel()) { + Stream *s = target.GetDebugger().GetOutputFile().get(); + if (s) { + ObjectFile *kernel_object_file = m_module_sp->GetObjectFile(); + if (kernel_object_file) { + addr_t file_address = + kernel_object_file->GetHeaderAddress().GetFileAddress(); + if (m_load_address != LLDB_INVALID_ADDRESS && + file_address != LLDB_INVALID_ADDRESS) { + s->Printf("Kernel slid 0x%" PRIx64 " in memory.\n", + m_load_address - file_address); } + } + { + s->Printf("Loaded kernel file %s\n", + m_module_sp->GetFileSpec().GetPath().c_str()); + } + s->Flush(); } - return is_loaded; + } + return is_loaded; } -uint32_t -DynamicLoaderDarwinKernel::KextImageInfo::GetAddressByteSize () -{ - if (m_memory_module_sp) - return m_memory_module_sp->GetArchitecture().GetAddressByteSize(); - if (m_module_sp) - return m_module_sp->GetArchitecture().GetAddressByteSize(); - return 0; +uint32_t DynamicLoaderDarwinKernel::KextImageInfo::GetAddressByteSize() { + if (m_memory_module_sp) + return m_memory_module_sp->GetArchitecture().GetAddressByteSize(); + if (m_module_sp) + return m_module_sp->GetArchitecture().GetAddressByteSize(); + return 0; } -lldb::ByteOrder -DynamicLoaderDarwinKernel::KextImageInfo::GetByteOrder() -{ - if (m_memory_module_sp) - return m_memory_module_sp->GetArchitecture().GetByteOrder(); - if (m_module_sp) - return m_module_sp->GetArchitecture().GetByteOrder(); - return endian::InlHostByteOrder(); +lldb::ByteOrder DynamicLoaderDarwinKernel::KextImageInfo::GetByteOrder() { + if (m_memory_module_sp) + return m_memory_module_sp->GetArchitecture().GetByteOrder(); + if (m_module_sp) + return m_module_sp->GetArchitecture().GetByteOrder(); + return endian::InlHostByteOrder(); } lldb_private::ArchSpec -DynamicLoaderDarwinKernel::KextImageInfo::GetArchitecture () const -{ - if (m_memory_module_sp) - return m_memory_module_sp->GetArchitecture(); - if (m_module_sp) - return m_module_sp->GetArchitecture(); - return lldb_private::ArchSpec (); +DynamicLoaderDarwinKernel::KextImageInfo::GetArchitecture() const { + if (m_memory_module_sp) + return m_memory_module_sp->GetArchitecture(); + if (m_module_sp) + return m_module_sp->GetArchitecture(); + return lldb_private::ArchSpec(); } - //---------------------------------------------------------------------- // Load the kernel module and initialize the "m_kernel" member. Return // true _only_ if the kernel is loaded the first time through (subsequent // calls to this function should return false after the kernel has been // already loaded). //---------------------------------------------------------------------- -void -DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() -{ - if (!m_kext_summary_header_ptr_addr.IsValid()) - { - m_kernel.Clear(); - m_kernel.SetModule (m_process->GetTarget().GetExecutableModule()); - m_kernel.SetIsKernel(true); - - ConstString kernel_name("mach_kernel"); - if (m_kernel.GetModule().get() - && m_kernel.GetModule()->GetObjectFile() - && !m_kernel.GetModule()->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty()) - { - kernel_name = m_kernel.GetModule()->GetObjectFile()->GetFileSpec().GetFilename(); - } - m_kernel.SetName (kernel_name.AsCString()); - - if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS) - { - m_kernel.SetLoadAddress(m_kernel_load_address); - if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS && m_kernel.GetModule()) - { - // We didn't get a hint from the process, so we will - // try the kernel at the address that it exists at in - // the file if we have one - ObjectFile *kernel_object_file = m_kernel.GetModule()->GetObjectFile(); - if (kernel_object_file) - { - addr_t load_address = kernel_object_file->GetHeaderAddress().GetLoadAddress(&m_process->GetTarget()); - addr_t file_address = kernel_object_file->GetHeaderAddress().GetFileAddress(); - if (load_address != LLDB_INVALID_ADDRESS && load_address != 0) - { - m_kernel.SetLoadAddress (load_address); - if (load_address != file_address) - { - // Don't accidentally relocate the kernel to the File address -- - // the Load address has already been set to its actual in-memory address. - // Mark it as IsLoaded. - m_kernel.SetProcessStopId (m_process->GetStopID()); - } - } - else - { - m_kernel.SetLoadAddress(file_address); - } - } - } - } - - if (m_kernel.GetLoadAddress() != LLDB_INVALID_ADDRESS) - { - if (!m_kernel.LoadImageUsingMemoryModule (m_process)) - { - m_kernel.LoadImageAtFileAddress (m_process); +void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { + if (!m_kext_summary_header_ptr_addr.IsValid()) { + m_kernel.Clear(); + m_kernel.SetModule(m_process->GetTarget().GetExecutableModule()); + m_kernel.SetIsKernel(true); + + ConstString kernel_name("mach_kernel"); + if (m_kernel.GetModule().get() && m_kernel.GetModule()->GetObjectFile() && + !m_kernel.GetModule() + ->GetObjectFile() + ->GetFileSpec() + .GetFilename() + .IsEmpty()) { + kernel_name = + m_kernel.GetModule()->GetObjectFile()->GetFileSpec().GetFilename(); + } + m_kernel.SetName(kernel_name.AsCString()); + + if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS) { + m_kernel.SetLoadAddress(m_kernel_load_address); + if (m_kernel.GetLoadAddress() == LLDB_INVALID_ADDRESS && + m_kernel.GetModule()) { + // We didn't get a hint from the process, so we will + // try the kernel at the address that it exists at in + // the file if we have one + ObjectFile *kernel_object_file = m_kernel.GetModule()->GetObjectFile(); + if (kernel_object_file) { + addr_t load_address = + kernel_object_file->GetHeaderAddress().GetLoadAddress( + &m_process->GetTarget()); + addr_t file_address = + kernel_object_file->GetHeaderAddress().GetFileAddress(); + if (load_address != LLDB_INVALID_ADDRESS && load_address != 0) { + m_kernel.SetLoadAddress(load_address); + if (load_address != file_address) { + // Don't accidentally relocate the kernel to the File address -- + // the Load address has already been set to its actual in-memory + // address. + // Mark it as IsLoaded. + m_kernel.SetProcessStopId(m_process->GetStopID()); } + } else { + m_kernel.SetLoadAddress(file_address); + } } + } + } - if (m_kernel.IsLoaded() && m_kernel.GetModule()) - { - static ConstString kext_summary_symbol ("gLoadedKextSummaries"); - const Symbol *symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType (kext_summary_symbol, eSymbolTypeData); - if (symbol) - { - m_kext_summary_header_ptr_addr = symbol->GetAddress(); - // Update all image infos - ReadAllKextSummaries (); - } - } - else - { - m_kernel.Clear(); - } + if (m_kernel.GetLoadAddress() != LLDB_INVALID_ADDRESS) { + if (!m_kernel.LoadImageUsingMemoryModule(m_process)) { + m_kernel.LoadImageAtFileAddress(m_process); + } } + + if (m_kernel.IsLoaded() && m_kernel.GetModule()) { + static ConstString kext_summary_symbol("gLoadedKextSummaries"); + const Symbol *symbol = + m_kernel.GetModule()->FindFirstSymbolWithNameAndType( + kext_summary_symbol, eSymbolTypeData); + if (symbol) { + m_kext_summary_header_ptr_addr = symbol->GetAddress(); + // Update all image infos + ReadAllKextSummaries(); + } + } else { + m_kernel.Clear(); + } + } } //---------------------------------------------------------------------- @@ -1101,591 +1049,531 @@ DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() // let our super class DynamicLoader class decide if we should stop // or not (based on global preference). //---------------------------------------------------------------------- -bool -DynamicLoaderDarwinKernel::BreakpointHitCallback (void *baton, - StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id) -{ - return static_cast<DynamicLoaderDarwinKernel*>(baton)->BreakpointHit (context, break_id, break_loc_id); +bool DynamicLoaderDarwinKernel::BreakpointHitCallback( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + return static_cast<DynamicLoaderDarwinKernel *>(baton)->BreakpointHit( + context, break_id, break_loc_id); } -bool -DynamicLoaderDarwinKernel::BreakpointHit (StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id) -{ - Log *log(GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf ("DynamicLoaderDarwinKernel::BreakpointHit (...)\n"); +bool DynamicLoaderDarwinKernel::BreakpointHit(StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderDarwinKernel::BreakpointHit (...)\n"); - ReadAllKextSummaries (); - - if (log) - PutToLog(log); + ReadAllKextSummaries(); - return GetStopWhenImagesChange(); + if (log) + PutToLog(log); + + return GetStopWhenImagesChange(); } +bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + // the all image infos is already valid for this process stop ID -bool -DynamicLoaderDarwinKernel::ReadKextSummaryHeader () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - // the all image infos is already valid for this process stop ID - - if (m_kext_summary_header_ptr_addr.IsValid()) - { - const uint32_t addr_size = m_kernel.GetAddressByteSize (); - const ByteOrder byte_order = m_kernel.GetByteOrder(); - Error error; - // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure - // which is currently 4 uint32_t and a pointer. - uint8_t buf[24]; - DataExtractor data (buf, sizeof(buf), byte_order, addr_size); - const size_t count = 4 * sizeof(uint32_t) + addr_size; - const bool prefer_file_cache = false; - if (m_process->GetTarget().ReadPointerFromMemory (m_kext_summary_header_ptr_addr, - prefer_file_cache, - error, - m_kext_summary_header_addr)) - { - // We got a valid address for our kext summary header and make sure it isn't NULL - if (m_kext_summary_header_addr.IsValid() && - m_kext_summary_header_addr.GetFileAddress() != 0) - { - const size_t bytes_read = m_process->GetTarget().ReadMemory (m_kext_summary_header_addr, prefer_file_cache, buf, count, error); - if (bytes_read == count) - { - lldb::offset_t offset = 0; - m_kext_summary_header.version = data.GetU32(&offset); - if (m_kext_summary_header.version > 128) - { - Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get(); - s->Printf ("WARNING: Unable to read kext summary header, got improbable version number %u\n", m_kext_summary_header.version); - // If we get an improbably large version number, we're probably getting bad memory. - m_kext_summary_header_addr.Clear(); - return false; - } - if (m_kext_summary_header.version >= 2) - { - m_kext_summary_header.entry_size = data.GetU32(&offset); - if (m_kext_summary_header.entry_size > 4096) - { - // If we get an improbably large entry_size, we're probably getting bad memory. - Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get(); - s->Printf ("WARNING: Unable to read kext summary header, got improbable entry_size %u\n", m_kext_summary_header.entry_size); - m_kext_summary_header_addr.Clear(); - return false; - } - } - else - { - // Versions less than 2 didn't have an entry size, it was hard coded - m_kext_summary_header.entry_size = KERNEL_MODULE_ENTRY_SIZE_VERSION_1; - } - m_kext_summary_header.entry_count = data.GetU32(&offset); - if (m_kext_summary_header.entry_count > 10000) - { - // If we get an improbably large number of kexts, we're probably getting bad memory. - Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get(); - s->Printf ("WARNING: Unable to read kext summary header, got improbable number of kexts %u\n", m_kext_summary_header.entry_count); - m_kext_summary_header_addr.Clear(); - return false; - } - return true; - } + if (m_kext_summary_header_ptr_addr.IsValid()) { + const uint32_t addr_size = m_kernel.GetAddressByteSize(); + const ByteOrder byte_order = m_kernel.GetByteOrder(); + Error error; + // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure + // which is currently 4 uint32_t and a pointer. + uint8_t buf[24]; + DataExtractor data(buf, sizeof(buf), byte_order, addr_size); + const size_t count = 4 * sizeof(uint32_t) + addr_size; + const bool prefer_file_cache = false; + if (m_process->GetTarget().ReadPointerFromMemory( + m_kext_summary_header_ptr_addr, prefer_file_cache, error, + m_kext_summary_header_addr)) { + // We got a valid address for our kext summary header and make sure it + // isn't NULL + if (m_kext_summary_header_addr.IsValid() && + m_kext_summary_header_addr.GetFileAddress() != 0) { + const size_t bytes_read = m_process->GetTarget().ReadMemory( + m_kext_summary_header_addr, prefer_file_cache, buf, count, error); + if (bytes_read == count) { + lldb::offset_t offset = 0; + m_kext_summary_header.version = data.GetU32(&offset); + if (m_kext_summary_header.version > 128) { + Stream *s = + m_process->GetTarget().GetDebugger().GetOutputFile().get(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable version number %u\n", + m_kext_summary_header.version); + // If we get an improbably large version number, we're probably + // getting bad memory. + m_kext_summary_header_addr.Clear(); + return false; + } + if (m_kext_summary_header.version >= 2) { + m_kext_summary_header.entry_size = data.GetU32(&offset); + if (m_kext_summary_header.entry_size > 4096) { + // If we get an improbably large entry_size, we're probably + // getting bad memory. + Stream *s = + m_process->GetTarget().GetDebugger().GetOutputFile().get(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable entry_size %u\n", + m_kext_summary_header.entry_size); + m_kext_summary_header_addr.Clear(); + return false; } + } else { + // Versions less than 2 didn't have an entry size, it was hard coded + m_kext_summary_header.entry_size = + KERNEL_MODULE_ENTRY_SIZE_VERSION_1; + } + m_kext_summary_header.entry_count = data.GetU32(&offset); + if (m_kext_summary_header.entry_count > 10000) { + // If we get an improbably large number of kexts, we're probably + // getting bad memory. + Stream *s = + m_process->GetTarget().GetDebugger().GetOutputFile().get(); + s->Printf("WARNING: Unable to read kext summary header, got " + "improbable number of kexts %u\n", + m_kext_summary_header.entry_count); + m_kext_summary_header_addr.Clear(); + return false; + } + return true; } + } } - m_kext_summary_header_addr.Clear(); - return false; + } + m_kext_summary_header_addr.Clear(); + return false; } -// We've either (a) just attached to a new kernel, or (b) the kexts-changed breakpoint was hit +// We've either (a) just attached to a new kernel, or (b) the kexts-changed +// breakpoint was hit // and we need to figure out what kexts have been added or removed. -// Read the kext summaries from the inferior kernel memory, compare them against the -// m_known_kexts vector and update the m_known_kexts vector as needed to keep in sync with the +// Read the kext summaries from the inferior kernel memory, compare them against +// the +// m_known_kexts vector and update the m_known_kexts vector as needed to keep in +// sync with the // inferior. -bool -DynamicLoaderDarwinKernel::ParseKextSummaries (const Address &kext_summary_addr, uint32_t count) -{ - KextImageInfo::collection kext_summaries; - Log *log(GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf ("Kexts-changed breakpoint hit, there are %d kexts currently.\n", count); - - std::lock_guard<std::recursive_mutex> guard(m_mutex); +bool DynamicLoaderDarwinKernel::ParseKextSummaries( + const Address &kext_summary_addr, uint32_t count) { + KextImageInfo::collection kext_summaries; + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("Kexts-changed breakpoint hit, there are %d kexts currently.\n", + count); - if (!ReadKextSummaries (kext_summary_addr, count, kext_summaries)) - return false; + std::lock_guard<std::recursive_mutex> guard(m_mutex); - // read the plugin.dynamic-loader.darwin-kernel.load-kexts setting -- if the user requested no - // kext loading, don't print any messages about kexts & don't try to read them. - const bool load_kexts = GetGlobalProperties()->GetLoadKexts(); - - // By default, all kexts we've loaded in the past are marked as "remove" and all of the kexts - // we just found out about from ReadKextSummaries are marked as "add". - std::vector<bool> to_be_removed(m_known_kexts.size(), true); - std::vector<bool> to_be_added(count, true); - - int number_of_new_kexts_being_added = 0; - int number_of_old_kexts_being_removed = m_known_kexts.size(); - - const uint32_t new_kexts_size = kext_summaries.size(); - const uint32_t old_kexts_size = m_known_kexts.size(); - - // The m_known_kexts vector may have entries that have been Cleared, - // or are a kernel. - for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++) - { - bool ignore = false; - KextImageInfo &image_info = m_known_kexts[old_kext]; - if (image_info.IsKernel()) - { - ignore = true; - } - else if (image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS && !image_info.GetModule()) - { - ignore = true; - } + if (!ReadKextSummaries(kext_summary_addr, count, kext_summaries)) + return false; - if (ignore) - { - number_of_old_kexts_being_removed--; - to_be_removed[old_kext] = false; - } + // read the plugin.dynamic-loader.darwin-kernel.load-kexts setting -- if the + // user requested no + // kext loading, don't print any messages about kexts & don't try to read + // them. + const bool load_kexts = GetGlobalProperties()->GetLoadKexts(); + + // By default, all kexts we've loaded in the past are marked as "remove" and + // all of the kexts + // we just found out about from ReadKextSummaries are marked as "add". + std::vector<bool> to_be_removed(m_known_kexts.size(), true); + std::vector<bool> to_be_added(count, true); + + int number_of_new_kexts_being_added = 0; + int number_of_old_kexts_being_removed = m_known_kexts.size(); + + const uint32_t new_kexts_size = kext_summaries.size(); + const uint32_t old_kexts_size = m_known_kexts.size(); + + // The m_known_kexts vector may have entries that have been Cleared, + // or are a kernel. + for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++) { + bool ignore = false; + KextImageInfo &image_info = m_known_kexts[old_kext]; + if (image_info.IsKernel()) { + ignore = true; + } else if (image_info.GetLoadAddress() == LLDB_INVALID_ADDRESS && + !image_info.GetModule()) { + ignore = true; } - // Scan over the list of kexts we just read from the kernel, note those that - // need to be added and those already loaded. - for (uint32_t new_kext = 0; new_kext < new_kexts_size; new_kext++) - { - bool add_this_one = true; - for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++) - { - if (m_known_kexts[old_kext] == kext_summaries[new_kext]) - { - // We already have this kext, don't re-load it. - to_be_added[new_kext] = false; - // This kext is still present, do not remove it. - to_be_removed[old_kext] = false; - - number_of_old_kexts_being_removed--; - add_this_one = false; - break; - } - } - if (add_this_one) - { - number_of_new_kexts_being_added++; - } + if (ignore) { + number_of_old_kexts_being_removed--; + to_be_removed[old_kext] = false; } - - if (number_of_new_kexts_being_added == 0 && number_of_old_kexts_being_removed == 0) - return true; - - Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get(); - if (s && load_kexts) - { - if (number_of_new_kexts_being_added > 0 && number_of_old_kexts_being_removed > 0) - { - s->Printf ("Loading %d kext modules and unloading %d kext modules ", number_of_new_kexts_being_added, number_of_old_kexts_being_removed); - } - else if (number_of_new_kexts_being_added > 0) - { - s->Printf ("Loading %d kext modules ", number_of_new_kexts_being_added); - } - else if (number_of_old_kexts_being_removed > 0) - { - s->Printf ("Unloading %d kext modules ", number_of_old_kexts_being_removed); - } + } + + // Scan over the list of kexts we just read from the kernel, note those that + // need to be added and those already loaded. + for (uint32_t new_kext = 0; new_kext < new_kexts_size; new_kext++) { + bool add_this_one = true; + for (uint32_t old_kext = 0; old_kext < old_kexts_size; old_kext++) { + if (m_known_kexts[old_kext] == kext_summaries[new_kext]) { + // We already have this kext, don't re-load it. + to_be_added[new_kext] = false; + // This kext is still present, do not remove it. + to_be_removed[old_kext] = false; + + number_of_old_kexts_being_removed--; + add_this_one = false; + break; + } } - - if (log) - { - if (load_kexts) - { - log->Printf ("DynamicLoaderDarwinKernel::ParseKextSummaries: %d kexts added, %d kexts removed", number_of_new_kexts_being_added, number_of_old_kexts_being_removed); - } - else - { - log->Printf ("DynamicLoaderDarwinKernel::ParseKextSummaries kext loading is disabled, else would have %d kexts added, %d kexts removed", number_of_new_kexts_being_added, number_of_old_kexts_being_removed); - } + if (add_this_one) { + number_of_new_kexts_being_added++; } + } + if (number_of_new_kexts_being_added == 0 && + number_of_old_kexts_being_removed == 0) + return true; - if (number_of_new_kexts_being_added > 0) - { - ModuleList loaded_module_list; - - const uint32_t num_of_new_kexts = kext_summaries.size(); - for (uint32_t new_kext = 0; new_kext < num_of_new_kexts; new_kext++) - { - if (to_be_added[new_kext] == true) - { - KextImageInfo &image_info = kext_summaries[new_kext]; - if (load_kexts) - { - if (!image_info.LoadImageUsingMemoryModule (m_process)) - { - image_info.LoadImageAtFileAddress (m_process); - } - } + Stream *s = m_process->GetTarget().GetDebugger().GetOutputFile().get(); + if (s && load_kexts) { + if (number_of_new_kexts_being_added > 0 && + number_of_old_kexts_being_removed > 0) { + s->Printf("Loading %d kext modules and unloading %d kext modules ", + number_of_new_kexts_being_added, + number_of_old_kexts_being_removed); + } else if (number_of_new_kexts_being_added > 0) { + s->Printf("Loading %d kext modules ", number_of_new_kexts_being_added); + } else if (number_of_old_kexts_being_removed > 0) { + s->Printf("Unloading %d kext modules ", + number_of_old_kexts_being_removed); + } + } + + if (log) { + if (load_kexts) { + log->Printf("DynamicLoaderDarwinKernel::ParseKextSummaries: %d kexts " + "added, %d kexts removed", + number_of_new_kexts_being_added, + number_of_old_kexts_being_removed); + } else { + log->Printf( + "DynamicLoaderDarwinKernel::ParseKextSummaries kext loading is " + "disabled, else would have %d kexts added, %d kexts removed", + number_of_new_kexts_being_added, number_of_old_kexts_being_removed); + } + } + + if (number_of_new_kexts_being_added > 0) { + ModuleList loaded_module_list; + + const uint32_t num_of_new_kexts = kext_summaries.size(); + for (uint32_t new_kext = 0; new_kext < num_of_new_kexts; new_kext++) { + if (to_be_added[new_kext] == true) { + KextImageInfo &image_info = kext_summaries[new_kext]; + if (load_kexts) { + if (!image_info.LoadImageUsingMemoryModule(m_process)) { + image_info.LoadImageAtFileAddress(m_process); + } + } - m_known_kexts.push_back(image_info); + m_known_kexts.push_back(image_info); - if (image_info.GetModule() && m_process->GetStopID() == image_info.GetProcessStopId()) - loaded_module_list.AppendIfNeeded (image_info.GetModule()); + if (image_info.GetModule() && + m_process->GetStopID() == image_info.GetProcessStopId()) + loaded_module_list.AppendIfNeeded(image_info.GetModule()); - if (s && load_kexts) - s->Printf ("."); + if (s && load_kexts) + s->Printf("."); - if (log) - kext_summaries[new_kext].PutToLog (log); - } - } - m_process->GetTarget().ModulesDidLoad (loaded_module_list); + if (log) + kext_summaries[new_kext].PutToLog(log); + } } - - if (number_of_old_kexts_being_removed > 0) - { - ModuleList loaded_module_list; - const uint32_t num_of_old_kexts = m_known_kexts.size(); - for (uint32_t old_kext = 0; old_kext < num_of_old_kexts; old_kext++) - { - ModuleList unloaded_module_list; - if (to_be_removed[old_kext]) - { - KextImageInfo &image_info = m_known_kexts[old_kext]; - // You can't unload the kernel. - if (!image_info.IsKernel()) - { - if (image_info.GetModule()) - { - unloaded_module_list.AppendIfNeeded (image_info.GetModule()); - } - if (s) - s->Printf ("."); - image_info.Clear(); - // should pull it out of the KextImageInfos vector but that would mutate the list and invalidate - // the to_be_removed bool vector; leaving it in place once Cleared() is relatively harmless. - } - } - m_process->GetTarget().ModulesDidUnload (unloaded_module_list, false); + m_process->GetTarget().ModulesDidLoad(loaded_module_list); + } + + if (number_of_old_kexts_being_removed > 0) { + ModuleList loaded_module_list; + const uint32_t num_of_old_kexts = m_known_kexts.size(); + for (uint32_t old_kext = 0; old_kext < num_of_old_kexts; old_kext++) { + ModuleList unloaded_module_list; + if (to_be_removed[old_kext]) { + KextImageInfo &image_info = m_known_kexts[old_kext]; + // You can't unload the kernel. + if (!image_info.IsKernel()) { + if (image_info.GetModule()) { + unloaded_module_list.AppendIfNeeded(image_info.GetModule()); + } + if (s) + s->Printf("."); + image_info.Clear(); + // should pull it out of the KextImageInfos vector but that would + // mutate the list and invalidate + // the to_be_removed bool vector; leaving it in place once Cleared() + // is relatively harmless. } + } + m_process->GetTarget().ModulesDidUnload(unloaded_module_list, false); } + } - if (s && load_kexts) - { - s->Printf (" done.\n"); - s->Flush (); - } + if (s && load_kexts) { + s->Printf(" done.\n"); + s->Flush(); + } - return true; + return true; } -uint32_t -DynamicLoaderDarwinKernel::ReadKextSummaries (const Address &kext_summary_addr, - uint32_t image_infos_count, - KextImageInfo::collection &image_infos) -{ - const ByteOrder endian = m_kernel.GetByteOrder(); - const uint32_t addr_size = m_kernel.GetAddressByteSize(); - - image_infos.resize(image_infos_count); - const size_t count = image_infos.size() * m_kext_summary_header.entry_size; - DataBufferHeap data(count, 0); - Error error; - - const bool prefer_file_cache = false; - const size_t bytes_read = m_process->GetTarget().ReadMemory (kext_summary_addr, - prefer_file_cache, - data.GetBytes(), - data.GetByteSize(), - error); - if (bytes_read == count) - { - - DataExtractor extractor (data.GetBytes(), data.GetByteSize(), endian, addr_size); - uint32_t i=0; - for (uint32_t kext_summary_offset = 0; - i < image_infos.size() && extractor.ValidOffsetForDataOfSize(kext_summary_offset, m_kext_summary_header.entry_size); - ++i, kext_summary_offset += m_kext_summary_header.entry_size) - { - lldb::offset_t offset = kext_summary_offset; - const void *name_data = extractor.GetData(&offset, KERNEL_MODULE_MAX_NAME); - if (name_data == NULL) - break; - image_infos[i].SetName ((const char *) name_data); - UUID uuid (extractor.GetData (&offset, 16), 16); - image_infos[i].SetUUID (uuid); - image_infos[i].SetLoadAddress (extractor.GetU64(&offset)); - image_infos[i].SetSize (extractor.GetU64(&offset)); - } - if (i < image_infos.size()) - image_infos.resize(i); - } - else - { - image_infos.clear(); +uint32_t DynamicLoaderDarwinKernel::ReadKextSummaries( + const Address &kext_summary_addr, uint32_t image_infos_count, + KextImageInfo::collection &image_infos) { + const ByteOrder endian = m_kernel.GetByteOrder(); + const uint32_t addr_size = m_kernel.GetAddressByteSize(); + + image_infos.resize(image_infos_count); + const size_t count = image_infos.size() * m_kext_summary_header.entry_size; + DataBufferHeap data(count, 0); + Error error; + + const bool prefer_file_cache = false; + const size_t bytes_read = m_process->GetTarget().ReadMemory( + kext_summary_addr, prefer_file_cache, data.GetBytes(), data.GetByteSize(), + error); + if (bytes_read == count) { + + DataExtractor extractor(data.GetBytes(), data.GetByteSize(), endian, + addr_size); + uint32_t i = 0; + for (uint32_t kext_summary_offset = 0; + i < image_infos.size() && + extractor.ValidOffsetForDataOfSize(kext_summary_offset, + m_kext_summary_header.entry_size); + ++i, kext_summary_offset += m_kext_summary_header.entry_size) { + lldb::offset_t offset = kext_summary_offset; + const void *name_data = + extractor.GetData(&offset, KERNEL_MODULE_MAX_NAME); + if (name_data == NULL) + break; + image_infos[i].SetName((const char *)name_data); + UUID uuid(extractor.GetData(&offset, 16), 16); + image_infos[i].SetUUID(uuid); + image_infos[i].SetLoadAddress(extractor.GetU64(&offset)); + image_infos[i].SetSize(extractor.GetU64(&offset)); } - return image_infos.size(); + if (i < image_infos.size()) + image_infos.resize(i); + } else { + image_infos.clear(); + } + return image_infos.size(); } -bool -DynamicLoaderDarwinKernel::ReadAllKextSummaries () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - if (ReadKextSummaryHeader ()) - { - if (m_kext_summary_header.entry_count > 0 && m_kext_summary_header_addr.IsValid()) - { - Address summary_addr (m_kext_summary_header_addr); - summary_addr.Slide(m_kext_summary_header.GetSize()); - if (!ParseKextSummaries (summary_addr, m_kext_summary_header.entry_count)) - { - m_known_kexts.clear(); - } - return true; - } +bool DynamicLoaderDarwinKernel::ReadAllKextSummaries() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + if (ReadKextSummaryHeader()) { + if (m_kext_summary_header.entry_count > 0 && + m_kext_summary_header_addr.IsValid()) { + Address summary_addr(m_kext_summary_header_addr); + summary_addr.Slide(m_kext_summary_header.GetSize()); + if (!ParseKextSummaries(summary_addr, + m_kext_summary_header.entry_count)) { + m_known_kexts.clear(); + } + return true; } - return false; + } + return false; } //---------------------------------------------------------------------- // Dump an image info structure to the file handle provided. //---------------------------------------------------------------------- -void -DynamicLoaderDarwinKernel::KextImageInfo::PutToLog (Log *log) const -{ - if (log == NULL) - return; - const uint8_t *u = (uint8_t *) m_uuid.GetBytes(); - - if (m_load_address == LLDB_INVALID_ADDRESS) - { - if (u) - { - log->Printf("\tuuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\" (UNLOADED)", - u[ 0], u[ 1], u[ 2], u[ 3], - u[ 4], u[ 5], u[ 6], u[ 7], - u[ 8], u[ 9], u[10], u[11], - u[12], u[13], u[14], u[15], - m_name.c_str()); - } - else - log->Printf("\tname=\"%s\" (UNLOADED)", m_name.c_str()); - } - else - { - if (u) - { - log->Printf("\taddr=0x%16.16" PRIx64 " size=0x%16.16" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\"", - m_load_address, m_size, - u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7], - u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15], - m_name.c_str()); - } - else - { - log->Printf("\t[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") name=\"%s\"", - m_load_address, m_load_address+m_size, m_name.c_str()); - } +void DynamicLoaderDarwinKernel::KextImageInfo::PutToLog(Log *log) const { + if (log == NULL) + return; + const uint8_t *u = (uint8_t *)m_uuid.GetBytes(); + + if (m_load_address == LLDB_INVALID_ADDRESS) { + if (u) { + log->Printf("\tuuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2." + "2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\" (UNLOADED)", + u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8], u[9], + u[10], u[11], u[12], u[13], u[14], u[15], m_name.c_str()); + } else + log->Printf("\tname=\"%s\" (UNLOADED)", m_name.c_str()); + } else { + if (u) { + log->Printf("\taddr=0x%16.16" PRIx64 " size=0x%16.16" PRIx64 + " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" + "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name=\"%s\"", + m_load_address, m_size, u[0], u[1], u[2], u[3], u[4], u[5], + u[6], u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], + u[15], m_name.c_str()); + } else { + log->Printf("\t[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") name=\"%s\"", + m_load_address, m_load_address + m_size, m_name.c_str()); } + } } //---------------------------------------------------------------------- // Dump the _dyld_all_image_infos members and all current image infos // that we have parsed to the file handle provided. //---------------------------------------------------------------------- -void -DynamicLoaderDarwinKernel::PutToLog(Log *log) const -{ - if (log == NULL) - return; - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - log->Printf("gLoadedKextSummaries = 0x%16.16" PRIx64 " { version=%u, entry_size=%u, entry_count=%u }", - m_kext_summary_header_addr.GetFileAddress(), - m_kext_summary_header.version, - m_kext_summary_header.entry_size, - m_kext_summary_header.entry_count); - - size_t i; - const size_t count = m_known_kexts.size(); - if (count > 0) - { - log->PutCString("Loaded:"); - for (i = 0; i<count; i++) - m_known_kexts[i].PutToLog(log); - } +void DynamicLoaderDarwinKernel::PutToLog(Log *log) const { + if (log == NULL) + return; + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + log->Printf("gLoadedKextSummaries = 0x%16.16" PRIx64 + " { version=%u, entry_size=%u, entry_count=%u }", + m_kext_summary_header_addr.GetFileAddress(), + m_kext_summary_header.version, m_kext_summary_header.entry_size, + m_kext_summary_header.entry_count); + + size_t i; + const size_t count = m_known_kexts.size(); + if (count > 0) { + log->PutCString("Loaded:"); + for (i = 0; i < count; i++) + m_known_kexts[i].PutToLog(log); + } } -void -DynamicLoaderDarwinKernel::PrivateInitialize(Process *process) -{ - DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState())); - Clear(true); - m_process = process; +void DynamicLoaderDarwinKernel::PrivateInitialize(Process *process) { + DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", + __FUNCTION__, StateAsCString(m_process->GetState())); + Clear(true); + m_process = process; } -void -DynamicLoaderDarwinKernel::SetNotificationBreakpointIfNeeded () -{ - if (m_break_id == LLDB_INVALID_BREAK_ID && m_kernel.GetModule()) - { - DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState())); - - - const bool internal_bp = true; - const bool hardware = false; - const LazyBool skip_prologue = eLazyBoolNo; - FileSpecList module_spec_list; - module_spec_list.Append (m_kernel.GetModule()->GetFileSpec()); - Breakpoint *bp = m_process->GetTarget().CreateBreakpoint (&module_spec_list, - NULL, - "OSKextLoadedKextSummariesUpdated", - eFunctionNameTypeFull, - eLanguageTypeUnknown, - 0, - skip_prologue, - internal_bp, - hardware).get(); - - bp->SetCallback (DynamicLoaderDarwinKernel::BreakpointHitCallback, this, true); - m_break_id = bp->GetID(); - } +void DynamicLoaderDarwinKernel::SetNotificationBreakpointIfNeeded() { + if (m_break_id == LLDB_INVALID_BREAK_ID && m_kernel.GetModule()) { + DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", + __FUNCTION__, StateAsCString(m_process->GetState())); + + const bool internal_bp = true; + const bool hardware = false; + const LazyBool skip_prologue = eLazyBoolNo; + FileSpecList module_spec_list; + module_spec_list.Append(m_kernel.GetModule()->GetFileSpec()); + Breakpoint *bp = + m_process->GetTarget() + .CreateBreakpoint(&module_spec_list, NULL, + "OSKextLoadedKextSummariesUpdated", + eFunctionNameTypeFull, eLanguageTypeUnknown, 0, + skip_prologue, internal_bp, hardware) + .get(); + + bp->SetCallback(DynamicLoaderDarwinKernel::BreakpointHitCallback, this, + true); + m_break_id = bp->GetID(); + } } //---------------------------------------------------------------------- // Member function that gets called when the process state changes. //---------------------------------------------------------------------- -void -DynamicLoaderDarwinKernel::PrivateProcessStateChanged (Process *process, StateType state) -{ - DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s(%s)\n", __FUNCTION__, StateAsCString(state)); - switch (state) - { - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - case eStateDetached: - Clear(false); - break; - - case eStateStopped: - UpdateIfNeeded(); - break; - - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - break; - } +void DynamicLoaderDarwinKernel::PrivateProcessStateChanged(Process *process, + StateType state) { + DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s(%s)\n", __FUNCTION__, + StateAsCString(state)); + switch (state) { + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + case eStateDetached: + Clear(false); + break; + + case eStateStopped: + UpdateIfNeeded(); + break; + + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + break; + } } ThreadPlanSP -DynamicLoaderDarwinKernel::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) -{ - ThreadPlanSP thread_plan_sp; - Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("Could not find symbol for step through."); - return thread_plan_sp; +DynamicLoaderDarwinKernel::GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) { + ThreadPlanSP thread_plan_sp; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Could not find symbol for step through."); + return thread_plan_sp; } -Error -DynamicLoaderDarwinKernel::CanLoadImage () -{ - Error error; - error.SetErrorString("always unsafe to load or unload shared libraries in the darwin kernel"); - return error; +Error DynamicLoaderDarwinKernel::CanLoadImage() { + Error error; + error.SetErrorString( + "always unsafe to load or unload shared libraries in the darwin kernel"); + return error; } -void -DynamicLoaderDarwinKernel::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - DebuggerInitialize); +void DynamicLoaderDarwinKernel::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); } -void -DynamicLoaderDarwinKernel::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void DynamicLoaderDarwinKernel::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -void -DynamicLoaderDarwinKernel::DebuggerInitialize (lldb_private::Debugger &debugger) -{ - if (!PluginManager::GetSettingForDynamicLoaderPlugin (debugger, DynamicLoaderDarwinKernelProperties::GetSettingName())) - { - const bool is_global_setting = true; - PluginManager::CreateSettingForDynamicLoaderPlugin (debugger, - GetGlobalProperties()->GetValueProperties(), - ConstString ("Properties for the DynamicLoaderDarwinKernel plug-in."), - is_global_setting); - } +void DynamicLoaderDarwinKernel::DebuggerInitialize( + lldb_private::Debugger &debugger) { + if (!PluginManager::GetSettingForDynamicLoaderPlugin( + debugger, DynamicLoaderDarwinKernelProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForDynamicLoaderPlugin( + debugger, GetGlobalProperties()->GetValueProperties(), + ConstString("Properties for the DynamicLoaderDarwinKernel plug-in."), + is_global_setting); + } } -lldb_private::ConstString -DynamicLoaderDarwinKernel::GetPluginNameStatic() -{ - static ConstString g_name("darwin-kernel"); - return g_name; +lldb_private::ConstString DynamicLoaderDarwinKernel::GetPluginNameStatic() { + static ConstString g_name("darwin-kernel"); + return g_name; } -const char * -DynamicLoaderDarwinKernel::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that watches for shared library loads/unloads in the MacOSX kernel."; +const char *DynamicLoaderDarwinKernel::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library loads/unloads " + "in the MacOSX kernel."; } - //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -DynamicLoaderDarwinKernel::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString DynamicLoaderDarwinKernel::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -DynamicLoaderDarwinKernel::GetPluginVersion() -{ - return 1; -} +uint32_t DynamicLoaderDarwinKernel::GetPluginVersion() { return 1; } lldb::ByteOrder -DynamicLoaderDarwinKernel::GetByteOrderFromMagic (uint32_t magic) -{ - switch (magic) - { - case llvm::MachO::MH_MAGIC: - case llvm::MachO::MH_MAGIC_64: - return endian::InlHostByteOrder(); - - case llvm::MachO::MH_CIGAM: - case llvm::MachO::MH_CIGAM_64: - if (endian::InlHostByteOrder() == lldb::eByteOrderBig) - return lldb::eByteOrderLittle; - else - return lldb::eByteOrderBig; - - default: - break; - } - return lldb::eByteOrderInvalid; -} +DynamicLoaderDarwinKernel::GetByteOrderFromMagic(uint32_t magic) { + switch (magic) { + case llvm::MachO::MH_MAGIC: + case llvm::MachO::MH_MAGIC_64: + return endian::InlHostByteOrder(); + case llvm::MachO::MH_CIGAM: + case llvm::MachO::MH_CIGAM_64: + if (endian::InlHostByteOrder() == lldb::eByteOrderBig) + return lldb::eByteOrderLittle; + else + return lldb::eByteOrderBig; + + default: + break; + } + return lldb::eByteOrderInvalid; +} diff --git a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h index 47fba086a4a9..695a4eaf881a 100644 --- a/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h +++ b/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h @@ -18,354 +18,288 @@ // Other libraries and framework includes // Project includes -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" -class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader -{ +class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader { public: - DynamicLoaderDarwinKernel(lldb_private::Process *process, lldb::addr_t kernel_addr); + DynamicLoaderDarwinKernel(lldb_private::Process *process, + lldb::addr_t kernel_addr); - ~DynamicLoaderDarwinKernel() override; + ~DynamicLoaderDarwinKernel() override; - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - static lldb_private::DynamicLoader * - CreateInstance (lldb_private::Process *process, bool force); + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); - static void - DebuggerInitialize (lldb_private::Debugger &debugger); + static void DebuggerInitialize(lldb_private::Debugger &debugger); - static lldb::addr_t - SearchForDarwinKernel (lldb_private::Process *process); + static lldb::addr_t SearchForDarwinKernel(lldb_private::Process *process); - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - void - DidAttach() override; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + void DidAttach() override; - void - DidLaunch() override; + void DidLaunch() override; - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan(lldb_private::Thread &thread, - bool stop_others) override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; - lldb_private::Error - CanLoadImage() override; + lldb_private::Error CanLoadImage() override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; protected: - void - PrivateInitialize (lldb_private::Process *process); + void PrivateInitialize(lldb_private::Process *process); + + void PrivateProcessStateChanged(lldb_private::Process *process, + lldb::StateType state); + + void UpdateIfNeeded(); + + void LoadKernelModuleIfNeeded(); + + void Clear(bool clear_process); + + void PutToLog(lldb_private::Log *log) const; + + static bool + BreakpointHitCallback(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + bool BreakpointHit(lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + uint32_t GetAddrByteSize() { return m_kernel.GetAddressByteSize(); } + + static lldb::ByteOrder GetByteOrderFromMagic(uint32_t magic); + + enum { + KERNEL_MODULE_MAX_NAME = 64u, + // Versions less than 2 didn't have an entry size, + // they had a 64 bit name, 16 byte UUID, 8 byte addr, + // 8 byte size, 8 byte version, 4 byte load tag, and + // 4 byte flags + KERNEL_MODULE_ENTRY_SIZE_VERSION_1 = 64u + 16u + 8u + 8u + 8u + 4u + 4u + }; + + // class KextImageInfo represents a single kext or kernel binary image. + // The class was designed to hold the information from the + // OSKextLoadedKextSummary + // structure (in libkern/libkern/OSKextLibPrivate.h from xnu). The kernel + // maintains + // a list of loded kexts in memory (the OSKextLoadedKextSummaryHeader + // structure, + // which points to an array of OSKextLoadedKextSummary's). + // + // A KextImageInfos may have - + // + // 1. The load address, name, UUID, and size of a kext/kernel binary in memory + // (read straight out of the kernel's list-of-kexts loaded) + // 2. A ModuleSP based on a MemoryModule read out of the kernel's memory + // (very unlikely to have any symbolic information) + // 3. A ModuleSP for an on-disk copy of the kext binary, possibly with debug + // info + // or a dSYM + // + // For performance reasons, the developer may prefer that lldb not load the + // kexts out + // of memory at the start of a kernel session. But we should build up / + // maintain a + // list of kexts that the kernel has told us about so we can relocate a kext + // module + // later if the user explicitly adds it to the target. + + class KextImageInfo { + public: + KextImageInfo() + : m_name(), m_module_sp(), m_memory_module_sp(), + m_load_process_stop_id(UINT32_MAX), m_uuid(), + m_load_address(LLDB_INVALID_ADDRESS), m_size(0), + m_kernel_image(false) {} + + void Clear() { + m_load_address = LLDB_INVALID_ADDRESS; + m_size = 0; + m_name.clear(); + m_uuid.Clear(); + m_module_sp.reset(); + m_memory_module_sp.reset(); + m_load_process_stop_id = UINT32_MAX; + } + + bool LoadImageAtFileAddress(lldb_private::Process *process); + + bool LoadImageUsingMemoryModule(lldb_private::Process *process); + + bool IsLoaded() { return m_load_process_stop_id != UINT32_MAX; } + + void SetLoadAddress( + lldb::addr_t load_addr); // Address of the Mach-O header for this binary + + lldb::addr_t + GetLoadAddress() const; // Address of the Mach-O header for this binary + + lldb_private::UUID GetUUID() const; + + void SetUUID(const lldb_private::UUID &uuid); - void - PrivateProcessStateChanged (lldb_private::Process *process, - lldb::StateType state); + void SetName(const char *); - void - UpdateIfNeeded(); + std::string GetName() const; - void - LoadKernelModuleIfNeeded (); + void SetModule(lldb::ModuleSP module); - void - Clear (bool clear_process); + lldb::ModuleSP GetModule(); - void - PutToLog (lldb_private::Log *log) const; + // try to fill in m_memory_module_sp from memory based on the m_load_address + bool ReadMemoryModule(lldb_private::Process *process); - static bool - BreakpointHitCallback (void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); + bool IsKernel() + const; // true if this is the mach_kernel; false if this is a kext + + void SetIsKernel(bool is_kernel); + + uint64_t GetSize() const; + + void SetSize(uint64_t size); - bool - BreakpointHit (lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); uint32_t - GetAddrByteSize() - { - return m_kernel.GetAddressByteSize(); + GetProcessStopId() const; // the stop-id when this binary was first noticed + + void SetProcessStopId(uint32_t stop_id); + + bool operator==(const KextImageInfo &rhs); + + uint32_t GetAddressByteSize(); // as determined by Mach-O header + + lldb::ByteOrder GetByteOrder(); // as determined by Mach-O header + + lldb_private::ArchSpec + GetArchitecture() const; // as determined by Mach-O header + + void PutToLog(lldb_private::Log *log) const; + + typedef std::vector<KextImageInfo> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + private: + std::string m_name; + lldb::ModuleSP m_module_sp; + lldb::ModuleSP m_memory_module_sp; + uint32_t m_load_process_stop_id; // the stop-id when this module was added + // to the Target + lldb_private::UUID + m_uuid; // UUID for this dylib if it has one, else all zeros + lldb::addr_t m_load_address; + uint64_t m_size; + bool m_kernel_image; // true if this is the kernel, false if this is a kext + }; + + struct OSKextLoadedKextSummaryHeader { + uint32_t version; + uint32_t entry_size; + uint32_t entry_count; + lldb::addr_t image_infos_addr; + + OSKextLoadedKextSummaryHeader() + : version(0), entry_size(0), entry_count(0), + image_infos_addr(LLDB_INVALID_ADDRESS) {} + + uint32_t GetSize() { + switch (version) { + case 0: + return 0; // Can't know the size without a valid version + case 1: + return 8; // Version 1 only had a version + entry_count + default: + break; + } + // Version 2 and above has version, entry_size, entry_count, and reserved + return 16; } - static lldb::ByteOrder - GetByteOrderFromMagic (uint32_t magic); - - enum - { - KERNEL_MODULE_MAX_NAME = 64u, - // Versions less than 2 didn't have an entry size, - // they had a 64 bit name, 16 byte UUID, 8 byte addr, - // 8 byte size, 8 byte version, 4 byte load tag, and - // 4 byte flags - KERNEL_MODULE_ENTRY_SIZE_VERSION_1 = 64u + 16u + 8u + 8u + 8u + 4u + 4u - }; - - // class KextImageInfo represents a single kext or kernel binary image. - // The class was designed to hold the information from the OSKextLoadedKextSummary - // structure (in libkern/libkern/OSKextLibPrivate.h from xnu). The kernel maintains - // a list of loded kexts in memory (the OSKextLoadedKextSummaryHeader structure, - // which points to an array of OSKextLoadedKextSummary's). - // - // A KextImageInfos may have - - // - // 1. The load address, name, UUID, and size of a kext/kernel binary in memory - // (read straight out of the kernel's list-of-kexts loaded) - // 2. A ModuleSP based on a MemoryModule read out of the kernel's memory - // (very unlikely to have any symbolic information) - // 3. A ModuleSP for an on-disk copy of the kext binary, possibly with debug info - // or a dSYM - // - // For performance reasons, the developer may prefer that lldb not load the kexts out - // of memory at the start of a kernel session. But we should build up / maintain a - // list of kexts that the kernel has told us about so we can relocate a kext module - // later if the user explicitly adds it to the target. - - class KextImageInfo - { - public: - KextImageInfo () : - m_name (), - m_module_sp (), - m_memory_module_sp (), - m_load_process_stop_id (UINT32_MAX), - m_uuid (), - m_load_address (LLDB_INVALID_ADDRESS), - m_size (0), - m_kernel_image (false) - { } - - void - Clear () - { - m_load_address = LLDB_INVALID_ADDRESS; - m_size = 0; - m_name.clear (); - m_uuid.Clear(); - m_module_sp.reset(); - m_memory_module_sp.reset(); - m_load_process_stop_id = UINT32_MAX; - } - - bool - LoadImageAtFileAddress (lldb_private::Process *process); - - bool - LoadImageUsingMemoryModule (lldb_private::Process *process); - - bool - IsLoaded () - { - return m_load_process_stop_id != UINT32_MAX; - } - - void - SetLoadAddress (lldb::addr_t load_addr); // Address of the Mach-O header for this binary - - lldb::addr_t - GetLoadAddress () const; // Address of the Mach-O header for this binary - - lldb_private::UUID - GetUUID () const; - - void - SetUUID (const lldb_private::UUID &uuid); - - void - SetName (const char *); - - std::string - GetName () const; - - void - SetModule (lldb::ModuleSP module); - - lldb::ModuleSP - GetModule (); - - // try to fill in m_memory_module_sp from memory based on the m_load_address - bool - ReadMemoryModule (lldb_private::Process *process); - - bool - IsKernel () const; // true if this is the mach_kernel; false if this is a kext - - void - SetIsKernel (bool is_kernel); - - uint64_t - GetSize () const; - - void - SetSize (uint64_t size); - - uint32_t - GetProcessStopId () const; // the stop-id when this binary was first noticed - - void - SetProcessStopId (uint32_t stop_id); - - bool - operator== (const KextImageInfo &rhs); - - uint32_t - GetAddressByteSize (); // as determined by Mach-O header - - lldb::ByteOrder - GetByteOrder(); // as determined by Mach-O header - - lldb_private::ArchSpec - GetArchitecture () const; // as determined by Mach-O header - - void - PutToLog (lldb_private::Log *log) const; - - typedef std::vector<KextImageInfo> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - private: - std::string m_name; - lldb::ModuleSP m_module_sp; - lldb::ModuleSP m_memory_module_sp; - uint32_t m_load_process_stop_id; // the stop-id when this module was added to the Target - lldb_private::UUID m_uuid; // UUID for this dylib if it has one, else all zeros - lldb::addr_t m_load_address; - uint64_t m_size; - bool m_kernel_image; // true if this is the kernel, false if this is a kext - }; - - struct OSKextLoadedKextSummaryHeader - { - uint32_t version; - uint32_t entry_size; - uint32_t entry_count; - lldb::addr_t image_infos_addr; - - OSKextLoadedKextSummaryHeader() : - version (0), - entry_size (0), - entry_count (0), - image_infos_addr (LLDB_INVALID_ADDRESS) - { - } - - uint32_t - GetSize() - { - switch (version) - { - case 0: return 0; // Can't know the size without a valid version - case 1: return 8; // Version 1 only had a version + entry_count - default: break; - } - // Version 2 and above has version, entry_size, entry_count, and reserved - return 16; - } - - void - Clear() - { - version = 0; - entry_size = 0; - entry_count = 0; - image_infos_addr = LLDB_INVALID_ADDRESS; - } - - bool - IsValid() const - { - return version >= 1 || version <= 2; - } - }; - - void - RegisterNotificationCallbacks(); - - void - UnregisterNotificationCallbacks(); - - void - SetNotificationBreakpointIfNeeded (); - - bool - ReadAllKextSummaries (); - - bool - ReadKextSummaryHeader (); - - bool - ParseKextSummaries (const lldb_private::Address &kext_summary_addr, - uint32_t count); - - void - UpdateImageInfosHeaderAndLoadCommands(KextImageInfo::collection &image_infos, - uint32_t infos_count, - bool update_executable); + void Clear() { + version = 0; + entry_size = 0; + entry_count = 0; + image_infos_addr = LLDB_INVALID_ADDRESS; + } - uint32_t - ReadKextSummaries (const lldb_private::Address &kext_summary_addr, - uint32_t image_infos_count, - KextImageInfo::collection &image_infos); + bool IsValid() const { return version >= 1 || version <= 2; } + }; + + void RegisterNotificationCallbacks(); + + void UnregisterNotificationCallbacks(); + + void SetNotificationBreakpointIfNeeded(); + + bool ReadAllKextSummaries(); + + bool ReadKextSummaryHeader(); + + bool ParseKextSummaries(const lldb_private::Address &kext_summary_addr, + uint32_t count); + + void + UpdateImageInfosHeaderAndLoadCommands(KextImageInfo::collection &image_infos, + uint32_t infos_count, + bool update_executable); + + uint32_t ReadKextSummaries(const lldb_private::Address &kext_summary_addr, + uint32_t image_infos_count, + KextImageInfo::collection &image_infos); - static lldb::addr_t - SearchForKernelAtSameLoadAddr (lldb_private::Process *process); + static lldb::addr_t + SearchForKernelAtSameLoadAddr(lldb_private::Process *process); - static lldb::addr_t - SearchForKernelWithDebugHints (lldb_private::Process *process); + static lldb::addr_t + SearchForKernelWithDebugHints(lldb_private::Process *process); - static lldb::addr_t - SearchForKernelNearPC (lldb_private::Process *process); + static lldb::addr_t SearchForKernelNearPC(lldb_private::Process *process); - static lldb::addr_t - SearchForKernelViaExhaustiveSearch (lldb_private::Process *process); + static lldb::addr_t + SearchForKernelViaExhaustiveSearch(lldb_private::Process *process); - static lldb_private::UUID - CheckForKernelImageAtAddress (lldb::addr_t addr, lldb_private::Process *process); + static lldb_private::UUID + CheckForKernelImageAtAddress(lldb::addr_t addr, + lldb_private::Process *process); - lldb::addr_t m_kernel_load_address; - KextImageInfo m_kernel; // Info about the current kernel image being used + lldb::addr_t m_kernel_load_address; + KextImageInfo m_kernel; // Info about the current kernel image being used - lldb_private::Address m_kext_summary_header_ptr_addr; - lldb_private::Address m_kext_summary_header_addr; - OSKextLoadedKextSummaryHeader m_kext_summary_header; - KextImageInfo::collection m_known_kexts; - mutable std::recursive_mutex m_mutex; - lldb::user_id_t m_break_id; + lldb_private::Address m_kext_summary_header_ptr_addr; + lldb_private::Address m_kext_summary_header_addr; + OSKextLoadedKextSummaryHeader m_kext_summary_header; + KextImageInfo::collection m_known_kexts; + mutable std::recursive_mutex m_mutex; + lldb::user_id_t m_break_id; private: - DISALLOW_COPY_AND_ASSIGN (DynamicLoaderDarwinKernel); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderDarwinKernel); }; #endif // liblldb_DynamicLoaderDarwinKernel_h_ diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp index 1f77539ca8df..3c64b2ffed3c 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp @@ -1,4 +1,4 @@ -//===-- DynamicLoaderHexagon.h ----------------------------------*- C++ -*-===// +//===-- DynamicLoaderHexagonDYLD.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,17 +10,17 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "lldb/Core/PluginManager.h" +#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" -#include "lldb/Breakpoint/BreakpointLocation.h" #include "DynamicLoaderHexagonDYLD.h" @@ -31,562 +31,490 @@ using namespace lldb_private; // // Notes about hexagon dynamic loading: // -// When we connect to a target we find the dyld breakpoint address. We put a +// When we connect to a target we find the dyld breakpoint address. We put +// a // breakpoint there with a callback 'RendezvousBreakpointHit()'. // -// It is possible to find the dyld structure address from the ELF symbol table, -// but in the case of the simulator it has not been initialized before the +// It is possible to find the dyld structure address from the ELF symbol +// table, +// but in the case of the simulator it has not been initialized before the // target calls dlinit(). // -// We can only safely parse the dyld structure after we hit the dyld breakpoint +// We can only safely parse the dyld structure after we hit the dyld +// breakpoint // since at that time we know dlinit() must have been called. // // Find the load address of a symbol -static lldb::addr_t findSymbolAddress( Process *proc, ConstString findName ) -{ - assert( proc != nullptr ); - - ModuleSP module = proc->GetTarget().GetExecutableModule(); - assert( module.get() != nullptr ); - - ObjectFile *exe = module->GetObjectFile(); - assert( exe != nullptr ); - - lldb_private::Symtab *symtab = exe->GetSymtab( ); - assert( symtab != nullptr ); - - for ( size_t i = 0; i < symtab->GetNumSymbols( ); i++ ) - { - const Symbol* sym = symtab->SymbolAtIndex( i ); - assert( sym != nullptr ); - const ConstString &symName = sym->GetName( ); - - if ( ConstString::Compare( findName, symName ) == 0 ) - { - Address addr = sym->GetAddress(); - return addr.GetLoadAddress( & proc->GetTarget() ); - } - } - return LLDB_INVALID_ADDRESS; -} +static lldb::addr_t findSymbolAddress(Process *proc, ConstString findName) { + assert(proc != nullptr); -void -DynamicLoaderHexagonDYLD::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); -} + ModuleSP module = proc->GetTarget().GetExecutableModule(); + assert(module.get() != nullptr); + + ObjectFile *exe = module->GetObjectFile(); + assert(exe != nullptr); + + lldb_private::Symtab *symtab = exe->GetSymtab(); + assert(symtab != nullptr); + + for (size_t i = 0; i < symtab->GetNumSymbols(); i++) { + const Symbol *sym = symtab->SymbolAtIndex(i); + assert(sym != nullptr); + const ConstString &symName = sym->GetName(); -void -DynamicLoaderHexagonDYLD::Terminate() -{ + if (ConstString::Compare(findName, symName) == 0) { + Address addr = sym->GetAddress(); + return addr.GetLoadAddress(&proc->GetTarget()); + } + } + return LLDB_INVALID_ADDRESS; } -lldb_private::ConstString -DynamicLoaderHexagonDYLD::GetPluginName() -{ - return GetPluginNameStatic(); +void DynamicLoaderHexagonDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); } -lldb_private::ConstString -DynamicLoaderHexagonDYLD::GetPluginNameStatic() -{ - static ConstString g_name("hexagon-dyld"); - return g_name; +void DynamicLoaderHexagonDYLD::Terminate() {} + +lldb_private::ConstString DynamicLoaderHexagonDYLD::GetPluginName() { + return GetPluginNameStatic(); } -const char * -DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that watches for shared library " - "loads/unloads in Hexagon processes."; +lldb_private::ConstString DynamicLoaderHexagonDYLD::GetPluginNameStatic() { + static ConstString g_name("hexagon-dyld"); + return g_name; } -uint32_t -DynamicLoaderHexagonDYLD::GetPluginVersion() -{ - return 1; +const char *DynamicLoaderHexagonDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Hexagon processes."; } -DynamicLoader * -DynamicLoaderHexagonDYLD::CreateInstance(Process *process, bool force) -{ - bool create = force; - if (!create) - { - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - if (triple_ref.getArch() == llvm::Triple::hexagon) - create = true; - } - - if (create) - return new DynamicLoaderHexagonDYLD(process); - return NULL; +uint32_t DynamicLoaderHexagonDYLD::GetPluginVersion() { return 1; } + +DynamicLoader *DynamicLoaderHexagonDYLD::CreateInstance(Process *process, + bool force) { + bool create = force; + if (!create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getArch() == llvm::Triple::hexagon) + create = true; + } + + if (create) + return new DynamicLoaderHexagonDYLD(process); + return NULL; } DynamicLoaderHexagonDYLD::DynamicLoaderHexagonDYLD(Process *process) - : DynamicLoader(process) - , m_rendezvous (process) - , m_load_offset(LLDB_INVALID_ADDRESS) - , m_entry_point(LLDB_INVALID_ADDRESS) - , m_dyld_bid (LLDB_INVALID_BREAK_ID) -{ + : DynamicLoader(process), m_rendezvous(process), + m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), + m_dyld_bid(LLDB_INVALID_BREAK_ID) {} + +DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD() { + if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { + m_process->GetTarget().RemoveBreakpointByID(m_dyld_bid); + m_dyld_bid = LLDB_INVALID_BREAK_ID; + } } -DynamicLoaderHexagonDYLD::~DynamicLoaderHexagonDYLD() -{ - if (m_dyld_bid != LLDB_INVALID_BREAK_ID) - { - m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid); - m_dyld_bid = LLDB_INVALID_BREAK_ID; - } -} +void DynamicLoaderHexagonDYLD::DidAttach() { + ModuleSP executable; + addr_t load_offset; -void -DynamicLoaderHexagonDYLD::DidAttach() -{ - ModuleSP executable; - addr_t load_offset; - - executable = GetTargetExecutable(); - - // Find the difference between the desired load address in the elf file - // and the real load address in memory - load_offset = ComputeLoadOffset(); - - // Check that there is a valid executable - if ( executable.get( ) == nullptr ) - return; - - // Disable JIT for hexagon targets because its not supported - m_process->SetCanJIT(false); - - // Enable Interpreting of function call expressions - m_process->SetCanInterpretFunctionCalls(true); - - // Add the current executable to the module list - ModuleList module_list; - module_list.Append(executable); - - // Map the loaded sections of this executable - if ( load_offset != LLDB_INVALID_ADDRESS ) - UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true); - - // AD: confirm this? - // Load into LLDB all of the currently loaded executables in the stub - LoadAllCurrentModules(); - - // AD: confirm this? - // Callback for the target to give it the loaded module list - m_process->GetTarget().ModulesDidLoad(module_list); - - // Try to set a breakpoint at the rendezvous breakpoint. - // DidLaunch uses ProbeEntry() instead. That sets a breakpoint, - // at the dyld breakpoint address, with a callback so that when hit, - // the dyld structure can be parsed. - if (! SetRendezvousBreakpoint() ) - { - // fail - } -} + executable = GetTargetExecutable(); + + // Find the difference between the desired load address in the elf file + // and the real load address in memory + load_offset = ComputeLoadOffset(); + + // Check that there is a valid executable + if (executable.get() == nullptr) + return; + + // Disable JIT for hexagon targets because its not supported + m_process->SetCanJIT(false); + + // Enable Interpreting of function call expressions + m_process->SetCanInterpretFunctionCalls(true); -void -DynamicLoaderHexagonDYLD::DidLaunch() -{ + // Add the current executable to the module list + ModuleList module_list; + module_list.Append(executable); + + // Map the loaded sections of this executable + if (load_offset != LLDB_INVALID_ADDRESS) + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true); + + // AD: confirm this? + // Load into LLDB all of the currently loaded executables in the stub + LoadAllCurrentModules(); + + // AD: confirm this? + // Callback for the target to give it the loaded module list + m_process->GetTarget().ModulesDidLoad(module_list); + + // Try to set a breakpoint at the rendezvous breakpoint. + // DidLaunch uses ProbeEntry() instead. That sets a breakpoint, + // at the dyld breakpoint address, with a callback so that when hit, + // the dyld structure can be parsed. + if (!SetRendezvousBreakpoint()) { + // fail + } } +void DynamicLoaderHexagonDYLD::DidLaunch() {} + /// Checks to see if the target module has changed, updates the target /// accordingly and returns the target executable module. -ModuleSP -DynamicLoaderHexagonDYLD::GetTargetExecutable() -{ - Target &target = m_process->GetTarget(); - ModuleSP executable = target.GetExecutableModule(); - - // There is no executable - if (! executable.get()) - return executable; - - // The target executable file does not exits - if (! executable->GetFileSpec().Exists()) - return executable; - - // Prep module for loading - ModuleSpec module_spec(executable->GetFileSpec(), executable->GetArchitecture()); - ModuleSP module_sp (new Module (module_spec)); - - // Check if the executable has changed and set it to the target executable if they differ. - if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) - { - // if the executable has changed ?? - if (module_sp->GetUUID() != executable->GetUUID()) - executable.reset(); - } - else if (executable->FileHasChanged()) - executable.reset(); - - if ( executable.get( ) ) - return executable; - - // TODO: What case is this code used? - executable = target.GetSharedModule(module_spec); - if (executable.get() != target.GetExecutableModulePointer()) - { - // Don't load dependent images since we are in dyld where we will know - // and find out about all images that are loaded - const bool get_dependent_images = false; - target.SetExecutableModule(executable, get_dependent_images); - } - +ModuleSP DynamicLoaderHexagonDYLD::GetTargetExecutable() { + Target &target = m_process->GetTarget(); + ModuleSP executable = target.GetExecutableModule(); + + // There is no executable + if (!executable.get()) + return executable; + + // The target executable file does not exits + if (!executable->GetFileSpec().Exists()) return executable; -} -//AD: Needs to be updated? -Error -DynamicLoaderHexagonDYLD::CanLoadImage() -{ - return Error(); + // Prep module for loading + ModuleSpec module_spec(executable->GetFileSpec(), + executable->GetArchitecture()); + ModuleSP module_sp(new Module(module_spec)); + + // Check if the executable has changed and set it to the target executable if + // they differ. + if (module_sp.get() && module_sp->GetUUID().IsValid() && + executable->GetUUID().IsValid()) { + // if the executable has changed ?? + if (module_sp->GetUUID() != executable->GetUUID()) + executable.reset(); + } else if (executable->FileHasChanged()) + executable.reset(); + + if (executable.get()) + return executable; + + // TODO: What case is this code used? + executable = target.GetSharedModule(module_spec); + if (executable.get() != target.GetExecutableModulePointer()) { + // Don't load dependent images since we are in dyld where we will know + // and find out about all images that are loaded + const bool get_dependent_images = false; + target.SetExecutableModule(executable, get_dependent_images); + } + + return executable; } -void -DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, - addr_t link_map_addr, - addr_t base_addr, - bool base_addr_is_offset) -{ - Target &target = m_process->GetTarget(); - const SectionList *sections = GetSectionListFromModule(module); +// AD: Needs to be updated? +Error DynamicLoaderHexagonDYLD::CanLoadImage() { return Error(); } - assert(sections && "SectionList missing from loaded module."); +void DynamicLoaderHexagonDYLD::UpdateLoadedSections(ModuleSP module, + addr_t link_map_addr, + addr_t base_addr, + bool base_addr_is_offset) { + Target &target = m_process->GetTarget(); + const SectionList *sections = GetSectionListFromModule(module); - m_loaded_modules[module] = link_map_addr; + assert(sections && "SectionList missing from loaded module."); - const size_t num_sections = sections->GetSize(); + m_loaded_modules[module] = link_map_addr; - for (unsigned i = 0; i < num_sections; ++i) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; + const size_t num_sections = sections->GetSize(); - // AD: 02/05/14 - // since our memory map starts from address 0, we must not ignore - // sections that load to address 0. This violates the reference - // ELF spec, however is used for Hexagon. + for (unsigned i = 0; i < num_sections; ++i) { + SectionSP section_sp(sections->GetSectionAtIndex(i)); + lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; - // If the file address of the section is zero then this is not an - // allocatable/loadable section (property of ELF sh_addr). Skip it. -// if (new_load_addr == base_addr) -// continue; + // AD: 02/05/14 + // since our memory map starts from address 0, we must not ignore + // sections that load to address 0. This violates the reference + // ELF spec, however is used for Hexagon. - target.SetSectionLoadAddress(section_sp, new_load_addr); - } + // If the file address of the section is zero then this is not an + // allocatable/loadable section (property of ELF sh_addr). Skip it. + // if (new_load_addr == base_addr) + // continue; + + target.SetSectionLoadAddress(section_sp, new_load_addr); + } } /// Removes the loaded sections from the target in @p module. /// /// @param module The module to traverse. -void -DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module) -{ - Target &target = m_process->GetTarget(); - const SectionList *sections = GetSectionListFromModule(module); +void DynamicLoaderHexagonDYLD::UnloadSections(const ModuleSP module) { + Target &target = m_process->GetTarget(); + const SectionList *sections = GetSectionListFromModule(module); - assert(sections && "SectionList missing from unloaded module."); + assert(sections && "SectionList missing from unloaded module."); - m_loaded_modules.erase(module); + m_loaded_modules.erase(module); - const size_t num_sections = sections->GetSize(); - for (size_t i = 0; i < num_sections; ++i) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - target.SetSectionUnloaded(section_sp); - } + const size_t num_sections = sections->GetSize(); + for (size_t i = 0; i < num_sections; ++i) { + SectionSP section_sp(sections->GetSectionAtIndex(i)); + target.SetSectionUnloaded(section_sp); + } } // Place a breakpoint on <_rtld_debug_state> -bool -DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - - // This is the original code, which want to look in the rendezvous structure - // to find the breakpoint address. Its backwards for us, since we can easily - // find the breakpoint address, since it is exported in our executable. - // We however know that we cant read the Rendezvous structure until we have hit - // the breakpoint once. - const ConstString dyldBpName( "_rtld_debug_state" ); - addr_t break_addr = findSymbolAddress( m_process, dyldBpName ); - - Target &target = m_process->GetTarget(); - - // Do not try to set the breakpoint if we don't know where to put it - if ( break_addr == LLDB_INVALID_ADDRESS ) - { - if ( log ) - log->Printf( "Unable to locate _rtld_debug_state breakpoint address" ); - - return false; - } - - // Save the address of the rendezvous structure - m_rendezvous.SetBreakAddress( break_addr ); - - // If we haven't set the breakpoint before then set it - if (m_dyld_bid == LLDB_INVALID_BREAK_ID) - { - Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get(); - dyld_break->SetCallback(RendezvousBreakpointHit, this, true); - dyld_break->SetBreakpointKind ("shared-library-event"); - m_dyld_bid = dyld_break->GetID(); - - // Make sure our breakpoint is at the right address. - assert - ( - target.GetBreakpointByID(m_dyld_bid)-> - FindLocationByAddress(break_addr)-> - GetBreakpoint().GetID() - == m_dyld_bid - ); - - if ( log && dyld_break == nullptr ) - log->Printf( "Failed to create _rtld_debug_state breakpoint" ); - - // check we have successfully set bp - return (dyld_break != nullptr); - } - else - // rendezvous already set - return true; +bool DynamicLoaderHexagonDYLD::SetRendezvousBreakpoint() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + // This is the original code, which want to look in the rendezvous structure + // to find the breakpoint address. Its backwards for us, since we can easily + // find the breakpoint address, since it is exported in our executable. + // We however know that we cant read the Rendezvous structure until we have + // hit + // the breakpoint once. + const ConstString dyldBpName("_rtld_debug_state"); + addr_t break_addr = findSymbolAddress(m_process, dyldBpName); + + Target &target = m_process->GetTarget(); + + // Do not try to set the breakpoint if we don't know where to put it + if (break_addr == LLDB_INVALID_ADDRESS) { + if (log) + log->Printf("Unable to locate _rtld_debug_state breakpoint address"); + + return false; + } + + // Save the address of the rendezvous structure + m_rendezvous.SetBreakAddress(break_addr); + + // If we haven't set the breakpoint before then set it + if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { + Breakpoint *dyld_break = + target.CreateBreakpoint(break_addr, true, false).get(); + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + m_dyld_bid = dyld_break->GetID(); + + // Make sure our breakpoint is at the right address. + assert(target.GetBreakpointByID(m_dyld_bid) + ->FindLocationByAddress(break_addr) + ->GetBreakpoint() + .GetID() == m_dyld_bid); + + if (log && dyld_break == nullptr) + log->Printf("Failed to create _rtld_debug_state breakpoint"); + + // check we have successfully set bp + return (dyld_break != nullptr); + } else + // rendezvous already set + return true; } // We have just hit our breakpoint at <_rtld_debug_state> -bool -DynamicLoaderHexagonDYLD::RendezvousBreakpointHit(void *baton, - StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); +bool DynamicLoaderHexagonDYLD::RendezvousBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if ( log ) - log->Printf( "Rendezvous breakpoint hit!" ); + if (log) + log->Printf("Rendezvous breakpoint hit!"); - DynamicLoaderHexagonDYLD* dyld_instance = nullptr; - dyld_instance = static_cast<DynamicLoaderHexagonDYLD*>(baton); + DynamicLoaderHexagonDYLD *dyld_instance = nullptr; + dyld_instance = static_cast<DynamicLoaderHexagonDYLD *>(baton); - // if the dyld_instance is still not valid then - // try to locate it on the symbol table - if ( !dyld_instance->m_rendezvous.IsValid( ) ) - { - Process *proc = dyld_instance->m_process; + // if the dyld_instance is still not valid then + // try to locate it on the symbol table + if (!dyld_instance->m_rendezvous.IsValid()) { + Process *proc = dyld_instance->m_process; - const ConstString dyldStructName( "_rtld_debug" ); - addr_t structAddr = findSymbolAddress( proc, dyldStructName ); + const ConstString dyldStructName("_rtld_debug"); + addr_t structAddr = findSymbolAddress(proc, dyldStructName); - if ( structAddr != LLDB_INVALID_ADDRESS ) - { - dyld_instance->m_rendezvous.SetRendezvousAddress( structAddr ); + if (structAddr != LLDB_INVALID_ADDRESS) { + dyld_instance->m_rendezvous.SetRendezvousAddress(structAddr); - if ( log ) - log->Printf( "Found _rtld_debug structure @ 0x%08" PRIx64, structAddr ); - } - else - { - if ( log ) - log->Printf( "Unable to resolve the _rtld_debug structure" ); - } + if (log) + log->Printf("Found _rtld_debug structure @ 0x%08" PRIx64, structAddr); + } else { + if (log) + log->Printf("Unable to resolve the _rtld_debug structure"); } + } - dyld_instance->RefreshModules(); + dyld_instance->RefreshModules(); - // Return true to stop the target, false to just let the target run. - return dyld_instance->GetStopWhenImagesChange(); + // Return true to stop the target, false to just let the target run. + return dyld_instance->GetStopWhenImagesChange(); } /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set /// of loaded modules. -void -DynamicLoaderHexagonDYLD::RefreshModules() -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - - if (!m_rendezvous.Resolve()) - return; - - HexagonDYLDRendezvous::iterator I; - HexagonDYLDRendezvous::iterator E; - - ModuleList &loaded_modules = m_process->GetTarget().GetImages(); - - if (m_rendezvous.ModulesDidLoad()) - { - ModuleList new_modules; - - E = m_rendezvous.loaded_end(); - for (I = m_rendezvous.loaded_begin(); I != E; ++I) - { - FileSpec file(I->path.c_str(), true); - ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); - if (module_sp.get()) - { - loaded_modules.AppendIfNeeded( module_sp ); - new_modules.Append(module_sp); - } - - if (log) - { - log->Printf( "Target is loading '%s'", I->path.c_str() ); - if (! module_sp.get() ) - log->Printf( "LLDB failed to load '%s'", I->path.c_str() ); - else - log->Printf( "LLDB successfully loaded '%s'", I->path.c_str() ); - } - - } - m_process->GetTarget().ModulesDidLoad(new_modules); +void DynamicLoaderHexagonDYLD::RefreshModules() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + if (!m_rendezvous.Resolve()) + return; + + HexagonDYLDRendezvous::iterator I; + HexagonDYLDRendezvous::iterator E; + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + if (m_rendezvous.ModulesDidLoad()) { + ModuleList new_modules; + + E = m_rendezvous.loaded_end(); + for (I = m_rendezvous.loaded_begin(); I != E; ++I) { + FileSpec file(I->path, true); + ModuleSP module_sp = + LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); + if (module_sp.get()) { + loaded_modules.AppendIfNeeded(module_sp); + new_modules.Append(module_sp); + } + + if (log) { + log->Printf("Target is loading '%s'", I->path.c_str()); + if (!module_sp.get()) + log->Printf("LLDB failed to load '%s'", I->path.c_str()); + else + log->Printf("LLDB successfully loaded '%s'", I->path.c_str()); + } } - - if (m_rendezvous.ModulesDidUnload()) - { - ModuleList old_modules; - - E = m_rendezvous.unloaded_end(); - for (I = m_rendezvous.unloaded_begin(); I != E; ++I) - { - FileSpec file(I->path.c_str(), true); - ModuleSpec module_spec(file); - ModuleSP module_sp = loaded_modules.FindFirstModule (module_spec); - - if (module_sp.get()) - { - old_modules.Append(module_sp); - UnloadSections(module_sp); - } - - if (log) - log->Printf( "Target is unloading '%s'", I->path.c_str() ); - - } - loaded_modules.Remove(old_modules); - m_process->GetTarget().ModulesDidUnload(old_modules, false); + m_process->GetTarget().ModulesDidLoad(new_modules); + } + + if (m_rendezvous.ModulesDidUnload()) { + ModuleList old_modules; + + E = m_rendezvous.unloaded_end(); + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) { + FileSpec file(I->path, true); + ModuleSpec module_spec(file); + ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec); + + if (module_sp.get()) { + old_modules.Append(module_sp); + UnloadSections(module_sp); + } + + if (log) + log->Printf("Target is unloading '%s'", I->path.c_str()); } + loaded_modules.Remove(old_modules); + m_process->GetTarget().ModulesDidUnload(old_modules, false); + } } -//AD: This is very different to the Static Loader code. +// AD: This is very different to the Static Loader code. // It may be wise to look over this and its relation to stack // unwinding. ThreadPlanSP -DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) -{ - ThreadPlanSP thread_plan_sp; - - StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); - const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); - Symbol *sym = context.symbol; - - if (sym == NULL || !sym->IsTrampoline()) - return thread_plan_sp; - - const ConstString sym_name = sym->GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled); - if (!sym_name) - return thread_plan_sp; - - SymbolContextList target_symbols; - Target &target = thread.GetProcess()->GetTarget(); - const ModuleList &images = target.GetImages(); - - images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); - size_t num_targets = target_symbols.GetSize(); - if (!num_targets) - return thread_plan_sp; - - typedef std::vector<lldb::addr_t> AddressVector; - AddressVector addrs; - for (size_t i = 0; i < num_targets; ++i) - { - SymbolContext context; - AddressRange range; - if (target_symbols.GetContextAtIndex(i, context)) - { - context.GetAddressRange(eSymbolContextEverything, 0, false, range); - lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); - if (addr != LLDB_INVALID_ADDRESS) - addrs.push_back(addr); - } - } +DynamicLoaderHexagonDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + ThreadPlanSP thread_plan_sp; - if (addrs.size() > 0) - { - AddressVector::iterator start = addrs.begin(); - AddressVector::iterator end = addrs.end(); + StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); + const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); + Symbol *sym = context.symbol; - std::sort(start, end); - addrs.erase(std::unique(start, end), end); - thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); - } + if (sym == NULL || !sym->IsTrampoline()) + return thread_plan_sp; + + const ConstString sym_name = sym->GetMangled().GetName( + lldb::eLanguageTypeUnknown, Mangled::ePreferMangled); + if (!sym_name) + return thread_plan_sp; + + SymbolContextList target_symbols; + Target &target = thread.GetProcess()->GetTarget(); + const ModuleList &images = target.GetImages(); + images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); + size_t num_targets = target_symbols.GetSize(); + if (!num_targets) return thread_plan_sp; + + typedef std::vector<lldb::addr_t> AddressVector; + AddressVector addrs; + for (size_t i = 0; i < num_targets; ++i) { + SymbolContext context; + AddressRange range; + if (target_symbols.GetContextAtIndex(i, context)) { + context.GetAddressRange(eSymbolContextEverything, 0, false, range); + lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); + if (addr != LLDB_INVALID_ADDRESS) + addrs.push_back(addr); + } + } + + if (addrs.size() > 0) { + AddressVector::iterator start = addrs.begin(); + AddressVector::iterator end = addrs.end(); + + std::sort(start, end); + addrs.erase(std::unique(start, end), end); + thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); + } + + return thread_plan_sp; } /// Helper for the entry breakpoint callback. Resolves the load addresses /// of all dependent modules. -void -DynamicLoaderHexagonDYLD::LoadAllCurrentModules() -{ - HexagonDYLDRendezvous::iterator I; - HexagonDYLDRendezvous::iterator E; - ModuleList module_list; - - if (!m_rendezvous.Resolve()) - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address", __FUNCTION__); - return; - } +void DynamicLoaderHexagonDYLD::LoadAllCurrentModules() { + HexagonDYLDRendezvous::iterator I; + HexagonDYLDRendezvous::iterator E; + ModuleList module_list; - // The rendezvous class doesn't enumerate the main module, so track - // that ourselves here. - ModuleSP executable = GetTargetExecutable(); - m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); - - - for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) - { - const char *module_path = I->path.c_str(); - FileSpec file(module_path, false); - ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); - if (module_sp.get()) - { - module_list.Append(module_sp); - } - else - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderHexagonDYLD::%s failed loading module %s at 0x%" PRIx64, - __FUNCTION__, module_path, I->base_addr); - } + if (!m_rendezvous.Resolve()) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf( + "DynamicLoaderHexagonDYLD::%s unable to resolve rendezvous address", + __FUNCTION__); + return; + } + + // The rendezvous class doesn't enumerate the main module, so track + // that ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { + const char *module_path = I->path.c_str(); + FileSpec file(module_path, false); + ModuleSP module_sp = + LoadModuleAtAddress(file, I->link_addr, I->base_addr, true); + if (module_sp.get()) { + module_list.Append(module_sp); + } else { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderHexagonDYLD::%s failed loading module %s at " + "0x%" PRIx64, + __FUNCTION__, module_path, I->base_addr); } + } - m_process->GetTarget().ModulesDidLoad(module_list); + m_process->GetTarget().ModulesDidLoad(module_list); } /// Computes a value for m_load_offset returning the computed address on /// success and LLDB_INVALID_ADDRESS on failure. -addr_t -DynamicLoaderHexagonDYLD::ComputeLoadOffset() -{ - // Here we could send a GDB packet to know the load offset - // - // send: $qOffsets#4b - // get: Text=0;Data=0;Bss=0 - // - // Currently qOffsets is not supported by pluginProcessGDBRemote - // - return 0; +addr_t DynamicLoaderHexagonDYLD::ComputeLoadOffset() { + // Here we could send a GDB packet to know the load offset + // + // send: $qOffsets#4b + // get: Text=0;Data=0;Bss=0 + // + // Currently qOffsets is not supported by pluginProcessGDBRemote + // + return 0; } // Here we must try to read the entry point directly from @@ -596,100 +524,97 @@ DynamicLoaderHexagonDYLD::ComputeLoadOffset() // an alternative is to look at the PC if we can be sure // that we have connected when the process is at the entry point. // I dont think that is reliable for us. -addr_t -DynamicLoaderHexagonDYLD::GetEntryPoint() -{ - if (m_entry_point != LLDB_INVALID_ADDRESS) - return m_entry_point; - // check we have a valid process - if ( m_process == nullptr ) - return LLDB_INVALID_ADDRESS; - // Get the current executable module - Module & module = *( m_process->GetTarget( ).GetExecutableModule( ).get( ) ); - // Get the object file (elf file) for this module - lldb_private::ObjectFile &object = *( module.GetObjectFile( ) ); - // Check if the file is executable (ie, not shared object or relocatable) - if ( object.IsExecutable() ) - { - // Get the entry point address for this object - lldb_private::Address entry = object.GetEntryPointAddress( ); - // Return the entry point address - return entry.GetFileAddress( ); - } - // No idea so back out +addr_t DynamicLoaderHexagonDYLD::GetEntryPoint() { + if (m_entry_point != LLDB_INVALID_ADDRESS) + return m_entry_point; + // check we have a valid process + if (m_process == nullptr) return LLDB_INVALID_ADDRESS; + // Get the current executable module + Module &module = *(m_process->GetTarget().GetExecutableModule().get()); + // Get the object file (elf file) for this module + lldb_private::ObjectFile &object = *(module.GetObjectFile()); + // Check if the file is executable (ie, not shared object or relocatable) + if (object.IsExecutable()) { + // Get the entry point address for this object + lldb_private::Address entry = object.GetEntryPointAddress(); + // Return the entry point address + return entry.GetFileAddress(); + } + // No idea so back out + return LLDB_INVALID_ADDRESS; } -const SectionList * -DynamicLoaderHexagonDYLD::GetSectionListFromModule(const ModuleSP module) const -{ - SectionList *sections = nullptr; - if (module.get()) - { - ObjectFile *obj_file = module->GetObjectFile(); - if (obj_file) - { - sections = obj_file->GetSectionList(); - } +const SectionList *DynamicLoaderHexagonDYLD::GetSectionListFromModule( + const ModuleSP module) const { + SectionList *sections = nullptr; + if (module.get()) { + ObjectFile *obj_file = module->GetObjectFile(); + if (obj_file) { + sections = obj_file->GetSectionList(); } - return sections; + } + return sections; } -static int ReadInt(Process *process, addr_t addr) -{ - Error error; - int value = (int)process->ReadUnsignedIntegerFromMemory(addr, sizeof(uint32_t), 0, error); - if (error.Fail()) - return -1; - else - return value; +static int ReadInt(Process *process, addr_t addr) { + Error error; + int value = (int)process->ReadUnsignedIntegerFromMemory( + addr, sizeof(uint32_t), 0, error); + if (error.Fail()) + return -1; + else + return value; } lldb::addr_t -DynamicLoaderHexagonDYLD::GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, - lldb::addr_t tls_file_addr) -{ - auto it = m_loaded_modules.find (module); - if (it == m_loaded_modules.end()) - return LLDB_INVALID_ADDRESS; - - addr_t link_map = it->second; - if (link_map == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - const HexagonDYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); - if (!metadata.valid) - return LLDB_INVALID_ADDRESS; - - // Get the thread pointer. - addr_t tp = thread->GetThreadPointer (); - if (tp == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - // Find the module's modid. - int modid = ReadInt (m_process, link_map + metadata.modid_offset); - if (modid == -1) - return LLDB_INVALID_ADDRESS; - - // Lookup the DTV stucture for this thread. - addr_t dtv_ptr = tp + metadata.dtv_offset; - addr_t dtv = ReadPointer (dtv_ptr); - if (dtv == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - // Find the TLS block for this module. - addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid; - addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset); - - Module *mod = module.get(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderHexagonDYLD::Performed TLS lookup: " - "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%i, tls_block=0x%" PRIx64, - mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block); - - if (tls_block == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - else - return tls_block + tls_file_addr; +DynamicLoaderHexagonDYLD::GetThreadLocalData(const lldb::ModuleSP module, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) { + auto it = m_loaded_modules.find(module); + if (it == m_loaded_modules.end()) + return LLDB_INVALID_ADDRESS; + + addr_t link_map = it->second; + if (link_map == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + const HexagonDYLDRendezvous::ThreadInfo &metadata = + m_rendezvous.GetThreadInfo(); + if (!metadata.valid) + return LLDB_INVALID_ADDRESS; + + // Get the thread pointer. + addr_t tp = thread->GetThreadPointer(); + if (tp == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the module's modid. + int modid = ReadInt(m_process, link_map + metadata.modid_offset); + if (modid == -1) + return LLDB_INVALID_ADDRESS; + + // Lookup the DTV structure for this thread. + addr_t dtv_ptr = tp + metadata.dtv_offset; + addr_t dtv = ReadPointer(dtv_ptr); + if (dtv == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the TLS block for this module. + addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; + addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset); + + Module *mod = module.get(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderHexagonDYLD::Performed TLS lookup: " + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 + ", modid=%i, tls_block=0x%" PRIx64, + mod->GetObjectName().AsCString(""), link_map, tp, modid, + tls_block); + + if (tls_block == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + else + return tls_block + tls_file_addr; } diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h index 67c32887d091..05709d07fd67 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -1,4 +1,4 @@ -//===-- DynamicLoaderHexagon.h ----------------------------------*- C++ -*-===// +//===-- DynamicLoaderHexagonDYLD.h ------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,150 +19,129 @@ #include "HexagonDYLDRendezvous.h" -class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader -{ +class DynamicLoaderHexagonDYLD : public lldb_private::DynamicLoader { public: - DynamicLoaderHexagonDYLD(lldb_private::Process *process); + DynamicLoaderHexagonDYLD(lldb_private::Process *process); - ~DynamicLoaderHexagonDYLD() override; + ~DynamicLoaderHexagonDYLD() override; - static void - Initialize(); + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - static lldb_private::DynamicLoader * - CreateInstance(lldb_private::Process *process, bool force); + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); - //------------------------------------------------------------------ - // DynamicLoader protocol - //------------------------------------------------------------------ + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ - void - DidAttach() override; + void DidAttach() override; - void - DidLaunch() override; + void DidLaunch() override; - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan(lldb_private::Thread &thread, - bool stop_others) override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; - lldb_private::Error - CanLoadImage() override; + lldb_private::Error CanLoadImage() override; - lldb::addr_t - GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) override; + lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; protected: - /// Runtime linker rendezvous structure. - HexagonDYLDRendezvous m_rendezvous; - - /// Virtual load address of the inferior process. - lldb::addr_t m_load_offset; - - /// Virtual entry address of the inferior process. - lldb::addr_t m_entry_point; - - /// Rendezvous breakpoint. - lldb::break_id_t m_dyld_bid; - - /// Loaded module list. (link map for each module) - std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules; - - /// Enables a breakpoint on a function called by the runtime - /// linker each time a module is loaded or unloaded. - bool - SetRendezvousBreakpoint(); - - /// Callback routine which updates the current list of loaded modules based - /// on the information supplied by the runtime linker. - static bool - RendezvousBreakpointHit(void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set - /// of loaded modules. - void - RefreshModules(); - - /// Updates the load address of every allocatable section in @p module. - /// - /// @param module The module to traverse. - /// - /// @param link_map_addr The virtual address of the link map for the @p module. - /// - /// @param base_addr The virtual base address @p module is loaded at. - void - UpdateLoadedSections(lldb::ModuleSP module, - lldb::addr_t link_map_addr, - lldb::addr_t base_addr, - bool base_addr_is_offset) override; - - /// Removes the loaded sections from the target in @p module. - /// - /// @param module The module to traverse. - void - UnloadSections(const lldb::ModuleSP module) override; - - /// Callback routine invoked when we hit the breakpoint on process entry. - /// - /// This routine is responsible for resolving the load addresses of all - /// dependent modules required by the inferior and setting up the rendezvous - /// breakpoint. - static bool - EntryBreakpointHit(void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - /// Helper for the entry breakpoint callback. Resolves the load addresses - /// of all dependent modules. - void - LoadAllCurrentModules(); - - /// Computes a value for m_load_offset returning the computed address on - /// success and LLDB_INVALID_ADDRESS on failure. - lldb::addr_t - ComputeLoadOffset(); - - /// Computes a value for m_entry_point returning the computed address on - /// success and LLDB_INVALID_ADDRESS on failure. - lldb::addr_t - GetEntryPoint(); - - /// Checks to see if the target module has changed, updates the target - /// accordingly and returns the target executable module. - lldb::ModuleSP - GetTargetExecutable(); - - /// return the address of the Rendezvous breakpoint - lldb::addr_t - FindRendezvousBreakpointAddress( ); + /// Runtime linker rendezvous structure. + HexagonDYLDRendezvous m_rendezvous; + + /// Virtual load address of the inferior process. + lldb::addr_t m_load_offset; + + /// Virtual entry address of the inferior process. + lldb::addr_t m_entry_point; + + /// Rendezvous breakpoint. + lldb::break_id_t m_dyld_bid; + + /// Loaded module list. (link map for each module) + std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> + m_loaded_modules; + + /// Enables a breakpoint on a function called by the runtime + /// linker each time a module is loaded or unloaded. + bool SetRendezvousBreakpoint(); + + /// Callback routine which updates the current list of loaded modules based + /// on the information supplied by the runtime linker. + static bool RendezvousBreakpointHit( + void *baton, lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set + /// of loaded modules. + void RefreshModules(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param link_map_addr The virtual address of the link map for the @p + /// module. + /// + /// @param base_addr The virtual base address @p module is loaded at. + void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset) override; + + /// Removes the loaded sections from the target in @p module. + /// + /// @param module The module to traverse. + void UnloadSections(const lldb::ModuleSP module) override; + + /// Callback routine invoked when we hit the breakpoint on process entry. + /// + /// This routine is responsible for resolving the load addresses of all + /// dependent modules required by the inferior and setting up the rendezvous + /// breakpoint. + static bool + EntryBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + /// Helper for the entry breakpoint callback. Resolves the load addresses + /// of all dependent modules. + void LoadAllCurrentModules(); + + /// Computes a value for m_load_offset returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t ComputeLoadOffset(); + + /// Computes a value for m_entry_point returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t GetEntryPoint(); + + /// Checks to see if the target module has changed, updates the target + /// accordingly and returns the target executable module. + lldb::ModuleSP GetTargetExecutable(); + + /// return the address of the Rendezvous breakpoint + lldb::addr_t FindRendezvousBreakpointAddress(); private: - const lldb_private::SectionList * - GetSectionListFromModule(const lldb::ModuleSP module) const; + const lldb_private::SectionList * + GetSectionListFromModule(const lldb::ModuleSP module) const; - DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderHexagonDYLD); }; #endif // liblldb_DynamicLoaderHexagonDYLD_h_ diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index 61f9b3d441ce..da0edc870f86 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -30,375 +30,343 @@ using namespace lldb_private; /// Locates the address of the rendezvous structure. Returns the address on /// success and LLDB_INVALID_ADDRESS on failure. -static addr_t -ResolveRendezvousAddress(Process *process) -{ - addr_t info_location; - addr_t info_addr; - Error error; +static addr_t ResolveRendezvousAddress(Process *process) { + addr_t info_location; + addr_t info_addr; + Error error; - info_location = process->GetImageInfoAddress(); + info_location = process->GetImageInfoAddress(); - if (info_location == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; + if (info_location == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; - info_addr = process->ReadPointerFromMemory(info_location, error); - if (error.Fail()) - return LLDB_INVALID_ADDRESS; + info_addr = process->ReadPointerFromMemory(info_location, error); + if (error.Fail()) + return LLDB_INVALID_ADDRESS; - if (info_addr == 0) - return LLDB_INVALID_ADDRESS; + if (info_addr == 0) + return LLDB_INVALID_ADDRESS; - return info_addr; + return info_addr; } HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process) - : m_process(process), - m_rendezvous_addr(LLDB_INVALID_ADDRESS), - m_current(), - m_previous(), - m_soentries(), - m_added_soentries(), - m_removed_soentries() -{ - m_thread_info.valid = false; - - // Cache a copy of the executable path - if (m_process) - { - Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); - if (exe_mod) - exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX); - } + : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), + m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() { + m_thread_info.valid = false; + + // Cache a copy of the executable path + if (m_process) { + Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); + if (exe_mod) + exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX); + } } -bool -HexagonDYLDRendezvous::Resolve() -{ - const size_t word_size = 4; - Rendezvous info; - size_t address_size; - size_t padding; - addr_t info_addr; - addr_t cursor; +bool HexagonDYLDRendezvous::Resolve() { + const size_t word_size = 4; + Rendezvous info; + size_t address_size; + size_t padding; + addr_t info_addr; + addr_t cursor; - address_size = m_process->GetAddressByteSize(); - padding = address_size - word_size; + address_size = m_process->GetAddressByteSize(); + padding = address_size - word_size; - if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) - cursor = info_addr = ResolveRendezvousAddress(m_process); - else - cursor = info_addr = m_rendezvous_addr; - - if (cursor == LLDB_INVALID_ADDRESS) - return false; + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) + cursor = info_addr = ResolveRendezvousAddress(m_process); + else + cursor = info_addr = m_rendezvous_addr; - if (!(cursor = ReadWord(cursor, &info.version, word_size))) - return false; + if (cursor == LLDB_INVALID_ADDRESS) + return false; - if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) - return false; + if (!(cursor = ReadWord(cursor, &info.version, word_size))) + return false; + + if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) + return false; - if (!(cursor = ReadPointer(cursor, &info.brk))) - return false; + if (!(cursor = ReadPointer(cursor, &info.brk))) + return false; - if (!(cursor = ReadWord(cursor, &info.state, word_size))) - return false; + if (!(cursor = ReadWord(cursor, &info.state, word_size))) + return false; - if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) - return false; + if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) + return false; - // The rendezvous was successfully read. Update our internal state. - m_rendezvous_addr = info_addr; - m_previous = m_current; - m_current = info; + // The rendezvous was successfully read. Update our internal state. + m_rendezvous_addr = info_addr; + m_previous = m_current; + m_current = info; - return UpdateSOEntries(); + return UpdateSOEntries(); } -void -HexagonDYLDRendezvous::SetRendezvousAddress( lldb::addr_t addr ) -{ - m_rendezvous_addr = addr; +void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) { + m_rendezvous_addr = addr; } -bool -HexagonDYLDRendezvous::IsValid() -{ - return m_rendezvous_addr != LLDB_INVALID_ADDRESS; +bool HexagonDYLDRendezvous::IsValid() { + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; } -bool -HexagonDYLDRendezvous::UpdateSOEntries() -{ - SOEntry entry; - - if (m_current.map_addr == 0) - return false; - - // When the previous and current states are consistent this is the first - // time we have been asked to update. Just take a snapshot of the currently - // loaded modules. - if (m_previous.state == eConsistent && m_current.state == eConsistent) - return TakeSnapshot(m_soentries); - - // If we are about to add or remove a shared object clear out the current - // state and take a snapshot of the currently loaded images. - if (m_current.state == eAdd || m_current.state == eDelete) - { - // this is a fudge so that we can clear the assert below. - m_previous.state = eConsistent; - // We hit this assert on the 2nd run of this function after running the calc example - assert(m_previous.state == eConsistent); - m_soentries.clear(); - m_added_soentries.clear(); - m_removed_soentries.clear(); - return TakeSnapshot(m_soentries); - } - assert(m_current.state == eConsistent); - - // Otherwise check the previous state to determine what to expect and update - // accordingly. - if (m_previous.state == eAdd) - return UpdateSOEntriesForAddition(); - else if (m_previous.state == eDelete) - return UpdateSOEntriesForDeletion(); +bool HexagonDYLDRendezvous::UpdateSOEntries() { + SOEntry entry; + if (m_current.map_addr == 0) return false; + + // When the previous and current states are consistent this is the first + // time we have been asked to update. Just take a snapshot of the currently + // loaded modules. + if (m_previous.state == eConsistent && m_current.state == eConsistent) + return TakeSnapshot(m_soentries); + + // If we are about to add or remove a shared object clear out the current + // state and take a snapshot of the currently loaded images. + if (m_current.state == eAdd || m_current.state == eDelete) { + // this is a fudge so that we can clear the assert below. + m_previous.state = eConsistent; + // We hit this assert on the 2nd run of this function after running the calc + // example + assert(m_previous.state == eConsistent); + m_soentries.clear(); + m_added_soentries.clear(); + m_removed_soentries.clear(); + return TakeSnapshot(m_soentries); + } + assert(m_current.state == eConsistent); + + // Otherwise check the previous state to determine what to expect and update + // accordingly. + if (m_previous.state == eAdd) + return UpdateSOEntriesForAddition(); + else if (m_previous.state == eDelete) + return UpdateSOEntriesForDeletion(); + + return false; } - -bool -HexagonDYLDRendezvous::UpdateSOEntriesForAddition() -{ - SOEntry entry; - iterator pos; - - assert(m_previous.state == eAdd); - - if (m_current.map_addr == 0) - return false; - - for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) - { - if (!ReadSOEntryFromMemory(cursor, entry)) - return false; - - // Only add shared libraries and not the executable. - // On Linux this is indicated by an empty path in the entry. - // On FreeBSD it is the name of the executable. - if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) - continue; - - pos = std::find(m_soentries.begin(), m_soentries.end(), entry); - if (pos == m_soentries.end()) - { - m_soentries.push_back(entry); - m_added_soentries.push_back(entry); - } + +bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() { + SOEntry entry; + iterator pos; + + assert(m_previous.state == eAdd); + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + // Only add shared libraries and not the executable. + // On Linux this is indicated by an empty path in the entry. + // On FreeBSD it is the name of the executable. + if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) + continue; + + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) { + m_soentries.push_back(entry); + m_added_soentries.push_back(entry); } + } - return true; + return true; } -bool -HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() -{ - SOEntryList entry_list; - iterator pos; +bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() { + SOEntryList entry_list; + iterator pos; - assert(m_previous.state == eDelete); + assert(m_previous.state == eDelete); - if (!TakeSnapshot(entry_list)) - return false; + if (!TakeSnapshot(entry_list)) + return false; - for (iterator I = begin(); I != end(); ++I) - { - pos = std::find(entry_list.begin(), entry_list.end(), *I); - if (pos == entry_list.end()) - m_removed_soentries.push_back(*I); - } + for (iterator I = begin(); I != end(); ++I) { + pos = std::find(entry_list.begin(), entry_list.end(), *I); + if (pos == entry_list.end()) + m_removed_soentries.push_back(*I); + } - m_soentries = entry_list; - return true; + m_soentries = entry_list; + return true; } -bool -HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) -{ - SOEntry entry; +bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) { + SOEntry entry; - if (m_current.map_addr == 0) - return false; + if (m_current.map_addr == 0) + return false; - for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) - { - if (!ReadSOEntryFromMemory(cursor, entry)) - return false; + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; - // Only add shared libraries and not the executable. - // On Linux this is indicated by an empty path in the entry. - // On FreeBSD it is the name of the executable. - if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) - continue; + // Only add shared libraries and not the executable. + // On Linux this is indicated by an empty path in the entry. + // On FreeBSD it is the name of the executable. + if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) + continue; - entry_list.push_back(entry); - } + entry_list.push_back(entry); + } - return true; + return true; } -addr_t -HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) -{ - Error error; +addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, + size_t size) { + Error error; - *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); - if (error.Fail()) - return 0; + *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); + if (error.Fail()) + return 0; - return addr + size; + return addr + size; } -addr_t -HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) -{ - Error error; - - *dst = m_process->ReadPointerFromMemory(addr, error); - if (error.Fail()) - return 0; +addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) { + Error error; + + *dst = m_process->ReadPointerFromMemory(addr, error); + if (error.Fail()) + return 0; - return addr + m_process->GetAddressByteSize(); + return addr + m_process->GetAddressByteSize(); } -std::string -HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) -{ - std::string str; - Error error; - size_t size; - char c; - - if (addr == LLDB_INVALID_ADDRESS) - return std::string(); - - for (;;) { - size = m_process->DoReadMemory(addr, &c, 1, error); - if (size != 1 || error.Fail()) - return std::string(); - if (c == 0) - break; - else { - str.push_back(c); - addr++; - } +std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) { + std::string str; + Error error; + size_t size; + char c; + + if (addr == LLDB_INVALID_ADDRESS) + return std::string(); + + for (;;) { + size = m_process->DoReadMemory(addr, &c, 1, error); + if (size != 1 || error.Fail()) + return std::string(); + if (c == 0) + break; + else { + str.push_back(c); + addr++; } + } - return str; + return str; } -bool -HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) -{ - entry.clear(); - entry.link_addr = addr; - - if (!(addr = ReadPointer(addr, &entry.base_addr))) - return false; - - if (!(addr = ReadPointer(addr, &entry.path_addr))) - return false; - - if (!(addr = ReadPointer(addr, &entry.dyn_addr))) - return false; - - if (!(addr = ReadPointer(addr, &entry.next))) - return false; - - if (!(addr = ReadPointer(addr, &entry.prev))) - return false; - - entry.path = ReadStringFromMemory(entry.path_addr); - - return true; -} +bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, + SOEntry &entry) { + entry.clear(); + entry.link_addr = addr; + + if (!(addr = ReadPointer(addr, &entry.base_addr))) + return false; -bool -HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value) -{ - Target& target = m_process->GetTarget(); + if (!(addr = ReadPointer(addr, &entry.path_addr))) + return false; - SymbolContextList list; - if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list)) - return false; + if (!(addr = ReadPointer(addr, &entry.dyn_addr))) + return false; - Address address = list[0].symbol->GetAddress(); - addr_t addr = address.GetLoadAddress (&target); - if (addr == LLDB_INVALID_ADDRESS) - return false; + if (!(addr = ReadPointer(addr, &entry.next))) + return false; - Error error; - value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error); - if (error.Fail()) - return false; + if (!(addr = ReadPointer(addr, &entry.prev))) + return false; - if (field == eSize) - value /= 8; // convert bits to bytes + entry.path = ReadStringFromMemory(entry.path_addr); - return true; + return true; } -const HexagonDYLDRendezvous::ThreadInfo& -HexagonDYLDRendezvous::GetThreadInfo() -{ - if (!m_thread_info.valid) - { - bool ok = true; +bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, + uint32_t &value) { + Target &target = m_process->GetTarget(); - ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset); - ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); - ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset); - ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset); + SymbolContextList list; + if (!target.GetImages().FindSymbolsWithNameAndType(ConstString(name), + eSymbolTypeAny, list)) + return false; - if (ok) - m_thread_info.valid = true; - } + Address address = list[0].symbol->GetAddress(); + addr_t addr = address.GetLoadAddress(&target); + if (addr == LLDB_INVALID_ADDRESS) + return false; + + Error error; + value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory( + addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error); + if (error.Fail()) + return false; - return m_thread_info; + if (field == eSize) + value /= 8; // convert bits to bytes + + return true; } -void -HexagonDYLDRendezvous::DumpToLog(Log *log) const -{ - int state = GetState(); - - if (!log) - return; - - log->PutCString("HexagonDYLDRendezvous:"); - log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); - log->Printf(" Version: %" PRIu64, GetVersion()); - log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); - log->Printf(" Break : %" PRIx64, GetBreakAddress()); - log->Printf(" LDBase : %" PRIx64, GetLDBase()); - log->Printf(" State : %s", - (state == eConsistent) ? "consistent" : - (state == eAdd) ? "add" : - (state == eDelete) ? "delete" : "unknown"); - - iterator I = begin(); - iterator E = end(); - - if (I != E) - log->PutCString("HexagonDYLDRendezvous SOEntries:"); - - for (int i = 1; I != E; ++I, ++i) - { - log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); - log->Printf(" Base : %" PRIx64, I->base_addr); - log->Printf(" Path : %" PRIx64, I->path_addr); - log->Printf(" Dyn : %" PRIx64, I->dyn_addr); - log->Printf(" Next : %" PRIx64, I->next); - log->Printf(" Prev : %" PRIx64, I->prev); - } +const HexagonDYLDRendezvous::ThreadInfo & +HexagonDYLDRendezvous::GetThreadInfo() { + if (!m_thread_info.valid) { + bool ok = true; + + ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset, + m_thread_info.dtv_offset); + ok &= + FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); + ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset, + m_thread_info.modid_offset); + ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset, + m_thread_info.tls_offset); + + if (ok) + m_thread_info.valid = true; + } + + return m_thread_info; +} + +void HexagonDYLDRendezvous::DumpToLog(Log *log) const { + int state = GetState(); + + if (!log) + return; + + log->PutCString("HexagonDYLDRendezvous:"); + log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); + log->Printf(" Version: %" PRIu64, GetVersion()); + log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); + log->Printf(" Break : %" PRIx64, GetBreakAddress()); + log->Printf(" LDBase : %" PRIx64, GetLDBase()); + log->Printf(" State : %s", + (state == eConsistent) + ? "consistent" + : (state == eAdd) ? "add" : (state == eDelete) ? "delete" + : "unknown"); + + iterator I = begin(); + iterator E = end(); + + if (I != E) + log->PutCString("HexagonDYLDRendezvous SOEntries:"); + + for (int i = 1; I != E; ++I, ++i) { + log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); + log->Printf(" Base : %" PRIx64, I->base_addr); + log->Printf(" Path : %" PRIx64, I->path_addr); + log->Printf(" Dyn : %" PRIx64, I->dyn_addr); + log->Printf(" Next : %" PRIx64, I->next); + log->Printf(" Prev : %" PRIx64, I->prev); + } } diff --git a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h index cd5121330457..b68f89b9ce83 100644 --- a/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -19,9 +19,8 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" -namespace lldb_private -{ - class Process; +namespace lldb_private { +class Process; } /// @class HexagonDYLDRendezvous @@ -31,249 +30,218 @@ namespace lldb_private /// runtime liker each time a module is loaded or unloaded. This class provides /// an interface to this structure and maintains a consistent snapshot of the /// currently loaded modules. -class HexagonDYLDRendezvous -{ - - // This structure is used to hold the contents of the debug rendezvous - // information (struct r_debug) as found in the inferiors memory. Note that - // the layout of this struct is not binary compatible, it is simply large - // enough to hold the information on both 32 and 64 bit platforms. - struct Rendezvous { - uint64_t version; - lldb::addr_t map_addr; - lldb::addr_t brk; - uint64_t state; - lldb::addr_t ldbase; - - Rendezvous() - : version (0) - , map_addr(LLDB_INVALID_ADDRESS) - , brk (LLDB_INVALID_ADDRESS) - , state (0) - , ldbase (0) - { } - - }; +class HexagonDYLDRendezvous { + + // This structure is used to hold the contents of the debug rendezvous + // information (struct r_debug) as found in the inferiors memory. Note that + // the layout of this struct is not binary compatible, it is simply large + // enough to hold the information on both 32 and 64 bit platforms. + struct Rendezvous { + uint64_t version; + lldb::addr_t map_addr; + lldb::addr_t brk; + uint64_t state; + lldb::addr_t ldbase; + + Rendezvous() + : version(0), map_addr(LLDB_INVALID_ADDRESS), brk(LLDB_INVALID_ADDRESS), + state(0), ldbase(0) {} + }; public: - // Various metadata supplied by the inferior's threading library to describe - // the per-thread state. - struct ThreadInfo { - bool valid; // whether we read valid metadata - uint32_t dtv_offset; // offset of DTV pointer within pthread - uint32_t dtv_slot_size; // size of one DTV slot - uint32_t modid_offset; // offset of module ID within link_map - uint32_t tls_offset; // offset of TLS pointer within DTV slot - }; - - HexagonDYLDRendezvous(lldb_private::Process *process); - - /// Update the internal snapshot of runtime linker rendezvous and recompute - /// the currently loaded modules. - /// - /// This method should be called once one start up, then once each time the - /// runtime linker enters the function given by GetBreakAddress(). - /// - /// @returns true on success and false on failure. - /// - /// @see GetBreakAddress(). - bool - Resolve(); - - /// @returns true if this rendezvous has been located in the inferiors - /// address space and false otherwise. - bool - IsValid(); - - /// @returns the address of the rendezvous structure in the inferiors - /// address space. - lldb::addr_t - GetRendezvousAddress() const { return m_rendezvous_addr; } - - /// Provide the dyld structure address - void - SetRendezvousAddress( lldb::addr_t ); - - /// @returns the version of the rendezvous protocol being used. - uint64_t - GetVersion() const { return m_current.version; } - - /// @returns address in the inferiors address space containing the linked - /// list of shared object descriptors. - lldb::addr_t - GetLinkMapAddress() const { return m_current.map_addr; } - - /// A breakpoint should be set at this address and Resolve called on each - /// hit. - /// - /// @returns the address of a function called by the runtime linker each - /// time a module is loaded/unloaded, or about to be loaded/unloaded. - /// - /// @see Resolve() - lldb::addr_t - GetBreakAddress() const { return m_current.brk; } - - /// In hexagon it is possible that we can know the dyld breakpoint without - /// having to find it from the rendezvous structure - /// - void - SetBreakAddress( lldb::addr_t addr ) { m_current.brk = addr; } - - /// Returns the current state of the rendezvous structure. - uint64_t - GetState() const { return m_current.state; } - - /// @returns the base address of the runtime linker in the inferiors address - /// space. - lldb::addr_t - GetLDBase() const { return m_current.ldbase; } - - /// @returns the thread layout metadata from the inferiors thread library. - const ThreadInfo& - GetThreadInfo(); - - /// @returns true if modules have been loaded into the inferior since the - /// last call to Resolve(). - bool - ModulesDidLoad() const { return !m_added_soentries.empty(); } - - /// @returns true if modules have been unloaded from the inferior since the - /// last call to Resolve(). - bool - ModulesDidUnload() const { return !m_removed_soentries.empty(); } - - void - DumpToLog(lldb_private::Log *log) const; - - /// @brief Constants describing the state of the rendezvous. - /// - /// @see GetState(). - enum RendezvousState - { - eConsistent = 0, - eAdd , - eDelete , - }; - - /// @brief Structure representing the shared objects currently loaded into - /// the inferior process. - /// - /// This object is a rough analogue to the struct link_map object which - /// actually lives in the inferiors memory. - struct SOEntry { - lldb::addr_t link_addr; ///< Address of this link_map. - lldb::addr_t base_addr; ///< Base address of the loaded object. - lldb::addr_t path_addr; ///< String naming the shared object. - lldb::addr_t dyn_addr; ///< Dynamic section of shared object. - lldb::addr_t next; ///< Address of next so_entry. - lldb::addr_t prev; ///< Address of previous so_entry. - std::string path; ///< File name of shared object. - - SOEntry() { clear(); } - - bool operator ==(const SOEntry &entry) { - return this->path == entry.path; - } - - void clear() { - link_addr = 0; - base_addr = 0; - path_addr = 0; - dyn_addr = 0; - next = 0; - prev = 0; - path.clear(); - } - }; + // Various metadata supplied by the inferior's threading library to describe + // the per-thread state. + struct ThreadInfo { + bool valid; // whether we read valid metadata + uint32_t dtv_offset; // offset of DTV pointer within pthread + uint32_t dtv_slot_size; // size of one DTV slot + uint32_t modid_offset; // offset of module ID within link_map + uint32_t tls_offset; // offset of TLS pointer within DTV slot + }; + + HexagonDYLDRendezvous(lldb_private::Process *process); + + /// Update the internal snapshot of runtime linker rendezvous and recompute + /// the currently loaded modules. + /// + /// This method should be called once one start up, then once each time the + /// runtime linker enters the function given by GetBreakAddress(). + /// + /// @returns true on success and false on failure. + /// + /// @see GetBreakAddress(). + bool Resolve(); + + /// @returns true if this rendezvous has been located in the inferiors + /// address space and false otherwise. + bool IsValid(); + + /// @returns the address of the rendezvous structure in the inferiors + /// address space. + lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; } + + /// Provide the dyld structure address + void SetRendezvousAddress(lldb::addr_t); + + /// @returns the version of the rendezvous protocol being used. + uint64_t GetVersion() const { return m_current.version; } + + /// @returns address in the inferiors address space containing the linked + /// list of shared object descriptors. + lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; } + + /// A breakpoint should be set at this address and Resolve called on each + /// hit. + /// + /// @returns the address of a function called by the runtime linker each + /// time a module is loaded/unloaded, or about to be loaded/unloaded. + /// + /// @see Resolve() + lldb::addr_t GetBreakAddress() const { return m_current.brk; } + + /// In hexagon it is possible that we can know the dyld breakpoint without + /// having to find it from the rendezvous structure + /// + void SetBreakAddress(lldb::addr_t addr) { m_current.brk = addr; } + + /// Returns the current state of the rendezvous structure. + uint64_t GetState() const { return m_current.state; } + + /// @returns the base address of the runtime linker in the inferiors address + /// space. + lldb::addr_t GetLDBase() const { return m_current.ldbase; } + + /// @returns the thread layout metadata from the inferiors thread library. + const ThreadInfo &GetThreadInfo(); + + /// @returns true if modules have been loaded into the inferior since the + /// last call to Resolve(). + bool ModulesDidLoad() const { return !m_added_soentries.empty(); } + + /// @returns true if modules have been unloaded from the inferior since the + /// last call to Resolve(). + bool ModulesDidUnload() const { return !m_removed_soentries.empty(); } + + void DumpToLog(lldb_private::Log *log) const; + + /// @brief Constants describing the state of the rendezvous. + /// + /// @see GetState(). + enum RendezvousState { + eConsistent = 0, + eAdd, + eDelete, + }; + + /// @brief Structure representing the shared objects currently loaded into + /// the inferior process. + /// + /// This object is a rough analogue to the struct link_map object which + /// actually lives in the inferiors memory. + struct SOEntry { + lldb::addr_t link_addr; ///< Address of this link_map. + lldb::addr_t base_addr; ///< Base address of the loaded object. + lldb::addr_t path_addr; ///< String naming the shared object. + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. + lldb::addr_t next; ///< Address of next so_entry. + lldb::addr_t prev; ///< Address of previous so_entry. + std::string path; ///< File name of shared object. + + SOEntry() { clear(); } + + bool operator==(const SOEntry &entry) { return this->path == entry.path; } + + void clear() { + link_addr = 0; + base_addr = 0; + path_addr = 0; + dyn_addr = 0; + next = 0; + prev = 0; + path.clear(); + } + }; protected: - typedef std::list<SOEntry> SOEntryList; + typedef std::list<SOEntry> SOEntryList; public: - typedef SOEntryList::const_iterator iterator; - - /// Iterators over all currently loaded modules. - iterator begin() const { return m_soentries.begin(); } - iterator end() const { return m_soentries.end(); } - - /// Iterators over all modules loaded into the inferior since the last call - /// to Resolve(). - iterator loaded_begin() const { return m_added_soentries.begin(); } - iterator loaded_end() const { return m_added_soentries.end(); } - - /// Iterators over all modules unloaded from the inferior since the last - /// call to Resolve(). - iterator unloaded_begin() const { return m_removed_soentries.begin(); } - iterator unloaded_end() const { return m_removed_soentries.end(); } - + typedef SOEntryList::const_iterator iterator; + + /// Iterators over all currently loaded modules. + iterator begin() const { return m_soentries.begin(); } + iterator end() const { return m_soentries.end(); } + + /// Iterators over all modules loaded into the inferior since the last call + /// to Resolve(). + iterator loaded_begin() const { return m_added_soentries.begin(); } + iterator loaded_end() const { return m_added_soentries.end(); } + + /// Iterators over all modules unloaded from the inferior since the last + /// call to Resolve(). + iterator unloaded_begin() const { return m_removed_soentries.begin(); } + iterator unloaded_end() const { return m_removed_soentries.end(); } + protected: - lldb_private::Process *m_process; + lldb_private::Process *m_process; - // Cached copy of executable pathname - char m_exe_path[PATH_MAX]; + // Cached copy of executable pathname + char m_exe_path[PATH_MAX]; - /// Location of the r_debug structure in the inferiors address space. - lldb::addr_t m_rendezvous_addr; + /// Location of the r_debug structure in the inferiors address space. + lldb::addr_t m_rendezvous_addr; - /// Current and previous snapshots of the rendezvous structure. - Rendezvous m_current; - Rendezvous m_previous; + /// Current and previous snapshots of the rendezvous structure. + Rendezvous m_current; + Rendezvous m_previous; - /// List of SOEntry objects corresponding to the current link map state. - SOEntryList m_soentries; + /// List of SOEntry objects corresponding to the current link map state. + SOEntryList m_soentries; - /// List of SOEntry's added to the link map since the last call to Resolve(). - SOEntryList m_added_soentries; + /// List of SOEntry's added to the link map since the last call to Resolve(). + SOEntryList m_added_soentries; - /// List of SOEntry's removed from the link map since the last call to - /// Resolve(). - SOEntryList m_removed_soentries; + /// List of SOEntry's removed from the link map since the last call to + /// Resolve(). + SOEntryList m_removed_soentries; - /// Threading metadata read from the inferior. - ThreadInfo m_thread_info; + /// Threading metadata read from the inferior. + ThreadInfo m_thread_info; - /// Reads an unsigned integer of @p size bytes from the inferior's address - /// space starting at @p addr. - /// - /// @returns addr + size if the read was successful and false otherwise. - lldb::addr_t - ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); + /// Reads an unsigned integer of @p size bytes from the inferior's address + /// space starting at @p addr. + /// + /// @returns addr + size if the read was successful and false otherwise. + lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); - /// Reads an address from the inferior's address space starting at @p addr. - /// - /// @returns addr + target address size if the read was successful and - /// 0 otherwise. - lldb::addr_t - ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); + /// Reads an address from the inferior's address space starting at @p addr. + /// + /// @returns addr + target address size if the read was successful and + /// 0 otherwise. + lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); - /// Reads a null-terminated C string from the memory location starting at @p - /// addr. - std::string - ReadStringFromMemory(lldb::addr_t addr); + /// Reads a null-terminated C string from the memory location starting at @p + /// addr. + std::string ReadStringFromMemory(lldb::addr_t addr); - /// Reads an SOEntry starting at @p addr. - bool - ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); + /// Reads an SOEntry starting at @p addr. + bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); - /// Updates the current set of SOEntries, the set of added entries, and the - /// set of removed entries. - bool - UpdateSOEntries(); + /// Updates the current set of SOEntries, the set of added entries, and the + /// set of removed entries. + bool UpdateSOEntries(); - bool - UpdateSOEntriesForAddition(); + bool UpdateSOEntriesForAddition(); - bool - UpdateSOEntriesForDeletion(); + bool UpdateSOEntriesForDeletion(); - /// Reads the current list of shared objects according to the link map - /// supplied by the runtime linker. - bool - TakeSnapshot(SOEntryList &entry_list); + /// Reads the current list of shared objects according to the link map + /// supplied by the runtime linker. + bool TakeSnapshot(SOEntryList &entry_list); - enum PThreadField { eSize, eNElem, eOffset }; + enum PThreadField { eSize, eNElem, eOffset }; - bool FindMetadata(const char *name, PThreadField field, uint32_t& value); + bool FindMetadata(const char *name, PThreadField field, uint32_t &value); }; #endif // liblldb_HexagonDYLDRendezvous_H_ diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt b/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt index 4d916b15f761..7dc3e98e6a57 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD DynamicLoaderMacOSXDYLD.cpp + DynamicLoaderMacOS.cpp DynamicLoaderDarwin.cpp ) diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index efca1bea4ad6..bd0e772f7783 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -7,6 +7,8 @@ // //===----------------------------------------------------------------------===// +#include "DynamicLoaderDarwin.h" + #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/DataBufferHeap.h" @@ -18,6 +20,7 @@ #include "lldb/Core/Section.h" #include "lldb/Core/State.h" #include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -30,12 +33,10 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanRunToAddress.h" -#include "DynamicLoaderDarwin.h" - //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF #include <stdio.h> -#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) #endif @@ -49,29 +50,18 @@ using namespace lldb; using namespace lldb_private; - //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -DynamicLoaderDarwin::DynamicLoaderDarwin (Process* process) - : DynamicLoader(process), - m_dyld_module_wp(), - m_libpthread_module_wp(), - m_pthread_getspecific_addr(), - m_tid_to_tls_map(), - m_dyld_image_infos(), - m_dyld_image_infos_stop_id(UINT32_MAX), - m_dyld(), - m_mutex() -{ -} +DynamicLoaderDarwin::DynamicLoaderDarwin(Process *process) + : DynamicLoader(process), m_dyld_module_wp(), m_libpthread_module_wp(), + m_pthread_getspecific_addr(), m_tid_to_tls_map(), m_dyld_image_infos(), + m_dyld_image_infos_stop_id(UINT32_MAX), m_dyld(), m_mutex() {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -DynamicLoaderDarwin::~DynamicLoaderDarwin() -{ -} +DynamicLoaderDarwin::~DynamicLoaderDarwin() {} //------------------------------------------------------------------ /// Called after attaching a process. @@ -79,12 +69,10 @@ DynamicLoaderDarwin::~DynamicLoaderDarwin() /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderDarwin::DidAttach () -{ - PrivateInitialize(m_process); - DoInitialImageFetch (); - SetNotificationBreakpoint (); +void DynamicLoaderDarwin::DidAttach() { + PrivateInitialize(m_process); + DoInitialImageFetch(); + SetNotificationBreakpoint(); } //------------------------------------------------------------------ @@ -93,570 +81,617 @@ DynamicLoaderDarwin::DidAttach () /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderDarwin::DidLaunch () -{ - PrivateInitialize(m_process); - DoInitialImageFetch (); - SetNotificationBreakpoint (); +void DynamicLoaderDarwin::DidLaunch() { + PrivateInitialize(m_process); + DoInitialImageFetch(); + SetNotificationBreakpoint(); } - //---------------------------------------------------------------------- // Clear out the state of this class. //---------------------------------------------------------------------- -void -DynamicLoaderDarwin::Clear (bool clear_process) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (clear_process) - m_process = NULL; - m_dyld_image_infos.clear(); - m_dyld_image_infos_stop_id = UINT32_MAX; - m_dyld.Clear(false); +void DynamicLoaderDarwin::Clear(bool clear_process) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (clear_process) + m_process = NULL; + m_dyld_image_infos.clear(); + m_dyld_image_infos_stop_id = UINT32_MAX; + m_dyld.Clear(false); } -ModuleSP -DynamicLoaderDarwin::FindTargetModuleForImageInfo (ImageInfo &image_info, bool can_create, bool *did_create_ptr) -{ - if (did_create_ptr) - *did_create_ptr = false; - - Target &target = m_process->GetTarget(); - const ModuleList &target_images = target.GetImages(); - ModuleSpec module_spec (image_info.file_spec); - module_spec.GetUUID() = image_info.uuid; - ModuleSP module_sp (target_images.FindFirstModule (module_spec)); - - if (module_sp && !module_spec.GetUUID().IsValid() && !module_sp->GetUUID().IsValid()) - { - // No UUID, we must rely upon the cached module modification - // time and the modification time of the file on disk - if (module_sp->GetModificationTime() != module_sp->GetFileSpec().GetModificationTime()) - module_sp.reset(); +ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo( + ImageInfo &image_info, bool can_create, bool *did_create_ptr) { + if (did_create_ptr) + *did_create_ptr = false; + + Target &target = m_process->GetTarget(); + const ModuleList &target_images = target.GetImages(); + ModuleSpec module_spec(image_info.file_spec); + module_spec.GetUUID() = image_info.uuid; + ModuleSP module_sp(target_images.FindFirstModule(module_spec)); + + if (module_sp && !module_spec.GetUUID().IsValid() && + !module_sp->GetUUID().IsValid()) { + // No UUID, we must rely upon the cached module modification + // time and the modification time of the file on disk + if (module_sp->GetModificationTime() != + FileSystem::GetModificationTime(module_sp->GetFileSpec())) + module_sp.reset(); + } + + if (!module_sp) { + if (can_create) { + module_sp = target.GetSharedModule(module_spec); + if (!module_sp || module_sp->GetObjectFile() == NULL) + module_sp = m_process->ReadModuleFromMemory(image_info.file_spec, + image_info.address); + + if (did_create_ptr) + *did_create_ptr = (bool)module_sp; } + } + return module_sp; +} - if (!module_sp) - { - if (can_create) - { - module_sp = target.GetSharedModule (module_spec); - if (!module_sp || module_sp->GetObjectFile() == NULL) - module_sp = m_process->ReadModuleFromMemory (image_info.file_spec, image_info.address); - - if (did_create_ptr) - *did_create_ptr = (bool) module_sp; +void DynamicLoaderDarwin::UnloadImages( + const std::vector<lldb::addr_t> &solib_addresses) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_process->GetStopID() == m_dyld_image_infos_stop_id) + return; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Target &target = m_process->GetTarget(); + if (log) + log->Printf("Removing %" PRId64 " modules.", + (uint64_t)solib_addresses.size()); + + ModuleList unloaded_module_list; + + for (addr_t solib_addr : solib_addresses) { + Address header; + if (header.SetLoadAddress(solib_addr, &target)) { + if (header.GetOffset() == 0) { + ModuleSP module_to_remove(header.GetModule()); + if (module_to_remove.get()) { + if (log) + log->Printf("Removing module at address 0x%" PRIx64, solib_addr); + // remove the sections from the Target + UnloadSections(module_to_remove); + // add this to the list of modules to remove + unloaded_module_list.AppendIfNeeded(module_to_remove); + // remove the entry from the m_dyld_image_infos + ImageInfo::collection::iterator pos, end = m_dyld_image_infos.end(); + for (pos = m_dyld_image_infos.begin(); pos != end; pos++) { + if (solib_addr == (*pos).address) { + m_dyld_image_infos.erase(pos); + break; + } + } } + } } - return module_sp; -} + } -DynamicLoaderDarwin::ImageInfo * -DynamicLoaderDarwin::FindImageInfoForAddress (addr_t load_address) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const size_t image_count = m_dyld_image_infos.size(); - for (size_t i = 0; i < image_count; i++) - { - if (load_address == m_dyld_image_infos[i].address) - { - return &m_dyld_image_infos[i]; - } + if (unloaded_module_list.GetSize() > 0) { + if (log) { + log->PutCString("Unloaded:"); + unloaded_module_list.LogUUIDAndPaths( + log, "DynamicLoaderDarwin::UnloadModules"); } - return NULL; + m_process->GetTarget().GetImages().Remove(unloaded_module_list); + m_dyld_image_infos_stop_id = m_process->GetStopID(); + } } -void -DynamicLoaderDarwin::UnloadImages (const std::vector<lldb::addr_t> &solib_addresses) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_process->GetStopID() == m_dyld_image_infos_stop_id) - return; +void DynamicLoaderDarwin::UnloadAllImages() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + ModuleList unloaded_modules_list; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - Target &target = m_process->GetTarget(); - if (log) - log->Printf ("Removing %" PRId64 " modules.", (uint64_t) solib_addresses.size()); - - ModuleList unloaded_module_list; - - for (addr_t solib_addr : solib_addresses) - { - Address header; - if (header.SetLoadAddress (solib_addr, &target)) - { - if (header.GetOffset() == 0) - { - ModuleSP module_to_remove (header.GetModule()); - if (module_to_remove.get()) - { - if (log) - log->Printf ("Removing module at address 0x%" PRIx64, solib_addr); - // remove the sections from the Target - UnloadSections (module_to_remove); - // add this to the list of modules to remove - unloaded_module_list.AppendIfNeeded (module_to_remove); - // remove the entry from the m_dyld_image_infos - ImageInfo::collection::iterator pos, end = m_dyld_image_infos.end(); - for (pos = m_dyld_image_infos.begin(); pos != end; pos++) - { - if (solib_addr == (*pos).address) - { - m_dyld_image_infos.erase(pos); - break; - } - } - } - } - } + Target &target = m_process->GetTarget(); + const ModuleList &target_modules = target.GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); + + size_t num_modules = target_modules.GetSize(); + ModuleSP dyld_sp(GetDYLDModule()); + + for (size_t i = 0; i < num_modules; i++) { + ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + + // Don't remove dyld - else we'll lose our breakpoint notifying us about + // libraries + // being re-loaded... + if (module_sp.get() != nullptr && module_sp.get() != dyld_sp.get()) { + UnloadSections(module_sp); + unloaded_modules_list.Append(module_sp); } + } - if (unloaded_module_list.GetSize() > 0) - { - if (log) - { - log->PutCString("Unloaded:"); - unloaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderDarwin::UnloadModules"); - } - m_process->GetTarget().GetImages().Remove (unloaded_module_list); - m_dyld_image_infos_stop_id = m_process->GetStopID(); + if (unloaded_modules_list.GetSize() != 0) { + if (log) { + log->PutCString("Unloaded:"); + unloaded_modules_list.LogUUIDAndPaths( + log, "DynamicLoaderDarwin::UnloadAllImages"); } + target.GetImages().Remove(unloaded_modules_list); + m_dyld_image_infos.clear(); + m_dyld_image_infos_stop_id = m_process->GetStopID(); + } } //---------------------------------------------------------------------- // Update the load addresses for all segments in MODULE using the // updated INFO that is passed in. //---------------------------------------------------------------------- -bool -DynamicLoaderDarwin::UpdateImageLoadAddress (Module *module, ImageInfo& info) -{ - bool changed = false; - if (module) - { - ObjectFile *image_object_file = module->GetObjectFile(); - if (image_object_file) - { - SectionList *section_list = image_object_file->GetSectionList (); - if (section_list) - { - std::vector<uint32_t> inaccessible_segment_indexes; - // We now know the slide amount, so go through all sections - // and update the load addresses with the correct values. - const size_t num_segments = info.segments.size(); - for (size_t i=0; i<num_segments; ++i) - { - // Only load a segment if it has protections. Things like - // __PAGEZERO don't have any protections, and they shouldn't - // be slid - SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name)); - - if (info.segments[i].maxprot == 0) - { - inaccessible_segment_indexes.push_back(i); - } - else - { - const addr_t new_section_load_addr = info.segments[i].vmaddr + info.slide; - static ConstString g_section_name_LINKEDIT ("__LINKEDIT"); - - if (section_sp) - { - // __LINKEDIT sections from files in the shared cache - // can overlap so check to see what the segment name is - // and pass "false" so we don't warn of overlapping - // "Section" objects, and "true" for all other sections. - const bool warn_multiple = section_sp->GetName() != g_section_name_LINKEDIT; - - changed = m_process->GetTarget().SetSectionLoadAddress (section_sp, new_section_load_addr, warn_multiple); - } - else - { - Host::SystemLog (Host::eSystemLogWarning, - "warning: unable to find and load segment named '%s' at 0x%" PRIx64 " in '%s' in macosx dynamic loader plug-in.\n", - info.segments[i].name.AsCString("<invalid>"), - (uint64_t)new_section_load_addr, - image_object_file->GetFileSpec().GetPath().c_str()); - } - } - } - - // If the loaded the file (it changed) and we have segments that - // are not readable or writeable, add them to the invalid memory - // region cache for the process. This will typically only be - // the __PAGEZERO segment in the main executable. We might be able - // to apply this more generally to more sections that have no - // protections in the future, but for now we are going to just - // do __PAGEZERO. - if (changed && !inaccessible_segment_indexes.empty()) - { - for (uint32_t i=0; i<inaccessible_segment_indexes.size(); ++i) - { - const uint32_t seg_idx = inaccessible_segment_indexes[i]; - SectionSP section_sp(section_list->FindSectionByName(info.segments[seg_idx].name)); - - if (section_sp) - { - static ConstString g_pagezero_section_name("__PAGEZERO"); - if (g_pagezero_section_name == section_sp->GetName()) - { - // __PAGEZERO never slides... - const lldb::addr_t vmaddr = info.segments[seg_idx].vmaddr; - const lldb::addr_t vmsize = info.segments[seg_idx].vmsize; - Process::LoadRange pagezero_range (vmaddr, vmsize); - m_process->AddInvalidMemoryRegion(pagezero_range); - } - } - } - } +bool DynamicLoaderDarwin::UpdateImageLoadAddress(Module *module, + ImageInfo &info) { + bool changed = false; + if (module) { + ObjectFile *image_object_file = module->GetObjectFile(); + if (image_object_file) { + SectionList *section_list = image_object_file->GetSectionList(); + if (section_list) { + std::vector<uint32_t> inaccessible_segment_indexes; + // We now know the slide amount, so go through all sections + // and update the load addresses with the correct values. + const size_t num_segments = info.segments.size(); + for (size_t i = 0; i < num_segments; ++i) { + // Only load a segment if it has protections. Things like + // __PAGEZERO don't have any protections, and they shouldn't + // be slid + SectionSP section_sp( + section_list->FindSectionByName(info.segments[i].name)); + + if (info.segments[i].maxprot == 0) { + inaccessible_segment_indexes.push_back(i); + } else { + const addr_t new_section_load_addr = + info.segments[i].vmaddr + info.slide; + static ConstString g_section_name_LINKEDIT("__LINKEDIT"); + + if (section_sp) { + // __LINKEDIT sections from files in the shared cache + // can overlap so check to see what the segment name is + // and pass "false" so we don't warn of overlapping + // "Section" objects, and "true" for all other sections. + const bool warn_multiple = + section_sp->GetName() != g_section_name_LINKEDIT; + + changed = m_process->GetTarget().SetSectionLoadAddress( + section_sp, new_section_load_addr, warn_multiple); + } else { + Host::SystemLog( + Host::eSystemLogWarning, + "warning: unable to find and load segment named '%s' at " + "0x%" PRIx64 " in '%s' in macosx dynamic loader plug-in.\n", + info.segments[i].name.AsCString("<invalid>"), + (uint64_t)new_section_load_addr, + image_object_file->GetFileSpec().GetPath().c_str()); } + } } + + // If the loaded the file (it changed) and we have segments that + // are not readable or writeable, add them to the invalid memory + // region cache for the process. This will typically only be + // the __PAGEZERO segment in the main executable. We might be able + // to apply this more generally to more sections that have no + // protections in the future, but for now we are going to just + // do __PAGEZERO. + if (changed && !inaccessible_segment_indexes.empty()) { + for (uint32_t i = 0; i < inaccessible_segment_indexes.size(); ++i) { + const uint32_t seg_idx = inaccessible_segment_indexes[i]; + SectionSP section_sp( + section_list->FindSectionByName(info.segments[seg_idx].name)); + + if (section_sp) { + static ConstString g_pagezero_section_name("__PAGEZERO"); + if (g_pagezero_section_name == section_sp->GetName()) { + // __PAGEZERO never slides... + const lldb::addr_t vmaddr = info.segments[seg_idx].vmaddr; + const lldb::addr_t vmsize = info.segments[seg_idx].vmsize; + Process::LoadRange pagezero_range(vmaddr, vmsize); + m_process->AddInvalidMemoryRegion(pagezero_range); + } + } + } + } + } } - // We might have an in memory image that was loaded as soon as it was created - if (info.load_stop_id == m_process->GetStopID()) - changed = true; - else if (changed) - { - // Update the stop ID when this library was updated - info.load_stop_id = m_process->GetStopID(); - } - return changed; + } + // We might have an in memory image that was loaded as soon as it was created + if (info.load_stop_id == m_process->GetStopID()) + changed = true; + else if (changed) { + // Update the stop ID when this library was updated + info.load_stop_id = m_process->GetStopID(); + } + return changed; } //---------------------------------------------------------------------- // Unload the segments in MODULE using the INFO that is passed in. //---------------------------------------------------------------------- -bool -DynamicLoaderDarwin::UnloadModuleSections (Module *module, ImageInfo& info) -{ - bool changed = false; - if (module) - { - ObjectFile *image_object_file = module->GetObjectFile(); - if (image_object_file) - { - SectionList *section_list = image_object_file->GetSectionList (); - if (section_list) - { - const size_t num_segments = info.segments.size(); - for (size_t i=0; i<num_segments; ++i) - { - SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name)); - if (section_sp) - { - const addr_t old_section_load_addr = info.segments[i].vmaddr + info.slide; - if (m_process->GetTarget().SetSectionUnloaded (section_sp, old_section_load_addr)) - changed = true; - } - else - { - Host::SystemLog (Host::eSystemLogWarning, - "warning: unable to find and unload segment named '%s' in '%s' in macosx dynamic loader plug-in.\n", - info.segments[i].name.AsCString("<invalid>"), - image_object_file->GetFileSpec().GetPath().c_str()); - } - } - } +bool DynamicLoaderDarwin::UnloadModuleSections(Module *module, + ImageInfo &info) { + bool changed = false; + if (module) { + ObjectFile *image_object_file = module->GetObjectFile(); + if (image_object_file) { + SectionList *section_list = image_object_file->GetSectionList(); + if (section_list) { + const size_t num_segments = info.segments.size(); + for (size_t i = 0; i < num_segments; ++i) { + SectionSP section_sp( + section_list->FindSectionByName(info.segments[i].name)); + if (section_sp) { + const addr_t old_section_load_addr = + info.segments[i].vmaddr + info.slide; + if (m_process->GetTarget().SetSectionUnloaded( + section_sp, old_section_load_addr)) + changed = true; + } else { + Host::SystemLog(Host::eSystemLogWarning, + "warning: unable to find and unload segment named " + "'%s' in '%s' in macosx dynamic loader plug-in.\n", + info.segments[i].name.AsCString("<invalid>"), + image_object_file->GetFileSpec().GetPath().c_str()); + } } + } } - return changed; + } + return changed; } - -// Given a JSON dictionary (from debugserver, most likely) of binary images loaded in the inferior +// Given a JSON dictionary (from debugserver, most likely) of binary images +// loaded in the inferior // process, add the images to the ImageInfo collection. -bool -DynamicLoaderDarwin::JSONImageInformationIntoImageInfo (StructuredData::ObjectSP image_details, ImageInfo::collection &image_infos) -{ - StructuredData::ObjectSP images_sp = image_details->GetAsDictionary()->GetValueForKey("images"); - if (images_sp.get() == nullptr) - return false; - - image_infos.resize (images_sp->GetAsArray()->GetSize()); - - for (size_t i = 0; i < image_infos.size(); i++) - { - StructuredData::ObjectSP image_sp = images_sp->GetAsArray()->GetItemAtIndex(i); - if (image_sp.get() == nullptr || image_sp->GetAsDictionary() == nullptr) - return false; - StructuredData::Dictionary *image = image_sp->GetAsDictionary(); - if (image->HasKey("load_address") == false - || image->HasKey("pathname") == false - || image->HasKey("mod_date") == false - || image->HasKey("mach_header") == false - || image->GetValueForKey("mach_header")->GetAsDictionary() == nullptr - || image->HasKey("segments") == false - || image->GetValueForKey("segments")->GetAsArray() == nullptr - || image->HasKey("uuid") == false ) - { - return false; - } - image_infos[i].address = image->GetValueForKey("load_address")->GetAsInteger()->GetValue(); - image_infos[i].mod_date = image->GetValueForKey("mod_date")->GetAsInteger()->GetValue(); - image_infos[i].file_spec.SetFile(image->GetValueForKey("pathname")->GetAsString()->GetValue().c_str(), false); - - StructuredData::Dictionary *mh = image->GetValueForKey("mach_header")->GetAsDictionary(); - image_infos[i].header.magic = mh->GetValueForKey("magic")->GetAsInteger()->GetValue(); - image_infos[i].header.cputype = mh->GetValueForKey("cputype")->GetAsInteger()->GetValue(); - image_infos[i].header.cpusubtype = mh->GetValueForKey("cpusubtype")->GetAsInteger()->GetValue(); - image_infos[i].header.filetype = mh->GetValueForKey("filetype")->GetAsInteger()->GetValue(); - - // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't currently send them - // in the reply. - - if (mh->HasKey("flags")) - image_infos[i].header.flags = mh->GetValueForKey("flags")->GetAsInteger()->GetValue(); - else - image_infos[i].header.flags = 0; - - if (mh->HasKey("ncmds")) - image_infos[i].header.ncmds = mh->GetValueForKey("ncmds")->GetAsInteger()->GetValue(); - else - image_infos[i].header.ncmds = 0; - - if (mh->HasKey("sizeofcmds")) - image_infos[i].header.sizeofcmds = mh->GetValueForKey("sizeofcmds")->GetAsInteger()->GetValue(); - else - image_infos[i].header.sizeofcmds = 0; - - StructuredData::Array *segments = image->GetValueForKey("segments")->GetAsArray(); - uint32_t segcount = segments->GetSize(); - for (size_t j = 0; j < segcount; j++) - { - Segment segment; - StructuredData::Dictionary *seg = segments->GetItemAtIndex(j)->GetAsDictionary(); - segment.name = ConstString(seg->GetValueForKey("name")->GetAsString()->GetValue().c_str()); - segment.vmaddr = seg->GetValueForKey("vmaddr")->GetAsInteger()->GetValue(); - segment.vmsize = seg->GetValueForKey("vmsize")->GetAsInteger()->GetValue(); - segment.fileoff = seg->GetValueForKey("fileoff")->GetAsInteger()->GetValue(); - segment.filesize = seg->GetValueForKey("filesize")->GetAsInteger()->GetValue(); - segment.maxprot = seg->GetValueForKey("maxprot")->GetAsInteger()->GetValue(); - - // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't currently send them - // in the reply. - - if (seg->HasKey("initprot")) - segment.initprot = seg->GetValueForKey("initprot")->GetAsInteger()->GetValue(); - else - segment.initprot = 0; - - if (seg->HasKey("flags")) - segment.flags = seg->GetValueForKey("flags")->GetAsInteger()->GetValue(); - else - segment.flags = 0; - - if (seg->HasKey("nsects")) - segment.nsects = seg->GetValueForKey("nsects")->GetAsInteger()->GetValue(); - else - segment.nsects = 0; - - image_infos[i].segments.push_back (segment); - } +bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( + StructuredData::ObjectSP image_details, + ImageInfo::collection &image_infos) { + StructuredData::ObjectSP images_sp = + image_details->GetAsDictionary()->GetValueForKey("images"); + if (images_sp.get() == nullptr) + return false; - image_infos[i].uuid.SetFromCString (image->GetValueForKey("uuid")->GetAsString()->GetValue().c_str()); - - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. - - // Determine the slide amount (if any) - const size_t num_sections = image_infos[i].segments.size(); - for (size_t k = 0; k < num_sections; ++k) - { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... - if ((image_infos[i].segments[k].fileoff == 0 && image_infos[i].segments[k].filesize > 0) - || (image_infos[i].segments[k].name == ConstString("__TEXT"))) - { - image_infos[i].slide = image_infos[i].address - image_infos[i].segments[k].vmaddr; - // We have found the slide amount, so we can exit - // this for loop. - break; - } - } + image_infos.resize(images_sp->GetAsArray()->GetSize()); + + for (size_t i = 0; i < image_infos.size(); i++) { + StructuredData::ObjectSP image_sp = + images_sp->GetAsArray()->GetItemAtIndex(i); + if (image_sp.get() == nullptr || image_sp->GetAsDictionary() == nullptr) + return false; + StructuredData::Dictionary *image = image_sp->GetAsDictionary(); + if (image->HasKey("load_address") == false || + image->HasKey("pathname") == false || + image->HasKey("mod_date") == false || + image->HasKey("mach_header") == false || + image->GetValueForKey("mach_header")->GetAsDictionary() == nullptr || + image->HasKey("segments") == false || + image->GetValueForKey("segments")->GetAsArray() == nullptr || + image->HasKey("uuid") == false) { + return false; + } + image_infos[i].address = + image->GetValueForKey("load_address")->GetAsInteger()->GetValue(); + image_infos[i].mod_date = + image->GetValueForKey("mod_date")->GetAsInteger()->GetValue(); + image_infos[i].file_spec.SetFile( + image->GetValueForKey("pathname")->GetAsString()->GetValue(), false); + + StructuredData::Dictionary *mh = + image->GetValueForKey("mach_header")->GetAsDictionary(); + image_infos[i].header.magic = + mh->GetValueForKey("magic")->GetAsInteger()->GetValue(); + image_infos[i].header.cputype = + mh->GetValueForKey("cputype")->GetAsInteger()->GetValue(); + image_infos[i].header.cpusubtype = + mh->GetValueForKey("cpusubtype")->GetAsInteger()->GetValue(); + image_infos[i].header.filetype = + mh->GetValueForKey("filetype")->GetAsInteger()->GetValue(); + + if (image->HasKey("min_version_os_name")) { + std::string os_name = image->GetValueForKey("min_version_os_name") + ->GetAsString() + ->GetValue(); + if (os_name == "macosx") + image_infos[i].os_type = llvm::Triple::MacOSX; + else if (os_name == "ios" || os_name == "iphoneos") + image_infos[i].os_type = llvm::Triple::IOS; + else if (os_name == "tvos") + image_infos[i].os_type = llvm::Triple::TvOS; + else if (os_name == "watchos") + image_infos[i].os_type = llvm::Triple::WatchOS; + } + if (image->HasKey("min_version_os_sdk")) { + image_infos[i].min_version_os_sdk = + image->GetValueForKey("min_version_os_sdk") + ->GetAsString() + ->GetValue(); } - return true; -} + // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't + // currently send them + // in the reply. -void -DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfos (ImageInfo::collection &image_infos) -{ - const size_t image_infos_size = image_infos.size(); - for (size_t i = 0; i < image_infos_size; i++) - { - if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) - { - UpdateDYLDImageInfoFromNewImageInfo (image_infos[i]); - break; // FIXME simulator debugging w/ multiple dylds - } + if (mh->HasKey("flags")) + image_infos[i].header.flags = + mh->GetValueForKey("flags")->GetAsInteger()->GetValue(); + else + image_infos[i].header.flags = 0; + + if (mh->HasKey("ncmds")) + image_infos[i].header.ncmds = + mh->GetValueForKey("ncmds")->GetAsInteger()->GetValue(); + else + image_infos[i].header.ncmds = 0; + + if (mh->HasKey("sizeofcmds")) + image_infos[i].header.sizeofcmds = + mh->GetValueForKey("sizeofcmds")->GetAsInteger()->GetValue(); + else + image_infos[i].header.sizeofcmds = 0; + + StructuredData::Array *segments = + image->GetValueForKey("segments")->GetAsArray(); + uint32_t segcount = segments->GetSize(); + for (size_t j = 0; j < segcount; j++) { + Segment segment; + StructuredData::Dictionary *seg = + segments->GetItemAtIndex(j)->GetAsDictionary(); + segment.name = ConstString( + seg->GetValueForKey("name")->GetAsString()->GetValue().c_str()); + segment.vmaddr = + seg->GetValueForKey("vmaddr")->GetAsInteger()->GetValue(); + segment.vmsize = + seg->GetValueForKey("vmsize")->GetAsInteger()->GetValue(); + segment.fileoff = + seg->GetValueForKey("fileoff")->GetAsInteger()->GetValue(); + segment.filesize = + seg->GetValueForKey("filesize")->GetAsInteger()->GetValue(); + segment.maxprot = + seg->GetValueForKey("maxprot")->GetAsInteger()->GetValue(); + + // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't + // currently send them + // in the reply. + + if (seg->HasKey("initprot")) + segment.initprot = + seg->GetValueForKey("initprot")->GetAsInteger()->GetValue(); + else + segment.initprot = 0; + + if (seg->HasKey("flags")) + segment.flags = + seg->GetValueForKey("flags")->GetAsInteger()->GetValue(); + else + segment.flags = 0; + + if (seg->HasKey("nsects")) + segment.nsects = + seg->GetValueForKey("nsects")->GetAsInteger()->GetValue(); + else + segment.nsects = 0; + + image_infos[i].segments.push_back(segment); + } + + image_infos[i].uuid.SetFromCString( + image->GetValueForKey("uuid")->GetAsString()->GetValue().c_str()); + + // All sections listed in the dyld image info structure will all + // either be fixed up already, or they will all be off by a single + // slide amount that is determined by finding the first segment + // that is at file offset zero which also has bytes (a file size + // that is greater than zero) in the object file. + + // Determine the slide amount (if any) + const size_t num_sections = image_infos[i].segments.size(); + for (size_t k = 0; k < num_sections; ++k) { + // Iterate through the object file sections to find the + // first section that starts of file offset zero and that + // has bytes in the file... + if ((image_infos[i].segments[k].fileoff == 0 && + image_infos[i].segments[k].filesize > 0) || + (image_infos[i].segments[k].name == ConstString("__TEXT"))) { + image_infos[i].slide = + image_infos[i].address - image_infos[i].segments[k].vmaddr; + // We have found the slide amount, so we can exit + // this for loop. + break; + } } + } + + return true; } -void -DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfo (ImageInfo &image_info) -{ - // FIXME simulator debugging w/ multiple dylds - if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) - { - const bool can_create = true; - ModuleSP dyld_sp = FindTargetModuleForImageInfo (image_info, can_create, NULL); - if (dyld_sp.get()) - { - Target &target = m_process->GetTarget(); - target.GetImages().AppendIfNeeded (dyld_sp); - UpdateImageLoadAddress (dyld_sp.get(), image_info); - SetDYLDModule (dyld_sp); +void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( + ImageInfo::collection &image_infos) { + uint32_t exe_idx = UINT32_MAX; + uint32_t dyld_idx = UINT32_MAX; + Target &target = m_process->GetTarget(); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + ConstString g_dyld_sim_filename("dyld_sim"); + + ArchSpec target_arch = target.GetArchitecture(); + const size_t image_infos_size = image_infos.size(); + for (size_t i = 0; i < image_infos_size; i++) { + if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) { + // In a "simulator" process (an x86 process that is ios/tvos/watchos) + // we will have two dyld modules -- a "dyld" that we want to keep track + // of, + // and a "dyld_sim" which we don't need to keep track of here. + // If the target is an x86 system and the OS of the dyld binary is + // ios/tvos/watchos, then we are looking at dyld_sym. + + // debugserver has only recently (late 2016) started sending up the + // os type for each binary it sees -- so if we don't have an os + // type, use a filename check as our next best guess. + if (image_infos[i].os_type == llvm::Triple::OSType::UnknownOS) { + if (image_infos[i].file_spec.GetFilename() != g_dyld_sim_filename) { + dyld_idx = i; + } + } else if (target_arch.GetTriple().getArch() == llvm::Triple::x86 || + target_arch.GetTriple().getArch() == llvm::Triple::x86_64) { + if (image_infos[i].os_type != llvm::Triple::OSType::IOS && + image_infos[i].os_type != llvm::Triple::TvOS && + image_infos[i].os_type != llvm::Triple::WatchOS) { + dyld_idx = i; } + } + } else if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) { + exe_idx = i; + } + } + + if (exe_idx != UINT32_MAX) { + const bool can_create = true; + ModuleSP exe_module_sp( + FindTargetModuleForImageInfo(image_infos[exe_idx], can_create, NULL)); + if (exe_module_sp) { + if (log) + log->Printf("Found executable module: %s", + exe_module_sp->GetFileSpec().GetPath().c_str()); + target.GetImages().AppendIfNeeded(exe_module_sp); + UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]); + if (exe_module_sp.get() != target.GetExecutableModulePointer()) { + const bool get_dependent_images = false; + target.SetExecutableModule(exe_module_sp, get_dependent_images); + } } + } + + if (dyld_idx != UINT32_MAX) { + const bool can_create = true; + ModuleSP dyld_sp = + FindTargetModuleForImageInfo(image_infos[dyld_idx], can_create, NULL); + if (dyld_sp.get()) { + if (log) + log->Printf("Found dyld module: %s", + dyld_sp->GetFileSpec().GetPath().c_str()); + target.GetImages().AppendIfNeeded(dyld_sp); + UpdateImageLoadAddress(dyld_sp.get(), image_infos[dyld_idx]); + SetDYLDModule(dyld_sp); + } + } } -void -DynamicLoaderDarwin::AddExecutableModuleIfInImageInfos (ImageInfo::collection &image_infos) -{ - const size_t image_infos_size = image_infos.size(); - for (size_t i = 0; i < image_infos_size; i++) - { - if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) - { - Target &target = m_process->GetTarget(); - const bool can_create = true; - ModuleSP exe_module_sp (FindTargetModuleForImageInfo (image_infos[i], can_create, NULL)); - - if (exe_module_sp) - { - UpdateImageLoadAddress (exe_module_sp.get(), image_infos[i]); - - if (exe_module_sp.get() != target.GetExecutableModulePointer()) - { - // Don't load dependent images since we are in dyld where we will know - // and find out about all images that are loaded. Also when setting the - // executable module, it will clear the targets module list, and if we - // have an in memory dyld module, it will get removed from the list - // so we will need to add it back after setting the executable module, - // so we first try and see if we already have a weak pointer to the - // dyld module, make it into a shared pointer, then add the executable, - // then re-add it back to make sure it is always in the list. - - const bool get_dependent_images = false; - m_process->GetTarget().SetExecutableModule (exe_module_sp, - get_dependent_images); - - UpdateDYLDImageInfoFromNewImageInfos (image_infos); - } - } - } +void DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfo( + ImageInfo &image_info) { + if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) { + const bool can_create = true; + ModuleSP dyld_sp = + FindTargetModuleForImageInfo(image_info, can_create, NULL); + if (dyld_sp.get()) { + Target &target = m_process->GetTarget(); + target.GetImages().AppendIfNeeded(dyld_sp); + UpdateImageLoadAddress(dyld_sp.get(), image_info); + SetDYLDModule(dyld_sp); } + } } -void -DynamicLoaderDarwin::SetDYLDModule (lldb::ModuleSP &dyld_module_sp) -{ - m_dyld_module_wp = dyld_module_sp; +void DynamicLoaderDarwin::SetDYLDModule(lldb::ModuleSP &dyld_module_sp) { + m_dyld_module_wp = dyld_module_sp; } -ModuleSP -DynamicLoaderDarwin::GetDYLDModule () -{ - ModuleSP dyld_sp (m_dyld_module_wp.lock()); - return dyld_sp; +ModuleSP DynamicLoaderDarwin::GetDYLDModule() { + ModuleSP dyld_sp(m_dyld_module_wp.lock()); + return dyld_sp; } -bool -DynamicLoaderDarwin::AddModulesUsingImageInfos (ImageInfo::collection &image_infos) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - // Now add these images to the main list. - ModuleList loaded_module_list; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - Target &target = m_process->GetTarget(); - ModuleList& target_images = target.GetImages(); - - for (uint32_t idx = 0; idx < image_infos.size(); ++idx) - { - if (log) - { - log->Printf ("Adding new image at address=0x%16.16" PRIx64 ".", image_infos[idx].address); - image_infos[idx].PutToLog (log); - } - - m_dyld_image_infos.push_back(image_infos[idx]); - - ModuleSP image_module_sp (FindTargetModuleForImageInfo (image_infos[idx], true, NULL)); - - if (image_module_sp) - { - ObjectFile *objfile = image_module_sp->GetObjectFile (); - if (objfile) - { - SectionList *sections = objfile->GetSectionList(); - if (sections) - { - ConstString commpage_dbstr("__commpage"); - Section *commpage_section = sections->FindSectionByName(commpage_dbstr).get(); - if (commpage_section) - { - ModuleSpec module_spec (objfile->GetFileSpec(), image_infos[idx].GetArchitecture ()); - module_spec.GetObjectName() = commpage_dbstr; - ModuleSP commpage_image_module_sp(target_images.FindFirstModule (module_spec)); - if (!commpage_image_module_sp) - { - module_spec.SetObjectOffset (objfile->GetFileOffset() + commpage_section->GetFileOffset()); - module_spec.SetObjectSize (objfile->GetByteSize()); - commpage_image_module_sp = target.GetSharedModule (module_spec); - if (!commpage_image_module_sp || commpage_image_module_sp->GetObjectFile() == NULL) - { - commpage_image_module_sp = m_process->ReadModuleFromMemory (image_infos[idx].file_spec, - image_infos[idx].address); - // Always load a memory image right away in the target in case - // we end up trying to read the symbol table from memory... The - // __LINKEDIT will need to be mapped so we can figure out where - // the symbol table bits are... - bool changed = false; - UpdateImageLoadAddress (commpage_image_module_sp.get(), image_infos[idx]); - target.GetImages().Append(commpage_image_module_sp); - if (changed) - { - image_infos[idx].load_stop_id = m_process->GetStopID(); - loaded_module_list.AppendIfNeeded (commpage_image_module_sp); - } - } - } - } - } - } +bool DynamicLoaderDarwin::AddModulesUsingImageInfos( + ImageInfo::collection &image_infos) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // Now add these images to the main list. + ModuleList loaded_module_list; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + Target &target = m_process->GetTarget(); + ModuleList &target_images = target.GetImages(); + + for (uint32_t idx = 0; idx < image_infos.size(); ++idx) { + if (log) { + log->Printf("Adding new image at address=0x%16.16" PRIx64 ".", + image_infos[idx].address); + image_infos[idx].PutToLog(log); + } - // UpdateImageLoadAddress will return true if any segments - // change load address. We need to check this so we don't - // mention that all loaded shared libraries are newly loaded - // each time we hit out dyld breakpoint since dyld will list all - // shared libraries each time. - if (UpdateImageLoadAddress (image_module_sp.get(), image_infos[idx])) - { - target_images.AppendIfNeeded(image_module_sp); - loaded_module_list.AppendIfNeeded (image_module_sp); + m_dyld_image_infos.push_back(image_infos[idx]); + + ModuleSP image_module_sp( + FindTargetModuleForImageInfo(image_infos[idx], true, NULL)); + + if (image_module_sp) { + ObjectFile *objfile = image_module_sp->GetObjectFile(); + if (objfile) { + SectionList *sections = objfile->GetSectionList(); + if (sections) { + ConstString commpage_dbstr("__commpage"); + Section *commpage_section = + sections->FindSectionByName(commpage_dbstr).get(); + if (commpage_section) { + ModuleSpec module_spec(objfile->GetFileSpec(), + image_infos[idx].GetArchitecture()); + module_spec.GetObjectName() = commpage_dbstr; + ModuleSP commpage_image_module_sp( + target_images.FindFirstModule(module_spec)); + if (!commpage_image_module_sp) { + module_spec.SetObjectOffset(objfile->GetFileOffset() + + commpage_section->GetFileOffset()); + module_spec.SetObjectSize(objfile->GetByteSize()); + commpage_image_module_sp = target.GetSharedModule(module_spec); + if (!commpage_image_module_sp || + commpage_image_module_sp->GetObjectFile() == NULL) { + commpage_image_module_sp = m_process->ReadModuleFromMemory( + image_infos[idx].file_spec, image_infos[idx].address); + // Always load a memory image right away in the target in case + // we end up trying to read the symbol table from memory... The + // __LINKEDIT will need to be mapped so we can figure out where + // the symbol table bits are... + bool changed = false; + UpdateImageLoadAddress(commpage_image_module_sp.get(), + image_infos[idx]); + target.GetImages().Append(commpage_image_module_sp); + if (changed) { + image_infos[idx].load_stop_id = m_process->GetStopID(); + loaded_module_list.AppendIfNeeded(commpage_image_module_sp); + } + } } + } } + } + + // UpdateImageLoadAddress will return true if any segments + // change load address. We need to check this so we don't + // mention that all loaded shared libraries are newly loaded + // each time we hit out dyld breakpoint since dyld will list all + // shared libraries each time. + if (UpdateImageLoadAddress(image_module_sp.get(), image_infos[idx])) { + target_images.AppendIfNeeded(image_module_sp); + loaded_module_list.AppendIfNeeded(image_module_sp); + } } - - if (loaded_module_list.GetSize() > 0) - { - if (log) - loaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderDarwin::ModulesDidLoad"); - m_process->GetTarget().ModulesDidLoad (loaded_module_list); - } - return true; -} + } + if (loaded_module_list.GetSize() > 0) { + if (log) + loaded_module_list.LogUUIDAndPaths(log, + "DynamicLoaderDarwin::ModulesDidLoad"); + m_process->GetTarget().ModulesDidLoad(loaded_module_list); + } + return true; +} //---------------------------------------------------------------------- // On Mac OS X libobjc (the Objective-C runtime) has several critical dispatch // functions written in hand-written assembly, and also have hand-written unwind -// information in the eh_frame section. Normally we prefer analyzing the -// assembly instructions of a currently executing frame to unwind from that frame -- +// information in the eh_frame section. Normally we prefer analyzing the +// assembly instructions of a currently executing frame to unwind from that +// frame -- // but on hand-written functions this profiling can fail. We should use the // eh_frame instructions for these functions all the time. // @@ -666,478 +701,469 @@ DynamicLoaderDarwin::AddModulesUsingImageInfos (ImageInfo::collection &image_inf // of our normal default assumption that they are not. //---------------------------------------------------------------------- -bool -DynamicLoaderDarwin::AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx) -{ - ModuleSP module_sp; - if (sym_ctx.symbol) - { - module_sp = sym_ctx.symbol->GetAddressRef().GetModule(); - } - if (module_sp.get() == NULL && sym_ctx.function) - { - module_sp = sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule(); - } - if (module_sp.get() == NULL) - return false; - - ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime(); - if (objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary (module_sp)) - { - return true; - } - +bool DynamicLoaderDarwin::AlwaysRelyOnEHUnwindInfo(SymbolContext &sym_ctx) { + ModuleSP module_sp; + if (sym_ctx.symbol) { + module_sp = sym_ctx.symbol->GetAddressRef().GetModule(); + } + if (module_sp.get() == NULL && sym_ctx.function) { + module_sp = + sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule(); + } + if (module_sp.get() == NULL) return false; -} + ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime(); + if (objc_runtime != NULL && objc_runtime->IsModuleObjCLibrary(module_sp)) { + return true; + } + return false; +} //---------------------------------------------------------------------- // Dump a Segment to the file handle provided. //---------------------------------------------------------------------- -void -DynamicLoaderDarwin::Segment::PutToLog (Log *log, lldb::addr_t slide) const -{ - if (log) - { - if (slide == 0) - log->Printf ("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")", - name.AsCString(""), - vmaddr + slide, - vmaddr + slide + vmsize); - else - log->Printf ("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") slide = 0x%" PRIx64, - name.AsCString(""), - vmaddr + slide, - vmaddr + slide + vmsize, - slide); - } +void DynamicLoaderDarwin::Segment::PutToLog(Log *log, + lldb::addr_t slide) const { + if (log) { + if (slide == 0) + log->Printf("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")", + name.AsCString(""), vmaddr + slide, vmaddr + slide + vmsize); + else + log->Printf("\t\t%16s [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 + ") slide = 0x%" PRIx64, + name.AsCString(""), vmaddr + slide, vmaddr + slide + vmsize, + slide); + } } const DynamicLoaderDarwin::Segment * -DynamicLoaderDarwin::ImageInfo::FindSegment (const ConstString &name) const -{ - const size_t num_segments = segments.size(); - for (size_t i=0; i<num_segments; ++i) - { - if (segments[i].name == name) - return &segments[i]; - } - return NULL; +DynamicLoaderDarwin::ImageInfo::FindSegment(const ConstString &name) const { + const size_t num_segments = segments.size(); + for (size_t i = 0; i < num_segments; ++i) { + if (segments[i].name == name) + return &segments[i]; + } + return NULL; } - //---------------------------------------------------------------------- // Dump an image info structure to the file handle provided. //---------------------------------------------------------------------- -void -DynamicLoaderDarwin::ImageInfo::PutToLog (Log *log) const -{ - if (log == NULL) - return; - const uint8_t *u = (const uint8_t *)uuid.GetBytes(); - - if (address == LLDB_INVALID_ADDRESS) - { - if (u) - { - log->Printf("\t modtime=0x%8.8" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s' (UNLOADED)", - mod_date, - u[ 0], u[ 1], u[ 2], u[ 3], - u[ 4], u[ 5], u[ 6], u[ 7], - u[ 8], u[ 9], u[10], u[11], - u[12], u[13], u[14], u[15], - file_spec.GetPath().c_str()); - } - else - log->Printf("\t modtime=0x%8.8" PRIx64 " path='%s' (UNLOADED)", - mod_date, - file_spec.GetPath().c_str()); - } - else - { - if (u) - { - log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s'", - address, - mod_date, - u[ 0], u[ 1], u[ 2], u[ 3], - u[ 4], u[ 5], u[ 6], u[ 7], - u[ 8], u[ 9], u[10], u[11], - u[12], u[13], u[14], u[15], - file_spec.GetPath().c_str()); - } - else - { - log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 " path='%s'", - address, - mod_date, - file_spec.GetPath().c_str()); - - } - for (uint32_t i=0; i<segments.size(); ++i) - segments[i].PutToLog(log, slide); +void DynamicLoaderDarwin::ImageInfo::PutToLog(Log *log) const { + if (log == NULL) + return; + const uint8_t *u = (const uint8_t *)uuid.GetBytes(); + + if (address == LLDB_INVALID_ADDRESS) { + if (u) { + log->Printf("\t modtime=0x%8.8" PRIx64 + " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" + "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s' (UNLOADED)", + mod_date, u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], + u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], + file_spec.GetPath().c_str()); + } else + log->Printf("\t modtime=0x%8.8" PRIx64 + " path='%s' (UNLOADED)", + mod_date, file_spec.GetPath().c_str()); + } else { + if (u) { + log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 + " uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-" + "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X path='%s'", + address, mod_date, u[0], u[1], u[2], u[3], u[4], u[5], u[6], + u[7], u[8], u[9], u[10], u[11], u[12], u[13], u[14], u[15], + file_spec.GetPath().c_str()); + } else { + log->Printf("\taddress=0x%16.16" PRIx64 " modtime=0x%8.8" PRIx64 + " path='%s'", + address, mod_date, file_spec.GetPath().c_str()); } + for (uint32_t i = 0; i < segments.size(); ++i) + segments[i].PutToLog(log, slide); + } } -void -DynamicLoaderDarwin::PrivateInitialize(Process *process) -{ - DEBUG_PRINTF("DynamicLoaderDarwin::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState())); - Clear(true); - m_process = process; - m_process->GetTarget().ClearAllLoadedSections(); +void DynamicLoaderDarwin::PrivateInitialize(Process *process) { + DEBUG_PRINTF("DynamicLoaderDarwin::%s() process state = %s\n", __FUNCTION__, + StateAsCString(m_process->GetState())); + Clear(true); + m_process = process; + m_process->GetTarget().ClearAllLoadedSections(); } //---------------------------------------------------------------------- // Member function that gets called when the process state changes. //---------------------------------------------------------------------- -void -DynamicLoaderDarwin::PrivateProcessStateChanged (Process *process, StateType state) -{ - DEBUG_PRINTF("DynamicLoaderDarwin::%s(%s)\n", __FUNCTION__, StateAsCString(state)); - switch (state) - { - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - case eStateDetached: - Clear(false); - break; - - case eStateStopped: - // Keep trying find dyld and set our notification breakpoint each time - // we stop until we succeed - if (!DidSetNotificationBreakpoint () && m_process->IsAlive()) - { - if (NeedToDoInitialImageFetch ()) - DoInitialImageFetch (); - - SetNotificationBreakpoint (); - } - break; - - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - break; +void DynamicLoaderDarwin::PrivateProcessStateChanged(Process *process, + StateType state) { + DEBUG_PRINTF("DynamicLoaderDarwin::%s(%s)\n", __FUNCTION__, + StateAsCString(state)); + switch (state) { + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateInvalid: + case eStateUnloaded: + case eStateExited: + case eStateDetached: + Clear(false); + break; + + case eStateStopped: + // Keep trying find dyld and set our notification breakpoint each time + // we stop until we succeed + if (!DidSetNotificationBreakpoint() && m_process->IsAlive()) { + if (NeedToDoInitialImageFetch()) + DoInitialImageFetch(); + + SetNotificationBreakpoint(); } + break; + + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + break; + } } ThreadPlanSP -DynamicLoaderDarwin::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) -{ - ThreadPlanSP thread_plan_sp; - StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get(); - const SymbolContext ¤t_context = current_frame->GetSymbolContext(eSymbolContextSymbol); - Symbol *current_symbol = current_context.symbol; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - TargetSP target_sp (thread.CalculateTarget()); - - if (current_symbol != NULL) - { - std::vector<Address> addresses; - - if (current_symbol->IsTrampoline()) - { - const ConstString &trampoline_name = current_symbol->GetMangled().GetName(current_symbol->GetLanguage(), Mangled::ePreferMangled); - - if (trampoline_name) - { - const ModuleList &images = target_sp->GetImages(); - - SymbolContextList code_symbols; - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, code_symbols); - size_t num_code_symbols = code_symbols.GetSize(); - - if (num_code_symbols > 0) - { - for (uint32_t i = 0; i < num_code_symbols; i++) - { - SymbolContext context; - AddressRange addr_range; - if (code_symbols.GetContextAtIndex(i, context)) - { - context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range); - addresses.push_back(addr_range.GetBaseAddress()); - if (log) - { - addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); - - log->Printf ("Found a trampoline target symbol at 0x%" PRIx64 ".", load_addr); - } - } - } - } - - SymbolContextList reexported_symbols; - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeReExported, reexported_symbols); - size_t num_reexported_symbols = reexported_symbols.GetSize(); - if (num_reexported_symbols > 0) - { - for (uint32_t i = 0; i < num_reexported_symbols; i++) - { - SymbolContext context; - if (reexported_symbols.GetContextAtIndex(i, context)) - { - if (context.symbol) - { - Symbol *actual_symbol = context.symbol->ResolveReExportedSymbol(*target_sp.get()); - if (actual_symbol) - { - const Address actual_symbol_addr = actual_symbol->GetAddress(); - if (actual_symbol_addr.IsValid()) - { - addresses.push_back(actual_symbol_addr); - if (log) - { - lldb::addr_t load_addr = actual_symbol_addr.GetLoadAddress(target_sp.get()); - log->Printf ("Found a re-exported symbol: %s at 0x%" PRIx64 ".", - actual_symbol->GetName().GetCString(), load_addr); - } - } - } - } - } - } - } - - SymbolContextList indirect_symbols; - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeResolver, indirect_symbols); - size_t num_indirect_symbols = indirect_symbols.GetSize(); - if (num_indirect_symbols > 0) - { - for (uint32_t i = 0; i < num_indirect_symbols; i++) - { - SymbolContext context; - AddressRange addr_range; - if (indirect_symbols.GetContextAtIndex(i, context)) - { - context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range); - addresses.push_back(addr_range.GetBaseAddress()); - if (log) - { - addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); - - log->Printf ("Found an indirect target symbol at 0x%" PRIx64 ".", load_addr); - } - } - } - } +DynamicLoaderDarwin::GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) { + ThreadPlanSP thread_plan_sp; + StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get(); + const SymbolContext ¤t_context = + current_frame->GetSymbolContext(eSymbolContextSymbol); + Symbol *current_symbol = current_context.symbol; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + TargetSP target_sp(thread.CalculateTarget()); + + if (current_symbol != NULL) { + std::vector<Address> addresses; + + if (current_symbol->IsTrampoline()) { + const ConstString &trampoline_name = current_symbol->GetMangled().GetName( + current_symbol->GetLanguage(), Mangled::ePreferMangled); + + if (trampoline_name) { + const ModuleList &images = target_sp->GetImages(); + + SymbolContextList code_symbols; + images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, + code_symbols); + size_t num_code_symbols = code_symbols.GetSize(); + + if (num_code_symbols > 0) { + for (uint32_t i = 0; i < num_code_symbols; i++) { + SymbolContext context; + AddressRange addr_range; + if (code_symbols.GetContextAtIndex(i, context)) { + context.GetAddressRange(eSymbolContextEverything, 0, false, + addr_range); + addresses.push_back(addr_range.GetBaseAddress()); + if (log) { + addr_t load_addr = + addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); + + log->Printf("Found a trampoline target symbol at 0x%" PRIx64 + ".", + load_addr); + } } + } } - else if (current_symbol->GetType() == eSymbolTypeReExported) - { - // I am not sure we could ever end up stopped AT a re-exported symbol. But just in case: - - const Symbol *actual_symbol = current_symbol->ResolveReExportedSymbol(*(target_sp.get())); - if (actual_symbol) - { - Address target_addr(actual_symbol->GetAddress()); - if (target_addr.IsValid()) - { - if (log) - log->Printf ("Found a re-exported symbol: %s pointing to: %s at 0x%" PRIx64 ".", - current_symbol->GetName().GetCString(), - actual_symbol->GetName().GetCString(), - target_addr.GetLoadAddress(target_sp.get())); - addresses.push_back (target_addr.GetLoadAddress(target_sp.get())); - + + SymbolContextList reexported_symbols; + images.FindSymbolsWithNameAndType( + trampoline_name, eSymbolTypeReExported, reexported_symbols); + size_t num_reexported_symbols = reexported_symbols.GetSize(); + if (num_reexported_symbols > 0) { + for (uint32_t i = 0; i < num_reexported_symbols; i++) { + SymbolContext context; + if (reexported_symbols.GetContextAtIndex(i, context)) { + if (context.symbol) { + Symbol *actual_symbol = + context.symbol->ResolveReExportedSymbol(*target_sp.get()); + if (actual_symbol) { + const Address actual_symbol_addr = + actual_symbol->GetAddress(); + if (actual_symbol_addr.IsValid()) { + addresses.push_back(actual_symbol_addr); + if (log) { + lldb::addr_t load_addr = + actual_symbol_addr.GetLoadAddress(target_sp.get()); + log->Printf( + "Found a re-exported symbol: %s at 0x%" PRIx64 ".", + actual_symbol->GetName().GetCString(), load_addr); + } + } } + } } + } } - - if (addresses.size() > 0) - { - // First check whether any of the addresses point to Indirect symbols, and if they do, resolve them: - std::vector<lldb::addr_t> load_addrs; - for (Address address : addresses) - { - Symbol *symbol = address.CalculateSymbolContextSymbol(); - if (symbol && symbol->IsIndirect()) - { - Error error; - Address symbol_address = symbol->GetAddress(); - addr_t resolved_addr = thread.GetProcess()->ResolveIndirectFunction(&symbol_address, error); - if (error.Success()) - { - load_addrs.push_back(resolved_addr); - if (log) - log->Printf("ResolveIndirectFunction found resolved target for %s at 0x%" PRIx64 ".", - symbol->GetName().GetCString(), resolved_addr); - } - } - else - { - load_addrs.push_back(address.GetLoadAddress(target_sp.get())); - } - + + SymbolContextList indirect_symbols; + images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeResolver, + indirect_symbols); + size_t num_indirect_symbols = indirect_symbols.GetSize(); + if (num_indirect_symbols > 0) { + for (uint32_t i = 0; i < num_indirect_symbols; i++) { + SymbolContext context; + AddressRange addr_range; + if (indirect_symbols.GetContextAtIndex(i, context)) { + context.GetAddressRange(eSymbolContextEverything, 0, false, + addr_range); + addresses.push_back(addr_range.GetBaseAddress()); + if (log) { + addr_t load_addr = + addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); + + log->Printf("Found an indirect target symbol at 0x%" PRIx64 ".", + load_addr); + } } - thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, load_addrs, stop_others)); + } } + } + } else if (current_symbol->GetType() == eSymbolTypeReExported) { + // I am not sure we could ever end up stopped AT a re-exported symbol. + // But just in case: + + const Symbol *actual_symbol = + current_symbol->ResolveReExportedSymbol(*(target_sp.get())); + if (actual_symbol) { + Address target_addr(actual_symbol->GetAddress()); + if (target_addr.IsValid()) { + if (log) + log->Printf( + "Found a re-exported symbol: %s pointing to: %s at 0x%" PRIx64 + ".", + current_symbol->GetName().GetCString(), + actual_symbol->GetName().GetCString(), + target_addr.GetLoadAddress(target_sp.get())); + addresses.push_back(target_addr.GetLoadAddress(target_sp.get())); + } + } } - else - { - if (log) - log->Printf ("Could not find symbol for step through."); + + if (addresses.size() > 0) { + // First check whether any of the addresses point to Indirect symbols, and + // if they do, resolve them: + std::vector<lldb::addr_t> load_addrs; + for (Address address : addresses) { + Symbol *symbol = address.CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) { + Error error; + Address symbol_address = symbol->GetAddress(); + addr_t resolved_addr = thread.GetProcess()->ResolveIndirectFunction( + &symbol_address, error); + if (error.Success()) { + load_addrs.push_back(resolved_addr); + if (log) + log->Printf("ResolveIndirectFunction found resolved target for " + "%s at 0x%" PRIx64 ".", + symbol->GetName().GetCString(), resolved_addr); + } + } else { + load_addrs.push_back(address.GetLoadAddress(target_sp.get())); + } + } + thread_plan_sp.reset( + new ThreadPlanRunToAddress(thread, load_addrs, stop_others)); } + } else { + if (log) + log->Printf("Could not find symbol for step through."); + } - return thread_plan_sp; + return thread_plan_sp; } -size_t -DynamicLoaderDarwin::FindEquivalentSymbols (lldb_private::Symbol *original_symbol, - lldb_private::ModuleList &images, - lldb_private::SymbolContextList &equivalent_symbols) -{ - const ConstString &trampoline_name = original_symbol->GetMangled().GetName(original_symbol->GetLanguage(), Mangled::ePreferMangled); - if (!trampoline_name) - return 0; - - size_t initial_size = equivalent_symbols.GetSize(); - - static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Za-z0-9\\$]+)$"; - std::string equivalent_regex_buf("^"); - equivalent_regex_buf.append (trampoline_name.GetCString()); - equivalent_regex_buf.append (resolver_name_regex); - - RegularExpression equivalent_name_regex (equivalent_regex_buf.c_str()); - const bool append = true; - images.FindSymbolsMatchingRegExAndType (equivalent_name_regex, eSymbolTypeCode, equivalent_symbols, append); - - return equivalent_symbols.GetSize() - initial_size; +size_t DynamicLoaderDarwin::FindEquivalentSymbols( + lldb_private::Symbol *original_symbol, lldb_private::ModuleList &images, + lldb_private::SymbolContextList &equivalent_symbols) { + const ConstString &trampoline_name = original_symbol->GetMangled().GetName( + original_symbol->GetLanguage(), Mangled::ePreferMangled); + if (!trampoline_name) + return 0; + + size_t initial_size = equivalent_symbols.GetSize(); + + static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Za-z0-9\\$]+)$"; + std::string equivalent_regex_buf("^"); + equivalent_regex_buf.append(trampoline_name.GetCString()); + equivalent_regex_buf.append(resolver_name_regex); + + RegularExpression equivalent_name_regex(equivalent_regex_buf); + const bool append = true; + images.FindSymbolsMatchingRegExAndType(equivalent_name_regex, eSymbolTypeCode, + equivalent_symbols, append); + + return equivalent_symbols.GetSize() - initial_size; } -lldb::ModuleSP -DynamicLoaderDarwin::GetPThreadLibraryModule() -{ - ModuleSP module_sp = m_libpthread_module_wp.lock(); - if (!module_sp) - { - SymbolContextList sc_list; - ModuleSpec module_spec; - module_spec.GetFileSpec().GetFilename().SetCString("libsystem_pthread.dylib"); - ModuleList module_list; - if (m_process->GetTarget().GetImages().FindModules(module_spec, module_list)) - { - if (module_list.GetSize() == 1) - { - module_sp = module_list.GetModuleAtIndex(0); - if (module_sp) - m_libpthread_module_wp = module_sp; - } - } +lldb::ModuleSP DynamicLoaderDarwin::GetPThreadLibraryModule() { + ModuleSP module_sp = m_libpthread_module_wp.lock(); + if (!module_sp) { + SymbolContextList sc_list; + ModuleSpec module_spec; + module_spec.GetFileSpec().GetFilename().SetCString( + "libsystem_pthread.dylib"); + ModuleList module_list; + if (m_process->GetTarget().GetImages().FindModules(module_spec, + module_list)) { + if (module_list.GetSize() == 1) { + module_sp = module_list.GetModuleAtIndex(0); + if (module_sp) + m_libpthread_module_wp = module_sp; + } } - return module_sp; + } + return module_sp; } -Address -DynamicLoaderDarwin::GetPthreadSetSpecificAddress() -{ - if (!m_pthread_getspecific_addr.IsValid()) - { - ModuleSP module_sp = GetPThreadLibraryModule(); - if (module_sp) - { - lldb_private::SymbolContextList sc_list; - module_sp->FindSymbolsWithNameAndType(ConstString("pthread_getspecific"), eSymbolTypeCode, sc_list); - SymbolContext sc; - if (sc_list.GetContextAtIndex(0, sc)) - { - if (sc.symbol) - m_pthread_getspecific_addr = sc.symbol->GetAddress(); - } - } +Address DynamicLoaderDarwin::GetPthreadSetSpecificAddress() { + if (!m_pthread_getspecific_addr.IsValid()) { + ModuleSP module_sp = GetPThreadLibraryModule(); + if (module_sp) { + lldb_private::SymbolContextList sc_list; + module_sp->FindSymbolsWithNameAndType(ConstString("pthread_getspecific"), + eSymbolTypeCode, sc_list); + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) { + if (sc.symbol) + m_pthread_getspecific_addr = sc.symbol->GetAddress(); + } } - return m_pthread_getspecific_addr; + } + return m_pthread_getspecific_addr; } lldb::addr_t -DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, const lldb::ThreadSP thread_sp, - lldb::addr_t tls_file_addr) -{ - if (!thread_sp || !module_sp) - return LLDB_INVALID_ADDRESS; - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - const uint32_t addr_size = m_process->GetAddressByteSize(); - uint8_t buf[sizeof(lldb::addr_t) * 3]; - - lldb_private::Address tls_addr; - if (module_sp->ResolveFileAddress(tls_file_addr, tls_addr)) - { - Error error; - const size_t tsl_data_size = addr_size * 3; - Target &target = m_process->GetTarget(); - if (target.ReadMemory(tls_addr, false, buf, tsl_data_size, error) == tsl_data_size) - { - const ByteOrder byte_order = m_process->GetByteOrder(); - DataExtractor data(buf, sizeof(buf), byte_order, addr_size); - lldb::offset_t offset = addr_size; // Skip the first pointer - const lldb::addr_t pthread_key = data.GetAddress(&offset); - const lldb::addr_t tls_offset = data.GetAddress(&offset); - if (pthread_key != 0) - { - // First check to see if we have already figured out the location - // of TLS data for the pthread_key on a specific thread yet. If we - // have we can re-use it since its location will not change unless - // the process execs. - const tid_t tid = thread_sp->GetID(); - auto tid_pos = m_tid_to_tls_map.find(tid); - if (tid_pos != m_tid_to_tls_map.end()) - { - auto tls_pos = tid_pos->second.find(pthread_key); - if (tls_pos != tid_pos->second.end()) - { - return tls_pos->second + tls_offset; - } - } - StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0); - if (frame_sp) - { - ClangASTContext *clang_ast_context = target.GetScratchClangASTContext(); - - if (!clang_ast_context) - return LLDB_INVALID_ADDRESS; - - CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - Address pthread_getspecific_addr = GetPthreadSetSpecificAddress(); - if (pthread_getspecific_addr.IsValid()) - { - EvaluateExpressionOptions options; - - lldb::ThreadPlanSP thread_plan_sp( - new ThreadPlanCallFunction(*thread_sp, pthread_getspecific_addr, clang_void_ptr_type, - llvm::ArrayRef<lldb::addr_t>(pthread_key), options)); - - DiagnosticManager execution_errors; - ExecutionContext exe_ctx(thread_sp); - lldb::ExpressionResults results = - m_process->RunThreadPlan(exe_ctx, thread_plan_sp, options, execution_errors); - - if (results == lldb::eExpressionCompleted) - { - lldb::ValueObjectSP result_valobj_sp = thread_plan_sp->GetReturnValueObject(); - if (result_valobj_sp) - { - const lldb::addr_t pthread_key_data = result_valobj_sp->GetValueAsUnsigned(0); - if (pthread_key_data) - { - m_tid_to_tls_map[tid].insert(std::make_pair(pthread_key, pthread_key_data)); - return pthread_key_data + tls_offset; - } - } - } - } +DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, + const lldb::ThreadSP thread_sp, + lldb::addr_t tls_file_addr) { + if (!thread_sp || !module_sp) + return LLDB_INVALID_ADDRESS; + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + const uint32_t addr_size = m_process->GetAddressByteSize(); + uint8_t buf[sizeof(lldb::addr_t) * 3]; + + lldb_private::Address tls_addr; + if (module_sp->ResolveFileAddress(tls_file_addr, tls_addr)) { + Error error; + const size_t tsl_data_size = addr_size * 3; + Target &target = m_process->GetTarget(); + if (target.ReadMemory(tls_addr, false, buf, tsl_data_size, error) == + tsl_data_size) { + const ByteOrder byte_order = m_process->GetByteOrder(); + DataExtractor data(buf, sizeof(buf), byte_order, addr_size); + lldb::offset_t offset = addr_size; // Skip the first pointer + const lldb::addr_t pthread_key = data.GetAddress(&offset); + const lldb::addr_t tls_offset = data.GetAddress(&offset); + if (pthread_key != 0) { + // First check to see if we have already figured out the location + // of TLS data for the pthread_key on a specific thread yet. If we + // have we can re-use it since its location will not change unless + // the process execs. + const tid_t tid = thread_sp->GetID(); + auto tid_pos = m_tid_to_tls_map.find(tid); + if (tid_pos != m_tid_to_tls_map.end()) { + auto tls_pos = tid_pos->second.find(pthread_key); + if (tls_pos != tid_pos->second.end()) { + return tls_pos->second + tls_offset; + } + } + StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0); + if (frame_sp) { + ClangASTContext *clang_ast_context = + target.GetScratchClangASTContext(); + + if (!clang_ast_context) + return LLDB_INVALID_ADDRESS; + + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + Address pthread_getspecific_addr = GetPthreadSetSpecificAddress(); + if (pthread_getspecific_addr.IsValid()) { + EvaluateExpressionOptions options; + + lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction( + *thread_sp, pthread_getspecific_addr, clang_void_ptr_type, + llvm::ArrayRef<lldb::addr_t>(pthread_key), options)); + + DiagnosticManager execution_errors; + ExecutionContext exe_ctx(thread_sp); + lldb::ExpressionResults results = m_process->RunThreadPlan( + exe_ctx, thread_plan_sp, options, execution_errors); + + if (results == lldb::eExpressionCompleted) { + lldb::ValueObjectSP result_valobj_sp = + thread_plan_sp->GetReturnValueObject(); + if (result_valobj_sp) { + const lldb::addr_t pthread_key_data = + result_valobj_sp->GetValueAsUnsigned(0); + if (pthread_key_data) { + m_tid_to_tls_map[tid].insert( + std::make_pair(pthread_key, pthread_key_data)); + return pthread_key_data + tls_offset; } + } } + } } + } } - return LLDB_INVALID_ADDRESS; + } + return LLDB_INVALID_ADDRESS; } +bool DynamicLoaderDarwin::UseDYLDSPI(Process *process) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + uint32_t major, minor, update; + + bool use_new_spi_interface = false; + + if (process->GetHostOSVersion(major, minor, update)) { + const llvm::Triple::OSType os_type = + process->GetTarget().GetArchitecture().GetTriple().getOS(); + + // macOS 10.12 and newer + if (os_type == llvm::Triple::MacOSX && + (major > 10 || (major == 10 && minor >= 12))) { + use_new_spi_interface = true; + } + + // iOS 10 and newer + if (os_type == llvm::Triple::IOS && major >= 10) { + use_new_spi_interface = true; + } + + // tvOS 10 and newer + if (os_type == llvm::Triple::TvOS && major >= 10) { + use_new_spi_interface = true; + } + + // watchOS 3 and newer + if (os_type == llvm::Triple::WatchOS && major >= 3) { + use_new_spi_interface = true; + } + } + + if (log) { + if (use_new_spi_interface) + log->Printf( + "DynamicLoaderDarwin::UseDYLDSPI: Use new DynamicLoader plugin"); + else + log->Printf( + "DynamicLoaderDarwin::UseDYLDSPI: Use old DynamicLoader plugin"); + } + return use_new_spi_interface; +} diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h index b7dd51d288df..2daa58de0cf6 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h @@ -18,274 +18,226 @@ // Other libraries and framework includes // Project includes -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/UUID.h" -#include "lldb/Host/Mutex.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/SafeMachO.h" +#include "llvm/ADT/Triple.h" + namespace lldb_private { -class DynamicLoaderDarwin : public lldb_private::DynamicLoader -{ +class DynamicLoaderDarwin : public lldb_private::DynamicLoader { public: - DynamicLoaderDarwin(lldb_private::Process *process); + DynamicLoaderDarwin(lldb_private::Process *process); - virtual ~DynamicLoaderDarwin() override; + virtual ~DynamicLoaderDarwin() override; - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - void - DidAttach() override; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + void DidAttach() override; - void - DidLaunch() override; + void DidLaunch() override; - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan(lldb_private::Thread &thread, - bool stop_others) override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; - size_t - FindEquivalentSymbols(lldb_private::Symbol *original_symbol, - lldb_private::ModuleList &module_list, - lldb_private::SymbolContextList &equivalent_symbols) override; - - lldb::addr_t - GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) override; + size_t FindEquivalentSymbols( + lldb_private::Symbol *original_symbol, + lldb_private::ModuleList &module_list, + lldb_private::SymbolContextList &equivalent_symbols) override; - bool - AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override; + lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) override; - virtual void - DoInitialImageFetch () = 0; + bool AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override; - virtual bool - NeedToDoInitialImageFetch () = 0; + virtual void DoInitialImageFetch() = 0; + + virtual bool NeedToDoInitialImageFetch() = 0; protected: - void - PrivateInitialize (lldb_private::Process *process); - - void - PrivateProcessStateChanged (lldb_private::Process *process, - lldb::StateType state); - - void - Clear (bool clear_process); - - // Clear method for classes derived from this one - virtual void - DoClear () = 0; - - void - SetDYLDModule (lldb::ModuleSP &dyld_module_sp); - - lldb::ModuleSP - GetDYLDModule (); - - class Segment - { - public: - Segment() : - name(), - vmaddr(LLDB_INVALID_ADDRESS), - vmsize(0), - fileoff(0), - filesize(0), - maxprot(0), - initprot(0), - nsects(0), - flags(0) - { - } - - lldb_private::ConstString name; - lldb::addr_t vmaddr; - lldb::addr_t vmsize; - lldb::addr_t fileoff; - lldb::addr_t filesize; - uint32_t maxprot; - uint32_t initprot; - uint32_t nsects; - uint32_t flags; - - bool - operator==(const Segment& rhs) const - { - return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize; - } - - void - PutToLog (lldb_private::Log *log, - lldb::addr_t slide) const; - - }; - - struct ImageInfo - { - lldb::addr_t address; // Address of mach header for this dylib - lldb::addr_t slide; // The amount to slide all segments by if there is a global slide. - lldb::addr_t mod_date; // Modification date for this dylib - lldb_private::FileSpec file_spec; // Resolved path for this dylib - lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros - llvm::MachO::mach_header header; // The mach header for this image - std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for this executable (from memory of inferior) - uint32_t load_stop_id; // The process stop ID that the sections for this image were loaded - - ImageInfo() : - address(LLDB_INVALID_ADDRESS), - slide(0), - mod_date(0), - file_spec(), - uuid(), - header(), - segments(), - load_stop_id(0) - { - } - - void - Clear(bool load_cmd_data_only) - { - if (!load_cmd_data_only) - { - address = LLDB_INVALID_ADDRESS; - slide = 0; - mod_date = 0; - file_spec.Clear(); - ::memset (&header, 0, sizeof(header)); - } - uuid.Clear(); - segments.clear(); - load_stop_id = 0; - } - - bool - operator == (const ImageInfo& rhs) const - { - return address == rhs.address - && slide == rhs.slide - && mod_date == rhs.mod_date - && file_spec == rhs.file_spec - && uuid == rhs.uuid - && memcmp(&header, &rhs.header, sizeof(header)) == 0 - && segments == rhs.segments; - } - - bool - UUIDValid() const - { - return uuid.IsValid(); - } - - uint32_t - GetAddressByteSize () - { - if (header.cputype) - { - if (header.cputype & llvm::MachO::CPU_ARCH_ABI64) - return 8; - else - return 4; - } - return 0; - } - - lldb_private::ArchSpec - GetArchitecture () const - { - return lldb_private::ArchSpec (lldb_private::eArchTypeMachO, header.cputype, header.cpusubtype); - } - - const Segment * - FindSegment (const lldb_private::ConstString &name) const; - - void - PutToLog (lldb_private::Log *log) const; - - typedef std::vector<ImageInfo> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - }; - - bool - UpdateImageLoadAddress(lldb_private::Module *module, ImageInfo& info); - - bool - UnloadModuleSections (lldb_private::Module *module, ImageInfo& info); - - ImageInfo * - FindImageInfoForAddress (lldb::addr_t load_address); - - lldb::ModuleSP - FindTargetModuleForImageInfo (ImageInfo &image_info, - bool can_create, - bool *did_create_ptr); - - void - UnloadImages (const std::vector<lldb::addr_t> &solib_addresses); - - virtual bool - SetNotificationBreakpoint () = 0; - - virtual void - ClearNotificationBreakpoint () = 0; - - virtual bool - DidSetNotificationBreakpoint () = 0; - - typedef std::map<uint64_t, lldb::addr_t> PthreadKeyToTLSMap; - typedef std::map<lldb::user_id_t, PthreadKeyToTLSMap> ThreadIDToTLSMap; - - std::recursive_mutex & - GetMutex () const - { - return m_mutex; + void PrivateInitialize(lldb_private::Process *process); + + void PrivateProcessStateChanged(lldb_private::Process *process, + lldb::StateType state); + + void Clear(bool clear_process); + + // Clear method for classes derived from this one + virtual void DoClear() = 0; + + void SetDYLDModule(lldb::ModuleSP &dyld_module_sp); + + lldb::ModuleSP GetDYLDModule(); + + class Segment { + public: + Segment() + : name(), vmaddr(LLDB_INVALID_ADDRESS), vmsize(0), fileoff(0), + filesize(0), maxprot(0), initprot(0), nsects(0), flags(0) {} + + lldb_private::ConstString name; + lldb::addr_t vmaddr; + lldb::addr_t vmsize; + lldb::addr_t fileoff; + lldb::addr_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; + + bool operator==(const Segment &rhs) const { + return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize; } - lldb::ModuleSP - GetPThreadLibraryModule(); + void PutToLog(lldb_private::Log *log, lldb::addr_t slide) const; + }; + + struct ImageInfo { + lldb::addr_t address; // Address of mach header for this dylib + lldb::addr_t slide; // The amount to slide all segments by if there is a + // global slide. + lldb::addr_t mod_date; // Modification date for this dylib + lldb_private::FileSpec file_spec; // Resolved path for this dylib + lldb_private::UUID + uuid; // UUID for this dylib if it has one, else all zeros + llvm::MachO::mach_header header; // The mach header for this image + std::vector<Segment> segments; // All segment vmaddr and vmsize pairs for + // this executable (from memory of inferior) + uint32_t load_stop_id; // The process stop ID that the sections for this + // image were loaded + llvm::Triple::OSType os_type; // LC_VERSION_MIN_... load command os type + std::string min_version_os_sdk; // LC_VERSION_MIN_... sdk value + + ImageInfo() + : address(LLDB_INVALID_ADDRESS), slide(0), mod_date(0), file_spec(), + uuid(), header(), segments(), load_stop_id(0), + os_type(llvm::Triple::OSType::UnknownOS), min_version_os_sdk() {} + + void Clear(bool load_cmd_data_only) { + if (!load_cmd_data_only) { + address = LLDB_INVALID_ADDRESS; + slide = 0; + mod_date = 0; + file_spec.Clear(); + ::memset(&header, 0, sizeof(header)); + } + uuid.Clear(); + segments.clear(); + load_stop_id = 0; + os_type = llvm::Triple::OSType::UnknownOS; + min_version_os_sdk.clear(); + } + + bool operator==(const ImageInfo &rhs) const { + return address == rhs.address && slide == rhs.slide && + mod_date == rhs.mod_date && file_spec == rhs.file_spec && + uuid == rhs.uuid && + memcmp(&header, &rhs.header, sizeof(header)) == 0 && + segments == rhs.segments && os_type == rhs.os_type; + } + + bool UUIDValid() const { return uuid.IsValid(); } + + uint32_t GetAddressByteSize() { + if (header.cputype) { + if (header.cputype & llvm::MachO::CPU_ARCH_ABI64) + return 8; + else + return 4; + } + return 0; + } + + lldb_private::ArchSpec GetArchitecture() const { + return lldb_private::ArchSpec(lldb_private::eArchTypeMachO, + header.cputype, header.cpusubtype); + } + + const Segment *FindSegment(const lldb_private::ConstString &name) const; + + void PutToLog(lldb_private::Log *log) const; + + typedef std::vector<ImageInfo> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + }; + + bool UpdateImageLoadAddress(lldb_private::Module *module, ImageInfo &info); + + bool UnloadModuleSections(lldb_private::Module *module, ImageInfo &info); + + lldb::ModuleSP FindTargetModuleForImageInfo(ImageInfo &image_info, + bool can_create, + bool *did_create_ptr); + + void UnloadImages(const std::vector<lldb::addr_t> &solib_addresses); + + void UnloadAllImages(); + + virtual bool SetNotificationBreakpoint() = 0; + + virtual void ClearNotificationBreakpoint() = 0; + + virtual bool DidSetNotificationBreakpoint() = 0; + + typedef std::map<uint64_t, lldb::addr_t> PthreadKeyToTLSMap; + typedef std::map<lldb::user_id_t, PthreadKeyToTLSMap> ThreadIDToTLSMap; + + std::recursive_mutex &GetMutex() const { return m_mutex; } + + lldb::ModuleSP GetPThreadLibraryModule(); + + lldb_private::Address GetPthreadSetSpecificAddress(); - lldb_private::Address - GetPthreadSetSpecificAddress(); + bool JSONImageInformationIntoImageInfo( + lldb_private::StructuredData::ObjectSP image_details, + ImageInfo::collection &image_infos); - bool - JSONImageInformationIntoImageInfo (lldb_private::StructuredData::ObjectSP image_details, ImageInfo::collection &image_infos); + // If image_infos contains / may contain dyld or executable image, call this + // method + // to keep our internal record keeping of the special binaries up-to-date. + void + UpdateSpecialBinariesFromNewImageInfos(ImageInfo::collection &image_infos); - // If image_infos contains / may contain dyld image, call this method - // to keep our internal record keeping of the special dyld binary up-to-date. - void - UpdateDYLDImageInfoFromNewImageInfos (ImageInfo::collection &image_infos); + // if image_info is a dyld binary, call this method + void UpdateDYLDImageInfoFromNewImageInfo(ImageInfo &image_info); - // if image_info is a dyld binary, call this method - void - UpdateDYLDImageInfoFromNewImageInfo (ImageInfo &image_info); + // If image_infos contains / may contain executable image, call this method + // to keep our internal record keeping of the special dyld binary up-to-date. + void AddExecutableModuleIfInImageInfos(ImageInfo::collection &image_infos); - // If image_infos contains / may contain executable image, call this method - // to keep our internal record keeping of the special dyld binary up-to-date. - void - AddExecutableModuleIfInImageInfos (ImageInfo::collection &image_infos); + bool AddModulesUsingImageInfos(ImageInfo::collection &image_infos); - bool - AddModulesUsingImageInfos (ImageInfo::collection &image_infos); + // Whether we should use the new dyld SPI to get shared library information, + // or read + // it directly out of the dyld_all_image_infos. Whether we use the (newer) + // DynamicLoaderMacOS + // plugin or the (older) DynamicLoaderMacOSX plugin. + static bool UseDYLDSPI(lldb_private::Process *process); - lldb::ModuleWP m_dyld_module_wp; - lldb::ModuleWP m_libpthread_module_wp; - lldb_private::Address m_pthread_getspecific_addr; - ThreadIDToTLSMap m_tid_to_tls_map; - ImageInfo::collection m_dyld_image_infos; // Current shared libraries information - uint32_t m_dyld_image_infos_stop_id; // The process stop ID that "m_dyld_image_infos" is valid for - ImageInfo m_dyld; - mutable std::recursive_mutex m_mutex; + lldb::ModuleWP m_dyld_module_wp; // the dyld whose file type (mac, ios, etc) + // matches the process + lldb::ModuleWP m_libpthread_module_wp; + lldb_private::Address m_pthread_getspecific_addr; + ThreadIDToTLSMap m_tid_to_tls_map; + ImageInfo::collection + m_dyld_image_infos; // Current shared libraries information + uint32_t m_dyld_image_infos_stop_id; // The process stop ID that + // "m_dyld_image_infos" is valid for + ImageInfo m_dyld; + mutable std::recursive_mutex m_mutex; private: - DISALLOW_COPY_AND_ASSIGN (DynamicLoaderDarwin); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderDarwin); }; } // namespace lldb_private diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp new file mode 100644 index 000000000000..7b027de783ed --- /dev/null +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -0,0 +1,522 @@ +//===-- DynamicLoaderMacOS.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/State.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +#include "DynamicLoaderDarwin.h" +#include "DynamicLoaderMacOS.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Create an instance of this class. This function is filled into +// the plugin info class that gets handed out by the plugin factory and +// allows the lldb to instantiate an instance of this class. +//---------------------------------------------------------------------- +DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process, + bool force) { + bool create = force; + if (!create) { + create = true; + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + create = (object_file->GetStrata() == ObjectFile::eStrataUser); + } + } + + if (create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + switch (triple_ref.getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + create = triple_ref.getVendor() == llvm::Triple::Apple; + break; + default: + create = false; + break; + } + } + } + + if (UseDYLDSPI(process) == false) { + create = false; + } + + if (create) + return new DynamicLoaderMacOS(process); + return NULL; +} + +//---------------------------------------------------------------------- +// Constructor +//---------------------------------------------------------------------- +DynamicLoaderMacOS::DynamicLoaderMacOS(Process *process) + : DynamicLoaderDarwin(process), m_image_infos_stop_id(UINT32_MAX), + m_break_id(LLDB_INVALID_BREAK_ID), m_mutex() {} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +DynamicLoaderMacOS::~DynamicLoaderMacOS() { + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) + m_process->GetTarget().RemoveBreakpointByID(m_break_id); +} + +bool DynamicLoaderMacOS::ProcessDidExec() { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + bool did_exec = false; + if (m_process) { + // If we are stopped after an exec, we will have only one thread... + if (m_process->GetThreadList().GetSize() == 1) { + // See if we are stopped at '_dyld_start' + ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); + if (thread_sp) { + lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); + if (frame_sp) { + const Symbol *symbol = + frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; + if (symbol) { + if (symbol->GetName() == ConstString("_dyld_start")) + did_exec = true; + } + } + } + } + } + + if (did_exec) { + m_libpthread_module_wp.reset(); + m_pthread_getspecific_addr.Clear(); + } + return did_exec; +} + +//---------------------------------------------------------------------- +// Clear out the state of this class. +//---------------------------------------------------------------------- +void DynamicLoaderMacOS::DoClear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) + m_process->GetTarget().RemoveBreakpointByID(m_break_id); + + m_break_id = LLDB_INVALID_BREAK_ID; +} + +//---------------------------------------------------------------------- +// Check if we have found DYLD yet +//---------------------------------------------------------------------- +bool DynamicLoaderMacOS::DidSetNotificationBreakpoint() { + return LLDB_BREAK_ID_IS_VALID(m_break_id); +} + +void DynamicLoaderMacOS::ClearNotificationBreakpoint() { + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) { + m_process->GetTarget().RemoveBreakpointByID(m_break_id); + } +} + +//---------------------------------------------------------------------- +// Try and figure out where dyld is by first asking the Process +// if it knows (which currently calls down in the lldb::Process +// to get the DYLD info (available on SnowLeopard only). If that fails, +// then check in the default addresses. +//---------------------------------------------------------------------- +void DynamicLoaderMacOS::DoInitialImageFetch() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + StructuredData::ObjectSP all_image_info_json_sp( + m_process->GetLoadedDynamicLibrariesInfos()); + ImageInfo::collection image_infos; + if (all_image_info_json_sp.get() && + all_image_info_json_sp->GetAsDictionary() && + all_image_info_json_sp->GetAsDictionary()->HasKey("images") && + all_image_info_json_sp->GetAsDictionary() + ->GetValueForKey("images") + ->GetAsArray()) { + if (JSONImageInformationIntoImageInfo(all_image_info_json_sp, + image_infos)) { + if (log) + log->Printf("Initial module fetch: Adding %" PRId64 " modules.\n", + (uint64_t)image_infos.size()); + + UpdateSpecialBinariesFromNewImageInfos(image_infos); + AddModulesUsingImageInfos(image_infos); + } + } + + m_dyld_image_infos_stop_id = m_process->GetStopID(); +} + +bool DynamicLoaderMacOS::NeedToDoInitialImageFetch() { return true; } + +//---------------------------------------------------------------------- +// Static callback function that gets called when our DYLD notification +// breakpoint gets hit. We update all of our image infos and then +// let our super class DynamicLoader class decide if we should stop +// or not (based on global preference). +//---------------------------------------------------------------------- +bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + // Let the event know that the images have changed + // DYLD passes three arguments to the notification breakpoint. + // Arg1: enum dyld_notify_mode mode - 0 = adding, 1 = removing, 2 = remove all + // Arg2: unsigned long icount - Number of shared libraries + // added/removed + // Arg3: uint64_t mach_headers[] - Array of load addresses of binaries + // added/removed + + DynamicLoaderMacOS *dyld_instance = (DynamicLoaderMacOS *)baton; + + ExecutionContext exe_ctx(context->exe_ctx_ref); + Process *process = exe_ctx.GetProcessPtr(); + + // This is a sanity check just in case this dyld_instance is an old dyld + // plugin's breakpoint still lying around. + if (process != dyld_instance->m_process) + return false; + + if (dyld_instance->m_image_infos_stop_id != UINT32_MAX && + process->GetStopID() < dyld_instance->m_image_infos_stop_id) { + return false; + } + + const lldb::ABISP &abi = process->GetABI(); + if (abi) { + // Build up the value array to store the three arguments given above, then + // get the values from the ABI: + + ClangASTContext *clang_ast_context = + process->GetTarget().GetScratchClangASTContext(); + ValueList argument_values; + + Value mode_value; // enum dyld_notify_mode { dyld_notify_adding=0, + // dyld_notify_removing=1, dyld_notify_remove_all=2 }; + Value count_value; // unsigned long count + Value headers_value; // uint64_t machHeaders[] (aka void*) + + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + CompilerType clang_uint32_type = + clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( + lldb::eEncodingUint, 32); + CompilerType clang_uint64_type = + clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( + lldb::eEncodingUint, 32); + + mode_value.SetValueType(Value::eValueTypeScalar); + mode_value.SetCompilerType(clang_uint32_type); + + if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 4) { + count_value.SetValueType(Value::eValueTypeScalar); + count_value.SetCompilerType(clang_uint32_type); + } else { + count_value.SetValueType(Value::eValueTypeScalar); + count_value.SetCompilerType(clang_uint64_type); + } + + headers_value.SetValueType(Value::eValueTypeScalar); + headers_value.SetCompilerType(clang_void_ptr_type); + + argument_values.PushValue(mode_value); + argument_values.PushValue(count_value); + argument_values.PushValue(headers_value); + + if (abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values)) { + uint32_t dyld_mode = + argument_values.GetValueAtIndex(0)->GetScalar().UInt(-1); + if (dyld_mode != static_cast<uint32_t>(-1)) { + // Okay the mode was right, now get the number of elements, and the + // array of new elements... + uint32_t image_infos_count = + argument_values.GetValueAtIndex(1)->GetScalar().UInt(-1); + if (image_infos_count != static_cast<uint32_t>(-1)) { + addr_t header_array = + argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(-1); + if (header_array != static_cast<uint64_t>(-1)) { + std::vector<addr_t> image_load_addresses; + for (uint64_t i = 0; i < image_infos_count; i++) { + Error error; + addr_t addr = process->ReadUnsignedIntegerFromMemory( + header_array + (8 * i), 8, LLDB_INVALID_ADDRESS, error); + if (addr != LLDB_INVALID_ADDRESS) { + image_load_addresses.push_back(addr); + } + } + if (dyld_mode == 0) { + // dyld_notify_adding + dyld_instance->AddBinaries(image_load_addresses); + } else if (dyld_mode == 1) { + // dyld_notify_removing + dyld_instance->UnloadImages(image_load_addresses); + } else if (dyld_mode == 2) { + // dyld_notify_remove_all + dyld_instance->UnloadAllImages(); + } + } + } + } + } + } else { + process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( + "No ABI plugin located for triple %s -- shared libraries will not be " + "registered!\n", + process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); + } + + // Return true to stop the target, false to just let the target run + return dyld_instance->GetStopWhenImagesChange(); +} + +void DynamicLoaderMacOS::AddBinaries( + const std::vector<lldb::addr_t> &load_addresses) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + ImageInfo::collection image_infos; + + if (log) + log->Printf("Adding %" PRId64 " modules.", (uint64_t)load_addresses.size()); + StructuredData::ObjectSP binaries_info_sp = + m_process->GetLoadedDynamicLibrariesInfos(load_addresses); + if (binaries_info_sp.get() && binaries_info_sp->GetAsDictionary() && + binaries_info_sp->GetAsDictionary()->HasKey("images") && + binaries_info_sp->GetAsDictionary() + ->GetValueForKey("images") + ->GetAsArray() && + binaries_info_sp->GetAsDictionary() + ->GetValueForKey("images") + ->GetAsArray() + ->GetSize() == load_addresses.size()) { + if (JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) { + UpdateSpecialBinariesFromNewImageInfos(image_infos); + AddModulesUsingImageInfos(image_infos); + } + m_dyld_image_infos_stop_id = m_process->GetStopID(); + } +} + +// Dump the _dyld_all_image_infos members and all current image infos +// that we have parsed to the file handle provided. +//---------------------------------------------------------------------- +void DynamicLoaderMacOS::PutToLog(Log *log) const { + if (log == NULL) + return; +} + +bool DynamicLoaderMacOS::SetNotificationBreakpoint() { + if (m_break_id == LLDB_INVALID_BREAK_ID) { + ConstString g_symbol_name("_dyld_debugger_notification"); + const Symbol *symbol = nullptr; + ModuleSP dyld_sp(GetDYLDModule()); + if (dyld_sp) { + symbol = dyld_sp->FindFirstSymbolWithNameAndType(g_symbol_name, + eSymbolTypeCode); + } + if (symbol && + (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) { + addr_t symbol_address = + symbol->GetAddressRef().GetOpcodeLoadAddress(&m_process->GetTarget()); + if (symbol_address != LLDB_INVALID_ADDRESS) { + bool internal = true; + bool hardware = false; + Breakpoint *breakpoint = + m_process->GetTarget() + .CreateBreakpoint(symbol_address, internal, hardware) + .get(); + breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, + true); + breakpoint->SetBreakpointKind("shared-library-event"); + m_break_id = breakpoint->GetID(); + } + } + } + return m_break_id != LLDB_INVALID_BREAK_ID; +} + +addr_t +DynamicLoaderMacOS::GetDyldLockVariableAddressFromModule(Module *module) { + SymbolContext sc; + SymbolVendor *sym_vendor = module->GetSymbolVendor(); + Target &target = m_process->GetTarget(); + if (sym_vendor) { + Symtab *symtab = sym_vendor->GetSymtab(); + if (symtab) { + std::vector<uint32_t> match_indexes; + ConstString g_symbol_name("_dyld_global_lock_held"); + uint32_t num_matches = 0; + num_matches = + symtab->AppendSymbolIndexesWithName(g_symbol_name, match_indexes); + if (num_matches == 1) { + Symbol *symbol = symtab->SymbolAtIndex(match_indexes[0]); + if (symbol && + (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) { + return symbol->GetAddressRef().GetOpcodeLoadAddress(&target); + } + } + } + } + return LLDB_INVALID_ADDRESS; +} + +// Look for this symbol: +// +// int __attribute__((visibility("hidden"))) _dyld_global_lock_held = +// 0; +// +// in libdyld.dylib. +Error DynamicLoaderMacOS::CanLoadImage() { + Error error; + addr_t symbol_address = LLDB_INVALID_ADDRESS; + Target &target = m_process->GetTarget(); + const ModuleList &target_modules = target.GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); + const size_t num_modules = target_modules.GetSize(); + ConstString g_libdyld_name("libdyld.dylib"); + + // Find any modules named "libdyld.dylib" and look for the symbol there first + for (size_t i = 0; i < num_modules; i++) { + Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i); + if (module_pointer) { + if (module_pointer->GetFileSpec().GetFilename() == g_libdyld_name) { + symbol_address = GetDyldLockVariableAddressFromModule(module_pointer); + if (symbol_address != LLDB_INVALID_ADDRESS) + break; + } + } + } + + // Search through all modules looking for the symbol in them + if (symbol_address == LLDB_INVALID_ADDRESS) { + for (size_t i = 0; i < num_modules; i++) { + Module *module_pointer = + target_modules.GetModulePointerAtIndexUnlocked(i); + if (module_pointer) { + addr_t symbol_address = + GetDyldLockVariableAddressFromModule(module_pointer); + if (symbol_address != LLDB_INVALID_ADDRESS) + break; + } + } + } + + // Default assumption is that it is OK to load images. + // Only say that we cannot load images if we find the symbol in libdyld and it + // indicates that + // we cannot. + + if (symbol_address != LLDB_INVALID_ADDRESS) { + { + int lock_held = + m_process->ReadUnsignedIntegerFromMemory(symbol_address, 4, 0, error); + if (lock_held != 0) { + error.SetErrorToGenericError(); + } + } + } else { + // If we were unable to find _dyld_global_lock_held in any modules, or it is + // not loaded into + // memory yet, we may be at process startup (sitting at _dyld_start) - so we + // should not allow + // dlopen calls. + error.SetErrorToGenericError(); + } + return error; +} + +bool DynamicLoaderMacOS::GetSharedCacheInformation( + lldb::addr_t &base_address, UUID &uuid, LazyBool &using_shared_cache, + LazyBool &private_shared_cache) { + base_address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + using_shared_cache = eLazyBoolCalculate; + private_shared_cache = eLazyBoolCalculate; + + if (m_process) { + StructuredData::ObjectSP info = m_process->GetSharedCacheInfo(); + StructuredData::Dictionary *info_dict = nullptr; + if (info.get() && info->GetAsDictionary()) { + info_dict = info->GetAsDictionary(); + } + + // {"shared_cache_base_address":140735683125248,"shared_cache_uuid":"DDB8D70C-C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false} + + if (info_dict && info_dict->HasKey("shared_cache_uuid") && + info_dict->HasKey("no_shared_cache") && + info_dict->HasKey("shared_cache_base_address")) { + base_address = info_dict->GetValueForKey("shared_cache_base_address") + ->GetIntegerValue(LLDB_INVALID_ADDRESS); + std::string uuid_str = + info_dict->GetValueForKey("shared_cache_uuid")->GetStringValue(); + if (!uuid_str.empty()) + uuid.SetFromCString(uuid_str.c_str()); + if (info_dict->GetValueForKey("no_shared_cache")->GetBooleanValue() == + false) + using_shared_cache = eLazyBoolYes; + else + using_shared_cache = eLazyBoolNo; + if (info_dict->GetValueForKey("shared_cache_private_cache") + ->GetBooleanValue()) + private_shared_cache = eLazyBoolYes; + else + private_shared_cache = eLazyBoolNo; + + return true; + } + } + return false; +} + +void DynamicLoaderMacOS::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} + +void DynamicLoaderMacOS::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString DynamicLoaderMacOS::GetPluginNameStatic() { + static ConstString g_name("macos-dyld"); + return g_name; +} + +const char *DynamicLoaderMacOS::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library loads/unloads " + "in MacOSX user processes."; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString DynamicLoaderMacOS::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t DynamicLoaderMacOS::GetPluginVersion() { return 1; } diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h new file mode 100644 index 000000000000..93273b13bb73 --- /dev/null +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h @@ -0,0 +1,117 @@ +//===-- DynamicLoaderMacOS.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS / +// watchOS) +// platforms late 2016 and newer, where lldb will call dyld SPI functions to get +// information about shared libraries, information about the shared cache, and +// the _dyld_debugger_notification function we put a breakpoint on give us an +// array of load addresses for solibs loaded and unloaded. The SPI will tell us +// about both dyld and the executable, in addition to all of the usual solibs. + +#ifndef liblldb_DynamicLoaderMacOS_h_ +#define liblldb_DynamicLoaderMacOS_h_ + +// C Includes +// C++ Includes +#include <mutex> +#include <vector> + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/StructuredData.h" +#include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/SafeMachO.h" + +#include "DynamicLoaderDarwin.h" + +class DynamicLoaderMacOS : public lldb_private::DynamicLoaderDarwin { +public: + DynamicLoaderMacOS(lldb_private::Process *process); + + virtual ~DynamicLoaderMacOS() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); + + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + bool ProcessDidExec() override; + + lldb_private::Error CanLoadImage() override; + + bool GetSharedCacheInformation( + lldb::addr_t &base_address, lldb_private::UUID &uuid, + lldb_private::LazyBool &using_shared_cache, + lldb_private::LazyBool &private_shared_cache) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + +protected: + void PutToLog(lldb_private::Log *log) const; + + void DoInitialImageFetch() override; + + bool NeedToDoInitialImageFetch() override; + + bool DidSetNotificationBreakpoint() override; + + void AddBinaries(const std::vector<lldb::addr_t> &load_addresses); + + void DoClear() override; + + static bool + NotifyBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + bool SetNotificationBreakpoint() override; + + void ClearNotificationBreakpoint() override; + + void UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos, + uint32_t infos_count, + bool update_executable); + + lldb::addr_t + GetDyldLockVariableAddressFromModule(lldb_private::Module *module); + + uint32_t m_image_infos_stop_id; // The Stop ID the last time we + // loaded/unloaded images + lldb::user_id_t m_break_id; + mutable std::recursive_mutex m_mutex; + +private: + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderMacOS); +}; + +#endif // liblldb_DynamicLoaderMacOS_h_ diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index a8bc216fb17e..9c5f1bce3bd3 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -20,21 +20,21 @@ #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" -#include "lldb/Target/StackFrame.h" -#include "DynamicLoaderMacOSXDYLD.h" #include "DynamicLoaderDarwin.h" +#include "DynamicLoaderMacOSXDYLD.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF #include <stdio.h> -#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) #endif @@ -48,164 +48,140 @@ using namespace lldb; using namespace lldb_private; - //---------------------------------------------------------------------- // Create an instance of this class. This function is filled into // the plugin info class that gets handed out by the plugin factory and // allows the lldb to instantiate an instance of this class. //---------------------------------------------------------------------- -DynamicLoader * -DynamicLoaderMacOSXDYLD::CreateInstance (Process* process, bool force) -{ - bool create = force; - if (!create) - { - create = true; - Module* exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - ObjectFile *object_file = exe_module->GetObjectFile(); - if (object_file) - { - create = (object_file->GetStrata() == ObjectFile::eStrataUser); - } - } - - if (create) - { - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - switch (triple_ref.getOS()) - { - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: - case llvm::Triple::IOS: - case llvm::Triple::TvOS: - case llvm::Triple::WatchOS: - create = triple_ref.getVendor() == llvm::Triple::Apple; - break; - default: - create = false; - break; - } - } +DynamicLoader *DynamicLoaderMacOSXDYLD::CreateInstance(Process *process, + bool force) { + bool create = force; + if (!create) { + create = true; + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + create = (object_file->GetStrata() == ObjectFile::eStrataUser); + } } - - if (create) - return new DynamicLoaderMacOSXDYLD (process); - return NULL; + + if (create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + switch (triple_ref.getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + create = triple_ref.getVendor() == llvm::Triple::Apple; + break; + default: + create = false; + break; + } + } + } + + if (UseDYLDSPI(process) == true) { + create = false; + } + + if (create) + return new DynamicLoaderMacOSXDYLD(process); + return NULL; } //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -DynamicLoaderMacOSXDYLD::DynamicLoaderMacOSXDYLD (Process* process) : - DynamicLoaderDarwin(process), - m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS), - m_dyld_all_image_infos(), - m_dyld_all_image_infos_stop_id (UINT32_MAX), - m_break_id(LLDB_INVALID_BREAK_ID), - m_mutex(), - m_process_image_addr_is_all_images_infos (false) -{ -} +DynamicLoaderMacOSXDYLD::DynamicLoaderMacOSXDYLD(Process *process) + : DynamicLoaderDarwin(process), + m_dyld_all_image_infos_addr(LLDB_INVALID_ADDRESS), + m_dyld_all_image_infos(), m_dyld_all_image_infos_stop_id(UINT32_MAX), + m_break_id(LLDB_INVALID_BREAK_ID), m_mutex(), + m_process_image_addr_is_all_images_infos(false) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -DynamicLoaderMacOSXDYLD::~DynamicLoaderMacOSXDYLD() -{ - if (LLDB_BREAK_ID_IS_VALID(m_break_id)) - m_process->GetTarget().RemoveBreakpointByID (m_break_id); +DynamicLoaderMacOSXDYLD::~DynamicLoaderMacOSXDYLD() { + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) + m_process->GetTarget().RemoveBreakpointByID(m_break_id); } -bool -DynamicLoaderMacOSXDYLD::ProcessDidExec () -{ - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - bool did_exec = false; - if (m_process) - { - // If we are stopped after an exec, we will have only one thread... - if (m_process->GetThreadList().GetSize() == 1) - { - // We know if a process has exec'ed if our "m_dyld_all_image_infos_addr" - // value differs from the Process' image info address. When a process - // execs itself it might cause a change if ASLR is enabled. - const addr_t shlib_addr = m_process->GetImageInfoAddress (); - if (m_process_image_addr_is_all_images_infos == true && shlib_addr != m_dyld_all_image_infos_addr) - { - // The image info address from the process is the 'dyld_all_image_infos' - // address and it has changed. - did_exec = true; - } - else if (m_process_image_addr_is_all_images_infos == false && shlib_addr == m_dyld.address) - { - // The image info address from the process is the mach_header - // address for dyld and it has changed. +bool DynamicLoaderMacOSXDYLD::ProcessDidExec() { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + bool did_exec = false; + if (m_process) { + // If we are stopped after an exec, we will have only one thread... + if (m_process->GetThreadList().GetSize() == 1) { + // We know if a process has exec'ed if our "m_dyld_all_image_infos_addr" + // value differs from the Process' image info address. When a process + // execs itself it might cause a change if ASLR is enabled. + const addr_t shlib_addr = m_process->GetImageInfoAddress(); + if (m_process_image_addr_is_all_images_infos == true && + shlib_addr != m_dyld_all_image_infos_addr) { + // The image info address from the process is the 'dyld_all_image_infos' + // address and it has changed. + did_exec = true; + } else if (m_process_image_addr_is_all_images_infos == false && + shlib_addr == m_dyld.address) { + // The image info address from the process is the mach_header + // address for dyld and it has changed. + did_exec = true; + } else { + // ASLR might be disabled and dyld could have ended up in the same + // location. We should try and detect if we are stopped at '_dyld_start' + ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); + if (thread_sp) { + lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); + if (frame_sp) { + const Symbol *symbol = + frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; + if (symbol) { + if (symbol->GetName() == ConstString("_dyld_start")) did_exec = true; } - else - { - // ASLR might be disabled and dyld could have ended up in the same - // location. We should try and detect if we are stopped at '_dyld_start' - ThreadSP thread_sp(m_process->GetThreadList().GetThreadAtIndex(0)); - if (thread_sp) - { - lldb::StackFrameSP frame_sp(thread_sp->GetStackFrameAtIndex(0)); - if (frame_sp) - { - const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol; - if (symbol) - { - if (symbol->GetName() == ConstString("_dyld_start")) - did_exec = true; - } - } - } - } - - if (did_exec) - { - m_libpthread_module_wp.reset(); - m_pthread_getspecific_addr.Clear(); - } + } } + } + + if (did_exec) { + m_libpthread_module_wp.reset(); + m_pthread_getspecific_addr.Clear(); + } } - return did_exec; + } + return did_exec; } //---------------------------------------------------------------------- // Clear out the state of this class. //---------------------------------------------------------------------- -void -DynamicLoaderMacOSXDYLD::DoClear () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); +void DynamicLoaderMacOSXDYLD::DoClear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (LLDB_BREAK_ID_IS_VALID(m_break_id)) - m_process->GetTarget().RemoveBreakpointByID (m_break_id); + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) + m_process->GetTarget().RemoveBreakpointByID(m_break_id); - m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS; - m_dyld_all_image_infos.Clear(); - m_break_id = LLDB_INVALID_BREAK_ID; + m_dyld_all_image_infos_addr = LLDB_INVALID_ADDRESS; + m_dyld_all_image_infos.Clear(); + m_break_id = LLDB_INVALID_BREAK_ID; } //---------------------------------------------------------------------- // Check if we have found DYLD yet //---------------------------------------------------------------------- -bool -DynamicLoaderMacOSXDYLD::DidSetNotificationBreakpoint() -{ - return LLDB_BREAK_ID_IS_VALID (m_break_id); +bool DynamicLoaderMacOSXDYLD::DidSetNotificationBreakpoint() { + return LLDB_BREAK_ID_IS_VALID(m_break_id); } -void -DynamicLoaderMacOSXDYLD::ClearNotificationBreakpoint () -{ - if (LLDB_BREAK_ID_IS_VALID (m_break_id)) - { - m_process->GetTarget().RemoveBreakpointByID (m_break_id); - } +void DynamicLoaderMacOSXDYLD::ClearNotificationBreakpoint() { + if (LLDB_BREAK_ID_IS_VALID(m_break_id)) { + m_process->GetTarget().RemoveBreakpointByID(m_break_id); + } } //---------------------------------------------------------------------- @@ -214,142 +190,127 @@ DynamicLoaderMacOSXDYLD::ClearNotificationBreakpoint () // to get the DYLD info (available on SnowLeopard only). If that fails, // then check in the default addresses. //---------------------------------------------------------------------- -void -DynamicLoaderMacOSXDYLD::DoInitialImageFetch() -{ - if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS) - { - // Check the image info addr as it might point to the - // mach header for dyld, or it might point to the - // dyld_all_image_infos struct - const addr_t shlib_addr = m_process->GetImageInfoAddress (); - if (shlib_addr != LLDB_INVALID_ADDRESS) - { - ByteOrder byte_order = m_process->GetTarget().GetArchitecture().GetByteOrder(); - uint8_t buf[4]; - DataExtractor data (buf, sizeof(buf), byte_order, 4); - Error error; - if (m_process->ReadMemory (shlib_addr, buf, 4, error) == 4) - { - lldb::offset_t offset = 0; - uint32_t magic = data.GetU32 (&offset); - switch (magic) - { - case llvm::MachO::MH_MAGIC: - case llvm::MachO::MH_MAGIC_64: - case llvm::MachO::MH_CIGAM: - case llvm::MachO::MH_CIGAM_64: - m_process_image_addr_is_all_images_infos = false; - ReadDYLDInfoFromMemoryAndSetNotificationCallback(shlib_addr); - return; - - default: - break; - } - } - // Maybe it points to the all image infos? - m_dyld_all_image_infos_addr = shlib_addr; - m_process_image_addr_is_all_images_infos = true; - } - } +void DynamicLoaderMacOSXDYLD::DoInitialImageFetch() { + if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS) { + // Check the image info addr as it might point to the + // mach header for dyld, or it might point to the + // dyld_all_image_infos struct + const addr_t shlib_addr = m_process->GetImageInfoAddress(); + if (shlib_addr != LLDB_INVALID_ADDRESS) { + ByteOrder byte_order = + m_process->GetTarget().GetArchitecture().GetByteOrder(); + uint8_t buf[4]; + DataExtractor data(buf, sizeof(buf), byte_order, 4); + Error error; + if (m_process->ReadMemory(shlib_addr, buf, 4, error) == 4) { + lldb::offset_t offset = 0; + uint32_t magic = data.GetU32(&offset); + switch (magic) { + case llvm::MachO::MH_MAGIC: + case llvm::MachO::MH_MAGIC_64: + case llvm::MachO::MH_CIGAM: + case llvm::MachO::MH_CIGAM_64: + m_process_image_addr_is_all_images_infos = false; + ReadDYLDInfoFromMemoryAndSetNotificationCallback(shlib_addr); + return; - if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) - { - if (ReadAllImageInfosStructure ()) - { - if (m_dyld_all_image_infos.dyldImageLoadAddress != LLDB_INVALID_ADDRESS) - ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos.dyldImageLoadAddress); - else - ReadDYLDInfoFromMemoryAndSetNotificationCallback (m_dyld_all_image_infos_addr & 0xfffffffffff00000ull); - return; + default: + break; } + } + // Maybe it points to the all image infos? + m_dyld_all_image_infos_addr = shlib_addr; + m_process_image_addr_is_all_images_infos = true; } - - // Check some default values - Module *executable = m_process->GetTarget().GetExecutableModulePointer(); - - if (executable) - { - const ArchSpec &exe_arch = executable->GetArchitecture(); - if (exe_arch.GetAddressByteSize() == 8) - { - ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull); - } - else if (exe_arch.GetMachine() == llvm::Triple::arm || exe_arch.GetMachine() == llvm::Triple::thumb || exe_arch.GetMachine() == llvm::Triple::aarch64) - { - ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000); - } - else - { - ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x8fe00000); - } + } + + if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) { + if (ReadAllImageInfosStructure()) { + if (m_dyld_all_image_infos.dyldImageLoadAddress != LLDB_INVALID_ADDRESS) + ReadDYLDInfoFromMemoryAndSetNotificationCallback( + m_dyld_all_image_infos.dyldImageLoadAddress); + else + ReadDYLDInfoFromMemoryAndSetNotificationCallback( + m_dyld_all_image_infos_addr & 0xfffffffffff00000ull); + return; } - return; + } + + // Check some default values + Module *executable = m_process->GetTarget().GetExecutableModulePointer(); + + if (executable) { + const ArchSpec &exe_arch = executable->GetArchitecture(); + if (exe_arch.GetAddressByteSize() == 8) { + ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x7fff5fc00000ull); + } else if (exe_arch.GetMachine() == llvm::Triple::arm || + exe_arch.GetMachine() == llvm::Triple::thumb || + exe_arch.GetMachine() == llvm::Triple::aarch64) { + ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x2fe00000); + } else { + ReadDYLDInfoFromMemoryAndSetNotificationCallback(0x8fe00000); + } + } + return; } //---------------------------------------------------------------------- // Assume that dyld is in memory at ADDR and try to parse it's load // commands //---------------------------------------------------------------------- -bool -DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr) -{ - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - DataExtractor data; // Load command data - if (ReadMachHeader (addr, &m_dyld.header, &data)) - { - if (m_dyld.header.filetype == llvm::MachO::MH_DYLINKER) - { - m_dyld.address = addr; - ModuleSP dyld_module_sp; - if (ParseLoadCommands (data, m_dyld, &m_dyld.file_spec)) - { - if (m_dyld.file_spec) - { - UpdateDYLDImageInfoFromNewImageInfo (m_dyld); - - } - } - dyld_module_sp = GetDYLDModule(); - - Target &target = m_process->GetTarget(); - - if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS && dyld_module_sp.get()) - { - static ConstString g_dyld_all_image_infos ("dyld_all_image_infos"); - const Symbol *symbol = dyld_module_sp->FindFirstSymbolWithNameAndType (g_dyld_all_image_infos, eSymbolTypeData); - if (symbol) - m_dyld_all_image_infos_addr = symbol->GetLoadAddress(&target); - } - - // Update all image infos - InitializeFromAllImageInfos (); - - // If we didn't have an executable before, but now we do, then the - // dyld module shared pointer might be unique and we may need to add - // it again (since Target::SetExecutableModule() will clear the - // images). So append the dyld module back to the list if it is - /// unique! - if (dyld_module_sp) - { - target.GetImages().AppendIfNeeded (dyld_module_sp); - - // At this point we should have read in dyld's module, and so we should set breakpoints in it: - ModuleList modules; - modules.Append(dyld_module_sp); - target.ModulesDidLoad(modules); - SetDYLDModule (dyld_module_sp); - } - return true; +bool DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback( + lldb::addr_t addr) { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + DataExtractor data; // Load command data + static ConstString g_dyld_all_image_infos("dyld_all_image_infos"); + if (ReadMachHeader(addr, &m_dyld.header, &data)) { + if (m_dyld.header.filetype == llvm::MachO::MH_DYLINKER) { + m_dyld.address = addr; + ModuleSP dyld_module_sp; + if (ParseLoadCommands(data, m_dyld, &m_dyld.file_spec)) { + if (m_dyld.file_spec) { + UpdateDYLDImageInfoFromNewImageInfo(m_dyld); } + } + dyld_module_sp = GetDYLDModule(); + + Target &target = m_process->GetTarget(); + + if (m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS && + dyld_module_sp.get()) { + const Symbol *symbol = dyld_module_sp->FindFirstSymbolWithNameAndType( + g_dyld_all_image_infos, eSymbolTypeData); + if (symbol) + m_dyld_all_image_infos_addr = symbol->GetLoadAddress(&target); + } + + // Update all image infos + InitializeFromAllImageInfos(); + + // If we didn't have an executable before, but now we do, then the + // dyld module shared pointer might be unique and we may need to add + // it again (since Target::SetExecutableModule() will clear the + // images). So append the dyld module back to the list if it is + /// unique! + if (dyld_module_sp) { + target.GetImages().AppendIfNeeded(dyld_module_sp); + + // At this point we should have read in dyld's module, and so we should + // set breakpoints in it: + ModuleList modules; + modules.Append(dyld_module_sp); + target.ModulesDidLoad(modules); + SetDYLDModule(dyld_module_sp); + } + + return true; } - return false; + } + return false; } -bool -DynamicLoaderMacOSXDYLD::NeedToDoInitialImageFetch () -{ - return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS; +bool DynamicLoaderMacOSXDYLD::NeedToDoInitialImageFetch() { + return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS; } //---------------------------------------------------------------------- @@ -358,392 +319,397 @@ DynamicLoaderMacOSXDYLD::NeedToDoInitialImageFetch () // let our super class DynamicLoader class decide if we should stop // or not (based on global preference). //---------------------------------------------------------------------- -bool -DynamicLoaderMacOSXDYLD::NotifyBreakpointHit (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) -{ - // Let the event know that the images have changed - // DYLD passes three arguments to the notification breakpoint. - // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing - // Arg2: uint32_t infoCount - Number of shared libraries added - // Arg3: dyld_image_info info[] - Array of structs of the form: - // const struct mach_header *imageLoadAddress - // const char *imageFilePath - // uintptr_t imageFileModDate (a time_t) - - DynamicLoaderMacOSXDYLD* dyld_instance = (DynamicLoaderMacOSXDYLD*) baton; - - // First step is to see if we've already initialized the all image infos. If we haven't then this function - // will do so and return true. In the course of initializing the all_image_infos it will read the complete - // current state, so we don't need to figure out what has changed from the data passed in to us. - - ExecutionContext exe_ctx (context->exe_ctx_ref); - Process *process = exe_ctx.GetProcessPtr(); - - // This is a sanity check just in case this dyld_instance is an old dyld plugin's breakpoint still lying around. - if (process != dyld_instance->m_process) - return false; - - if (dyld_instance->InitializeFromAllImageInfos()) - return dyld_instance->GetStopWhenImagesChange(); - - const lldb::ABISP &abi = process->GetABI(); - if (abi) - { - // Build up the value array to store the three arguments given above, then get the values from the ABI: - - ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); - ValueList argument_values; - Value input_value; - - CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - CompilerType clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 32); - input_value.SetValueType (Value::eValueTypeScalar); - input_value.SetCompilerType (clang_uint32_type); -// input_value.SetContext (Value::eContextTypeClangType, clang_uint32_type); - argument_values.PushValue (input_value); - argument_values.PushValue (input_value); - input_value.SetCompilerType (clang_void_ptr_type); - // input_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type); - argument_values.PushValue (input_value); - - if (abi->GetArgumentValues (exe_ctx.GetThreadRef(), argument_values)) - { - uint32_t dyld_mode = argument_values.GetValueAtIndex(0)->GetScalar().UInt (-1); - if (dyld_mode != static_cast<uint32_t>(-1)) - { - // Okay the mode was right, now get the number of elements, and the array of new elements... - uint32_t image_infos_count = argument_values.GetValueAtIndex(1)->GetScalar().UInt (-1); - if (image_infos_count != static_cast<uint32_t>(-1)) - { - // Got the number added, now go through the array of added elements, putting out the mach header - // address, and adding the image. - // Note, I'm not putting in logging here, since the AddModules & RemoveModules functions do - // all the logging internally. - - lldb::addr_t image_infos_addr = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(); - if (dyld_mode == 0) - { - // This is add: - dyld_instance->AddModulesUsingImageInfosAddress (image_infos_addr, image_infos_count); - } - else - { - // This is remove: - dyld_instance->RemoveModulesUsingImageInfosAddress (image_infos_addr, image_infos_count); - } - - } - } +bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + // Let the event know that the images have changed + // DYLD passes three arguments to the notification breakpoint. + // Arg1: enum dyld_image_mode mode - 0 = adding, 1 = removing + // Arg2: uint32_t infoCount - Number of shared libraries added + // Arg3: dyld_image_info info[] - Array of structs of the form: + // const struct mach_header + // *imageLoadAddress + // const char *imageFilePath + // uintptr_t imageFileModDate (a time_t) + + DynamicLoaderMacOSXDYLD *dyld_instance = (DynamicLoaderMacOSXDYLD *)baton; + + // First step is to see if we've already initialized the all image infos. If + // we haven't then this function + // will do so and return true. In the course of initializing the + // all_image_infos it will read the complete + // current state, so we don't need to figure out what has changed from the + // data passed in to us. + + ExecutionContext exe_ctx(context->exe_ctx_ref); + Process *process = exe_ctx.GetProcessPtr(); + + // This is a sanity check just in case this dyld_instance is an old dyld + // plugin's breakpoint still lying around. + if (process != dyld_instance->m_process) + return false; + + if (dyld_instance->InitializeFromAllImageInfos()) + return dyld_instance->GetStopWhenImagesChange(); + + const lldb::ABISP &abi = process->GetABI(); + if (abi) { + // Build up the value array to store the three arguments given above, then + // get the values from the ABI: + + ClangASTContext *clang_ast_context = + process->GetTarget().GetScratchClangASTContext(); + ValueList argument_values; + Value input_value; + + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + CompilerType clang_uint32_type = + clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( + lldb::eEncodingUint, 32); + input_value.SetValueType(Value::eValueTypeScalar); + input_value.SetCompilerType(clang_uint32_type); + // input_value.SetContext (Value::eContextTypeClangType, + // clang_uint32_type); + argument_values.PushValue(input_value); + argument_values.PushValue(input_value); + input_value.SetCompilerType(clang_void_ptr_type); + // input_value.SetContext (Value::eContextTypeClangType, + // clang_void_ptr_type); + argument_values.PushValue(input_value); + + if (abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values)) { + uint32_t dyld_mode = + argument_values.GetValueAtIndex(0)->GetScalar().UInt(-1); + if (dyld_mode != static_cast<uint32_t>(-1)) { + // Okay the mode was right, now get the number of elements, and the + // array of new elements... + uint32_t image_infos_count = + argument_values.GetValueAtIndex(1)->GetScalar().UInt(-1); + if (image_infos_count != static_cast<uint32_t>(-1)) { + // Got the number added, now go through the array of added elements, + // putting out the mach header + // address, and adding the image. + // Note, I'm not putting in logging here, since the AddModules & + // RemoveModules functions do + // all the logging internally. + + lldb::addr_t image_infos_addr = + argument_values.GetValueAtIndex(2)->GetScalar().ULongLong(); + if (dyld_mode == 0) { + // This is add: + dyld_instance->AddModulesUsingImageInfosAddress(image_infos_addr, + image_infos_count); + } else { + // This is remove: + dyld_instance->RemoveModulesUsingImageInfosAddress( + image_infos_addr, image_infos_count); + } } + } } - else - { - process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf("No ABI plugin located for triple %s -- shared libraries will not be registered!\n", process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); - } - - // Return true to stop the target, false to just let the target run - return dyld_instance->GetStopWhenImagesChange(); + } else { + process->GetTarget().GetDebugger().GetAsyncErrorStream()->Printf( + "No ABI plugin located for triple %s -- shared libraries will not be " + "registered!\n", + process->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()); + } + + // Return true to stop the target, false to just let the target run + return dyld_instance->GetStopWhenImagesChange(); } -bool -DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); +bool DynamicLoaderMacOSXDYLD::ReadAllImageInfosStructure() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); - // the all image infos is already valid for this process stop ID - if (m_process->GetStopID() == m_dyld_all_image_infos_stop_id) - return true; + // the all image infos is already valid for this process stop ID + if (m_process->GetStopID() == m_dyld_all_image_infos_stop_id) + return true; - m_dyld_all_image_infos.Clear(); - if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) - { - ByteOrder byte_order = m_process->GetTarget().GetArchitecture().GetByteOrder(); - uint32_t addr_size = 4; - if (m_dyld_all_image_infos_addr > UINT32_MAX) - addr_size = 8; + m_dyld_all_image_infos.Clear(); + if (m_dyld_all_image_infos_addr != LLDB_INVALID_ADDRESS) { + ByteOrder byte_order = + m_process->GetTarget().GetArchitecture().GetByteOrder(); + uint32_t addr_size = + m_process->GetTarget().GetArchitecture().GetAddressByteSize(); - uint8_t buf[256]; - DataExtractor data (buf, sizeof(buf), byte_order, addr_size); - lldb::offset_t offset = 0; + uint8_t buf[256]; + DataExtractor data(buf, sizeof(buf), byte_order, addr_size); + lldb::offset_t offset = 0; - const size_t count_v2 = sizeof (uint32_t) + // version - sizeof (uint32_t) + // infoArrayCount - addr_size + // infoArray - addr_size + // notification - addr_size + // processDetachedFromSharedRegion + libSystemInitialized + pad - addr_size; // dyldImageLoadAddress - const size_t count_v11 = count_v2 + - addr_size + // jitInfo - addr_size + // dyldVersion - addr_size + // errorMessage - addr_size + // terminationFlags - addr_size + // coreSymbolicationShmPage - addr_size + // systemOrderFlag - addr_size + // uuidArrayCount - addr_size + // uuidArray - addr_size + // dyldAllImageInfosAddress - addr_size + // initialImageCount - addr_size + // errorKind - addr_size + // errorClientOfDylibPath - addr_size + // errorTargetDylibPath - addr_size; // errorSymbol - const size_t count_v13 = count_v11 + - addr_size + // sharedCacheSlide - sizeof (uuid_t); // sharedCacheUUID - UNUSED_IF_ASSERT_DISABLED(count_v13); - assert (sizeof (buf) >= count_v13); - - Error error; - if (m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, 4, error) == 4) - { - m_dyld_all_image_infos.version = data.GetU32(&offset); - // If anything in the high byte is set, we probably got the byte - // order incorrect (the process might not have it set correctly - // yet due to attaching to a program without a specified file). - if (m_dyld_all_image_infos.version & 0xff000000) - { - // We have guessed the wrong byte order. Swap it and try - // reading the version again. - if (byte_order == eByteOrderLittle) - byte_order = eByteOrderBig; - else - byte_order = eByteOrderLittle; - - data.SetByteOrder (byte_order); - offset = 0; - m_dyld_all_image_infos.version = data.GetU32(&offset); - } - } + const size_t count_v2 = sizeof(uint32_t) + // version + sizeof(uint32_t) + // infoArrayCount + addr_size + // infoArray + addr_size + // notification + addr_size + // processDetachedFromSharedRegion + + // libSystemInitialized + pad + addr_size; // dyldImageLoadAddress + const size_t count_v11 = count_v2 + addr_size + // jitInfo + addr_size + // dyldVersion + addr_size + // errorMessage + addr_size + // terminationFlags + addr_size + // coreSymbolicationShmPage + addr_size + // systemOrderFlag + addr_size + // uuidArrayCount + addr_size + // uuidArray + addr_size + // dyldAllImageInfosAddress + addr_size + // initialImageCount + addr_size + // errorKind + addr_size + // errorClientOfDylibPath + addr_size + // errorTargetDylibPath + addr_size; // errorSymbol + const size_t count_v13 = count_v11 + addr_size + // sharedCacheSlide + sizeof(uuid_t); // sharedCacheUUID + UNUSED_IF_ASSERT_DISABLED(count_v13); + assert(sizeof(buf) >= count_v13); + + Error error; + if (m_process->ReadMemory(m_dyld_all_image_infos_addr, buf, 4, error) == + 4) { + m_dyld_all_image_infos.version = data.GetU32(&offset); + // If anything in the high byte is set, we probably got the byte + // order incorrect (the process might not have it set correctly + // yet due to attaching to a program without a specified file). + if (m_dyld_all_image_infos.version & 0xff000000) { + // We have guessed the wrong byte order. Swap it and try + // reading the version again. + if (byte_order == eByteOrderLittle) + byte_order = eByteOrderBig; else - { - return false; - } + byte_order = eByteOrderLittle; + + data.SetByteOrder(byte_order); + offset = 0; + m_dyld_all_image_infos.version = data.GetU32(&offset); + } + } else { + return false; + } - const size_t count = (m_dyld_all_image_infos.version >= 11) ? count_v11 : count_v2; - - const size_t bytes_read = m_process->ReadMemory (m_dyld_all_image_infos_addr, buf, count, error); - if (bytes_read == count) - { - offset = 0; - m_dyld_all_image_infos.version = data.GetU32(&offset); - m_dyld_all_image_infos.dylib_info_count = data.GetU32(&offset); - m_dyld_all_image_infos.dylib_info_addr = data.GetPointer(&offset); - m_dyld_all_image_infos.notification = data.GetPointer(&offset); - m_dyld_all_image_infos.processDetachedFromSharedRegion = data.GetU8(&offset); - m_dyld_all_image_infos.libSystemInitialized = data.GetU8(&offset); - // Adjust for padding. - offset += addr_size - 2; - m_dyld_all_image_infos.dyldImageLoadAddress = data.GetPointer(&offset); - if (m_dyld_all_image_infos.version >= 11) - { - offset += addr_size * 8; - uint64_t dyld_all_image_infos_addr = data.GetPointer(&offset); - - // When we started, we were given the actual address of the all_image_infos - // struct (probably via TASK_DYLD_INFO) in memory - this address is stored in - // m_dyld_all_image_infos_addr and is the most accurate address we have. - - // We read the dyld_all_image_infos struct from memory; it contains its own address. - // If the address in the struct does not match the actual address, - // the dyld we're looking at has been loaded at a different location (slid) from - // where it intended to load. The addresses in the dyld_all_image_infos struct - // are the original, non-slid addresses, and need to be adjusted. Most importantly - // the address of dyld and the notification address need to be adjusted. - - if (dyld_all_image_infos_addr != m_dyld_all_image_infos_addr) - { - uint64_t image_infos_offset = dyld_all_image_infos_addr - m_dyld_all_image_infos.dyldImageLoadAddress; - uint64_t notification_offset = m_dyld_all_image_infos.notification - m_dyld_all_image_infos.dyldImageLoadAddress; - m_dyld_all_image_infos.dyldImageLoadAddress = m_dyld_all_image_infos_addr - image_infos_offset; - m_dyld_all_image_infos.notification = m_dyld_all_image_infos.dyldImageLoadAddress + notification_offset; - } - } - m_dyld_all_image_infos_stop_id = m_process->GetStopID(); - return true; + const size_t count = + (m_dyld_all_image_infos.version >= 11) ? count_v11 : count_v2; + + const size_t bytes_read = + m_process->ReadMemory(m_dyld_all_image_infos_addr, buf, count, error); + if (bytes_read == count) { + offset = 0; + m_dyld_all_image_infos.version = data.GetU32(&offset); + m_dyld_all_image_infos.dylib_info_count = data.GetU32(&offset); + m_dyld_all_image_infos.dylib_info_addr = data.GetPointer(&offset); + m_dyld_all_image_infos.notification = data.GetPointer(&offset); + m_dyld_all_image_infos.processDetachedFromSharedRegion = + data.GetU8(&offset); + m_dyld_all_image_infos.libSystemInitialized = data.GetU8(&offset); + // Adjust for padding. + offset += addr_size - 2; + m_dyld_all_image_infos.dyldImageLoadAddress = data.GetPointer(&offset); + if (m_dyld_all_image_infos.version >= 11) { + offset += addr_size * 8; + uint64_t dyld_all_image_infos_addr = data.GetPointer(&offset); + + // When we started, we were given the actual address of the + // all_image_infos + // struct (probably via TASK_DYLD_INFO) in memory - this address is + // stored in + // m_dyld_all_image_infos_addr and is the most accurate address we have. + + // We read the dyld_all_image_infos struct from memory; it contains its + // own address. + // If the address in the struct does not match the actual address, + // the dyld we're looking at has been loaded at a different location + // (slid) from + // where it intended to load. The addresses in the dyld_all_image_infos + // struct + // are the original, non-slid addresses, and need to be adjusted. Most + // importantly + // the address of dyld and the notification address need to be adjusted. + + if (dyld_all_image_infos_addr != m_dyld_all_image_infos_addr) { + uint64_t image_infos_offset = + dyld_all_image_infos_addr - + m_dyld_all_image_infos.dyldImageLoadAddress; + uint64_t notification_offset = + m_dyld_all_image_infos.notification - + m_dyld_all_image_infos.dyldImageLoadAddress; + m_dyld_all_image_infos.dyldImageLoadAddress = + m_dyld_all_image_infos_addr - image_infos_offset; + m_dyld_all_image_infos.notification = + m_dyld_all_image_infos.dyldImageLoadAddress + notification_offset; } + } + m_dyld_all_image_infos_stop_id = m_process->GetStopID(); + return true; } - return false; + } + return false; } +bool DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress( + lldb::addr_t image_infos_addr, uint32_t image_infos_count) { + ImageInfo::collection image_infos; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("Adding %d modules.\n", image_infos_count); -bool -DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count) -{ - ImageInfo::collection image_infos; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf ("Adding %d modules.\n", image_infos_count); - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - if (m_process->GetStopID() == m_dyld_image_infos_stop_id) - return true; + std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + if (m_process->GetStopID() == m_dyld_image_infos_stop_id) + return true; - StructuredData::ObjectSP image_infos_json_sp = m_process->GetLoadedDynamicLibrariesInfos (image_infos_addr, image_infos_count); - if (image_infos_json_sp.get() - && image_infos_json_sp->GetAsDictionary() - && image_infos_json_sp->GetAsDictionary()->HasKey("images") - && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray() - && image_infos_json_sp->GetAsDictionary()->GetValueForKey("images")->GetAsArray()->GetSize() == image_infos_count) - { - bool return_value = false; - if (JSONImageInformationIntoImageInfo (image_infos_json_sp, image_infos)) - { - AddExecutableModuleIfInImageInfos (image_infos); - return_value = AddModulesUsingImageInfos (image_infos); - } - m_dyld_image_infos_stop_id = m_process->GetStopID(); - return return_value; + StructuredData::ObjectSP image_infos_json_sp = + m_process->GetLoadedDynamicLibrariesInfos(image_infos_addr, + image_infos_count); + if (image_infos_json_sp.get() && image_infos_json_sp->GetAsDictionary() && + image_infos_json_sp->GetAsDictionary()->HasKey("images") && + image_infos_json_sp->GetAsDictionary() + ->GetValueForKey("images") + ->GetAsArray() && + image_infos_json_sp->GetAsDictionary() + ->GetValueForKey("images") + ->GetAsArray() + ->GetSize() == image_infos_count) { + bool return_value = false; + if (JSONImageInformationIntoImageInfo(image_infos_json_sp, image_infos)) { + UpdateSpecialBinariesFromNewImageInfos(image_infos); + return_value = AddModulesUsingImageInfos(image_infos); } - - if (!ReadImageInfos (image_infos_addr, image_infos_count, image_infos)) - return false; - - UpdateImageInfosHeaderAndLoadCommands (image_infos, image_infos_count, false); - bool return_value = AddModulesUsingImageInfos (image_infos); m_dyld_image_infos_stop_id = m_process->GetStopID(); return return_value; + } + + if (!ReadImageInfos(image_infos_addr, image_infos_count, image_infos)) + return false; + + UpdateImageInfosHeaderAndLoadCommands(image_infos, image_infos_count, false); + bool return_value = AddModulesUsingImageInfos(image_infos); + m_dyld_image_infos_stop_id = m_process->GetStopID(); + return return_value; } -bool -DynamicLoaderMacOSXDYLD::RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count) -{ - ImageInfo::collection image_infos; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - if (m_process->GetStopID() == m_dyld_image_infos_stop_id) - return true; +bool DynamicLoaderMacOSXDYLD::RemoveModulesUsingImageInfosAddress( + lldb::addr_t image_infos_addr, uint32_t image_infos_count) { + ImageInfo::collection image_infos; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - // First read in the image_infos for the removed modules, and their headers & load commands. - if (!ReadImageInfos (image_infos_addr, image_infos_count, image_infos)) - { - if (log) - log->PutCString ("Failed reading image infos array."); - return false; - } - + std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + if (m_process->GetStopID() == m_dyld_image_infos_stop_id) + return true; + + // First read in the image_infos for the removed modules, and their headers & + // load commands. + if (!ReadImageInfos(image_infos_addr, image_infos_count, image_infos)) { if (log) - log->Printf ("Removing %d modules.", image_infos_count); - - ModuleList unloaded_module_list; - for (uint32_t idx = 0; idx < image_infos.size(); ++idx) - { - if (log) - { - log->Printf ("Removing module at address=0x%16.16" PRIx64 ".", image_infos[idx].address); - image_infos[idx].PutToLog (log); - } - - // Remove this image_infos from the m_all_image_infos. We do the comparison by address - // rather than by file spec because we can have many modules with the same "file spec" in the - // case that they are modules loaded from memory. - // - // Also copy over the uuid from the old entry to the removed entry so we can - // use it to lookup the module in the module list. - - ImageInfo::collection::iterator pos, end = m_dyld_image_infos.end(); - for (pos = m_dyld_image_infos.begin(); pos != end; pos++) - { - if (image_infos[idx].address == (*pos).address) - { - image_infos[idx].uuid = (*pos).uuid; - - // Add the module from this image_info to the "unloaded_module_list". We'll remove them all at - // one go later on. - - ModuleSP unload_image_module_sp (FindTargetModuleForImageInfo (image_infos[idx], false, NULL)); - if (unload_image_module_sp.get()) - { - // When we unload, be sure to use the image info from the old list, - // since that has sections correctly filled in. - UnloadModuleSections (unload_image_module_sp.get(), *pos); - unloaded_module_list.AppendIfNeeded (unload_image_module_sp); - } - else - { - if (log) - { - log->Printf ("Could not find module for unloading info entry:"); - image_infos[idx].PutToLog(log); - } - } - - // Then remove it from the m_dyld_image_infos: - - m_dyld_image_infos.erase(pos); - break; - } - } - - if (pos == end) - { - if (log) - { - log->Printf ("Could not find image_info entry for unloading image:"); - image_infos[idx].PutToLog(log); - } - } + log->PutCString("Failed reading image infos array."); + return false; + } + + if (log) + log->Printf("Removing %d modules.", image_infos_count); + + ModuleList unloaded_module_list; + for (uint32_t idx = 0; idx < image_infos.size(); ++idx) { + if (log) { + log->Printf("Removing module at address=0x%16.16" PRIx64 ".", + image_infos[idx].address); + image_infos[idx].PutToLog(log); } - if (unloaded_module_list.GetSize() > 0) - { - if (log) - { - log->PutCString("Unloaded:"); - unloaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderMacOSXDYLD::ModulesDidUnload"); + + // Remove this image_infos from the m_all_image_infos. We do the comparison + // by address + // rather than by file spec because we can have many modules with the same + // "file spec" in the + // case that they are modules loaded from memory. + // + // Also copy over the uuid from the old entry to the removed entry so we can + // use it to lookup the module in the module list. + + ImageInfo::collection::iterator pos, end = m_dyld_image_infos.end(); + for (pos = m_dyld_image_infos.begin(); pos != end; pos++) { + if (image_infos[idx].address == (*pos).address) { + image_infos[idx].uuid = (*pos).uuid; + + // Add the module from this image_info to the "unloaded_module_list". + // We'll remove them all at + // one go later on. + + ModuleSP unload_image_module_sp( + FindTargetModuleForImageInfo(image_infos[idx], false, NULL)); + if (unload_image_module_sp.get()) { + // When we unload, be sure to use the image info from the old list, + // since that has sections correctly filled in. + UnloadModuleSections(unload_image_module_sp.get(), *pos); + unloaded_module_list.AppendIfNeeded(unload_image_module_sp); + } else { + if (log) { + log->Printf("Could not find module for unloading info entry:"); + image_infos[idx].PutToLog(log); + } } - m_process->GetTarget().GetImages().Remove (unloaded_module_list); + + // Then remove it from the m_dyld_image_infos: + + m_dyld_image_infos.erase(pos); + break; + } } - m_dyld_image_infos_stop_id = m_process->GetStopID(); - return true; -} -bool -DynamicLoaderMacOSXDYLD::ReadImageInfos (lldb::addr_t image_infos_addr, - uint32_t image_infos_count, - ImageInfo::collection &image_infos) -{ - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - const ByteOrder endian = GetByteOrderFromMagic (m_dyld.header.magic); - const uint32_t addr_size = m_dyld.GetAddressByteSize(); - - image_infos.resize(image_infos_count); - const size_t count = image_infos.size() * 3 * addr_size; - DataBufferHeap info_data(count, 0); - Error error; - const size_t bytes_read = m_process->ReadMemory (image_infos_addr, - info_data.GetBytes(), - info_data.GetByteSize(), - error); - if (bytes_read == count) - { - lldb::offset_t info_data_offset = 0; - DataExtractor info_data_ref(info_data.GetBytes(), info_data.GetByteSize(), endian, addr_size); - for (size_t i = 0; i < image_infos.size() && info_data_ref.ValidOffset(info_data_offset); i++) - { - image_infos[i].address = info_data_ref.GetPointer(&info_data_offset); - lldb::addr_t path_addr = info_data_ref.GetPointer(&info_data_offset); - image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset); - - char raw_path[PATH_MAX]; - m_process->ReadCStringFromMemory (path_addr, raw_path, sizeof(raw_path), error); - // don't resolve the path - if (error.Success()) - { - const bool resolve_path = false; - image_infos[i].file_spec.SetFile(raw_path, resolve_path); - } - } - return true; + if (pos == end) { + if (log) { + log->Printf("Could not find image_info entry for unloading image:"); + image_infos[idx].PutToLog(log); + } } - else - { - return false; + } + if (unloaded_module_list.GetSize() > 0) { + if (log) { + log->PutCString("Unloaded:"); + unloaded_module_list.LogUUIDAndPaths( + log, "DynamicLoaderMacOSXDYLD::ModulesDidUnload"); + } + m_process->GetTarget().GetImages().Remove(unloaded_module_list); + } + m_dyld_image_infos_stop_id = m_process->GetStopID(); + return true; +} + +bool DynamicLoaderMacOSXDYLD::ReadImageInfos( + lldb::addr_t image_infos_addr, uint32_t image_infos_count, + ImageInfo::collection &image_infos) { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + const ByteOrder endian = GetByteOrderFromMagic(m_dyld.header.magic); + const uint32_t addr_size = m_dyld.GetAddressByteSize(); + + image_infos.resize(image_infos_count); + const size_t count = image_infos.size() * 3 * addr_size; + DataBufferHeap info_data(count, 0); + Error error; + const size_t bytes_read = m_process->ReadMemory( + image_infos_addr, info_data.GetBytes(), info_data.GetByteSize(), error); + if (bytes_read == count) { + lldb::offset_t info_data_offset = 0; + DataExtractor info_data_ref(info_data.GetBytes(), info_data.GetByteSize(), + endian, addr_size); + for (size_t i = 0; + i < image_infos.size() && info_data_ref.ValidOffset(info_data_offset); + i++) { + image_infos[i].address = info_data_ref.GetPointer(&info_data_offset); + lldb::addr_t path_addr = info_data_ref.GetPointer(&info_data_offset); + image_infos[i].mod_date = info_data_ref.GetPointer(&info_data_offset); + + char raw_path[PATH_MAX]; + m_process->ReadCStringFromMemory(path_addr, raw_path, sizeof(raw_path), + error); + // don't resolve the path + if (error.Success()) { + const bool resolve_path = false; + image_infos[i].file_spec.SetFile(raw_path, resolve_path); + } } + return true; + } else { + return false; + } } //---------------------------------------------------------------------- @@ -753,74 +719,68 @@ DynamicLoaderMacOSXDYLD::ReadImageInfos (lldb::addr_t image_infos_addr, // we're reading the dyld infos. Return true if we actually read anything, // and false otherwise. //---------------------------------------------------------------------- -bool -DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos () -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - if (m_process->GetStopID() == m_dyld_image_infos_stop_id - || m_dyld_image_infos.size() != 0) - return false; - - if (ReadAllImageInfosStructure ()) - { - // Nothing to load or unload? - if (m_dyld_all_image_infos.dylib_info_count == 0) - return true; - - if (m_dyld_all_image_infos.dylib_info_addr == 0) - { - // DYLD is updating the images now. So we should say we have no images, and then we'll - // figure it out when we hit the added breakpoint. - return false; - } - else - { - if (!AddModulesUsingImageInfosAddress (m_dyld_all_image_infos.dylib_info_addr, - m_dyld_all_image_infos.dylib_info_count)) - { - DEBUG_PRINTF("%s", "unable to read all data for all_dylib_infos."); - m_dyld_image_infos.clear(); - } - } +bool DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - // Now we have one more bit of business. If there is a library left in the images for our target that - // doesn't have a load address, then it must be something that we were expecting to load (for instance we - // read a load command for it) but it didn't in fact load - probably because DYLD_*_PATH pointed - // to an equivalent version. We don't want it to stay in the target's module list or it will confuse - // us, so unload it here. - Target &target = m_process->GetTarget(); - const ModuleList &target_modules = target.GetImages(); - ModuleList not_loaded_modules; - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - - size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) - { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked (i); - if (!module_sp->IsLoadedInTarget (&target)) - { - if (log) - { - StreamString s; - module_sp->GetDescription (&s); - log->Printf ("Unloading pre-run module: %s.", s.GetData ()); - } - not_loaded_modules.Append (module_sp); - } - } - - if (not_loaded_modules.GetSize() != 0) - { - target.GetImages().Remove(not_loaded_modules); + std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + if (m_process->GetStopID() == m_dyld_image_infos_stop_id || + m_dyld_image_infos.size() != 0) + return false; + + if (ReadAllImageInfosStructure()) { + // Nothing to load or unload? + if (m_dyld_all_image_infos.dylib_info_count == 0) + return true; + + if (m_dyld_all_image_infos.dylib_info_addr == 0) { + // DYLD is updating the images now. So we should say we have no images, + // and then we'll + // figure it out when we hit the added breakpoint. + return false; + } else { + if (!AddModulesUsingImageInfosAddress( + m_dyld_all_image_infos.dylib_info_addr, + m_dyld_all_image_infos.dylib_info_count)) { + DEBUG_PRINTF("%s", "unable to read all data for all_dylib_infos."); + m_dyld_image_infos.clear(); + } + } + + // Now we have one more bit of business. If there is a library left in the + // images for our target that + // doesn't have a load address, then it must be something that we were + // expecting to load (for instance we + // read a load command for it) but it didn't in fact load - probably because + // DYLD_*_PATH pointed + // to an equivalent version. We don't want it to stay in the target's + // module list or it will confuse + // us, so unload it here. + Target &target = m_process->GetTarget(); + const ModuleList &target_modules = target.GetImages(); + ModuleList not_loaded_modules; + std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); + + size_t num_modules = target_modules.GetSize(); + for (size_t i = 0; i < num_modules; i++) { + ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + if (!module_sp->IsLoadedInTarget(&target)) { + if (log) { + StreamString s; + module_sp->GetDescription(&s); + log->Printf("Unloading pre-run module: %s.", s.GetData()); } + not_loaded_modules.Append(module_sp); + } + } - return true; + if (not_loaded_modules.GetSize() != 0) { + target.GetImages().Remove(not_loaded_modules); } - else - return false; + + return true; + } else + return false; } //---------------------------------------------------------------------- @@ -829,166 +789,161 @@ DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos () // // Returns true if we succeed, false if we fail for any reason. //---------------------------------------------------------------------- -bool -DynamicLoaderMacOSXDYLD::ReadMachHeader (lldb::addr_t addr, llvm::MachO::mach_header *header, DataExtractor *load_command_data) -{ - DataBufferHeap header_bytes(sizeof(llvm::MachO::mach_header), 0); - Error error; - size_t bytes_read = m_process->ReadMemory (addr, - header_bytes.GetBytes(), - header_bytes.GetByteSize(), - error); - if (bytes_read == sizeof(llvm::MachO::mach_header)) - { - lldb::offset_t offset = 0; - ::memset (header, 0, sizeof(llvm::MachO::mach_header)); - - // Get the magic byte unswapped so we can figure out what we are dealing with - DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), endian::InlHostByteOrder(), 4); - header->magic = data.GetU32(&offset); - lldb::addr_t load_cmd_addr = addr; - data.SetByteOrder(DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header->magic)); - switch (header->magic) - { - case llvm::MachO::MH_MAGIC: - case llvm::MachO::MH_CIGAM: - data.SetAddressByteSize(4); - load_cmd_addr += sizeof(llvm::MachO::mach_header); - break; - - case llvm::MachO::MH_MAGIC_64: - case llvm::MachO::MH_CIGAM_64: - data.SetAddressByteSize(8); - load_cmd_addr += sizeof(llvm::MachO::mach_header_64); - break; - - default: - return false; - } - - // Read the rest of dyld's mach header - if (data.GetU32(&offset, &header->cputype, (sizeof(llvm::MachO::mach_header)/sizeof(uint32_t)) - 1)) - { - if (load_command_data == NULL) - return true; // We were able to read the mach_header and weren't asked to read the load command bytes - - DataBufferSP load_cmd_data_sp(new DataBufferHeap(header->sizeofcmds, 0)); - - size_t load_cmd_bytes_read = m_process->ReadMemory (load_cmd_addr, - load_cmd_data_sp->GetBytes(), - load_cmd_data_sp->GetByteSize(), - error); - - if (load_cmd_bytes_read == header->sizeofcmds) - { - // Set the load command data and also set the correct endian - // swap settings and the correct address size - load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds); - load_command_data->SetByteOrder(data.GetByteOrder()); - load_command_data->SetAddressByteSize(data.GetAddressByteSize()); - return true; // We successfully read the mach_header and the load command data - } +bool DynamicLoaderMacOSXDYLD::ReadMachHeader(lldb::addr_t addr, + llvm::MachO::mach_header *header, + DataExtractor *load_command_data) { + DataBufferHeap header_bytes(sizeof(llvm::MachO::mach_header), 0); + Error error; + size_t bytes_read = m_process->ReadMemory(addr, header_bytes.GetBytes(), + header_bytes.GetByteSize(), error); + if (bytes_read == sizeof(llvm::MachO::mach_header)) { + lldb::offset_t offset = 0; + ::memset(header, 0, sizeof(llvm::MachO::mach_header)); + + // Get the magic byte unswapped so we can figure out what we are dealing + // with + DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), + endian::InlHostByteOrder(), 4); + header->magic = data.GetU32(&offset); + lldb::addr_t load_cmd_addr = addr; + data.SetByteOrder( + DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(header->magic)); + switch (header->magic) { + case llvm::MachO::MH_MAGIC: + case llvm::MachO::MH_CIGAM: + data.SetAddressByteSize(4); + load_cmd_addr += sizeof(llvm::MachO::mach_header); + break; + + case llvm::MachO::MH_MAGIC_64: + case llvm::MachO::MH_CIGAM_64: + data.SetAddressByteSize(8); + load_cmd_addr += sizeof(llvm::MachO::mach_header_64); + break; + + default: + return false; + } - return false; // We weren't able to read the load command data - } + // Read the rest of dyld's mach header + if (data.GetU32(&offset, &header->cputype, + (sizeof(llvm::MachO::mach_header) / sizeof(uint32_t)) - + 1)) { + if (load_command_data == NULL) + return true; // We were able to read the mach_header and weren't asked + // to read the load command bytes + + DataBufferSP load_cmd_data_sp(new DataBufferHeap(header->sizeofcmds, 0)); + + size_t load_cmd_bytes_read = + m_process->ReadMemory(load_cmd_addr, load_cmd_data_sp->GetBytes(), + load_cmd_data_sp->GetByteSize(), error); + + if (load_cmd_bytes_read == header->sizeofcmds) { + // Set the load command data and also set the correct endian + // swap settings and the correct address size + load_command_data->SetData(load_cmd_data_sp, 0, header->sizeofcmds); + load_command_data->SetByteOrder(data.GetByteOrder()); + load_command_data->SetAddressByteSize(data.GetAddressByteSize()); + return true; // We successfully read the mach_header and the load + // command data + } + + return false; // We weren't able to read the load command data } - return false; // We failed the read the mach_header + } + return false; // We failed the read the mach_header } - //---------------------------------------------------------------------- // Parse the load commands for an image //---------------------------------------------------------------------- -uint32_t -DynamicLoaderMacOSXDYLD::ParseLoadCommands (const DataExtractor& data, ImageInfo& dylib_info, FileSpec *lc_id_dylinker) -{ - lldb::offset_t offset = 0; - uint32_t cmd_idx; - Segment segment; - dylib_info.Clear (true); - - for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++) - { - // Clear out any load command specific data from DYLIB_INFO since - // we are about to read it. - - if (data.ValidOffsetForDataOfSize (offset, sizeof(llvm::MachO::load_command))) - { - llvm::MachO::load_command load_cmd; - lldb::offset_t load_cmd_offset = offset; - load_cmd.cmd = data.GetU32 (&offset); - load_cmd.cmdsize = data.GetU32 (&offset); - switch (load_cmd.cmd) - { - case llvm::MachO::LC_SEGMENT: - { - segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16); - // We are putting 4 uint32_t values 4 uint64_t values so - // we have to use multiple 32 bit gets below. - segment.vmaddr = data.GetU32 (&offset); - segment.vmsize = data.GetU32 (&offset); - segment.fileoff = data.GetU32 (&offset); - segment.filesize = data.GetU32 (&offset); - // Extract maxprot, initprot, nsects and flags all at once - data.GetU32(&offset, &segment.maxprot, 4); - dylib_info.segments.push_back (segment); - } - break; - - case llvm::MachO::LC_SEGMENT_64: - { - segment.name.SetTrimmedCStringWithLength ((const char *)data.GetData(&offset, 16), 16); - // Extract vmaddr, vmsize, fileoff, and filesize all at once - data.GetU64(&offset, &segment.vmaddr, 4); - // Extract maxprot, initprot, nsects and flags all at once - data.GetU32(&offset, &segment.maxprot, 4); - dylib_info.segments.push_back (segment); - } - break; - - case llvm::MachO::LC_ID_DYLINKER: - if (lc_id_dylinker) - { - const lldb::offset_t name_offset = load_cmd_offset + data.GetU32 (&offset); - const char *path = data.PeekCStr (name_offset); - lc_id_dylinker->SetFile (path, true); - } - break; - - case llvm::MachO::LC_UUID: - dylib_info.uuid.SetBytes(data.GetData (&offset, 16)); - break; - - default: - break; - } - // Set offset to be the beginning of the next load command. - offset = load_cmd_offset + load_cmd.cmdsize; +uint32_t DynamicLoaderMacOSXDYLD::ParseLoadCommands(const DataExtractor &data, + ImageInfo &dylib_info, + FileSpec *lc_id_dylinker) { + lldb::offset_t offset = 0; + uint32_t cmd_idx; + Segment segment; + dylib_info.Clear(true); + + for (cmd_idx = 0; cmd_idx < dylib_info.header.ncmds; cmd_idx++) { + // Clear out any load command specific data from DYLIB_INFO since + // we are about to read it. + + if (data.ValidOffsetForDataOfSize(offset, + sizeof(llvm::MachO::load_command))) { + llvm::MachO::load_command load_cmd; + lldb::offset_t load_cmd_offset = offset; + load_cmd.cmd = data.GetU32(&offset); + load_cmd.cmdsize = data.GetU32(&offset); + switch (load_cmd.cmd) { + case llvm::MachO::LC_SEGMENT: { + segment.name.SetTrimmedCStringWithLength( + (const char *)data.GetData(&offset, 16), 16); + // We are putting 4 uint32_t values 4 uint64_t values so + // we have to use multiple 32 bit gets below. + segment.vmaddr = data.GetU32(&offset); + segment.vmsize = data.GetU32(&offset); + segment.fileoff = data.GetU32(&offset); + segment.filesize = data.GetU32(&offset); + // Extract maxprot, initprot, nsects and flags all at once + data.GetU32(&offset, &segment.maxprot, 4); + dylib_info.segments.push_back(segment); + } break; + + case llvm::MachO::LC_SEGMENT_64: { + segment.name.SetTrimmedCStringWithLength( + (const char *)data.GetData(&offset, 16), 16); + // Extract vmaddr, vmsize, fileoff, and filesize all at once + data.GetU64(&offset, &segment.vmaddr, 4); + // Extract maxprot, initprot, nsects and flags all at once + data.GetU32(&offset, &segment.maxprot, 4); + dylib_info.segments.push_back(segment); + } break; + + case llvm::MachO::LC_ID_DYLINKER: + if (lc_id_dylinker) { + const lldb::offset_t name_offset = + load_cmd_offset + data.GetU32(&offset); + const char *path = data.PeekCStr(name_offset); + lc_id_dylinker->SetFile(path, true); } + break; + + case llvm::MachO::LC_UUID: + dylib_info.uuid.SetBytes(data.GetData(&offset, 16)); + break; + + default: + break; + } + // Set offset to be the beginning of the next load command. + offset = load_cmd_offset + load_cmd.cmdsize; } - - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. - - // Determine the slide amount (if any) - const size_t num_sections = dylib_info.segments.size(); - for (size_t i = 0; i < num_sections; ++i) - { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... - if ((dylib_info.segments[i].fileoff == 0 && dylib_info.segments[i].filesize > 0) || (dylib_info.segments[i].name == ConstString("__TEXT"))) - { - dylib_info.slide = dylib_info.address - dylib_info.segments[i].vmaddr; - // We have found the slide amount, so we can exit - // this for loop. - break; - } + } + + // All sections listed in the dyld image info structure will all + // either be fixed up already, or they will all be off by a single + // slide amount that is determined by finding the first segment + // that is at file offset zero which also has bytes (a file size + // that is greater than zero) in the object file. + + // Determine the slide amount (if any) + const size_t num_sections = dylib_info.segments.size(); + for (size_t i = 0; i < num_sections; ++i) { + // Iterate through the object file sections to find the + // first section that starts of file offset zero and that + // has bytes in the file... + if ((dylib_info.segments[i].fileoff == 0 && + dylib_info.segments[i].filesize > 0) || + (dylib_info.segments[i].name == ConstString("__TEXT"))) { + dylib_info.slide = dylib_info.address - dylib_info.segments[i].vmaddr; + // We have found the slide amount, so we can exit + // this for loop. + break; } - return cmd_idx; + } + return cmd_idx; } //---------------------------------------------------------------------- @@ -996,240 +951,278 @@ DynamicLoaderMacOSXDYLD::ParseLoadCommands (const DataExtractor& data, ImageInfo // _dyld_all_image_infos structure points to and cache the results. //---------------------------------------------------------------------- -void -DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos, - uint32_t infos_count, - bool update_executable) -{ - uint32_t exe_idx = UINT32_MAX; - // Read any UUID values that we can get - for (uint32_t i = 0; i < infos_count; i++) - { - if (!image_infos[i].UUIDValid()) - { - DataExtractor data; // Load command data - if (!ReadMachHeader (image_infos[i].address, &image_infos[i].header, &data)) - continue; - - ParseLoadCommands (data, image_infos[i], NULL); - - if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) - exe_idx = i; - - } +void DynamicLoaderMacOSXDYLD::UpdateImageInfosHeaderAndLoadCommands( + ImageInfo::collection &image_infos, uint32_t infos_count, + bool update_executable) { + uint32_t exe_idx = UINT32_MAX; + // Read any UUID values that we can get + for (uint32_t i = 0; i < infos_count; i++) { + if (!image_infos[i].UUIDValid()) { + DataExtractor data; // Load command data + if (!ReadMachHeader(image_infos[i].address, &image_infos[i].header, + &data)) + continue; + + ParseLoadCommands(data, image_infos[i], NULL); + + if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) + exe_idx = i; } - - Target &target = m_process->GetTarget(); - - if (exe_idx < image_infos.size()) - { - const bool can_create = true; - ModuleSP exe_module_sp (FindTargetModuleForImageInfo (image_infos[exe_idx], can_create, NULL)); - - if (exe_module_sp) - { - UpdateImageLoadAddress (exe_module_sp.get(), image_infos[exe_idx]); - - if (exe_module_sp.get() != target.GetExecutableModulePointer()) - { - // Don't load dependent images since we are in dyld where we will know - // and find out about all images that are loaded. Also when setting the - // executable module, it will clear the targets module list, and if we - // have an in memory dyld module, it will get removed from the list - // so we will need to add it back after setting the executable module, - // so we first try and see if we already have a weak pointer to the - // dyld module, make it into a shared pointer, then add the executable, - // then re-add it back to make sure it is always in the list. - ModuleSP dyld_module_sp(GetDYLDModule ()); - - const bool get_dependent_images = false; - m_process->GetTarget().SetExecutableModule (exe_module_sp, - get_dependent_images); - - if (dyld_module_sp) - { - if(target.GetImages().AppendIfNeeded (dyld_module_sp)) - { - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - - // Also add it to the section list. - UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld); - } - } - } + } + + Target &target = m_process->GetTarget(); + + if (exe_idx < image_infos.size()) { + const bool can_create = true; + ModuleSP exe_module_sp( + FindTargetModuleForImageInfo(image_infos[exe_idx], can_create, NULL)); + + if (exe_module_sp) { + UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]); + + if (exe_module_sp.get() != target.GetExecutableModulePointer()) { + // Don't load dependent images since we are in dyld where we will know + // and find out about all images that are loaded. Also when setting the + // executable module, it will clear the targets module list, and if we + // have an in memory dyld module, it will get removed from the list + // so we will need to add it back after setting the executable module, + // so we first try and see if we already have a weak pointer to the + // dyld module, make it into a shared pointer, then add the executable, + // then re-add it back to make sure it is always in the list. + ModuleSP dyld_module_sp(GetDYLDModule()); + + const bool get_dependent_images = false; + m_process->GetTarget().SetExecutableModule(exe_module_sp, + get_dependent_images); + + if (dyld_module_sp) { + if (target.GetImages().AppendIfNeeded(dyld_module_sp)) { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + + // Also add it to the section list. + UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld); + } } + } } + } } - //---------------------------------------------------------------------- // Dump the _dyld_all_image_infos members and all current image infos // that we have parsed to the file handle provided. //---------------------------------------------------------------------- -void -DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const -{ - if (log == NULL) - return; - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - log->Printf("dyld_all_image_infos = { version=%d, count=%d, addr=0x%8.8" PRIx64 ", notify=0x%8.8" PRIx64 " }", - m_dyld_all_image_infos.version, - m_dyld_all_image_infos.dylib_info_count, - (uint64_t)m_dyld_all_image_infos.dylib_info_addr, - (uint64_t)m_dyld_all_image_infos.notification); - size_t i; - const size_t count = m_dyld_image_infos.size(); - if (count > 0) - { - log->PutCString("Loaded:"); - for (i = 0; i<count; i++) - m_dyld_image_infos[i].PutToLog(log); - } -} +void DynamicLoaderMacOSXDYLD::PutToLog(Log *log) const { + if (log == NULL) + return; -bool -DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint () -{ - DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState())); - if (m_break_id == LLDB_INVALID_BREAK_ID) - { - if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS) - { - Address so_addr; - // Set the notification breakpoint and install a breakpoint - // callback function that will get called each time the - // breakpoint gets hit. We will use this to track when shared - // libraries get loaded/unloaded. - bool resolved = m_process->GetTarget().ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr); - if (!resolved) - { - ModuleSP dyld_module_sp = m_dyld_module_wp.lock(); - if (dyld_module_sp) - { - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - - UpdateImageLoadAddress (dyld_module_sp.get(), m_dyld); - resolved = m_process->GetTarget().ResolveLoadAddress(m_dyld_all_image_infos.notification, so_addr); - } - } + std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + log->Printf( + "dyld_all_image_infos = { version=%d, count=%d, addr=0x%8.8" PRIx64 + ", notify=0x%8.8" PRIx64 " }", + m_dyld_all_image_infos.version, m_dyld_all_image_infos.dylib_info_count, + (uint64_t)m_dyld_all_image_infos.dylib_info_addr, + (uint64_t)m_dyld_all_image_infos.notification); + size_t i; + const size_t count = m_dyld_image_infos.size(); + if (count > 0) { + log->PutCString("Loaded:"); + for (i = 0; i < count; i++) + m_dyld_image_infos[i].PutToLog(log); + } +} - if (resolved) - { - Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint (so_addr, true, false).get(); - dyld_break->SetCallback (DynamicLoaderMacOSXDYLD::NotifyBreakpointHit, this, true); - dyld_break->SetBreakpointKind ("shared-library-event"); - m_break_id = dyld_break->GetID(); - } +bool DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint() { + DEBUG_PRINTF("DynamicLoaderMacOSXDYLD::%s() process state = %s\n", + __FUNCTION__, StateAsCString(m_process->GetState())); + if (m_break_id == LLDB_INVALID_BREAK_ID) { + if (m_dyld_all_image_infos.notification != LLDB_INVALID_ADDRESS) { + Address so_addr; + // Set the notification breakpoint and install a breakpoint + // callback function that will get called each time the + // breakpoint gets hit. We will use this to track when shared + // libraries get loaded/unloaded. + bool resolved = m_process->GetTarget().ResolveLoadAddress( + m_dyld_all_image_infos.notification, so_addr); + if (!resolved) { + ModuleSP dyld_module_sp = GetDYLDModule(); + if (dyld_module_sp) { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); + + UpdateImageLoadAddress(dyld_module_sp.get(), m_dyld); + resolved = m_process->GetTarget().ResolveLoadAddress( + m_dyld_all_image_infos.notification, so_addr); } + } + + if (resolved) { + Breakpoint *dyld_break = + m_process->GetTarget().CreateBreakpoint(so_addr, true, false).get(); + dyld_break->SetCallback(DynamicLoaderMacOSXDYLD::NotifyBreakpointHit, + this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + m_break_id = dyld_break->GetID(); + } } - return m_break_id != LLDB_INVALID_BREAK_ID; + } + return m_break_id != LLDB_INVALID_BREAK_ID; } -Error -DynamicLoaderMacOSXDYLD::CanLoadImage () -{ - Error error; - // In order for us to tell if we can load a shared library we verify that - // the dylib_info_addr isn't zero (which means no shared libraries have - // been set yet, or dyld is currently mucking with the shared library list). - if (ReadAllImageInfosStructure ()) - { - // TODO: also check the _dyld_global_lock_held variable in libSystem.B.dylib? - // TODO: check the malloc lock? - // TODO: check the objective C lock? - if (m_dyld_all_image_infos.dylib_info_addr != 0) - return error; // Success - } - - error.SetErrorString("unsafe to load or unload shared libraries"); - return error; +Error DynamicLoaderMacOSXDYLD::CanLoadImage() { + Error error; + // In order for us to tell if we can load a shared library we verify that + // the dylib_info_addr isn't zero (which means no shared libraries have + // been set yet, or dyld is currently mucking with the shared library list). + if (ReadAllImageInfosStructure()) { + // TODO: also check the _dyld_global_lock_held variable in + // libSystem.B.dylib? + // TODO: check the malloc lock? + // TODO: check the objective C lock? + if (m_dyld_all_image_infos.dylib_info_addr != 0) + return error; // Success + } + + error.SetErrorString("unsafe to load or unload shared libraries"); + return error; } -void -DynamicLoaderMacOSXDYLD::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); -} +bool DynamicLoaderMacOSXDYLD::GetSharedCacheInformation( + lldb::addr_t &base_address, UUID &uuid, LazyBool &using_shared_cache, + LazyBool &private_shared_cache) { + base_address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + using_shared_cache = eLazyBoolCalculate; + private_shared_cache = eLazyBoolCalculate; + + if (m_process) { + addr_t all_image_infos = m_process->GetImageInfoAddress(); + + // The address returned by GetImageInfoAddress may be the address of dyld + // (don't want) + // or it may be the address of the dyld_all_image_infos structure (want). + // The first four + // bytes will be either the version field (all_image_infos) or a Mach-O file + // magic constant. + // Version 13 and higher of dyld_all_image_infos is required to get the + // sharedCacheUUID field. + + Error err; + uint32_t version_or_magic = + m_process->ReadUnsignedIntegerFromMemory(all_image_infos, 4, -1, err); + if (version_or_magic != static_cast<uint32_t>(-1) && + version_or_magic != llvm::MachO::MH_MAGIC && + version_or_magic != llvm::MachO::MH_CIGAM && + version_or_magic != llvm::MachO::MH_MAGIC_64 && + version_or_magic != llvm::MachO::MH_CIGAM_64 && + version_or_magic >= 13) { + addr_t sharedCacheUUID_address = LLDB_INVALID_ADDRESS; + int wordsize = m_process->GetAddressByteSize(); + if (wordsize == 8) { + sharedCacheUUID_address = + all_image_infos + 160; // sharedCacheUUID <mach-o/dyld_images.h> + } + if (wordsize == 4) { + sharedCacheUUID_address = + all_image_infos + 84; // sharedCacheUUID <mach-o/dyld_images.h> + } + if (sharedCacheUUID_address != LLDB_INVALID_ADDRESS) { + uuid_t shared_cache_uuid; + if (m_process->ReadMemory(sharedCacheUUID_address, shared_cache_uuid, + sizeof(uuid_t), err) == sizeof(uuid_t)) { + uuid.SetBytes(shared_cache_uuid); + if (uuid.IsValid()) { + using_shared_cache = eLazyBoolYes; + } + } + + if (version_or_magic >= 15) { + // The sharedCacheBaseAddress field is the next one in the + // dyld_all_image_infos struct. + addr_t sharedCacheBaseAddr_address = sharedCacheUUID_address + 16; + Error error; + base_address = m_process->ReadUnsignedIntegerFromMemory( + sharedCacheBaseAddr_address, wordsize, LLDB_INVALID_ADDRESS, + error); + if (error.Fail()) + base_address = LLDB_INVALID_ADDRESS; + } -void -DynamicLoaderMacOSXDYLD::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); + return true; + } + + // + // add + // NB: sharedCacheBaseAddress is the next field in dyld_all_image_infos + // after + // sharedCacheUUID -- that is, 16 bytes after it, if we wanted to fetch + // it. + } + } + return false; } +void DynamicLoaderMacOSXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); +} -lldb_private::ConstString -DynamicLoaderMacOSXDYLD::GetPluginNameStatic() -{ - static ConstString g_name("macosx-dyld"); - return g_name; +void DynamicLoaderMacOSXDYLD::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -const char * -DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that watches for shared library loads/unloads in MacOSX user processes."; +lldb_private::ConstString DynamicLoaderMacOSXDYLD::GetPluginNameStatic() { + static ConstString g_name("macosx-dyld"); + return g_name; } +const char *DynamicLoaderMacOSXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library loads/unloads " + "in MacOSX user processes."; +} //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -DynamicLoaderMacOSXDYLD::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString DynamicLoaderMacOSXDYLD::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -DynamicLoaderMacOSXDYLD::GetPluginVersion() -{ - return 1; -} +uint32_t DynamicLoaderMacOSXDYLD::GetPluginVersion() { return 1; } -uint32_t -DynamicLoaderMacOSXDYLD::AddrByteSize() -{ - std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); +uint32_t DynamicLoaderMacOSXDYLD::AddrByteSize() { + std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); - switch (m_dyld.header.magic) - { - case llvm::MachO::MH_MAGIC: - case llvm::MachO::MH_CIGAM: - return 4; - - case llvm::MachO::MH_MAGIC_64: - case llvm::MachO::MH_CIGAM_64: - return 8; - - default: - break; - } - return 0; + switch (m_dyld.header.magic) { + case llvm::MachO::MH_MAGIC: + case llvm::MachO::MH_CIGAM: + return 4; + + case llvm::MachO::MH_MAGIC_64: + case llvm::MachO::MH_CIGAM_64: + return 8; + + default: + break; + } + return 0; } -lldb::ByteOrder -DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(uint32_t magic) -{ - switch (magic) - { - case llvm::MachO::MH_MAGIC: - case llvm::MachO::MH_MAGIC_64: - return endian::InlHostByteOrder(); - - case llvm::MachO::MH_CIGAM: - case llvm::MachO::MH_CIGAM_64: - if (endian::InlHostByteOrder() == lldb::eByteOrderBig) - return lldb::eByteOrderLittle; - else - return lldb::eByteOrderBig; - - default: - break; - } - return lldb::eByteOrderInvalid; +lldb::ByteOrder DynamicLoaderMacOSXDYLD::GetByteOrderFromMagic(uint32_t magic) { + switch (magic) { + case llvm::MachO::MH_MAGIC: + case llvm::MachO::MH_MAGIC_64: + return endian::InlHostByteOrder(); + + case llvm::MachO::MH_CIGAM: + case llvm::MachO::MH_CIGAM_64: + if (endian::InlHostByteOrder() == lldb::eByteOrderBig) + return lldb::eByteOrderLittle; + else + return lldb::eByteOrderBig; + + default: + break; + } + return lldb::eByteOrderInvalid; } diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h index 637bd8640d24..25ccf702e965 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h @@ -7,197 +7,180 @@ // //===----------------------------------------------------------------------===// +// This is the DynamicLoader plugin for Darwin (macOS / iPhoneOS / tvOS / +// watchOS) +// platforms earlier than 2016, where lldb would read the "dyld_all_image_infos" +// dyld internal structure to understand where things were loaded and the +// solib loaded/unloaded notification function we put a breakpoint on gives us +// an array of (load address, mod time, file path) tuples. +// +// As of late 2016, the new DynamicLoaderMacOS plugin should be used, which uses +// dyld SPI functions to get the same information without reading internal dyld +// data structures. + #ifndef liblldb_DynamicLoaderMacOSXDYLD_h_ #define liblldb_DynamicLoaderMacOSXDYLD_h_ // C Includes // C++ Includes -#include <vector> #include <mutex> +#include <vector> // Other libraries and framework includes // Project includes -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/StructuredData.h" #include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/SafeMachO.h" #include "DynamicLoaderDarwin.h" -class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoaderDarwin -{ +class DynamicLoaderMacOSXDYLD : public lldb_private::DynamicLoaderDarwin { public: - DynamicLoaderMacOSXDYLD(lldb_private::Process *process); + DynamicLoaderMacOSXDYLD(lldb_private::Process *process); - virtual ~DynamicLoaderMacOSXDYLD() override; + virtual ~DynamicLoaderMacOSXDYLD() override; - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - static lldb_private::DynamicLoader * - CreateInstance (lldb_private::Process *process, bool force); + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - bool - ProcessDidExec() override; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + bool ProcessDidExec() override; - lldb_private::Error - CanLoadImage() override; + lldb_private::Error CanLoadImage() override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + bool GetSharedCacheInformation( + lldb::addr_t &base_address, lldb_private::UUID &uuid, + lldb_private::LazyBool &using_shared_cache, + lldb_private::LazyBool &private_shared_cache) override; - uint32_t - GetPluginVersion() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; protected: - void - PutToLog(lldb_private::Log *log) const; - - void - DoInitialImageFetch () override; - - bool - NeedToDoInitialImageFetch () override; - - bool - DidSetNotificationBreakpoint () override; - - void - DoClear () override; - - bool - ReadDYLDInfoFromMemoryAndSetNotificationCallback (lldb::addr_t addr); - - static bool - NotifyBreakpointHit (void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - uint32_t - AddrByteSize(); - - bool - ReadMachHeader (lldb::addr_t addr, - llvm::MachO::mach_header *header, - lldb_private::DataExtractor *load_command_data); - - uint32_t - ParseLoadCommands (const lldb_private::DataExtractor& data, - ImageInfo& dylib_info, - lldb_private::FileSpec *lc_id_dylinker); - - struct DYLDAllImageInfos - { - uint32_t version; - uint32_t dylib_info_count; // Version >= 1 - lldb::addr_t dylib_info_addr; // Version >= 1 - lldb::addr_t notification; // Version >= 1 - bool processDetachedFromSharedRegion; // Version >= 1 - bool libSystemInitialized; // Version >= 2 - lldb::addr_t dyldImageLoadAddress; // Version >= 2 - - DYLDAllImageInfos() : - version (0), - dylib_info_count (0), - dylib_info_addr (LLDB_INVALID_ADDRESS), - notification (LLDB_INVALID_ADDRESS), - processDetachedFromSharedRegion (false), - libSystemInitialized (false), - dyldImageLoadAddress (LLDB_INVALID_ADDRESS) - { - } - - void - Clear() - { - version = 0; - dylib_info_count = 0; - dylib_info_addr = LLDB_INVALID_ADDRESS; - notification = LLDB_INVALID_ADDRESS; - processDetachedFromSharedRegion = false; - libSystemInitialized = false; - dyldImageLoadAddress = LLDB_INVALID_ADDRESS; - } - - bool - IsValid() const - { - return version >= 1 || version <= 6; - } - }; - - static lldb::ByteOrder - GetByteOrderFromMagic(uint32_t magic); - - bool - SetNotificationBreakpoint () override; - - void - ClearNotificationBreakpoint () override; - - // There is a little tricky bit where you might initially attach while dyld is updating - // the all_image_infos, and you can't read the infos, so you have to continue and pick it - // up when you hit the update breakpoint. At that point, you need to run this initialize - // function, but when you do it that way you DON'T need to do the extra work you would at - // the breakpoint. - // So this function will only do actual work if the image infos haven't been read yet. - // If it does do any work, then it will return true, and false otherwise. That way you can - // call it in the breakpoint action, and if it returns true you're done. - bool - InitializeFromAllImageInfos (); - - bool - ReadAllImageInfosStructure (); - - bool - AddModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count); - - bool - RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count); - - void - UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos, - uint32_t infos_count, - bool update_executable); - - bool - ReadImageInfos (lldb::addr_t image_infos_addr, - uint32_t image_infos_count, - ImageInfo::collection &image_infos); - - lldb::addr_t m_dyld_all_image_infos_addr; - DYLDAllImageInfos m_dyld_all_image_infos; - uint32_t m_dyld_all_image_infos_stop_id; - lldb::user_id_t m_break_id; - mutable std::recursive_mutex m_mutex; - bool m_process_image_addr_is_all_images_infos; + void PutToLog(lldb_private::Log *log) const; + + void DoInitialImageFetch() override; + + bool NeedToDoInitialImageFetch() override; + + bool DidSetNotificationBreakpoint() override; + + void DoClear() override; + + bool ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb::addr_t addr); + + static bool + NotifyBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + uint32_t AddrByteSize(); + + bool ReadMachHeader(lldb::addr_t addr, llvm::MachO::mach_header *header, + lldb_private::DataExtractor *load_command_data); + + uint32_t ParseLoadCommands(const lldb_private::DataExtractor &data, + ImageInfo &dylib_info, + lldb_private::FileSpec *lc_id_dylinker); + + struct DYLDAllImageInfos { + uint32_t version; + uint32_t dylib_info_count; // Version >= 1 + lldb::addr_t dylib_info_addr; // Version >= 1 + lldb::addr_t notification; // Version >= 1 + bool processDetachedFromSharedRegion; // Version >= 1 + bool libSystemInitialized; // Version >= 2 + lldb::addr_t dyldImageLoadAddress; // Version >= 2 + + DYLDAllImageInfos() + : version(0), dylib_info_count(0), + dylib_info_addr(LLDB_INVALID_ADDRESS), + notification(LLDB_INVALID_ADDRESS), + processDetachedFromSharedRegion(false), libSystemInitialized(false), + dyldImageLoadAddress(LLDB_INVALID_ADDRESS) {} + + void Clear() { + version = 0; + dylib_info_count = 0; + dylib_info_addr = LLDB_INVALID_ADDRESS; + notification = LLDB_INVALID_ADDRESS; + processDetachedFromSharedRegion = false; + libSystemInitialized = false; + dyldImageLoadAddress = LLDB_INVALID_ADDRESS; + } + + bool IsValid() const { return version >= 1 || version <= 6; } + }; + + static lldb::ByteOrder GetByteOrderFromMagic(uint32_t magic); + + bool SetNotificationBreakpoint() override; + + void ClearNotificationBreakpoint() override; + + // There is a little tricky bit where you might initially attach while dyld is + // updating + // the all_image_infos, and you can't read the infos, so you have to continue + // and pick it + // up when you hit the update breakpoint. At that point, you need to run this + // initialize + // function, but when you do it that way you DON'T need to do the extra work + // you would at + // the breakpoint. + // So this function will only do actual work if the image infos haven't been + // read yet. + // If it does do any work, then it will return true, and false otherwise. + // That way you can + // call it in the breakpoint action, and if it returns true you're done. + bool InitializeFromAllImageInfos(); + + bool ReadAllImageInfosStructure(); + + bool AddModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr, + uint32_t image_infos_count); + + bool RemoveModulesUsingImageInfosAddress(lldb::addr_t image_infos_addr, + uint32_t image_infos_count); + + void UpdateImageInfosHeaderAndLoadCommands(ImageInfo::collection &image_infos, + uint32_t infos_count, + bool update_executable); + + bool ReadImageInfos(lldb::addr_t image_infos_addr, uint32_t image_infos_count, + ImageInfo::collection &image_infos); + + lldb::addr_t m_dyld_all_image_infos_addr; + DYLDAllImageInfos m_dyld_all_image_infos; + uint32_t m_dyld_all_image_infos_stop_id; + lldb::user_id_t m_break_id; + mutable std::recursive_mutex m_mutex; + bool m_process_image_addr_is_all_images_infos; private: - DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXDYLD); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderMacOSXDYLD); }; #endif // liblldb_DynamicLoaderMacOSXDYLD_h_ diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp index 04a6792fbf01..ec655c6f9b32 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp @@ -28,113 +28,92 @@ using namespace lldb; using namespace lldb_private; -static bool -GetMaxU64(DataExtractor &data, - lldb::offset_t *offset_ptr, - uint64_t *value, - unsigned int byte_size) -{ - lldb::offset_t saved_offset = *offset_ptr; - *value = data.GetMaxU64(offset_ptr, byte_size); - return *offset_ptr != saved_offset; +static bool GetMaxU64(DataExtractor &data, lldb::offset_t *offset_ptr, + uint64_t *value, unsigned int byte_size) { + lldb::offset_t saved_offset = *offset_ptr; + *value = data.GetMaxU64(offset_ptr, byte_size); + return *offset_ptr != saved_offset; } -static bool -ParseAuxvEntry(DataExtractor &data, - AuxVector::Entry &entry, - lldb::offset_t *offset_ptr, - unsigned int byte_size) -{ - if (!GetMaxU64(data, offset_ptr, &entry.type, byte_size)) - return false; +static bool ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry, + lldb::offset_t *offset_ptr, unsigned int byte_size) { + if (!GetMaxU64(data, offset_ptr, &entry.type, byte_size)) + return false; - if (!GetMaxU64(data, offset_ptr, &entry.value, byte_size)) - return false; + if (!GetMaxU64(data, offset_ptr, &entry.value, byte_size)) + return false; - return true; + return true; } -DataBufferSP -AuxVector::GetAuxvData() -{ - if (m_process) - return m_process->GetAuxvData (); - else - return DataBufferSP (); +DataBufferSP AuxVector::GetAuxvData() { + if (m_process) + return m_process->GetAuxvData(); + else + return DataBufferSP(); } -void -AuxVector::ParseAuxv(DataExtractor &data) -{ - const unsigned int byte_size = m_process->GetAddressByteSize(); - lldb::offset_t offset = 0; +void AuxVector::ParseAuxv(DataExtractor &data) { + const unsigned int byte_size = m_process->GetAddressByteSize(); + lldb::offset_t offset = 0; - for (;;) - { - Entry entry; + for (;;) { + Entry entry; - if (!ParseAuxvEntry(data, entry, &offset, byte_size)) - break; + if (!ParseAuxvEntry(data, entry, &offset, byte_size)) + break; - if (entry.type == AT_NULL) - break; + if (entry.type == AT_NULL) + break; - if (entry.type == AT_IGNORE) - continue; + if (entry.type == AT_IGNORE) + continue; - m_auxv.push_back(entry); - } + m_auxv.push_back(entry); + } } -AuxVector::AuxVector(Process *process) - : m_process(process) -{ - DataExtractor data; - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); +AuxVector::AuxVector(Process *process) : m_process(process) { + DataExtractor data; + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + data.SetData(GetAuxvData()); + data.SetByteOrder(m_process->GetByteOrder()); + data.SetAddressByteSize(m_process->GetAddressByteSize()); - data.SetData(GetAuxvData()); - data.SetByteOrder(m_process->GetByteOrder()); - data.SetAddressByteSize(m_process->GetAddressByteSize()); - - ParseAuxv(data); + ParseAuxv(data); - if (log) - DumpToLog(log); + if (log) + DumpToLog(log); } -AuxVector::iterator -AuxVector::FindEntry(EntryType type) const -{ - for (iterator I = begin(); I != end(); ++I) - { - if (I->type == static_cast<uint64_t>(type)) - return I; - } +AuxVector::iterator AuxVector::FindEntry(EntryType type) const { + for (iterator I = begin(); I != end(); ++I) { + if (I->type == static_cast<uint64_t>(type)) + return I; + } - return end(); + return end(); } -void -AuxVector::DumpToLog(Log *log) const -{ - if (!log) - return; +void AuxVector::DumpToLog(Log *log) const { + if (!log) + return; - log->PutCString("AuxVector: "); - for (iterator I = begin(); I != end(); ++I) - { - log->Printf(" %s [%" PRIu64 "]: %" PRIx64, GetEntryName(*I), I->type, I->value); - } + log->PutCString("AuxVector: "); + for (iterator I = begin(); I != end(); ++I) { + log->Printf(" %s [%" PRIu64 "]: %" PRIx64, GetEntryName(*I), I->type, + I->value); + } } -const char * -AuxVector::GetEntryName(EntryType type) -{ - const char *name = "AT_???"; +const char *AuxVector::GetEntryName(EntryType type) { + const char *name = "AT_???"; -#define ENTRY_NAME(_type) _type: name = #_type - switch (type) - { +#define ENTRY_NAME(_type) \ + _type: \ + name = #_type + switch (type) { case ENTRY_NAME(AT_NULL); break; case ENTRY_NAME(AT_IGNORE); break; case ENTRY_NAME(AT_EXECFD); break; @@ -173,4 +152,3 @@ AuxVector::GetEntryName(EntryType type) return name; } - diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h index 2d39eddcacc6..9c3e1b002a24 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h @@ -19,7 +19,7 @@ namespace lldb_private { class DataExtractor; -} +} /// @class AuxVector /// @brief Represents a processes auxiliary vector. @@ -31,85 +31,80 @@ class DataExtractor; class AuxVector { public: - AuxVector(lldb_private::Process *process); - - struct Entry { - uint64_t type; - uint64_t value; - - Entry() : type(0), value(0) { } - }; - - /// Constants describing the type of entry. - /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information. - enum EntryType { - AT_NULL = 0, ///< End of auxv. - AT_IGNORE = 1, ///< Ignore entry. - AT_EXECFD = 2, ///< File descriptor of program. - AT_PHDR = 3, ///< Program headers. - AT_PHENT = 4, ///< Size of program header. - AT_PHNUM = 5, ///< Number of program headers. - AT_PAGESZ = 6, ///< Page size. - AT_BASE = 7, ///< Interpreter base address. - AT_FLAGS = 8, ///< Flags. - AT_ENTRY = 9, ///< Program entry point. - AT_NOTELF = 10, ///< Set if program is not an ELF. - AT_UID = 11, ///< UID. - AT_EUID = 12, ///< Effective UID. - AT_GID = 13, ///< GID. - AT_EGID = 14, ///< Effective GID. - AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). - AT_PLATFORM = 15, ///< String identifying platform. - AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities. - AT_FPUCW = 18, ///< Used FPU control word. - AT_DCACHEBSIZE = 19, ///< Data cache block size. - AT_ICACHEBSIZE = 20, ///< Instruction cache block size. - AT_UCACHEBSIZE = 21, ///< Unified cache block size. - AT_IGNOREPPC = 22, ///< Entry should be ignored. - AT_SECURE = 23, ///< Boolean, was exec setuid-like? - AT_BASE_PLATFORM = 24, ///< String identifying real platforms. - AT_RANDOM = 25, ///< Address of 16 random bytes. - AT_EXECFN = 31, ///< Filename of executable. - AT_SYSINFO = 32, ///< Pointer to the global system page used for system calls and other nice things. - AT_SYSINFO_EHDR = 33, - AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches. - AT_L1D_CACHESHAPE = 35, - AT_L2_CACHESHAPE = 36, - AT_L3_CACHESHAPE = 37, - }; + AuxVector(lldb_private::Process *process); + + struct Entry { + uint64_t type; + uint64_t value; + + Entry() : type(0), value(0) {} + }; + + /// Constants describing the type of entry. + /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information. + enum EntryType { + AT_NULL = 0, ///< End of auxv. + AT_IGNORE = 1, ///< Ignore entry. + AT_EXECFD = 2, ///< File descriptor of program. + AT_PHDR = 3, ///< Program headers. + AT_PHENT = 4, ///< Size of program header. + AT_PHNUM = 5, ///< Number of program headers. + AT_PAGESZ = 6, ///< Page size. + AT_BASE = 7, ///< Interpreter base address. + AT_FLAGS = 8, ///< Flags. + AT_ENTRY = 9, ///< Program entry point. + AT_NOTELF = 10, ///< Set if program is not an ELF. + AT_UID = 11, ///< UID. + AT_EUID = 12, ///< Effective UID. + AT_GID = 13, ///< GID. + AT_EGID = 14, ///< Effective GID. + AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). + AT_PLATFORM = 15, ///< String identifying platform. + AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities. + AT_FPUCW = 18, ///< Used FPU control word. + AT_DCACHEBSIZE = 19, ///< Data cache block size. + AT_ICACHEBSIZE = 20, ///< Instruction cache block size. + AT_UCACHEBSIZE = 21, ///< Unified cache block size. + AT_IGNOREPPC = 22, ///< Entry should be ignored. + AT_SECURE = 23, ///< Boolean, was exec setuid-like? + AT_BASE_PLATFORM = 24, ///< String identifying real platforms. + AT_RANDOM = 25, ///< Address of 16 random bytes. + AT_EXECFN = 31, ///< Filename of executable. + AT_SYSINFO = 32, ///< Pointer to the global system page used for system + ///calls and other nice things. + AT_SYSINFO_EHDR = 33, + AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches. + AT_L1D_CACHESHAPE = 35, + AT_L2_CACHESHAPE = 36, + AT_L3_CACHESHAPE = 37, + }; private: - typedef std::vector<Entry> EntryVector; + typedef std::vector<Entry> EntryVector; public: - typedef EntryVector::const_iterator iterator; + typedef EntryVector::const_iterator iterator; - iterator begin() const { return m_auxv.begin(); } - iterator end() const { return m_auxv.end(); } + iterator begin() const { return m_auxv.begin(); } + iterator end() const { return m_auxv.end(); } - iterator - FindEntry(EntryType type) const; + iterator FindEntry(EntryType type) const; - static const char * - GetEntryName(const Entry &entry) { - return GetEntryName(static_cast<EntryType>(entry.type)); - } + static const char *GetEntryName(const Entry &entry) { + return GetEntryName(static_cast<EntryType>(entry.type)); + } - static const char * - GetEntryName(EntryType type); + static const char *GetEntryName(EntryType type); - void - DumpToLog(lldb_private::Log *log) const; + void DumpToLog(lldb_private::Log *log) const; private: - lldb_private::Process *m_process; - EntryVector m_auxv; + lldb_private::Process *m_process; + EntryVector m_auxv; - lldb::DataBufferSP - GetAuxvData(); + lldb::DataBufferSP GetAuxvData(); - void - ParseAuxv(lldb_private::DataExtractor &data); + void ParseAuxv(lldb_private::DataExtractor &data); }; #endif diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp index 443f97ed0ba1..136bf6561a21 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -30,631 +30,582 @@ using namespace lldb_private; /// Locates the address of the rendezvous structure. Returns the address on /// success and LLDB_INVALID_ADDRESS on failure. -static addr_t -ResolveRendezvousAddress(Process *process) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - addr_t info_location; - addr_t info_addr; - Error error; - - if (!process) - { - if (log) - log->Printf ("%s null process provided", __FUNCTION__); - return LLDB_INVALID_ADDRESS; - } +static addr_t ResolveRendezvousAddress(Process *process) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + addr_t info_location; + addr_t info_addr; + Error error; - // Try to get it from our process. This might be a remote process and might - // grab it via some remote-specific mechanism. - info_location = process->GetImageInfoAddress(); + if (!process) { if (log) - log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); - - // If the process fails to return an address, fall back to seeing if the local object file can help us find it. - if (info_location == LLDB_INVALID_ADDRESS) - { - Target *target = &process->GetTarget(); - if (target) - { - ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); - Address addr = obj_file->GetImageInfoAddress(target); - - if (addr.IsValid()) - { - info_location = addr.GetLoadAddress(target); - if (log) - log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location); - } - else - { - if (log) - log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__); - } - } - } - - if (info_location == LLDB_INVALID_ADDRESS) - { + log->Printf("%s null process provided", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } + + // Try to get it from our process. This might be a remote process and might + // grab it via some remote-specific mechanism. + info_location = process->GetImageInfoAddress(); + if (log) + log->Printf("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); + + // If the process fails to return an address, fall back to seeing if the local + // object file can help us find it. + if (info_location == LLDB_INVALID_ADDRESS) { + Target *target = &process->GetTarget(); + if (target) { + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(target); + + if (addr.IsValid()) { + info_location = addr.GetLoadAddress(target); if (log) - log->Printf ("%s FAILED - invalid info address", __FUNCTION__); - return LLDB_INVALID_ADDRESS; + log->Printf( + "%s resolved via direct object file approach to 0x%" PRIx64, + __FUNCTION__, info_location); + } else { + if (log) + log->Printf("%s FAILED - direct object file approach did not yield a " + "valid address", + __FUNCTION__); + } } + } + if (info_location == LLDB_INVALID_ADDRESS) { if (log) - log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location); + log->Printf("%s FAILED - invalid info address", __FUNCTION__); + return LLDB_INVALID_ADDRESS; + } - info_addr = process->ReadPointerFromMemory(info_location, error); - if (error.Fail()) - { - if (log) - log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ()); - return LLDB_INVALID_ADDRESS; - } + if (log) + log->Printf("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, + __FUNCTION__, process->GetAddressByteSize(), info_location); - if (info_addr == 0) - { - if (log) - log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location); - return LLDB_INVALID_ADDRESS; - } + info_addr = process->ReadPointerFromMemory(info_location, error); + if (error.Fail()) { + if (log) + log->Printf("%s FAILED - could not read from the info location: %s", + __FUNCTION__, error.AsCString()); + return LLDB_INVALID_ADDRESS; + } - return info_addr; + if (info_addr == 0) { + if (log) + log->Printf("%s FAILED - the rendezvous address contained at 0x%" PRIx64 + " returned a null value", + __FUNCTION__, info_location); + return LLDB_INVALID_ADDRESS; + } + + return info_addr; } DYLDRendezvous::DYLDRendezvous(Process *process) - : m_process(process), - m_rendezvous_addr(LLDB_INVALID_ADDRESS), - m_current(), - m_previous(), - m_loaded_modules(), - m_soentries(), - m_added_soentries(), - m_removed_soentries() -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - - m_thread_info.valid = false; - - // Cache a copy of the executable path - if (m_process) - { - Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); - if (exe_mod) - { - m_exe_file_spec = exe_mod->GetPlatformFileSpec(); - if (log) - log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", - __FUNCTION__, m_exe_file_spec.GetCString()); - } - else - { - if (log) - log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__); - } + : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(), + m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(), + m_removed_soentries() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + m_thread_info.valid = false; + + // Cache a copy of the executable path + if (m_process) { + Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); + if (exe_mod) { + m_exe_file_spec = exe_mod->GetPlatformFileSpec(); + if (log) + log->Printf("DYLDRendezvous::%s exe module executable path set: '%s'", + __FUNCTION__, m_exe_file_spec.GetCString()); + } else { + if (log) + log->Printf("DYLDRendezvous::%s cannot cache exe module path: null " + "executable module pointer", + __FUNCTION__); } + } } -bool -DYLDRendezvous::Resolve() -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); +bool DYLDRendezvous::Resolve() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + const size_t word_size = 4; + Rendezvous info; + size_t address_size; + size_t padding; + addr_t info_addr; + addr_t cursor; + + address_size = m_process->GetAddressByteSize(); + padding = address_size - word_size; + if (log) + log->Printf("DYLDRendezvous::%s address size: %" PRIu64 + ", padding %" PRIu64, + __FUNCTION__, uint64_t(address_size), uint64_t(padding)); + + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) + cursor = info_addr = ResolveRendezvousAddress(m_process); + else + cursor = info_addr = m_rendezvous_addr; + if (log) + log->Printf("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor); + + if (cursor == LLDB_INVALID_ADDRESS) + return false; - const size_t word_size = 4; - Rendezvous info; - size_t address_size; - size_t padding; - addr_t info_addr; - addr_t cursor; + if (!(cursor = ReadWord(cursor, &info.version, word_size))) + return false; - address_size = m_process->GetAddressByteSize(); - padding = address_size - word_size; - if (log) - log->Printf ("DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64, __FUNCTION__, uint64_t(address_size), uint64_t(padding)); + if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) + return false; - if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) - cursor = info_addr = ResolveRendezvousAddress(m_process); - else - cursor = info_addr = m_rendezvous_addr; - if (log) - log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor); + if (!(cursor = ReadPointer(cursor, &info.brk))) + return false; - if (cursor == LLDB_INVALID_ADDRESS) - return false; + if (!(cursor = ReadWord(cursor, &info.state, word_size))) + return false; - if (!(cursor = ReadWord(cursor, &info.version, word_size))) - return false; + if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) + return false; - if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) - return false; + // The rendezvous was successfully read. Update our internal state. + m_rendezvous_addr = info_addr; + m_previous = m_current; + m_current = info; - if (!(cursor = ReadPointer(cursor, &info.brk))) - return false; + if (UpdateSOEntries(true)) + return true; - if (!(cursor = ReadWord(cursor, &info.state, word_size))) - return false; + return UpdateSOEntries(); +} - if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) - return false; +bool DYLDRendezvous::IsValid() { + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; +} - // The rendezvous was successfully read. Update our internal state. - m_rendezvous_addr = info_addr; - m_previous = m_current; - m_current = info; +bool DYLDRendezvous::UpdateSOEntries(bool fromRemote) { + SOEntry entry; + LoadedModuleInfoList module_list; - if (UpdateSOEntries (true)) - return true; + // If we can't get the SO info from the remote, return failure. + if (fromRemote && m_process->LoadModules(module_list) == 0) + return false; - return UpdateSOEntries(); -} + if (!fromRemote && m_current.map_addr == 0) + return false; -bool -DYLDRendezvous::IsValid() -{ - return m_rendezvous_addr != LLDB_INVALID_ADDRESS; + // When the previous and current states are consistent this is the first + // time we have been asked to update. Just take a snapshot of the currently + // loaded modules. + if (m_previous.state == eConsistent && m_current.state == eConsistent) + return fromRemote ? SaveSOEntriesFromRemote(module_list) + : TakeSnapshot(m_soentries); + + // If we are about to add or remove a shared object clear out the current + // state and take a snapshot of the currently loaded images. + if (m_current.state == eAdd || m_current.state == eDelete) { + // Some versions of the android dynamic linker might send two + // notifications with state == eAdd back to back. Ignore them + // until we get an eConsistent notification. + if (!(m_previous.state == eConsistent || + (m_previous.state == eAdd && m_current.state == eDelete))) + return false; + + m_soentries.clear(); + if (fromRemote) + return SaveSOEntriesFromRemote(module_list); + + m_added_soentries.clear(); + m_removed_soentries.clear(); + return TakeSnapshot(m_soentries); + } + assert(m_current.state == eConsistent); + + // Otherwise check the previous state to determine what to expect and update + // accordingly. + if (m_previous.state == eAdd) + return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries(); + else if (m_previous.state == eDelete) + return fromRemote ? RemoveSOEntriesFromRemote(module_list) + : RemoveSOEntries(); + + return false; } -bool -DYLDRendezvous::UpdateSOEntries(bool fromRemote) -{ - SOEntry entry; - LoadedModuleInfoList module_list; +bool DYLDRendezvous::FillSOEntryFromModuleInfo( + LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) { + addr_t link_map_addr; + addr_t base_addr; + addr_t dyn_addr; + std::string name; - // If we can't get the SO info from the remote, return failure. - if (fromRemote && m_process->LoadModules (module_list) == 0) - return false; + if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) || + !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name)) + return false; - if (!fromRemote && m_current.map_addr == 0) - return false; + entry.link_addr = link_map_addr; + entry.base_addr = base_addr; + entry.dyn_addr = dyn_addr; - // When the previous and current states are consistent this is the first - // time we have been asked to update. Just take a snapshot of the currently - // loaded modules. - if (m_previous.state == eConsistent && m_current.state == eConsistent) - return fromRemote ? SaveSOEntriesFromRemote(module_list) : TakeSnapshot(m_soentries); - - // If we are about to add or remove a shared object clear out the current - // state and take a snapshot of the currently loaded images. - if (m_current.state == eAdd || m_current.state == eDelete) - { - // Some versions of the android dynamic linker might send two - // notifications with state == eAdd back to back. Ignore them - // until we get an eConsistent notification. - if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete))) - return false; - - m_soentries.clear(); - if (fromRemote) - return SaveSOEntriesFromRemote(module_list); - - m_added_soentries.clear(); - m_removed_soentries.clear(); - return TakeSnapshot(m_soentries); - } - assert(m_current.state == eConsistent); + entry.file_spec.SetFile(name, false); - // Otherwise check the previous state to determine what to expect and update - // accordingly. - if (m_previous.state == eAdd) - return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries(); - else if (m_previous.state == eDelete) - return fromRemote ? RemoveSOEntriesFromRemote(module_list) : RemoveSOEntries(); + UpdateBaseAddrIfNecessary(entry, name); - return false; + // not needed if we're using ModuleInfos + entry.next = 0; + entry.prev = 0; + entry.path_addr = 0; + + return true; } -bool -DYLDRendezvous::FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, - SOEntry &entry) -{ - addr_t link_map_addr; - addr_t base_addr; - addr_t dyn_addr; - std::string name; - - if (!modInfo.get_link_map (link_map_addr) || - !modInfo.get_base (base_addr) || - !modInfo.get_dynamic (dyn_addr) || - !modInfo.get_name (name)) - return false; +bool DYLDRendezvous::SaveSOEntriesFromRemote( + LoadedModuleInfoList &module_list) { + for (auto const &modInfo : module_list.m_list) { + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; - entry.link_addr = link_map_addr; - entry.base_addr = base_addr; - entry.dyn_addr = dyn_addr; + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } - entry.file_spec.SetFile(name, false); + m_loaded_modules = module_list; + return true; +} - UpdateBaseAddrIfNecessary(entry, name); +bool DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) { + for (auto const &modInfo : module_list.m_list) { + bool found = false; + for (auto const &existing : m_loaded_modules.m_list) { + if (modInfo == existing) { + found = true; + break; + } + } - // not needed if we're using ModuleInfos - entry.next = 0; - entry.prev = 0; - entry.path_addr = 0; + if (found) + continue; - return true; + SOEntry entry; + if (!FillSOEntryFromModuleInfo(modInfo, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) + m_soentries.push_back(entry); + } + + m_loaded_modules = module_list; + return true; } -bool -DYLDRendezvous::SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list) -{ - for (auto const & modInfo : module_list.m_list) - { - SOEntry entry; - if (!FillSOEntryFromModuleInfo(modInfo, entry)) - return false; - - // Only add shared libraries and not the executable. - if (!SOEntryIsMainExecutable(entry)) - m_soentries.push_back(entry); +bool DYLDRendezvous::RemoveSOEntriesFromRemote( + LoadedModuleInfoList &module_list) { + for (auto const &existing : m_loaded_modules.m_list) { + bool found = false; + for (auto const &modInfo : module_list.m_list) { + if (modInfo == existing) { + found = true; + break; + } } - m_loaded_modules = module_list; - return true; + if (found) + continue; -} + SOEntry entry; + if (!FillSOEntryFromModuleInfo(existing, entry)) + return false; + + // Only add shared libraries and not the executable. + if (!SOEntryIsMainExecutable(entry)) { + auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + return false; -bool -DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) -{ - for (auto const & modInfo : module_list.m_list) - { - bool found = false; - for (auto const & existing : m_loaded_modules.m_list) - { - if (modInfo == existing) - { - found = true; - break; - } - } - - if (found) - continue; - - SOEntry entry; - if (!FillSOEntryFromModuleInfo(modInfo, entry)) - return false; - - // Only add shared libraries and not the executable. - if (!SOEntryIsMainExecutable(entry)) - m_soentries.push_back(entry); + m_soentries.erase(pos); } + } - m_loaded_modules = module_list; - return true; + m_loaded_modules = module_list; + return true; } -bool -DYLDRendezvous::RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list) -{ - for (auto const & existing : m_loaded_modules.m_list) - { - bool found = false; - for (auto const & modInfo : module_list.m_list) - { - if (modInfo == existing) - { - found = true; - break; - } - } - - if (found) - continue; - - SOEntry entry; - if (!FillSOEntryFromModuleInfo(existing, entry)) - return false; - - // Only add shared libraries and not the executable. - if (!SOEntryIsMainExecutable(entry)) - { - auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry); - if (pos == m_soentries.end()) - return false; - - m_soentries.erase(pos); - } - } +bool DYLDRendezvous::AddSOEntries() { + SOEntry entry; + iterator pos; - m_loaded_modules = module_list; - return true; -} + assert(m_previous.state == eAdd); -bool -DYLDRendezvous::AddSOEntries() -{ - SOEntry entry; - iterator pos; + if (m_current.map_addr == 0) + return false; - assert(m_previous.state == eAdd); + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; - if (m_current.map_addr == 0) - return false; + // Only add shared libraries and not the executable. + if (SOEntryIsMainExecutable(entry)) + continue; - for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) - { - if (!ReadSOEntryFromMemory(cursor, entry)) - return false; - - // Only add shared libraries and not the executable. - if (SOEntryIsMainExecutable(entry)) - continue; - - pos = std::find(m_soentries.begin(), m_soentries.end(), entry); - if (pos == m_soentries.end()) - { - m_soentries.push_back(entry); - m_added_soentries.push_back(entry); - } + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) { + m_soentries.push_back(entry); + m_added_soentries.push_back(entry); } + } - return true; + return true; } -bool -DYLDRendezvous::RemoveSOEntries() -{ - SOEntryList entry_list; - iterator pos; +bool DYLDRendezvous::RemoveSOEntries() { + SOEntryList entry_list; + iterator pos; - assert(m_previous.state == eDelete); + assert(m_previous.state == eDelete); - if (!TakeSnapshot(entry_list)) - return false; + if (!TakeSnapshot(entry_list)) + return false; - for (iterator I = begin(); I != end(); ++I) - { - pos = std::find(entry_list.begin(), entry_list.end(), *I); - if (pos == entry_list.end()) - m_removed_soentries.push_back(*I); - } + for (iterator I = begin(); I != end(); ++I) { + pos = std::find(entry_list.begin(), entry_list.end(), *I); + if (pos == entry_list.end()) + m_removed_soentries.push_back(*I); + } - m_soentries = entry_list; - return true; + m_soentries = entry_list; + return true; } -bool -DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) -{ - // On Linux the executable is indicated by an empty path in the entry. On - // FreeBSD and on Android it is the full path to the executable. - - auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); - switch (triple.getOS()) - { - case llvm::Triple::FreeBSD: - return entry.file_spec == m_exe_file_spec; - case llvm::Triple::Linux: - if (triple.isAndroid()) - return entry.file_spec == m_exe_file_spec; - return !entry.file_spec; - default: - return false; - } +bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) { + // On Linux the executable is indicated by an empty path in the entry. On + // FreeBSD and on Android it is the full path to the executable. + + auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::FreeBSD: + return entry.file_spec == m_exe_file_spec; + case llvm::Triple::Linux: + if (triple.isAndroid()) + return entry.file_spec == m_exe_file_spec; + return !entry.file_spec; + default: + return false; + } } -bool -DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) -{ - SOEntry entry; +bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) { + SOEntry entry; - if (m_current.map_addr == 0) - return false; + if (m_current.map_addr == 0) + return false; - // Clear previous entries since we are about to obtain an up to date list. - entry_list.clear(); + // Clear previous entries since we are about to obtain an up to date list. + entry_list.clear(); - for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) - { - if (!ReadSOEntryFromMemory(cursor, entry)) - return false; + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; - // Only add shared libraries and not the executable. - if (SOEntryIsMainExecutable(entry)) - continue; + // Only add shared libraries and not the executable. + if (SOEntryIsMainExecutable(entry)) + continue; - entry_list.push_back(entry); - } + entry_list.push_back(entry); + } - return true; + return true; } -addr_t -DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) -{ - Error error; +addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) { + Error error; - *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); - if (error.Fail()) - return 0; + *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); + if (error.Fail()) + return 0; - return addr + size; + return addr + size; } -addr_t -DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) -{ - Error error; - - *dst = m_process->ReadPointerFromMemory(addr, error); - if (error.Fail()) - return 0; +addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) { + Error error; - return addr + m_process->GetAddressByteSize(); + *dst = m_process->ReadPointerFromMemory(addr, error); + if (error.Fail()) + return 0; + + return addr + m_process->GetAddressByteSize(); } -std::string -DYLDRendezvous::ReadStringFromMemory(addr_t addr) -{ - std::string str; - Error error; +std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) { + std::string str; + Error error; - if (addr == LLDB_INVALID_ADDRESS) - return std::string(); + if (addr == LLDB_INVALID_ADDRESS) + return std::string(); - m_process->ReadCStringFromMemory(addr, str, error); + m_process->ReadCStringFromMemory(addr, str, error); - return str; + return str; } -// Returns true if the load bias reported by the linker is incorrect for the given entry. This -// function is used to handle cases where we want to work around a bug in the system linker. -static bool -isLoadBiasIncorrect(Target& target, const std::string& file_path) -{ - // On Android L (API 21, 22) the load address of the "/system/bin/linker" isn't filled in - // correctly. - uint32_t os_major = 0, os_minor = 0, os_update = 0; - if (target.GetArchitecture().GetTriple().isAndroid() && - target.GetPlatform()->GetOSVersion(os_major, os_minor, os_update) && - (os_major == 21 || os_major == 22) && - (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64")) - { - return true; - } +// Returns true if the load bias reported by the linker is incorrect for the +// given entry. This +// function is used to handle cases where we want to work around a bug in the +// system linker. +static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) { + // On Android L (API 21, 22) the load address of the "/system/bin/linker" + // isn't filled in + // correctly. + uint32_t os_major = 0, os_minor = 0, os_update = 0; + if (target.GetArchitecture().GetTriple().isAndroid() && + target.GetPlatform()->GetOSVersion(os_major, os_minor, os_update) && + (os_major == 21 || os_major == 22) && + (file_path == "/system/bin/linker" || + file_path == "/system/bin/linker64")) { + return true; + } - return false; + return false; } -void -DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path) -{ - // If the load bias reported by the linker is incorrect then fetch the load address of the file - // from the proc file system. - if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) - { - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - bool is_loaded = false; - Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); - if (error.Success() && is_loaded) - entry.base_addr = load_addr; - } +void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry, + std::string const &file_path) { + // If the load bias reported by the linker is incorrect then fetch the load + // address of the file + // from the proc file system. + if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) { + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + bool is_loaded = false; + Error error = + m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); + if (error.Success() && is_loaded) + entry.base_addr = load_addr; + } } -bool -DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) -{ - entry.clear(); +bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) { + entry.clear(); - entry.link_addr = addr; - - if (!(addr = ReadPointer(addr, &entry.base_addr))) - return false; + entry.link_addr = addr; - // mips adds an extra load offset field to the link map struct on - // FreeBSD and NetBSD (need to validate other OSes). - // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57 - const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); - if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD - || arch.GetTriple().getOS() == llvm::Triple::NetBSD) && - (arch.GetMachine() == llvm::Triple::mips || arch.GetMachine() == llvm::Triple::mipsel - || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::mips64el)) - { - addr_t mips_l_offs; - if (!(addr = ReadPointer(addr, &mips_l_offs))) - return false; - if (mips_l_offs != 0 && mips_l_offs != entry.base_addr) - return false; - } - - if (!(addr = ReadPointer(addr, &entry.path_addr))) - return false; - - if (!(addr = ReadPointer(addr, &entry.dyn_addr))) - return false; - - if (!(addr = ReadPointer(addr, &entry.next))) - return false; - - if (!(addr = ReadPointer(addr, &entry.prev))) - return false; + if (!(addr = ReadPointer(addr, &entry.base_addr))) + return false; - std::string file_path = ReadStringFromMemory(entry.path_addr); - entry.file_spec.SetFile(file_path, false); + // mips adds an extra load offset field to the link map struct on + // FreeBSD and NetBSD (need to validate other OSes). + // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57 + const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); + if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD || + arch.GetTriple().getOS() == llvm::Triple::NetBSD) && + (arch.GetMachine() == llvm::Triple::mips || + arch.GetMachine() == llvm::Triple::mipsel || + arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::mips64el)) { + addr_t mips_l_offs; + if (!(addr = ReadPointer(addr, &mips_l_offs))) + return false; + if (mips_l_offs != 0 && mips_l_offs != entry.base_addr) + return false; + } + + if (!(addr = ReadPointer(addr, &entry.path_addr))) + return false; - UpdateBaseAddrIfNecessary(entry, file_path); + if (!(addr = ReadPointer(addr, &entry.dyn_addr))) + return false; - return true; -} + if (!(addr = ReadPointer(addr, &entry.next))) + return false; + if (!(addr = ReadPointer(addr, &entry.prev))) + return false; -bool -DYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value) -{ - Target& target = m_process->GetTarget(); + std::string file_path = ReadStringFromMemory(entry.path_addr); + entry.file_spec.SetFile(file_path, false); - SymbolContextList list; - if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list)) - return false; + UpdateBaseAddrIfNecessary(entry, file_path); - Address address = list[0].symbol->GetAddress(); - addr_t addr = address.GetLoadAddress (&target); - if (addr == LLDB_INVALID_ADDRESS) - return false; + return true; +} - Error error; - value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error); - if (error.Fail()) - return false; +bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field, + uint32_t &value) { + Target &target = m_process->GetTarget(); - if (field == eSize) - value /= 8; // convert bits to bytes + SymbolContextList list; + if (!target.GetImages().FindSymbolsWithNameAndType(ConstString(name), + eSymbolTypeAny, list)) + return false; - return true; + Address address = list[0].symbol->GetAddress(); + addr_t addr = address.GetLoadAddress(&target); + if (addr == LLDB_INVALID_ADDRESS) + return false; + + Error error; + value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory( + addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error); + if (error.Fail()) + return false; + + if (field == eSize) + value /= 8; // convert bits to bytes + + return true; } -const DYLDRendezvous::ThreadInfo& -DYLDRendezvous::GetThreadInfo() -{ - if (!m_thread_info.valid) - { - bool ok = true; +const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() { + if (!m_thread_info.valid) { + bool ok = true; - ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset); - ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); - ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset); - ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset); + ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset, + m_thread_info.dtv_offset); + ok &= + FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); + ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset, + m_thread_info.modid_offset); + ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset, + m_thread_info.tls_offset); - if (ok) - m_thread_info.valid = true; - } + if (ok) + m_thread_info.valid = true; + } - return m_thread_info; + return m_thread_info; } -void -DYLDRendezvous::DumpToLog(Log *log) const -{ - int state = GetState(); - - if (!log) - return; - - log->PutCString("DYLDRendezvous:"); - log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); - log->Printf(" Version: %" PRIu64, GetVersion()); - log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); - log->Printf(" Break : %" PRIx64, GetBreakAddress()); - log->Printf(" LDBase : %" PRIx64, GetLDBase()); - log->Printf(" State : %s", - (state == eConsistent) ? "consistent" : - (state == eAdd) ? "add" : - (state == eDelete) ? "delete" : "unknown"); - - iterator I = begin(); - iterator E = end(); - - if (I != E) - log->PutCString("DYLDRendezvous SOEntries:"); - - for (int i = 1; I != E; ++I, ++i) - { - log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString()); - log->Printf(" Base : %" PRIx64, I->base_addr); - log->Printf(" Path : %" PRIx64, I->path_addr); - log->Printf(" Dyn : %" PRIx64, I->dyn_addr); - log->Printf(" Next : %" PRIx64, I->next); - log->Printf(" Prev : %" PRIx64, I->prev); - } +void DYLDRendezvous::DumpToLog(Log *log) const { + int state = GetState(); + + if (!log) + return; + + log->PutCString("DYLDRendezvous:"); + log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); + log->Printf(" Version: %" PRIu64, GetVersion()); + log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); + log->Printf(" Break : %" PRIx64, GetBreakAddress()); + log->Printf(" LDBase : %" PRIx64, GetLDBase()); + log->Printf(" State : %s", + (state == eConsistent) + ? "consistent" + : (state == eAdd) ? "add" : (state == eDelete) ? "delete" + : "unknown"); + + iterator I = begin(); + iterator E = end(); + + if (I != E) + log->PutCString("DYLDRendezvous SOEntries:"); + + for (int i = 1; I != E; ++I, ++i) { + log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString()); + log->Printf(" Base : %" PRIx64, I->base_addr); + log->Printf(" Path : %" PRIx64, I->path_addr); + log->Printf(" Dyn : %" PRIx64, I->dyn_addr); + log->Printf(" Next : %" PRIx64, I->next); + log->Printf(" Prev : %" PRIx64, I->prev); + } } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index 8498116c808f..55b8bd7fb49e 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -16,9 +16,9 @@ #include <string> // Other libraries and framework includes +#include "lldb/Host/FileSpec.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/LoadedModuleInfoList.h" @@ -37,251 +37,220 @@ class Process; /// currently loaded modules. class DYLDRendezvous { - // This structure is used to hold the contents of the debug rendezvous - // information (struct r_debug) as found in the inferiors memory. Note that - // the layout of this struct is not binary compatible, it is simply large - // enough to hold the information on both 32 and 64 bit platforms. - struct Rendezvous { - uint64_t version; - lldb::addr_t map_addr; - lldb::addr_t brk; - uint64_t state; - lldb::addr_t ldbase; - - Rendezvous() - : version(0), map_addr(0), brk(0), state(0), ldbase(0) { } - }; + // This structure is used to hold the contents of the debug rendezvous + // information (struct r_debug) as found in the inferiors memory. Note that + // the layout of this struct is not binary compatible, it is simply large + // enough to hold the information on both 32 and 64 bit platforms. + struct Rendezvous { + uint64_t version; + lldb::addr_t map_addr; + lldb::addr_t brk; + uint64_t state; + lldb::addr_t ldbase; + + Rendezvous() : version(0), map_addr(0), brk(0), state(0), ldbase(0) {} + }; public: - // Various metadata supplied by the inferior's threading library to describe - // the per-thread state. - struct ThreadInfo { - bool valid; // whether we read valid metadata - uint32_t dtv_offset; // offset of DTV pointer within pthread - uint32_t dtv_slot_size; // size of one DTV slot - uint32_t modid_offset; // offset of module ID within link_map - uint32_t tls_offset; // offset of TLS pointer within DTV slot - }; - - DYLDRendezvous(lldb_private::Process *process); - - /// Update the internal snapshot of runtime linker rendezvous and recompute - /// the currently loaded modules. - /// - /// This method should be called once one start up, then once each time the - /// runtime linker enters the function given by GetBreakAddress(). - /// - /// @returns true on success and false on failure. - /// - /// @see GetBreakAddress(). - bool - Resolve(); - - /// @returns true if this rendezvous has been located in the inferiors - /// address space and false otherwise. - bool - IsValid(); - - /// @returns the address of the rendezvous structure in the inferiors - /// address space. - lldb::addr_t - GetRendezvousAddress() const { return m_rendezvous_addr; } - - /// @returns the version of the rendezvous protocol being used. - uint64_t - GetVersion() const { return m_current.version; } - - /// @returns address in the inferiors address space containing the linked - /// list of shared object descriptors. - lldb::addr_t - GetLinkMapAddress() const { return m_current.map_addr; } - - /// A breakpoint should be set at this address and Resolve called on each - /// hit. - /// - /// @returns the address of a function called by the runtime linker each - /// time a module is loaded/unloaded, or about to be loaded/unloaded. - /// - /// @see Resolve() - lldb::addr_t - GetBreakAddress() const { return m_current.brk; } - - /// Returns the current state of the rendezvous structure. - uint64_t - GetState() const { return m_current.state; } - - /// @returns the base address of the runtime linker in the inferiors address - /// space. - lldb::addr_t - GetLDBase() const { return m_current.ldbase; } - - /// @returns the thread layout metadata from the inferiors thread library. - const ThreadInfo& - GetThreadInfo(); - - /// @returns true if modules have been loaded into the inferior since the - /// last call to Resolve(). - bool - ModulesDidLoad() const { return !m_added_soentries.empty(); } - - /// @returns true if modules have been unloaded from the inferior since the - /// last call to Resolve(). - bool - ModulesDidUnload() const { return !m_removed_soentries.empty(); } - - void - DumpToLog(lldb_private::Log *log) const; - - /// @brief Constants describing the state of the rendezvous. - /// - /// @see GetState(). - enum RendezvousState { - eConsistent, - eAdd, - eDelete - }; - - /// @brief Structure representing the shared objects currently loaded into - /// the inferior process. - /// - /// This object is a rough analogue to the struct link_map object which - /// actually lives in the inferiors memory. - struct SOEntry { - lldb::addr_t link_addr; ///< Address of this link_map. - lldb::addr_t base_addr; ///< Base address of the loaded object. - lldb::addr_t path_addr; ///< String naming the shared object. - lldb::addr_t dyn_addr; ///< Dynamic section of shared object. - lldb::addr_t next; ///< Address of next so_entry. - lldb::addr_t prev; ///< Address of previous so_entry. - lldb_private::FileSpec file_spec; ///< File spec of shared object. - - SOEntry() { clear(); } - - bool operator ==(const SOEntry &entry) { - return file_spec == entry.file_spec; - } - - void clear() { - link_addr = 0; - base_addr = 0; - path_addr = 0; - dyn_addr = 0; - next = 0; - prev = 0; - file_spec.Clear(); - } - }; + // Various metadata supplied by the inferior's threading library to describe + // the per-thread state. + struct ThreadInfo { + bool valid; // whether we read valid metadata + uint32_t dtv_offset; // offset of DTV pointer within pthread + uint32_t dtv_slot_size; // size of one DTV slot + uint32_t modid_offset; // offset of module ID within link_map + uint32_t tls_offset; // offset of TLS pointer within DTV slot + }; + + DYLDRendezvous(lldb_private::Process *process); + + /// Update the internal snapshot of runtime linker rendezvous and recompute + /// the currently loaded modules. + /// + /// This method should be called once one start up, then once each time the + /// runtime linker enters the function given by GetBreakAddress(). + /// + /// @returns true on success and false on failure. + /// + /// @see GetBreakAddress(). + bool Resolve(); + + /// @returns true if this rendezvous has been located in the inferiors + /// address space and false otherwise. + bool IsValid(); + + /// @returns the address of the rendezvous structure in the inferiors + /// address space. + lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; } + + /// @returns the version of the rendezvous protocol being used. + uint64_t GetVersion() const { return m_current.version; } + + /// @returns address in the inferiors address space containing the linked + /// list of shared object descriptors. + lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; } + + /// A breakpoint should be set at this address and Resolve called on each + /// hit. + /// + /// @returns the address of a function called by the runtime linker each + /// time a module is loaded/unloaded, or about to be loaded/unloaded. + /// + /// @see Resolve() + lldb::addr_t GetBreakAddress() const { return m_current.brk; } + + /// Returns the current state of the rendezvous structure. + uint64_t GetState() const { return m_current.state; } + + /// @returns the base address of the runtime linker in the inferiors address + /// space. + lldb::addr_t GetLDBase() const { return m_current.ldbase; } + + /// @returns the thread layout metadata from the inferiors thread library. + const ThreadInfo &GetThreadInfo(); + + /// @returns true if modules have been loaded into the inferior since the + /// last call to Resolve(). + bool ModulesDidLoad() const { return !m_added_soentries.empty(); } + + /// @returns true if modules have been unloaded from the inferior since the + /// last call to Resolve(). + bool ModulesDidUnload() const { return !m_removed_soentries.empty(); } + + void DumpToLog(lldb_private::Log *log) const; + + /// @brief Constants describing the state of the rendezvous. + /// + /// @see GetState(). + enum RendezvousState { eConsistent, eAdd, eDelete }; + + /// @brief Structure representing the shared objects currently loaded into + /// the inferior process. + /// + /// This object is a rough analogue to the struct link_map object which + /// actually lives in the inferiors memory. + struct SOEntry { + lldb::addr_t link_addr; ///< Address of this link_map. + lldb::addr_t base_addr; ///< Base address of the loaded object. + lldb::addr_t path_addr; ///< String naming the shared object. + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. + lldb::addr_t next; ///< Address of next so_entry. + lldb::addr_t prev; ///< Address of previous so_entry. + lldb_private::FileSpec file_spec; ///< File spec of shared object. + + SOEntry() { clear(); } + + bool operator==(const SOEntry &entry) { + return file_spec == entry.file_spec; + } + + void clear() { + link_addr = 0; + base_addr = 0; + path_addr = 0; + dyn_addr = 0; + next = 0; + prev = 0; + file_spec.Clear(); + } + }; protected: - typedef std::list<SOEntry> SOEntryList; + typedef std::list<SOEntry> SOEntryList; public: - typedef SOEntryList::const_iterator iterator; - - /// Iterators over all currently loaded modules. - iterator begin() const { return m_soentries.begin(); } - iterator end() const { return m_soentries.end(); } - - /// Iterators over all modules loaded into the inferior since the last call - /// to Resolve(). - iterator loaded_begin() const { return m_added_soentries.begin(); } - iterator loaded_end() const { return m_added_soentries.end(); } - - /// Iterators over all modules unloaded from the inferior since the last - /// call to Resolve(). - iterator unloaded_begin() const { return m_removed_soentries.begin(); } - iterator unloaded_end() const { return m_removed_soentries.end(); } - + typedef SOEntryList::const_iterator iterator; + + /// Iterators over all currently loaded modules. + iterator begin() const { return m_soentries.begin(); } + iterator end() const { return m_soentries.end(); } + + /// Iterators over all modules loaded into the inferior since the last call + /// to Resolve(). + iterator loaded_begin() const { return m_added_soentries.begin(); } + iterator loaded_end() const { return m_added_soentries.end(); } + + /// Iterators over all modules unloaded from the inferior since the last + /// call to Resolve(). + iterator unloaded_begin() const { return m_removed_soentries.begin(); } + iterator unloaded_end() const { return m_removed_soentries.end(); } + protected: - lldb_private::Process *m_process; + lldb_private::Process *m_process; - // Cached copy of executable file spec - lldb_private::FileSpec m_exe_file_spec; + // Cached copy of executable file spec + lldb_private::FileSpec m_exe_file_spec; - /// Location of the r_debug structure in the inferiors address space. - lldb::addr_t m_rendezvous_addr; + /// Location of the r_debug structure in the inferiors address space. + lldb::addr_t m_rendezvous_addr; - /// Current and previous snapshots of the rendezvous structure. - Rendezvous m_current; - Rendezvous m_previous; + /// Current and previous snapshots of the rendezvous structure. + Rendezvous m_current; + Rendezvous m_previous; - /// List of currently loaded SO modules - LoadedModuleInfoList m_loaded_modules; + /// List of currently loaded SO modules + LoadedModuleInfoList m_loaded_modules; - /// List of SOEntry objects corresponding to the current link map state. - SOEntryList m_soentries; + /// List of SOEntry objects corresponding to the current link map state. + SOEntryList m_soentries; - /// List of SOEntry's added to the link map since the last call to Resolve(). - SOEntryList m_added_soentries; + /// List of SOEntry's added to the link map since the last call to Resolve(). + SOEntryList m_added_soentries; - /// List of SOEntry's removed from the link map since the last call to - /// Resolve(). - SOEntryList m_removed_soentries; + /// List of SOEntry's removed from the link map since the last call to + /// Resolve(). + SOEntryList m_removed_soentries; - /// Threading metadata read from the inferior. - ThreadInfo m_thread_info; + /// Threading metadata read from the inferior. + ThreadInfo m_thread_info; - /// Reads an unsigned integer of @p size bytes from the inferior's address - /// space starting at @p addr. - /// - /// @returns addr + size if the read was successful and false otherwise. - lldb::addr_t - ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); + /// Reads an unsigned integer of @p size bytes from the inferior's address + /// space starting at @p addr. + /// + /// @returns addr + size if the read was successful and false otherwise. + lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); - /// Reads an address from the inferior's address space starting at @p addr. - /// - /// @returns addr + target address size if the read was successful and - /// 0 otherwise. - lldb::addr_t - ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); + /// Reads an address from the inferior's address space starting at @p addr. + /// + /// @returns addr + target address size if the read was successful and + /// 0 otherwise. + lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); - /// Reads a null-terminated C string from the memory location starting at @p - /// addr. - std::string - ReadStringFromMemory(lldb::addr_t addr); + /// Reads a null-terminated C string from the memory location starting at @p + /// addr. + std::string ReadStringFromMemory(lldb::addr_t addr); - /// Reads an SOEntry starting at @p addr. - bool - ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); + /// Reads an SOEntry starting at @p addr. + bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); - /// Updates the current set of SOEntries, the set of added entries, and the - /// set of removed entries. - bool - UpdateSOEntries(bool fromRemote = false); + /// Updates the current set of SOEntries, the set of added entries, and the + /// set of removed entries. + bool UpdateSOEntries(bool fromRemote = false); - bool - FillSOEntryFromModuleInfo (LoadedModuleInfoList::LoadedModuleInfo const & modInfo, - SOEntry &entry); + bool FillSOEntryFromModuleInfo( + LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry); - bool - SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list); + bool SaveSOEntriesFromRemote(LoadedModuleInfoList &module_list); - bool - AddSOEntriesFromRemote(LoadedModuleInfoList &module_list); + bool AddSOEntriesFromRemote(LoadedModuleInfoList &module_list); - bool - RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list); + bool RemoveSOEntriesFromRemote(LoadedModuleInfoList &module_list); - bool - AddSOEntries(); + bool AddSOEntries(); - bool - RemoveSOEntries(); + bool RemoveSOEntries(); - void - UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path); + void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path); - bool - SOEntryIsMainExecutable(const SOEntry &entry); + bool SOEntryIsMainExecutable(const SOEntry &entry); - /// Reads the current list of shared objects according to the link map - /// supplied by the runtime linker. - bool - TakeSnapshot(SOEntryList &entry_list); + /// Reads the current list of shared objects according to the link map + /// supplied by the runtime linker. + bool TakeSnapshot(SOEntryList &entry_list); - enum PThreadField { eSize, eNElem, eOffset }; + enum PThreadField { eSize, eNElem, eOffset }; - bool FindMetadata(const char *name, PThreadField field, uint32_t& value); + bool FindMetadata(const char *name, PThreadField field, uint32_t &value); }; #endif diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 6515c02f37e0..fc225eebe605 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -1,4 +1,4 @@ -//===-- DynamicLoaderPOSIX.h ------------------------------------*- C++ -*-===// +//===-- DynamicLoaderPOSIXDYLD.cpp ------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,280 +7,267 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes +// Main header include +#include "DynamicLoaderPOSIXDYLD.h" + +// Project includes +#include "AuxVector.h" + // Other libraries and framework includes -#include "lldb/Core/PluginManager.h" +#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Target/Platform.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" +#include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanRunToAddress.h" -#include "lldb/Breakpoint/BreakpointLocation.h" -#include "AuxVector.h" -#include "DynamicLoaderPOSIXDYLD.h" +// C++ Includes +// C Includes using namespace lldb; using namespace lldb_private; -void -DynamicLoaderPOSIXDYLD::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); +void DynamicLoaderPOSIXDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); } -void -DynamicLoaderPOSIXDYLD::Terminate() -{ -} +void DynamicLoaderPOSIXDYLD::Terminate() {} -lldb_private::ConstString -DynamicLoaderPOSIXDYLD::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString DynamicLoaderPOSIXDYLD::GetPluginName() { + return GetPluginNameStatic(); } -lldb_private::ConstString -DynamicLoaderPOSIXDYLD::GetPluginNameStatic() -{ - static ConstString g_name("linux-dyld"); - return g_name; +lldb_private::ConstString DynamicLoaderPOSIXDYLD::GetPluginNameStatic() { + static ConstString g_name("linux-dyld"); + return g_name; } -const char * -DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that watches for shared library " - "loads/unloads in POSIX processes."; +const char *DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in POSIX processes."; } -uint32_t -DynamicLoaderPOSIXDYLD::GetPluginVersion() -{ - return 1; -} - -DynamicLoader * -DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, bool force) -{ - bool create = force; - if (!create) - { - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - if (triple_ref.getOS() == llvm::Triple::Linux || - triple_ref.getOS() == llvm::Triple::FreeBSD) - create = true; - } - - if (create) - return new DynamicLoaderPOSIXDYLD (process); - return NULL; +uint32_t DynamicLoaderPOSIXDYLD::GetPluginVersion() { return 1; } + +DynamicLoader *DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, + bool force) { + bool create = force; + if (!create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::Linux || + triple_ref.getOS() == llvm::Triple::FreeBSD) + create = true; + } + + if (create) + return new DynamicLoaderPOSIXDYLD(process); + return NULL; } DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process) - : DynamicLoader(process), - m_rendezvous(process), - m_load_offset(LLDB_INVALID_ADDRESS), - m_entry_point(LLDB_INVALID_ADDRESS), - m_auxv(), - m_dyld_bid(LLDB_INVALID_BREAK_ID), - m_vdso_base(LLDB_INVALID_ADDRESS) -{ + : DynamicLoader(process), m_rendezvous(process), + m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), + m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID), + m_vdso_base(LLDB_INVALID_ADDRESS) {} + +DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() { + if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { + m_process->GetTarget().RemoveBreakpointByID(m_dyld_bid); + m_dyld_bid = LLDB_INVALID_BREAK_ID; + } } -DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() -{ - if (m_dyld_bid != LLDB_INVALID_BREAK_ID) - { - m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid); - m_dyld_bid = LLDB_INVALID_BREAK_ID; +void DynamicLoaderPOSIXDYLD::DidAttach() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + m_auxv.reset(new AuxVector(m_process)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + // ask the process if it can load any of its own modules + m_process->LoadModules(); + + ModuleSP executable_sp = GetTargetExecutable(); + ResolveExecutableModule(executable_sp); + + // find the main process load offset + addr_t load_offset = ComputeLoadOffset(); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " executable '%s', load_offset 0x%" PRIx64, + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + executable_sp ? executable_sp->GetFileSpec().GetPath().c_str() + : "<null executable>", + load_offset); + + EvalVdsoStatus(); + + // if we dont have a load address we cant re-base + bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; + + // if we have a valid executable + if (executable_sp.get()) { + lldb_private::ObjectFile *obj = executable_sp->GetObjectFile(); + if (obj) { + // don't rebase if the module already has a load address + Target &target = m_process->GetTarget(); + Address addr = obj->GetImageInfoAddress(&target); + if (addr.GetLoadAddress(&target) != LLDB_INVALID_ADDRESS) + rebase_exec = false; } -} + } else { + // no executable, nothing to re-base + rebase_exec = false; + } -void -DynamicLoaderPOSIXDYLD::DidAttach() -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - - m_auxv.reset(new AuxVector(m_process)); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reloaded auxv data", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - - // ask the process if it can load any of its own modules - m_process->LoadModules (); - - ModuleSP executable_sp = GetTargetExecutable (); - ResolveExecutableModule (executable_sp); + // if the target executable should be re-based + if (rebase_exec) { + ModuleList module_list; - // find the main process load offset - addr_t load_offset = ComputeLoadOffset (); + module_list.Append(executable_sp); if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " executable '%s', load_offset 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, executable_sp ? executable_sp->GetFileSpec().GetPath().c_str () : "<null executable>", load_offset); - - EvalVdsoStatus(); - - // if we dont have a load address we cant re-base - bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; - - // if we have a valid executable - if (executable_sp.get()) - { - lldb_private::ObjectFile * obj = executable_sp->GetObjectFile(); - if (obj) - { - // don't rebase if the module already has a load address - Target & target = m_process->GetTarget (); - Address addr = obj->GetImageInfoAddress (&target); - if (addr.GetLoadAddress (&target) != LLDB_INVALID_ADDRESS) - rebase_exec = false; - } - } - else - { - // no executable, nothing to re-base - rebase_exec = false; + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " added executable '%s' to module load list", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + executable_sp->GetFileSpec().GetPath().c_str()); + + UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset, + true); + + // When attaching to a target, there are two possible states: + // (1) We already crossed the entry point and therefore the rendezvous + // structure is ready to be used and we can load the list of modules + // and place the rendezvous breakpoint. + // (2) We didn't cross the entry point yet, so these structures are not + // ready; we should behave as if we just launched the target and + // call ProbeEntry(). This will place a breakpoint on the entry + // point which itself will be hit after the rendezvous structure is + // set up and will perform actions described in (1). + if (m_rendezvous.Resolve()) { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 + " rendezvous could resolve: attach assuming dynamic loader " + "info is available now", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + LoadAllCurrentModules(); + SetRendezvousBreakpoint(); + } else { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 + " rendezvous could not yet resolve: adding breakpoint to " + "catch future rendezvous setup", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + ProbeEntry(); } - // if the target executable should be re-based - if (rebase_exec) - { - ModuleList module_list; - - module_list.Append(executable_sp); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " added executable '%s' to module load list", - __FUNCTION__, - m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, - executable_sp->GetFileSpec().GetPath().c_str ()); - - UpdateLoadedSections(executable_sp, LLDB_INVALID_ADDRESS, load_offset, true); - - // When attaching to a target, there are two possible states: - // (1) We already crossed the entry point and therefore the rendezvous - // structure is ready to be used and we can load the list of modules - // and place the rendezvous breakpoint. - // (2) We didn't cross the entry point yet, so these structures are not - // ready; we should behave as if we just launched the target and - // call ProbeEntry(). This will place a breakpoint on the entry - // point which itself will be hit after the rendezvous structure is - // set up and will perform actions described in (1). - if (m_rendezvous.Resolve()) - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could resolve: attach assuming dynamic loader info is available now", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - LoadAllCurrentModules(); - SetRendezvousBreakpoint(); - } - else - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s() pid %" PRIu64 " rendezvous could not yet resolve: adding breakpoint to catch future rendezvous setup", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - ProbeEntry(); - } - - m_process->GetTarget().ModulesDidLoad(module_list); - if (log) - { - log->Printf ("DynamicLoaderPOSIXDYLD::%s told the target about the modules that loaded:", __FUNCTION__); - for (auto module_sp : module_list.Modules ()) - { - log->Printf ("-- [module] %s (pid %" PRIu64 ")", - module_sp ? module_sp->GetFileSpec().GetPath().c_str () : "<null>", - m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - } - } + m_process->GetTarget().ModulesDidLoad(module_list); + if (log) { + log->Printf("DynamicLoaderPOSIXDYLD::%s told the target about the " + "modules that loaded:", + __FUNCTION__); + for (auto module_sp : module_list.Modules()) { + log->Printf("-- [module] %s (pid %" PRIu64 ")", + module_sp ? module_sp->GetFileSpec().GetPath().c_str() + : "<null>", + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + } } + } } -void -DynamicLoaderPOSIXDYLD::DidLaunch() -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__); +void DynamicLoaderPOSIXDYLD::DidLaunch() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s()", __FUNCTION__); - ModuleSP executable; - addr_t load_offset; + ModuleSP executable; + addr_t load_offset; - m_auxv.reset(new AuxVector(m_process)); + m_auxv.reset(new AuxVector(m_process)); - executable = GetTargetExecutable(); - load_offset = ComputeLoadOffset(); - EvalVdsoStatus(); + executable = GetTargetExecutable(); + load_offset = ComputeLoadOffset(); + EvalVdsoStatus(); - if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) - { - ModuleList module_list; - module_list.Append(executable); - UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true); + if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) { + ModuleList module_list; + module_list.Append(executable); + UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset, true); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__); - ProbeEntry(); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", + __FUNCTION__); + ProbeEntry(); - m_process->GetTarget().ModulesDidLoad(module_list); - } + m_process->GetTarget().ModulesDidLoad(module_list); + } } -Error -DynamicLoaderPOSIXDYLD::CanLoadImage() -{ - return Error(); -} +Error DynamicLoaderPOSIXDYLD::CanLoadImage() { return Error(); } -void -DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, - addr_t link_map_addr, - addr_t base_addr, - bool base_addr_is_offset) -{ - m_loaded_modules[module] = link_map_addr; - UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); +void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, + addr_t link_map_addr, + addr_t base_addr, + bool base_addr_is_offset) { + m_loaded_modules[module] = link_map_addr; + UpdateLoadedSectionsCommon(module, base_addr, base_addr_is_offset); } -void -DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) -{ - m_loaded_modules.erase(module); +void DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) { + m_loaded_modules.erase(module); - UnloadSectionsCommon(module); + UnloadSectionsCommon(module); } -void -DynamicLoaderPOSIXDYLD::ProbeEntry() -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - - const addr_t entry = GetEntryPoint(); - if (entry == LLDB_INVALID_ADDRESS) - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned no address, not setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID); - return; - } +void DynamicLoaderPOSIXDYLD::ProbeEntry() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + const addr_t entry = GetEntryPoint(); + if (entry == LLDB_INVALID_ADDRESS) { if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " GetEntryPoint() returned address 0x%" PRIx64 ", setting entry breakpoint", __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, entry); - - if (m_process) - { - Breakpoint *const entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get(); - entry_break->SetCallback(EntryBreakpointHit, this, true); - entry_break->SetBreakpointKind("shared-library-event"); - - // Shoudn't hit this more than once. - entry_break->SetOneShot (true); - } + log->Printf( + "DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " GetEntryPoint() returned no address, not setting entry breakpoint", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + return; + } + + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " GetEntryPoint() returned address 0x%" PRIx64 + ", setting entry breakpoint", + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + entry); + + if (m_process) { + Breakpoint *const entry_break = + m_process->GetTarget().CreateBreakpoint(entry, true, false).get(); + entry_break->SetCallback(EntryBreakpointHit, this, true); + entry_break->SetBreakpointKind("shared-library-event"); + + // Shoudn't hit this more than once. + entry_break->SetOneShot(true); + } } // The runtime linker has run and initialized the rendezvous structure once the @@ -289,405 +276,429 @@ DynamicLoaderPOSIXDYLD::ProbeEntry() // dependent modules for the process. Similarly, we can discover the runtime // linker function and setup a breakpoint to notify us of any dynamically loaded // modules (via dlopen). -bool -DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton, - StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id) -{ - assert(baton && "null baton"); - if (!baton) - return false; - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID); - - // Disable the breakpoint --- if a stop happens right after this, which we've seen on occasion, we don't - // want the breakpoint stepping thread-plan logic to show a breakpoint instruction at the disassembled - // entry point to the program. Disabling it prevents it. (One-shot is not enough - one-shot removal logic - // only happens after the breakpoint goes public, which wasn't happening in our scenario). - if (dyld_instance->m_process) - { - BreakpointSP breakpoint_sp = dyld_instance->m_process->GetTarget().GetBreakpointByID (break_id); - if (breakpoint_sp) - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " disabling breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id); - breakpoint_sp->SetEnabled (false); - } - else - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " failed to find breakpoint for breakpoint id %" PRIu64, __FUNCTION__, dyld_instance->m_process->GetID (), break_id); - } - } - else - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64 " no Process instance! Cannot disable breakpoint", __FUNCTION__, break_id); +bool DynamicLoaderPOSIXDYLD::EntryBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(baton && "null baton"); + if (!baton) + return false; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + DynamicLoaderPOSIXDYLD *const dyld_instance = + static_cast<DynamicLoaderPOSIXDYLD *>(baton); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, + __FUNCTION__, + dyld_instance->m_process ? dyld_instance->m_process->GetID() + : LLDB_INVALID_PROCESS_ID); + + // Disable the breakpoint --- if a stop happens right after this, which we've + // seen on occasion, we don't + // want the breakpoint stepping thread-plan logic to show a breakpoint + // instruction at the disassembled + // entry point to the program. Disabling it prevents it. (One-shot is not + // enough - one-shot removal logic + // only happens after the breakpoint goes public, which wasn't happening in + // our scenario). + if (dyld_instance->m_process) { + BreakpointSP breakpoint_sp = + dyld_instance->m_process->GetTarget().GetBreakpointByID(break_id); + if (breakpoint_sp) { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " disabling breakpoint id %" PRIu64, + __FUNCTION__, dyld_instance->m_process->GetID(), break_id); + breakpoint_sp->SetEnabled(false); + } else { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " failed to find breakpoint for breakpoint id %" PRIu64, + __FUNCTION__, dyld_instance->m_process->GetID(), break_id); } - - dyld_instance->LoadAllCurrentModules(); - dyld_instance->SetRendezvousBreakpoint(); - return false; // Continue running. + } else { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s breakpoint id %" PRIu64 + " no Process instance! Cannot disable breakpoint", + __FUNCTION__, break_id); + } + + dyld_instance->LoadAllCurrentModules(); + dyld_instance->SetRendezvousBreakpoint(); + return false; // Continue running. } -void -DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() -{ - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - - addr_t break_addr = m_rendezvous.GetBreakAddress(); - Target &target = m_process->GetTarget(); - - if (m_dyld_bid == LLDB_INVALID_BREAK_ID) - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " setting rendezvous break address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, break_addr); - Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get(); - dyld_break->SetCallback(RendezvousBreakpointHit, this, true); - dyld_break->SetBreakpointKind ("shared-library-event"); - m_dyld_bid = dyld_break->GetID(); - } - else - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " reusing break id %" PRIu32 ", address at 0x%" PRIx64, __FUNCTION__, m_process ? m_process->GetID () : LLDB_INVALID_PROCESS_ID, m_dyld_bid, break_addr); - } +void DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - // Make sure our breakpoint is at the right address. - assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid); -} + addr_t break_addr = m_rendezvous.GetBreakAddress(); + Target &target = m_process->GetTarget(); -bool -DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton, - StoppointCallbackContext *context, - user_id_t break_id, - user_id_t break_loc_id) -{ - assert (baton && "null baton"); - if (!baton) - return false; - - Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - DynamicLoaderPOSIXDYLD *const dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); + if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID); - - dyld_instance->RefreshModules(); - - // Return true to stop the target, false to just let the target run. - const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange(); + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " setting rendezvous break address at 0x%" PRIx64, + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + break_addr); + Breakpoint *dyld_break = + target.CreateBreakpoint(break_addr, true, false).get(); + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + m_dyld_bid = dyld_break->GetID(); + } else { if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 " stop_when_images_change=%s", __FUNCTION__, dyld_instance->m_process ? dyld_instance->m_process->GetID () : LLDB_INVALID_PROCESS_ID, stop_when_images_change ? "true" : "false"); - return stop_when_images_change; + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " reusing break id %" PRIu32 ", address at 0x%" PRIx64, + __FUNCTION__, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + m_dyld_bid, break_addr); + } + + // Make sure our breakpoint is at the right address. + assert(target.GetBreakpointByID(m_dyld_bid) + ->FindLocationByAddress(break_addr) + ->GetBreakpoint() + .GetID() == m_dyld_bid); +} + +bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(baton && "null baton"); + if (!baton) + return false; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + DynamicLoaderPOSIXDYLD *const dyld_instance = + static_cast<DynamicLoaderPOSIXDYLD *>(baton); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s called for pid %" PRIu64, + __FUNCTION__, + dyld_instance->m_process ? dyld_instance->m_process->GetID() + : LLDB_INVALID_PROCESS_ID); + + dyld_instance->RefreshModules(); + + // Return true to stop the target, false to just let the target run. + const bool stop_when_images_change = dyld_instance->GetStopWhenImagesChange(); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 + " stop_when_images_change=%s", + __FUNCTION__, + dyld_instance->m_process ? dyld_instance->m_process->GetID() + : LLDB_INVALID_PROCESS_ID, + stop_when_images_change ? "true" : "false"); + return stop_when_images_change; } -void -DynamicLoaderPOSIXDYLD::RefreshModules() -{ - if (!m_rendezvous.Resolve()) - return; - - DYLDRendezvous::iterator I; - DYLDRendezvous::iterator E; - - ModuleList &loaded_modules = m_process->GetTarget().GetImages(); - - if (m_rendezvous.ModulesDidLoad()) - { - ModuleList new_modules; - - E = m_rendezvous.loaded_end(); - for (I = m_rendezvous.loaded_begin(); I != E; ++I) - { - ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); - if (module_sp.get()) - { - loaded_modules.AppendIfNeeded(module_sp); - new_modules.Append(module_sp); - } - } - m_process->GetTarget().ModulesDidLoad(new_modules); +void DynamicLoaderPOSIXDYLD::RefreshModules() { + if (!m_rendezvous.Resolve()) + return; + + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + if (m_rendezvous.ModulesDidLoad()) { + ModuleList new_modules; + + E = m_rendezvous.loaded_end(); + for (I = m_rendezvous.loaded_begin(); I != E; ++I) { + ModuleSP module_sp = + LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); + if (module_sp.get()) { + loaded_modules.AppendIfNeeded(module_sp); + new_modules.Append(module_sp); + } } - - if (m_rendezvous.ModulesDidUnload()) - { - ModuleList old_modules; - - E = m_rendezvous.unloaded_end(); - for (I = m_rendezvous.unloaded_begin(); I != E; ++I) - { - ModuleSpec module_spec{I->file_spec}; - ModuleSP module_sp = loaded_modules.FindFirstModule (module_spec); - - if (module_sp.get()) - { - old_modules.Append(module_sp); - UnloadSections(module_sp); - } - } - loaded_modules.Remove(old_modules); - m_process->GetTarget().ModulesDidUnload(old_modules, false); + m_process->GetTarget().ModulesDidLoad(new_modules); + } + + if (m_rendezvous.ModulesDidUnload()) { + ModuleList old_modules; + + E = m_rendezvous.unloaded_end(); + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) { + ModuleSpec module_spec{I->file_spec}; + ModuleSP module_sp = loaded_modules.FindFirstModule(module_spec); + + if (module_sp.get()) { + old_modules.Append(module_sp); + UnloadSections(module_sp); + } } + loaded_modules.Remove(old_modules); + m_process->GetTarget().ModulesDidUnload(old_modules, false); + } } ThreadPlanSP -DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) -{ - ThreadPlanSP thread_plan_sp; - - StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); - const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); - Symbol *sym = context.symbol; - - if (sym == NULL || !sym->IsTrampoline()) - return thread_plan_sp; - - ConstString sym_name = sym->GetName(); - if (!sym_name) - return thread_plan_sp; - - SymbolContextList target_symbols; - Target &target = thread.GetProcess()->GetTarget(); - const ModuleList &images = target.GetImages(); - - images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); - size_t num_targets = target_symbols.GetSize(); - if (!num_targets) - return thread_plan_sp; - - typedef std::vector<lldb::addr_t> AddressVector; - AddressVector addrs; - for (size_t i = 0; i < num_targets; ++i) - { - SymbolContext context; - AddressRange range; - if (target_symbols.GetContextAtIndex(i, context)) - { - context.GetAddressRange(eSymbolContextEverything, 0, false, range); - lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); - if (addr != LLDB_INVALID_ADDRESS) - addrs.push_back(addr); - } - } +DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + ThreadPlanSP thread_plan_sp; - if (addrs.size() > 0) - { - AddressVector::iterator start = addrs.begin(); - AddressVector::iterator end = addrs.end(); + StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); + const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); + Symbol *sym = context.symbol; - std::sort(start, end); - addrs.erase(std::unique(start, end), end); - thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); - } + if (sym == NULL || !sym->IsTrampoline()) + return thread_plan_sp; + ConstString sym_name = sym->GetName(); + if (!sym_name) return thread_plan_sp; -} -void -DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() -{ - DYLDRendezvous::iterator I; - DYLDRendezvous::iterator E; - ModuleList module_list; - - if (!m_rendezvous.Resolve()) - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD rendezvous address", - __FUNCTION__); - return; + SymbolContextList target_symbols; + Target &target = thread.GetProcess()->GetTarget(); + const ModuleList &images = target.GetImages(); + + images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); + size_t num_targets = target_symbols.GetSize(); + if (!num_targets) + return thread_plan_sp; + + typedef std::vector<lldb::addr_t> AddressVector; + AddressVector addrs; + for (size_t i = 0; i < num_targets; ++i) { + SymbolContext context; + AddressRange range; + if (target_symbols.GetContextAtIndex(i, context)) { + context.GetAddressRange(eSymbolContextEverything, 0, false, range); + lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); + if (addr != LLDB_INVALID_ADDRESS) + addrs.push_back(addr); } + } + + if (addrs.size() > 0) { + AddressVector::iterator start = addrs.begin(); + AddressVector::iterator end = addrs.end(); - // The rendezvous class doesn't enumerate the main module, so track - // that ourselves here. - ModuleSP executable = GetTargetExecutable(); - m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); - if (m_vdso_base != LLDB_INVALID_ADDRESS) - { - FileSpec file_spec("[vdso]", false); - ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS, m_vdso_base, false); - if (module_sp.get()) - { - module_list.Append(module_sp); - } + std::sort(start, end); + addrs.erase(std::unique(start, end), end); + thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); + } + + return thread_plan_sp; +} + +void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + ModuleList module_list; + + if (!m_rendezvous.Resolve()) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD " + "rendezvous address", + __FUNCTION__); + return; + } + + // The rendezvous class doesn't enumerate the main module, so track + // that ourselves here. + ModuleSP executable = GetTargetExecutable(); + m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); + if (m_vdso_base != LLDB_INVALID_ADDRESS) { + FileSpec file_spec("[vdso]", false); + ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS, + m_vdso_base, false); + if (module_sp.get()) { + module_list.Append(module_sp); } - for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) - { - ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); - if (module_sp.get()) - { - module_list.Append(module_sp); - } - else - { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64, - __FUNCTION__, I->file_spec.GetCString(), I->base_addr); - } + } + + std::vector<FileSpec> module_names; + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) + module_names.push_back(I->file_spec); + m_process->PrefetchModuleSpecs( + module_names, m_process->GetTarget().GetArchitecture().GetTriple()); + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) { + ModuleSP module_sp = + LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); + if (module_sp.get()) { + module_list.Append(module_sp); + } else { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf( + "DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64, + __FUNCTION__, I->file_spec.GetCString(), I->base_addr); } + } - m_process->GetTarget().ModulesDidLoad(module_list); + m_process->GetTarget().ModulesDidLoad(module_list); } -addr_t -DynamicLoaderPOSIXDYLD::ComputeLoadOffset() -{ - addr_t virt_entry; +addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { + addr_t virt_entry; - if (m_load_offset != LLDB_INVALID_ADDRESS) - return m_load_offset; + if (m_load_offset != LLDB_INVALID_ADDRESS) + return m_load_offset; - if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; + if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; - ModuleSP module = m_process->GetTarget().GetExecutableModule(); - if (!module) - return LLDB_INVALID_ADDRESS; + ModuleSP module = m_process->GetTarget().GetExecutableModule(); + if (!module) + return LLDB_INVALID_ADDRESS; - ObjectFile *exe = module->GetObjectFile(); - if (!exe) - return LLDB_INVALID_ADDRESS; + ObjectFile *exe = module->GetObjectFile(); + if (!exe) + return LLDB_INVALID_ADDRESS; - Address file_entry = exe->GetEntryPointAddress(); + Address file_entry = exe->GetEntryPointAddress(); - if (!file_entry.IsValid()) - return LLDB_INVALID_ADDRESS; - - m_load_offset = virt_entry - file_entry.GetFileAddress(); - return m_load_offset; -} + if (!file_entry.IsValid()) + return LLDB_INVALID_ADDRESS; -void -DynamicLoaderPOSIXDYLD::EvalVdsoStatus() -{ - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_SYSINFO_EHDR); + m_load_offset = virt_entry - file_entry.GetFileAddress(); + return m_load_offset; +} - if (I != m_auxv->end()) - m_vdso_base = I->value; +void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() { + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_SYSINFO_EHDR); + if (I != m_auxv->end()) + m_vdso_base = I->value; } -addr_t -DynamicLoaderPOSIXDYLD::GetEntryPoint() -{ - if (m_entry_point != LLDB_INVALID_ADDRESS) - return m_entry_point; +addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() { + if (m_entry_point != LLDB_INVALID_ADDRESS) + return m_entry_point; - if (m_auxv.get() == NULL) - return LLDB_INVALID_ADDRESS; + if (m_auxv.get() == NULL) + return LLDB_INVALID_ADDRESS; - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); - if (I == m_auxv->end()) - return LLDB_INVALID_ADDRESS; + if (I == m_auxv->end()) + return LLDB_INVALID_ADDRESS; - m_entry_point = static_cast<addr_t>(I->value); + m_entry_point = static_cast<addr_t>(I->value); - const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); + const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); - // On ppc64, the entry point is actually a descriptor. Dereference it. - if (arch.GetMachine() == llvm::Triple::ppc64) - m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8); + // On ppc64, the entry point is actually a descriptor. Dereference it. + if (arch.GetMachine() == llvm::Triple::ppc64) + m_entry_point = ReadUnsignedIntWithSizeInBytes(m_entry_point, 8); - return m_entry_point; + return m_entry_point; } lldb::addr_t -DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, const lldb::ThreadSP thread, - lldb::addr_t tls_file_addr) -{ - auto it = m_loaded_modules.find (module_sp); - if (it == m_loaded_modules.end()) - return LLDB_INVALID_ADDRESS; - - addr_t link_map = it->second; - if (link_map == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); - if (!metadata.valid) - return LLDB_INVALID_ADDRESS; - - // Get the thread pointer. - addr_t tp = thread->GetThreadPointer (); - if (tp == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - // Find the module's modid. - int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit - int64_t modid = ReadUnsignedIntWithSizeInBytes (link_map + metadata.modid_offset, modid_size); - if (modid == -1) - return LLDB_INVALID_ADDRESS; - - // Lookup the DTV structure for this thread. - addr_t dtv_ptr = tp + metadata.dtv_offset; - addr_t dtv = ReadPointer (dtv_ptr); - if (dtv == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - - // Find the TLS block for this module. - addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid; - addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset); - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::Performed TLS lookup: " - "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", - module_sp->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block); - - if (tls_block == LLDB_INVALID_ADDRESS) - return LLDB_INVALID_ADDRESS; - else - return tls_block + tls_file_addr; +DynamicLoaderPOSIXDYLD::GetThreadLocalData(const lldb::ModuleSP module_sp, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) { + auto it = m_loaded_modules.find(module_sp); + if (it == m_loaded_modules.end()) + return LLDB_INVALID_ADDRESS; + + addr_t link_map = it->second; + if (link_map == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo(); + if (!metadata.valid) + return LLDB_INVALID_ADDRESS; + + // Get the thread pointer. + addr_t tp = thread->GetThreadPointer(); + if (tp == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the module's modid. + int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit + int64_t modid = ReadUnsignedIntWithSizeInBytes( + link_map + metadata.modid_offset, modid_size); + if (modid == -1) + return LLDB_INVALID_ADDRESS; + + // Lookup the DTV structure for this thread. + addr_t dtv_ptr = tp + metadata.dtv_offset; + addr_t dtv = ReadPointer(dtv_ptr); + if (dtv == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + // Find the TLS block for this module. + addr_t dtv_slot = dtv + metadata.dtv_slot_size * modid; + addr_t tls_block = ReadPointer(dtv_slot + metadata.tls_offset); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::Performed TLS lookup: " + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 + ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", + module_sp->GetObjectName().AsCString(""), link_map, tp, + (int64_t)modid, tls_block); + + if (tls_block == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + else + return tls_block + tls_file_addr; } -void -DynamicLoaderPOSIXDYLD::ResolveExecutableModule (lldb::ModuleSP &module_sp) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); +void DynamicLoaderPOSIXDYLD::ResolveExecutableModule( + lldb::ModuleSP &module_sp) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); - if (m_process == nullptr) - return; + if (m_process == nullptr) + return; - auto &target = m_process->GetTarget (); - const auto platform_sp = target.GetPlatform (); + auto &target = m_process->GetTarget(); + const auto platform_sp = target.GetPlatform(); - ProcessInstanceInfo process_info; - if (!m_process->GetProcessInfo(process_info)) - { - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s - failed to get process info for pid %" PRIu64, - __FUNCTION__, m_process->GetID ()); - return; - } + ProcessInstanceInfo process_info; + if (!m_process->GetProcessInfo(process_info)) { + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s - failed to get process info for " + "pid %" PRIu64, + __FUNCTION__, m_process->GetID()); + return; + } + + if (log) + log->Printf("DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 + ": %s", + __FUNCTION__, m_process->GetID(), + process_info.GetExecutableFile().GetPath().c_str()); + + ModuleSpec module_spec(process_info.GetExecutableFile(), + process_info.GetArchitecture()); + if (module_sp && module_sp->MatchesModuleSpec(module_spec)) + return; + + const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths()); + auto error = platform_sp->ResolveExecutable( + module_spec, module_sp, + !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); + if (error.Fail()) { + StreamString stream; + module_spec.Dump(stream); if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s - got executable by pid %" PRIu64 ": %s", - __FUNCTION__, m_process->GetID (), process_info.GetExecutableFile ().GetPath ().c_str ()); - - ModuleSpec module_spec (process_info.GetExecutableFile (), process_info.GetArchitecture ()); - if (module_sp && module_sp->MatchesModuleSpec (module_spec)) - return; - - const auto executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - auto error = platform_sp->ResolveExecutable ( - module_spec, module_sp, !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr); - if (error.Fail ()) - { - StreamString stream; - module_spec.Dump (stream); - - if (log) - log->Printf ("DynamicLoaderPOSIXDYLD::%s - failed to resolve executable with module spec \"%s\": %s", - __FUNCTION__, stream.GetString ().c_str (), error.AsCString ()); - return; - } + log->Printf("DynamicLoaderPOSIXDYLD::%s - failed to resolve executable " + "with module spec \"%s\": %s", + __FUNCTION__, stream.GetData(), error.AsCString()); + return; + } + + target.SetExecutableModule(module_sp, false); +} - target.SetExecutableModule (module_sp, false); +bool DynamicLoaderPOSIXDYLD::AlwaysRelyOnEHUnwindInfo( + lldb_private::SymbolContext &sym_ctx) { + ModuleSP module_sp; + if (sym_ctx.symbol) + module_sp = sym_ctx.symbol->GetAddressRef().GetModule(); + if (!module_sp && sym_ctx.function) + module_sp = + sym_ctx.function->GetAddressRange().GetBaseAddress().GetModule(); + if (!module_sp) + return false; + + return module_sp->GetFileSpec().GetPath() == "[vdso]"; } diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 890808c5179c..1e8333fb099a 100644 --- a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -21,159 +21,139 @@ class AuxVector; -class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader -{ +class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader { public: - DynamicLoaderPOSIXDYLD(lldb_private::Process *process); + DynamicLoaderPOSIXDYLD(lldb_private::Process *process); - ~DynamicLoaderPOSIXDYLD() override; + ~DynamicLoaderPOSIXDYLD() override; - static void - Initialize(); + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - static lldb_private::DynamicLoader * - CreateInstance(lldb_private::Process *process, bool force); + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); - //------------------------------------------------------------------ - // DynamicLoader protocol - //------------------------------------------------------------------ + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ - void - DidAttach() override; + void DidAttach() override; - void - DidLaunch() override; + void DidLaunch() override; - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan(lldb_private::Thread &thread, - bool stop_others) override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; - lldb_private::Error - CanLoadImage() override; + lldb_private::Error CanLoadImage() override; - lldb::addr_t - GetThreadLocalData(const lldb::ModuleSP module, const lldb::ThreadSP thread, lldb::addr_t tls_file_addr) override; + lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, + const lldb::ThreadSP thread, + lldb::addr_t tls_file_addr) override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; protected: - /// Runtime linker rendezvous structure. - DYLDRendezvous m_rendezvous; - - /// Virtual load address of the inferior process. - lldb::addr_t m_load_offset; - - /// Virtual entry address of the inferior process. - lldb::addr_t m_entry_point; - - /// Auxiliary vector of the inferior process. - std::unique_ptr<AuxVector> m_auxv; - - /// Rendezvous breakpoint. - lldb::break_id_t m_dyld_bid; - - /// Contains AT_SYSINFO_EHDR, which means a vDSO has been - /// mapped to the address space - lldb::addr_t m_vdso_base; - - /// Loaded module list. (link map for each module) - std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> m_loaded_modules; - - /// Enables a breakpoint on a function called by the runtime - /// linker each time a module is loaded or unloaded. - virtual void - SetRendezvousBreakpoint(); - - /// Callback routine which updates the current list of loaded modules based - /// on the information supplied by the runtime linker. - static bool - RendezvousBreakpointHit(void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set - /// of loaded modules. - void - RefreshModules(); - - /// Updates the load address of every allocatable section in @p module. - /// - /// @param module The module to traverse. - /// - /// @param link_map_addr The virtual address of the link map for the @p module. - /// - /// @param base_addr The virtual base address @p module is loaded at. - void - UpdateLoadedSections(lldb::ModuleSP module, - lldb::addr_t link_map_addr, - lldb::addr_t base_addr, - bool base_addr_is_offset) override; - - /// Removes the loaded sections from the target in @p module. - /// - /// @param module The module to traverse. - void - UnloadSections(const lldb::ModuleSP module) override; - - /// Resolves the entry point for the current inferior process and sets a - /// breakpoint at that address. - void - ProbeEntry(); - - /// Callback routine invoked when we hit the breakpoint on process entry. - /// - /// This routine is responsible for resolving the load addresses of all - /// dependent modules required by the inferior and setting up the rendezvous - /// breakpoint. - static bool - EntryBreakpointHit(void *baton, - lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - - /// Helper for the entry breakpoint callback. Resolves the load addresses - /// of all dependent modules. - virtual void - LoadAllCurrentModules(); - - /// Computes a value for m_load_offset returning the computed address on - /// success and LLDB_INVALID_ADDRESS on failure. - lldb::addr_t - ComputeLoadOffset(); - - /// Computes a value for m_entry_point returning the computed address on - /// success and LLDB_INVALID_ADDRESS on failure. - lldb::addr_t - GetEntryPoint(); - - /// Evaluate if Aux vectors contain vDSO information - /// in case they do, read and assign the address to m_vdso_base - void - EvalVdsoStatus(); - - /// Loads Module from inferior process. - void - ResolveExecutableModule(lldb::ModuleSP &module_sp); + /// Runtime linker rendezvous structure. + DYLDRendezvous m_rendezvous; + + /// Virtual load address of the inferior process. + lldb::addr_t m_load_offset; + + /// Virtual entry address of the inferior process. + lldb::addr_t m_entry_point; + + /// Auxiliary vector of the inferior process. + std::unique_ptr<AuxVector> m_auxv; + + /// Rendezvous breakpoint. + lldb::break_id_t m_dyld_bid; + + /// Contains AT_SYSINFO_EHDR, which means a vDSO has been + /// mapped to the address space + lldb::addr_t m_vdso_base; + + /// Loaded module list. (link map for each module) + std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>> + m_loaded_modules; + + /// Enables a breakpoint on a function called by the runtime + /// linker each time a module is loaded or unloaded. + virtual void SetRendezvousBreakpoint(); + + /// Callback routine which updates the current list of loaded modules based + /// on the information supplied by the runtime linker. + static bool RendezvousBreakpointHit( + void *baton, lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set + /// of loaded modules. + void RefreshModules(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param link_map_addr The virtual address of the link map for the @p + /// module. + /// + /// @param base_addr The virtual base address @p module is loaded at. + void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr, + lldb::addr_t base_addr, + bool base_addr_is_offset) override; + + /// Removes the loaded sections from the target in @p module. + /// + /// @param module The module to traverse. + void UnloadSections(const lldb::ModuleSP module) override; + + /// Resolves the entry point for the current inferior process and sets a + /// breakpoint at that address. + void ProbeEntry(); + + /// Callback routine invoked when we hit the breakpoint on process entry. + /// + /// This routine is responsible for resolving the load addresses of all + /// dependent modules required by the inferior and setting up the rendezvous + /// breakpoint. + static bool + EntryBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + /// Helper for the entry breakpoint callback. Resolves the load addresses + /// of all dependent modules. + virtual void LoadAllCurrentModules(); + + /// Computes a value for m_load_offset returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t ComputeLoadOffset(); + + /// Computes a value for m_entry_point returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t GetEntryPoint(); + + /// Evaluate if Aux vectors contain vDSO information + /// in case they do, read and assign the address to m_vdso_base + void EvalVdsoStatus(); + + /// Loads Module from inferior process. + void ResolveExecutableModule(lldb::ModuleSP &module_sp); + + bool AlwaysRelyOnEHUnwindInfo(lldb_private::SymbolContext &sym_ctx) override; private: - DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); }; #endif // liblldb_DynamicLoaderPOSIXDYLD_h_ diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index daa21adf3a95..04f1f3390570 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -23,50 +23,42 @@ using namespace lldb_private; // the plugin info class that gets handed out by the plugin factory and // allows the lldb to instantiate an instance of this class. //---------------------------------------------------------------------- -DynamicLoader * -DynamicLoaderStatic::CreateInstance (Process* process, bool force) -{ - bool create = force; - if (!create) - { - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - const llvm::Triple::OSType os_type = triple_ref.getOS(); - if ((os_type == llvm::Triple::UnknownOS)) - create = true; +DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process, + bool force) { + bool create = force; + if (!create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + const llvm::Triple::OSType os_type = triple_ref.getOS(); + if ((os_type == llvm::Triple::UnknownOS)) + create = true; + } + + if (!create) { + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module) { + ObjectFile *object_file = exe_module->GetObjectFile(); + if (object_file) { + create = (object_file->GetStrata() == ObjectFile::eStrataRawImage); + } } - - if (!create) - { - Module *exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - ObjectFile *object_file = exe_module->GetObjectFile(); - if (object_file) - { - create = (object_file->GetStrata() == ObjectFile::eStrataRawImage); - } - } - } - - if (create) - return new DynamicLoaderStatic (process); - return NULL; + } + + if (create) + return new DynamicLoaderStatic(process); + return NULL; } //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -DynamicLoaderStatic::DynamicLoaderStatic (Process* process) : - DynamicLoader(process) -{ -} +DynamicLoaderStatic::DynamicLoaderStatic(Process *process) + : DynamicLoader(process) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -DynamicLoaderStatic::~DynamicLoaderStatic() -{ -} +DynamicLoaderStatic::~DynamicLoaderStatic() {} //------------------------------------------------------------------ /// Called after attaching a process. @@ -74,11 +66,7 @@ DynamicLoaderStatic::~DynamicLoaderStatic() /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderStatic::DidAttach () -{ - LoadAllImagesAtFileAddresses(); -} +void DynamicLoaderStatic::DidAttach() { LoadAllImagesAtFileAddresses(); } //------------------------------------------------------------------ /// Called after attaching a process. @@ -86,124 +74,94 @@ DynamicLoaderStatic::DidAttach () /// Allow DynamicLoader plug-ins to execute some code after /// attaching to a process. //------------------------------------------------------------------ -void -DynamicLoaderStatic::DidLaunch () -{ - LoadAllImagesAtFileAddresses(); -} - -void -DynamicLoaderStatic::LoadAllImagesAtFileAddresses () -{ - const ModuleList &module_list = m_process->GetTarget().GetImages(); - - ModuleList loaded_module_list; - - // Disable JIT for static dynamic loader targets - m_process->SetCanJIT(false); - - std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); - - const size_t num_modules = module_list.GetSize(); - for (uint32_t idx = 0; idx < num_modules; ++idx) - { - ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (idx)); - if (module_sp) - { - bool changed = false; - ObjectFile *image_object_file = module_sp->GetObjectFile(); - if (image_object_file) - { - SectionList *section_list = image_object_file->GetSectionList (); - if (section_list) - { - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment - // that is at file offset zero which also has bytes (a file size - // that is greater than zero) in the object file. - - // Determine the slide amount (if any) - 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 the - // first section that starts of file offset zero and that - // has bytes in the file... - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - if (section_sp) - { - if (m_process->GetTarget().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress())) - changed = true; - } - } - } +void DynamicLoaderStatic::DidLaunch() { LoadAllImagesAtFileAddresses(); } + +void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { + const ModuleList &module_list = m_process->GetTarget().GetImages(); + + ModuleList loaded_module_list; + + // Disable JIT for static dynamic loader targets + m_process->SetCanJIT(false); + + std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); + + const size_t num_modules = module_list.GetSize(); + for (uint32_t idx = 0; idx < num_modules; ++idx) { + ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(idx)); + if (module_sp) { + bool changed = false; + ObjectFile *image_object_file = module_sp->GetObjectFile(); + if (image_object_file) { + SectionList *section_list = image_object_file->GetSectionList(); + if (section_list) { + // All sections listed in the dyld image info structure will all + // either be fixed up already, or they will all be off by a single + // slide amount that is determined by finding the first segment + // that is at file offset zero which also has bytes (a file size + // that is greater than zero) in the object file. + + // Determine the slide amount (if any) + 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 the + // first section that starts of file offset zero and that + // has bytes in the file... + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (section_sp) { + if (m_process->GetTarget().SetSectionLoadAddress( + section_sp, section_sp->GetFileAddress())) + changed = true; } - - if (changed) - loaded_module_list.AppendIfNeeded (module_sp); + } } + } + + if (changed) + loaded_module_list.AppendIfNeeded(module_sp); } + } - m_process->GetTarget().ModulesDidLoad (loaded_module_list); + m_process->GetTarget().ModulesDidLoad(loaded_module_list); } ThreadPlanSP -DynamicLoaderStatic::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) -{ - return ThreadPlanSP(); +DynamicLoaderStatic::GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) { + return ThreadPlanSP(); } -Error -DynamicLoaderStatic::CanLoadImage () -{ - Error error; - error.SetErrorString ("can't load images on with a static debug session"); - return error; +Error DynamicLoaderStatic::CanLoadImage() { + Error error; + error.SetErrorString("can't load images on with a static debug session"); + return error; } -void -DynamicLoaderStatic::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance); +void DynamicLoaderStatic::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); } -void -DynamicLoaderStatic::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void DynamicLoaderStatic::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } - -lldb_private::ConstString -DynamicLoaderStatic::GetPluginNameStatic() -{ - static ConstString g_name("static"); - return g_name; +lldb_private::ConstString DynamicLoaderStatic::GetPluginNameStatic() { + static ConstString g_name("static"); + return g_name; } -const char * -DynamicLoaderStatic::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that will load any images at the static addresses contained in each image."; +const char *DynamicLoaderStatic::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that will load any images at the static " + "addresses contained in each image."; } - //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -DynamicLoaderStatic::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -DynamicLoaderStatic::GetPluginVersion() -{ - return 1; +lldb_private::ConstString DynamicLoaderStatic::GetPluginName() { + return GetPluginNameStatic(); } +uint32_t DynamicLoaderStatic::GetPluginVersion() { return 1; } diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index 67694c96025c..c6122edf50cf 100644 --- a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -14,69 +14,57 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Target/DynamicLoader.h" -#include "lldb/Host/FileSpec.h" #include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" -class DynamicLoaderStatic : public lldb_private::DynamicLoader -{ +class DynamicLoaderStatic : public lldb_private::DynamicLoader { public: - DynamicLoaderStatic(lldb_private::Process *process); + DynamicLoaderStatic(lldb_private::Process *process); - ~DynamicLoaderStatic() override; + ~DynamicLoaderStatic() override; - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static const char * - GetPluginDescriptionStatic(); + static const char *GetPluginDescriptionStatic(); - static lldb_private::DynamicLoader * - CreateInstance (lldb_private::Process *process, bool force); + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); - //------------------------------------------------------------------ - /// Called after attaching a process. - /// - /// Allow DynamicLoader plug-ins to execute some code after - /// attaching to a process. - //------------------------------------------------------------------ - void - DidAttach() override; + //------------------------------------------------------------------ + /// Called after attaching a process. + /// + /// Allow DynamicLoader plug-ins to execute some code after + /// attaching to a process. + //------------------------------------------------------------------ + void DidAttach() override; - void - DidLaunch() override; + void DidLaunch() override; - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan(lldb_private::Thread &thread, - bool stop_others) override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others) override; - lldb_private::Error - CanLoadImage() override; + lldb_private::Error CanLoadImage() override; - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; private: - void - LoadAllImagesAtFileAddresses (); + void LoadAllImagesAtFileAddresses(); - DISALLOW_COPY_AND_ASSIGN (DynamicLoaderStatic); + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderStatic); }; #endif // liblldb_DynamicLoaderStatic_h_ diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp index dd391b4ca4d2..20bf3609f46f 100644 --- a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp @@ -1,4 +1,5 @@ -//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------*- C++ -*-===// +//===-- DynamicLoaderWindowsDYLD.cpp --------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -19,86 +20,57 @@ using namespace lldb; using namespace lldb_private; DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process) - : DynamicLoader(process) -{ -} + : DynamicLoader(process) {} -DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() -{ -} +DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() {} -void -DynamicLoaderWindowsDYLD::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); +void DynamicLoaderWindowsDYLD::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); } -void -DynamicLoaderWindowsDYLD::Terminate() -{ -} +void DynamicLoaderWindowsDYLD::Terminate() {} -ConstString -DynamicLoaderWindowsDYLD::GetPluginNameStatic() -{ - static ConstString g_plugin_name("windows-dyld"); - return g_plugin_name; +ConstString DynamicLoaderWindowsDYLD::GetPluginNameStatic() { + static ConstString g_plugin_name("windows-dyld"); + return g_plugin_name; } -const char * -DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() -{ - return "Dynamic loader plug-in that watches for shared library " - "loads/unloads in Windows processes."; +const char *DynamicLoaderWindowsDYLD::GetPluginDescriptionStatic() { + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Windows processes."; } -DynamicLoader * -DynamicLoaderWindowsDYLD::CreateInstance(Process *process, bool force) -{ - bool should_create = force; - if (!should_create) - { - const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); - if (triple_ref.getOS() == llvm::Triple::Win32) - should_create = true; - } - - if (should_create) - return new DynamicLoaderWindowsDYLD(process); - - return nullptr; -} +DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process, + bool force) { + bool should_create = force; + if (!should_create) { + const llvm::Triple &triple_ref = + process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::Win32) + should_create = true; + } -void -DynamicLoaderWindowsDYLD::DidAttach() -{ -} + if (should_create) + return new DynamicLoaderWindowsDYLD(process); -void -DynamicLoaderWindowsDYLD::DidLaunch() -{ + return nullptr; } -Error -DynamicLoaderWindowsDYLD::CanLoadImage() -{ - return Error(); -} +void DynamicLoaderWindowsDYLD::DidAttach() {} -ConstString -DynamicLoaderWindowsDYLD::GetPluginName() -{ - return GetPluginNameStatic(); -} +void DynamicLoaderWindowsDYLD::DidLaunch() {} -uint32_t -DynamicLoaderWindowsDYLD::GetPluginVersion() -{ - return 1; +Error DynamicLoaderWindowsDYLD::CanLoadImage() { return Error(); } + +ConstString DynamicLoaderWindowsDYLD::GetPluginName() { + return GetPluginNameStatic(); } +uint32_t DynamicLoaderWindowsDYLD::GetPluginVersion() { return 1; } + ThreadPlanSP -DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) -{ - return ThreadPlanSP(); +DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + return ThreadPlanSP(); } diff --git a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h index 8c479819c535..3494082eea8d 100644 --- a/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h +++ b/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h @@ -14,33 +14,32 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-forward.h" #include "lldb/Target/DynamicLoader.h" +#include "lldb/lldb-forward.h" -namespace lldb_private -{ +namespace lldb_private { -class DynamicLoaderWindowsDYLD : public DynamicLoader -{ +class DynamicLoaderWindowsDYLD : public DynamicLoader { public: - DynamicLoaderWindowsDYLD(Process *process); + DynamicLoaderWindowsDYLD(Process *process); - ~DynamicLoaderWindowsDYLD() override; + ~DynamicLoaderWindowsDYLD() override; - static void Initialize(); - static void Terminate(); - static ConstString GetPluginNameStatic(); - static const char *GetPluginDescriptionStatic(); + static void Initialize(); + static void Terminate(); + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic(); - static DynamicLoader *CreateInstance(Process *process, bool force); + static DynamicLoader *CreateInstance(Process *process, bool force); - void DidAttach() override; - void DidLaunch() override; - Error CanLoadImage() override; - lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, bool stop) override; + void DidAttach() override; + void DidLaunch() override; + Error CanLoadImage() override; + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop) override; - ConstString GetPluginName() override; - uint32_t GetPluginVersion() override; + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; }; } // namespace lldb_private |