diff options
Diffstat (limited to 'lldb/source/Plugins')
9 files changed, 934 insertions, 74 deletions
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt index 4d916b15f76..7dc3e98e6a5 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD DynamicLoaderMacOSXDYLD.cpp + DynamicLoaderMacOS.cpp DynamicLoaderDarwin.cpp ) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index efca1bea4ad..b17d171204c 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -151,21 +151,6 @@ DynamicLoaderDarwin::FindTargetModuleForImageInfo (ImageInfo &image_info, bool c 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]; - } - } - return NULL; -} - void DynamicLoaderDarwin::UnloadImages (const std::vector<lldb::addr_t> &solib_addresses) { @@ -223,6 +208,46 @@ DynamicLoaderDarwin::UnloadImages (const std::vector<lldb::addr_t> &solib_addres } } +void +DynamicLoaderDarwin::UnloadAllImages () +{ + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER)); + ModuleList unloaded_modules_list; + + 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_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. @@ -401,6 +426,23 @@ DynamicLoaderDarwin::JSONImageInformationIntoImageInfo (StructuredData::ObjectSP 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(); + } + // Fields that aren't used by DynamicLoaderDarwin so debugserver doesn't currently send them // in the reply. @@ -483,71 +525,99 @@ DynamicLoaderDarwin::JSONImageInformationIntoImageInfo (StructuredData::ObjectSP } void -DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfos (ImageInfo::collection &image_infos) +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) { - UpdateDYLDImageInfoFromNewImageInfo (image_infos[i]); - break; // FIXME simulator debugging w/ multiple dylds + // 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; } } -} -void -DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfo (ImageInfo &image_info) -{ - // FIXME simulator debugging w/ multiple dylds - if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) + if (exe_idx != UINT32_MAX) { const bool can_create = true; - ModuleSP dyld_sp = FindTargetModuleForImageInfo (image_info, can_create, NULL); + 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()) { - Target &target = m_process->GetTarget(); + if (log) + log->Printf ("Found dyld module: %s", dyld_sp->GetFileSpec().GetPath().c_str()); target.GetImages().AppendIfNeeded (dyld_sp); - UpdateImageLoadAddress (dyld_sp.get(), image_info); + UpdateImageLoadAddress (dyld_sp.get(), image_infos[dyld_idx]); SetDYLDModule (dyld_sp); } } } void -DynamicLoaderDarwin::AddExecutableModuleIfInImageInfos (ImageInfo::collection &image_infos) +DynamicLoaderDarwin::UpdateDYLDImageInfoFromNewImageInfo (ImageInfo &image_info) { - const size_t image_infos_size = image_infos.size(); - for (size_t i = 0; i < image_infos_size; i++) + if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) { - if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) + const bool can_create = true; + ModuleSP dyld_sp = FindTargetModuleForImageInfo (image_info, can_create, NULL); + if (dyld_sp.get()) { 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); - } - } + target.GetImages().AppendIfNeeded (dyld_sp); + UpdateImageLoadAddress (dyld_sp.get(), image_info); + SetDYLDModule (dyld_sp); } } } @@ -1141,3 +1211,57 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, const ll 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; + } + } + + + // FIXME: Temporarily force the use of the old DynamicLoader plugin until all + // the different use cases have been tested & the updated SPIs are available + // everywhere. + use_new_spi_interface = false; + + 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/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h index b7dd51d288d..98042188b18 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h @@ -26,6 +26,8 @@ #include "lldb/Target/Process.h" #include "lldb/Utility/SafeMachO.h" +#include "llvm/ADT/Triple.h" + namespace lldb_private { class DynamicLoaderDarwin : public lldb_private::DynamicLoader @@ -137,6 +139,8 @@ protected: 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), @@ -146,7 +150,9 @@ protected: uuid(), header(), segments(), - load_stop_id(0) + load_stop_id(0), + os_type (llvm::Triple::OSType::UnknownOS), + min_version_os_sdk() { } @@ -164,6 +170,8 @@ protected: uuid.Clear(); segments.clear(); load_stop_id = 0; + os_type = llvm::Triple::OSType::UnknownOS; + min_version_os_sdk.clear(); } bool @@ -175,7 +183,8 @@ protected: && file_spec == rhs.file_spec && uuid == rhs.uuid && memcmp(&header, &rhs.header, sizeof(header)) == 0 - && segments == rhs.segments; + && segments == rhs.segments + && os_type == rhs.os_type; } bool @@ -220,9 +229,6 @@ protected: bool UnloadModuleSections (lldb_private::Module *module, ImageInfo& info); - ImageInfo * - FindImageInfoForAddress (lldb::addr_t load_address); - lldb::ModuleSP FindTargetModuleForImageInfo (ImageInfo &image_info, bool can_create, @@ -231,6 +237,9 @@ protected: void UnloadImages (const std::vector<lldb::addr_t> &solib_addresses); + void + UnloadAllImages (); + virtual bool SetNotificationBreakpoint () = 0; @@ -258,10 +267,10 @@ protected: bool JSONImageInformationIntoImageInfo (lldb_private::StructuredData::ObjectSP image_details, 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. + // 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 - UpdateDYLDImageInfoFromNewImageInfos (ImageInfo::collection &image_infos); + UpdateSpecialBinariesFromNewImageInfos (ImageInfo::collection &image_infos); // if image_info is a dyld binary, call this method void @@ -275,7 +284,13 @@ protected: bool AddModulesUsingImageInfos (ImageInfo::collection &image_infos); - lldb::ModuleWP m_dyld_module_wp; + // 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; // 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; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp new file mode 100644 index 00000000000..bc1cc62cced --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -0,0 +1,528 @@ +//===-- 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/SymbolVendor.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/StackFrame.h" + +#include "DynamicLoaderMacOS.h" +#include "DynamicLoaderDarwin.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(); + } + } + } + return error; +} + +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/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h new file mode 100644 index 00000000000..79eee51c46b --- /dev/null +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h @@ -0,0 +1,129 @@ +//===-- 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 <vector> +#include <mutex> + +// 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/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; + + //------------------------------------------------------------------ + // 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/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index a8bc216fb17..109abd04b0c 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -89,6 +89,11 @@ DynamicLoaderMacOSXDYLD::CreateInstance (Process* process, bool force) } } } + + if (UseDYLDSPI (process) == true) + { + create = false; + } if (create) return new DynamicLoaderMacOSXDYLD (process); @@ -296,6 +301,7 @@ DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb:: { 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) @@ -316,7 +322,6 @@ DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb:: 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); @@ -340,6 +345,7 @@ DynamicLoaderMacOSXDYLD::ReadDYLDInfoFromMemoryAndSetNotificationCallback(lldb:: target.ModulesDidLoad(modules); SetDYLDModule (dyld_module_sp); } + return true; } } @@ -592,7 +598,7 @@ DynamicLoaderMacOSXDYLD::AddModulesUsingImageInfosAddress (lldb::addr_t image_in bool return_value = false; if (JSONImageInformationIntoImageInfo (image_infos_json_sp, image_infos)) { - AddExecutableModuleIfInImageInfos (image_infos); + UpdateSpecialBinariesFromNewImageInfos (image_infos); return_value = AddModulesUsingImageInfos (image_infos); } m_dyld_image_infos_stop_id = m_process->GetStopID(); @@ -1105,7 +1111,7 @@ DynamicLoaderMacOSXDYLD::SetNotificationBreakpoint () 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(); + ModuleSP dyld_module_sp = GetDYLDModule(); if (dyld_module_sp) { std::lock_guard<std::recursive_mutex> baseclass_guard(GetMutex()); diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h index 637bd8640d2..81e16d1f454 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h @@ -7,6 +7,17 @@ // //===----------------------------------------------------------------------===// + +// 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_ diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 4d56f6ea3ba..728c5123dda 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -4165,7 +4165,7 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) StreamString packet; packet << "jThreadExtendedInfo:"; - args_dict->Dump (packet); + args_dict->Dump (packet, false); // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape @@ -4194,6 +4194,44 @@ ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) { + + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); + args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); + + return GetLoadedDynamicLibrariesInfos_sender (args_dict); +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos () +{ + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + + args_dict->GetAsDictionary()->AddBooleanItem ("fetch_all_solibs", true); + + return GetLoadedDynamicLibrariesInfos_sender (args_dict); +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (const std::vector<lldb::addr_t> &load_addresses) +{ + StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); + StructuredData::ArraySP addresses(new StructuredData::Array); + + for (auto addr : load_addresses) + { + StructuredData::ObjectSP addr_sp (new StructuredData::Integer (addr)); + addresses->AddItem (addr_sp); + } + + args_dict->GetAsDictionary()->AddItem ("solib_addresses", addresses); + + return GetLoadedDynamicLibrariesInfos_sender (args_dict); +} + +StructuredData::ObjectSP +ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender (StructuredData::ObjectSP args_dict) +{ StructuredData::ObjectSP object_sp; if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) @@ -4201,13 +4239,9 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres // Scope for the scoped timeout object GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); - StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); - args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); - args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); - StreamString packet; packet << "jGetLoadedDynamicLibrariesInfos:"; - args_dict->Dump (packet); + args_dict->Dump (packet, false); // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape @@ -4233,6 +4267,9 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_addres return object_sp; } + + + // Establish the largest memory read/write payloads we should use. // If the remote stub has a max packet size, stay under that size. // diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 6d373965fc4..694e16656b4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -261,6 +261,15 @@ public: StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override; + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos () override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos (const std::vector<lldb::addr_t> &load_addresses) override; + + StructuredData::ObjectSP + GetLoadedDynamicLibrariesInfos_sender (StructuredData::ObjectSP args); + protected: friend class ThreadGDBRemote; friend class GDBRemoteCommunicationClient; |