|  | //===-- DynamicLoaderMacOSXDYLD.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/DataBuffer.h" | 
|  | #include "lldb/Core/DataBufferHeap.h" | 
|  | #include "lldb/Core/Debugger.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/Core/State.h" | 
|  | #include "lldb/Symbol/ClangASTContext.h" | 
|  | #include "lldb/Symbol/Function.h" | 
|  | #include "lldb/Symbol/ObjectFile.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 "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__) | 
|  | #else | 
|  | #define DEBUG_PRINTF(fmt, ...) | 
|  | #endif | 
|  |  | 
|  | #ifndef __APPLE__ | 
|  | #include "Utility/UuidCompatibility.h" | 
|  | #else | 
|  | #include <uuid/uuid.h> | 
|  | #endif | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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) {} | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Destructor | 
|  | //---------------------------------------------------------------------- | 
|  | 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. | 
|  | 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(); | 
|  | } | 
|  | } | 
|  | } | 
|  | return did_exec; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Clear out the state of this class. | 
|  | //---------------------------------------------------------------------- | 
|  | 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); | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | void DynamicLoaderMacOSXDYLD::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 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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 | 
|  | 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; | 
|  | } | 
|  |  | 
|  | bool DynamicLoaderMacOSXDYLD::NeedToDoInitialImageFetch() { | 
|  | return m_dyld_all_image_infos_addr == LLDB_INVALID_ADDRESS; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // 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 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(); | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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); | 
|  | } | 
|  | } 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; | 
|  | } | 
|  | } | 
|  | 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); | 
|  |  | 
|  | 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)) { | 
|  | UpdateSpecialBinariesFromNewImageInfos(image_infos); | 
|  | 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; | 
|  |  | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  | } | 
|  | } | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // If we have found where the "_dyld_all_image_infos" lives in memory, | 
|  | // read the current info from it, and then update all image load | 
|  | // addresses (or lack thereof).  Only do this if this is the first time | 
|  | // 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(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Read a mach_header at ADDR into HEADER, and also fill in the load | 
|  | // command data into LOAD_COMMAND_DATA if it is non-NULL. | 
|  | // | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | return false; // We weren't able to read the load command data | 
|  | } | 
|  | } | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | //---------------------------------------------------------------------- | 
|  | // Read the mach_header and load commands for each image that the | 
|  | // _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; | 
|  | } | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } | 
|  |  | 
|  | void DynamicLoaderMacOSXDYLD::Terminate() { | 
|  | PluginManager::UnregisterPlugin(CreateInstance); | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | uint32_t DynamicLoaderMacOSXDYLD::GetPluginVersion() { return 1; } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } |