[Lldb-commits] [lldb] r134672 - in /lldb/trunk: include/lldb/Target/Target.h lldb.xcodeproj/project.pbxproj source/Plugins/DynamicLoader/MacOSX-Kernel/ source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile source/Target/Target.cpp
Greg Clayton
gclayton at apple.com
Thu Jul 7 17:48:10 PDT 2011
Author: gclayton
Date: Thu Jul 7 19:48:09 2011
New Revision: 134672
URL: http://llvm.org/viewvc/llvm-project?rev=134672&view=rev
Log:
Added the start of the darwin dynamic loader plug-in. It isn't hooked up to
be detected yet, but most of the initial code is there and needs to be
debugged more.
Added:
lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/
lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp
lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h
lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile
Modified:
lldb/trunk/include/lldb/Target/Target.h
lldb/trunk/lldb.xcodeproj/project.pbxproj
lldb/trunk/source/Target/Target.cpp
Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=134672&r1=134671&r2=134672&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Thu Jul 7 19:48:09 2011
@@ -474,6 +474,32 @@
}
+ //------------------------------------------------------------------
+ /// Load a module in this target by at the section file addresses
+ /// with an optional constant slide applied to each section.
+ ///
+ /// This function will load all top level sections at their file
+ /// addresses and apply an optional constant slide amount to each
+ /// section. This can be used to easily load a module at the same
+ /// addresses that are contained in the object file (trust that
+ /// the addresses in an object file are the correct load addresses).
+ ///
+ /// @param[in] module
+ /// The module to load.
+ ///
+ /// @param[in] slide
+ /// A constant slide to add to each file address as each section
+ /// is being loaded.
+ ///
+ /// @return
+ /// \b true if loading the module at the specified address
+ /// causes a section to be loaded when it previously wasn't, or
+ /// if a section changes load address. Returns \b false if
+ /// the sections were all already loaded at these addresses.
+ //------------------------------------------------------------------
+ bool
+ LoadModuleWithSlide (Module *module, lldb::addr_t slide);
+
static Target *
GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr,
const SymbolContext *sc_ptr);
Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=134672&r1=134671&r2=134672&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Thu Jul 7 19:48:09 2011
@@ -381,6 +381,7 @@
26DE20651161904E00A093E2 /* SBSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20641161904E00A093E2 /* SBSymbol.cpp */; };
26ECA04313665FED008D1F18 /* ARM_DWARF_Registers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */; };
26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26ED3D6C13C563810017D45E /* OptionGroupVariable.cpp */; };
+ 26F4214413C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F4214113C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp */; };
26F5C27710F3D9E4009D5894 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27310F3D9E4009D5894 /* Driver.cpp */; };
26F5C27810F3D9E4009D5894 /* IOChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27510F3D9E4009D5894 /* IOChannel.cpp */; };
26F5C32510F3DF23009D5894 /* libpython.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32410F3DF23009D5894 /* libpython.dylib */; };
@@ -1051,6 +1052,8 @@
26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ARM_DWARF_Registers.cpp; path = source/Utility/ARM_DWARF_Registers.cpp; sourceTree = "<group>"; };
26ED3D6C13C563810017D45E /* OptionGroupVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionGroupVariable.cpp; path = source/Interpreter/OptionGroupVariable.cpp; sourceTree = "<group>"; };
26ED3D6F13C5638A0017D45E /* OptionGroupVariable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionGroupVariable.h; path = include/lldb/Interpreter/OptionGroupVariable.h; sourceTree = "<group>"; };
+ 26F4214113C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLoaderMacOSXKernel.cpp; sourceTree = "<group>"; };
+ 26F4214213C6515B00E04E5E /* DynamicLoaderMacOSXKernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicLoaderMacOSXKernel.h; sourceTree = "<group>"; };
26F5C26A10F3D9A4009D5894 /* lldb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lldb; sourceTree = BUILT_PRODUCTS_DIR; };
26F5C27210F3D9E4009D5894 /* lldb-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "lldb-Info.plist"; path = "tools/driver/lldb-Info.plist"; sourceTree = "<group>"; };
26F5C27310F3D9E4009D5894 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = tools/driver/Driver.cpp; sourceTree = "<group>"; };
@@ -1407,6 +1410,7 @@
isa = PBXGroup;
children = (
260C897910F57C5600BB2B04 /* MacOSX-DYLD */,
+ 26F4214013C6515B00E04E5E /* MacOSX-Kernel */,
268A683C1321B505000E3FB8 /* Static */,
);
path = DynamicLoader;
@@ -2473,6 +2477,15 @@
name = "lldb-platform";
sourceTree = "<group>";
};
+ 26F4214013C6515B00E04E5E /* MacOSX-Kernel */ = {
+ isa = PBXGroup;
+ children = (
+ 26F4214113C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp */,
+ 26F4214213C6515B00E04E5E /* DynamicLoaderMacOSXKernel.h */,
+ );
+ path = "MacOSX-Kernel";
+ sourceTree = "<group>";
+ };
26F5C22410F3D950009D5894 /* Tools */ = {
isa = PBXGroup;
children = (
@@ -3251,6 +3264,7 @@
49D8FB3913B5598F00411094 /* ClangASTImporter.cpp in Sources */,
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */,
26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */,
+ 26F4214413C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Added: lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp?rev=134672&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp (added)
+++ lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.cpp Thu Jul 7 19:48:09 2011
@@ -0,0 +1,1232 @@
+//===-- DynamicLoaderMacOSXKernel.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/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "DynamicLoaderMacOSXKernel.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
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// FIXME - The ObjC Runtime trampoline handler doesn't really belong here.
+/// I am putting it here so I can invoke it in the Trampoline code here, but
+/// it should be moved to the ObjC Runtime support when it is set up.
+
+
+//----------------------------------------------------------------------
+// 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 *
+DynamicLoaderMacOSXKernel::CreateInstance (Process* process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::Darwin && triple_ref.getVendor() == llvm::Triple::Apple)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderMacOSXKernel (process);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXKernel::DynamicLoaderMacOSXKernel (Process* process) :
+ DynamicLoader(process),
+ m_kernel(),
+ m_kext_summary_header_addr (LLDB_INVALID_ADDRESS),
+ m_kext_summary_header (),
+ m_kext_summary_header_stop_id (0),
+ m_break_id (LLDB_INVALID_BREAK_ID),
+ m_kext_summaries(),
+ m_kext_summaries_stop_id (UINT32_MAX),
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_notification_callbacks ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderMacOSXKernel::~DynamicLoaderMacOSXKernel()
+{
+ Clear(true);
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::DidAttach ()
+{
+ PrivateInitialize(m_process);
+ LoadKernelModule();
+ SetNotificationBreakpoint ();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::DidLaunch ()
+{
+ PrivateInitialize(m_process);
+ LoadKernelModule();
+ SetNotificationBreakpoint ();
+}
+
+
+//----------------------------------------------------------------------
+// Clear out the state of this class.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::Clear (bool clear_process)
+{
+ Mutex::Locker locker(m_mutex);
+
+ if (m_process->IsAlive() && LLDB_BREAK_ID_IS_VALID(m_break_id))
+ m_process->ClearBreakpointSiteByID(m_break_id);
+
+ if (clear_process)
+ m_process = NULL;
+ m_kernel.Clear(false);
+ m_kext_summary_header_addr = LLDB_INVALID_ADDRESS;
+ m_kext_summaries.clear();
+ m_kext_summaries_stop_id = 0;
+ m_break_id = LLDB_INVALID_BREAK_ID;
+}
+
+//----------------------------------------------------------------------
+// Check if we have found DYLD yet
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXKernel::DidSetNotificationBreakpoint() const
+{
+ return LLDB_BREAK_ID_IS_VALID (m_break_id);
+}
+
+//----------------------------------------------------------------------
+// Load the kernel module and initialize the "m_kernel" member. Return
+// true _only_ if the kernel is loaded the first time through (subsequent
+// calls to this function should return false after the kernel has been
+// already loaded).
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXKernel::LoadKernelModule()
+{
+ if (m_kext_summary_header_addr == LLDB_INVALID_ADDRESS)
+ {
+ m_kernel.Clear(false);
+ m_kernel.module_sp = m_process->GetTarget().GetExecutableModule();
+ if (m_kernel.module_sp)
+ {
+ static ConstString mach_header_name ("_mh_execute_header");
+ const Symbol *symbol = m_kernel.module_sp->FindFirstSymbolWithNameAndType (mach_header_name, eSymbolTypeAbsolute);
+ if (symbol)
+ {
+ m_kernel.address = symbol->GetValue().GetFileAddress();
+ DataExtractor data; // Load command data
+ if (ReadMachHeader (m_kernel.address, &m_kernel.header, &data))
+ {
+ if (m_kernel.header.filetype == llvm::MachO::HeaderFileTypeDynamicLinkEditor)
+ {
+ if (ParseLoadCommands (data, m_kernel))
+ UpdateImageLoadAddress (m_kernel);
+
+ // Update all image infos
+ ReadAllKextSummaries (false);
+ return true;
+ }
+ }
+ else
+ {
+ m_kernel.Clear(false);
+ }
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+DynamicLoaderMacOSXKernel::FindTargetModule (OSKextLoadedKextSummary &image_info, bool can_create, bool *did_create_ptr)
+{
+ if (did_create_ptr)
+ *did_create_ptr = false;
+
+ const bool image_info_uuid_is_valid = image_info.uuid.IsValid();
+
+ if (image_info.module_sp)
+ {
+ if (image_info_uuid_is_valid)
+ {
+ if (image_info.module_sp->GetUUID() == image_info.uuid)
+ return true;
+ else
+ image_info.module_sp.reset();
+ }
+ else
+ return true;
+ }
+
+ ModuleList &target_images = m_process->GetTarget().GetImages();
+ if (image_info_uuid_is_valid)
+ image_info.module_sp = target_images.FindModule(image_info.uuid);
+
+ if (image_info.module_sp)
+ return true;
+
+ ArchSpec arch (image_info.GetArchitecture ());
+ if (can_create)
+ {
+ if (image_info_uuid_is_valid)
+ {
+ image_info.module_sp = m_process->GetTarget().GetSharedModule (FileSpec(),
+ arch,
+ &image_info.uuid);
+ if (did_create_ptr)
+ *did_create_ptr = image_info.module_sp;
+ }
+ }
+ return image_info.module_sp;
+}
+
+bool
+DynamicLoaderMacOSXKernel::UpdateCommPageLoadAddress(Module *module)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_sections = section_list->GetSize();
+ for (uint32_t i=0; i<num_sections; ++i)
+ {
+ Section* section = section_list->GetSectionAtIndex (i).get();
+ if (section)
+ {
+ const addr_t new_section_load_addr = section->GetFileAddress ();
+ const addr_t old_section_load_addr = m_process->GetTarget().GetSectionLoadList().GetSectionLoadAddress (section);
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section, section->GetFileAddress ()))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXKernel::UpdateImageLoadAddress (OSKextLoadedKextSummary& info)
+{
+ Module *module = info.module_sp.get();
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ // We now know the slide amount, so go through all sections
+ // and update the load addresses with the correct values.
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ const addr_t new_section_load_addr = info.segments[i].vmaddr;
+ if (section_sp)
+ {
+ const addr_t old_section_load_addr = m_process->GetTarget().GetSectionLoadList().GetSectionLoadAddress (section_sp.get());
+ if (old_section_load_addr == LLDB_INVALID_ADDRESS ||
+ old_section_load_addr != new_section_load_addr)
+ {
+ if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp.get(), new_section_load_addr))
+ changed = true;
+ }
+ }
+ else
+ {
+ fprintf (stderr,
+ "warning: unable to find and load segment named '%s' at 0x%llx in '%s/%s' in macosx dynamic loader plug-in.\n",
+ info.segments[i].name.AsCString("<invalid>"),
+ (uint64_t)new_section_load_addr,
+ image_object_file->GetFileSpec().GetDirectory().AsCString(),
+ image_object_file->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+//----------------------------------------------------------------------
+// Update the load addresses for all segments in MODULE using the
+// updated INFO that is passed in.
+//----------------------------------------------------------------------
+bool
+DynamicLoaderMacOSXKernel::UnloadImageLoadAddress (OSKextLoadedKextSummary& info)
+{
+ Module *module = info.module_sp.get();
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *image_object_file = module->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ uint32_t num_segments = info.segments.size();
+ for (uint32_t i=0; i<num_segments; ++i)
+ {
+ SectionSP section_sp(section_list->FindSectionByName(info.segments[i].name));
+ if (section_sp)
+ {
+ const addr_t old_section_load_addr = info.segments[i].vmaddr;
+ if (m_process->GetTarget().GetSectionLoadList().SetSectionUnloaded (section_sp.get(), old_section_load_addr))
+ changed = true;
+ }
+ else
+ {
+ fprintf (stderr,
+ "warning: unable to find and unload segment named '%s' in '%s/%s' in macosx dynamic loader plug-in.\n",
+ info.segments[i].name.AsCString("<invalid>"),
+ image_object_file->GetFileSpec().GetDirectory().AsCString(),
+ image_object_file->GetFileSpec().GetFilename().AsCString());
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
+//----------------------------------------------------------------------
+// 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
+DynamicLoaderMacOSXKernel::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)
+
+ DynamicLoaderMacOSXKernel* dyld_instance = (DynamicLoaderMacOSXKernel*) 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.
+
+ if (!dyld_instance->ReadAllKextSummaries(false))
+ {
+ Process *process = context->exe_ctx.process;
+ const lldb::ABISP &abi = process->GetABI();
+ if (abi != NULL)
+ {
+ // 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;
+
+ void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+ void *clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint, 32);
+ input_value.SetValueType (Value::eValueTypeScalar);
+ input_value.SetContext (Value::eContextTypeClangType, clang_uint32_type);
+ argument_values.PushValue(input_value);
+ argument_values.PushValue(input_value);
+ input_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type);
+ argument_values.PushValue (input_value);
+
+ if (abi->GetArgumentValues (*context->exe_ctx.thread, argument_values))
+ {
+ uint32_t dyld_mode = argument_values.GetValueAtIndex(0)->GetScalar().UInt (-1);
+ if (dyld_mode != -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 != -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 kext_summary_addr = argument_values.GetValueAtIndex(2)->GetScalar().ULongLong();
+ if (dyld_mode == 0)
+ {
+ // This is add:
+ dyld_instance->ParseKextSummaries (kext_summary_addr, image_infos_count);
+ }
+ else
+ {
+ // This is remove:
+ dyld_instance->RemoveModulesUsingImageInfosAddress (kext_summary_addr, image_infos_count);
+ }
+
+ }
+ }
+ }
+ }
+ }
+ // Return true to stop the target, false to just let the target run
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+bool
+DynamicLoaderMacOSXKernel::ReadKextSummaryHeader ()
+{
+ Mutex::Locker locker(m_mutex);
+
+ // the all image infos is already valid for this process stop ID
+ if (m_process->GetStopID() == m_kext_summaries_stop_id)
+ return true;
+
+ m_kext_summaries.clear();
+ if (m_kext_summary_header_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t addr_size = m_kernel.GetAddressByteSize ();
+ const ByteOrder byte_order = m_kernel.GetByteOrder();
+ Error error;
+ // Read enough bytes for a "OSKextLoadedKextSummaryHeader" structure
+ // which is currenty 4 uint32_t and a pointer.
+ uint8_t buf[24];
+ DataExtractor data (buf, sizeof(buf), byte_order, addr_size);
+ const size_t count = 4 * sizeof(uint32_t) + addr_size;
+ const size_t bytes_read = m_process->ReadMemory (m_kext_summary_header_addr, buf, count, error);
+ if (bytes_read == count)
+ {
+ uint32_t offset = 0;
+ m_kext_summary_header.version = data.GetU32(&offset);
+ m_kext_summary_header.entry_size = data.GetU32(&offset);
+ m_kext_summary_header.entry_count = data.GetU32(&offset);
+ m_kext_summary_header.reserved = data.GetU32(&offset);
+ m_kext_summary_header_stop_id = m_process->GetStopID();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+DynamicLoaderMacOSXKernel::ParseKextSummaries (lldb::addr_t kext_summary_addr, uint32_t count)
+{
+ OSKextLoadedKextSummary::collection kext_summaries;
+ LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+ if (log)
+ log->Printf ("Adding %d modules.\n");
+
+ Mutex::Locker locker(m_mutex);
+ if (m_process->GetStopID() == m_kext_summaries_stop_id)
+ return true;
+
+ if (!ReadKextSummaries (kext_summary_addr, count, kext_summaries))
+ return false;
+
+ for (uint32_t i = 0; i < count; i++)
+ {
+ if (!kext_summaries[i].UUIDValid())
+ {
+ DataExtractor data; // Load command data
+ if (!ReadMachHeader (kext_summaries[i].address, &kext_summaries[i].header, &data))
+ continue;
+
+ ParseLoadCommands (data, kext_summaries[i]);
+ }
+ }
+ bool return_value = AddModulesUsingImageInfos (kext_summaries);
+ m_kext_summaries_stop_id = m_process->GetStopID();
+ return return_value;
+}
+
+// Adds the modules in image_infos to m_kext_summaries.
+// NB don't call this passing in m_kext_summaries.
+
+bool
+DynamicLoaderMacOSXKernel::AddModulesUsingImageInfos (OSKextLoadedKextSummary::collection &image_infos)
+{
+ // Now add these images to the main list.
+ ModuleList loaded_module_list;
+ LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ for (uint32_t idx = 0; idx < image_infos.size(); ++idx)
+ {
+ if (log)
+ {
+ log->Printf ("Adding new image at address=0x%16.16llx.", image_infos[idx].address);
+ image_infos[idx].PutToLog (log.get());
+ }
+
+ m_kext_summaries.push_back(image_infos[idx]);
+
+ if (FindTargetModule (image_infos[idx], true, NULL))
+ {
+ // UpdateImageLoadAddress will return true if any segments
+ // change load address. We need to check this so we don't
+ // mention that all loaded shared libraries are newly loaded
+ // each time we hit out dyld breakpoint since dyld will list all
+ // shared libraries each time.
+ if (UpdateImageLoadAddress (image_infos[idx]))
+ {
+ loaded_module_list.AppendIfNeeded (image_infos[idx].module_sp);
+ }
+ }
+ }
+
+ if (loaded_module_list.GetSize() > 0)
+ {
+ // FIXME: This should really be in the Runtime handlers class, which should get
+ // called by the target's ModulesDidLoad, but we're doing it all locally for now
+ // to save time.
+ // Also, I'm assuming there can be only one libobjc dylib loaded...
+
+ ObjCLanguageRuntime *objc_runtime = m_process->GetObjCLanguageRuntime();
+ if (objc_runtime != NULL && !objc_runtime->HasReadObjCLibrary())
+ {
+ size_t num_modules = loaded_module_list.GetSize();
+ for (int i = 0; i < num_modules; i++)
+ {
+ if (objc_runtime->IsModuleObjCLibrary (loaded_module_list.GetModuleAtIndex (i)))
+ {
+ objc_runtime->ReadObjCLibrary (loaded_module_list.GetModuleAtIndex (i));
+ break;
+ }
+ }
+ }
+ if (log)
+ loaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderMacOSXKernel::ModulesDidLoad");
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+ }
+ return true;
+}
+
+bool
+DynamicLoaderMacOSXKernel::RemoveModulesUsingImageInfosAddress (lldb::addr_t kext_summary_addr, uint32_t image_infos_count)
+{
+ OSKextLoadedKextSummary::collection image_infos;
+ LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ Mutex::Locker locker(m_mutex);
+ if (m_process->GetStopID() == m_kext_summaries_stop_id)
+ return true;
+
+ // First read in the image_infos for the removed modules, and their headers & load commands.
+ if (!ReadKextSummaries (kext_summary_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.16llx.", image_infos[idx].address);
+ image_infos[idx].PutToLog (log.get());
+ }
+
+ // Remove this image_infos from the m_all_image_infos. We do the comparision 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.
+
+ OSKextLoadedKextSummary::collection::iterator pos, end = m_kext_summaries.end();
+ for (pos = m_kext_summaries.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.
+
+ if (FindTargetModule (image_infos[idx], false, NULL))
+ {
+ UnloadImageLoadAddress (image_infos[idx]);
+ unloaded_module_list.AppendIfNeeded (image_infos[idx].module_sp);
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("Could not find module for unloading info entry:");
+ image_infos[idx].PutToLog(log.get());
+ }
+ }
+
+ // Then remove it from the m_kext_summaries:
+
+ m_kext_summaries.erase(pos);
+ break;
+ }
+ }
+
+ if (pos == end)
+ {
+ if (log)
+ {
+ log->Printf ("Could not find image_info entry for unloading image:");
+ image_infos[idx].PutToLog(log.get());
+ }
+ }
+ }
+ if (unloaded_module_list.GetSize() > 0)
+ {
+ if (log)
+ {
+ log->PutCString("Unloaded:");
+ unloaded_module_list.LogUUIDAndPaths (log, "DynamicLoaderMacOSXKernel::ModulesDidUnload");
+ }
+ m_process->GetTarget().ModulesDidUnload (unloaded_module_list);
+ }
+ m_kext_summaries_stop_id = m_process->GetStopID();
+ return true;
+}
+
+uint32_t
+DynamicLoaderMacOSXKernel::ReadKextSummaries (lldb::addr_t kext_summary_addr,
+ uint32_t image_infos_count,
+ OSKextLoadedKextSummary::collection &image_infos)
+{
+ const ByteOrder endian = m_kernel.GetByteOrder();
+ const uint32_t addr_size = m_kernel.GetAddressByteSize();
+
+ image_infos.resize(image_infos_count);
+ const size_t count = image_infos.size() * m_kext_summary_header.entry_size;
+ DataBufferHeap data(count, 0);
+ Error error;
+ const size_t bytes_read = m_process->ReadMemory (kext_summary_addr,
+ data.GetBytes(),
+ data.GetByteSize(),
+ error);
+ if (bytes_read == count)
+ {
+ uint32_t offset = 0;
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), endian, addr_size);
+ uint32_t i=0;
+ for (; i < image_infos.size() && extractor.ValidOffsetForDataOfSize(offset, m_kext_summary_header.entry_size); ++i)
+ {
+ const void *name_data = extractor.GetData(&offset, KERNEL_MODULE_MAX_NAME);
+ if (name_data == NULL)
+ break;
+ memcpy (image_infos[i].name, name_data, KERNEL_MODULE_MAX_NAME);
+ image_infos[i].uuid.SetBytes(extractor.GetData (&offset, 16));
+ image_infos[i].address = extractor.GetU64(&offset);
+ image_infos[i].size = extractor.GetU64(&offset);
+ image_infos[i].version = extractor.GetU64(&offset);
+ image_infos[i].load_tag = extractor.GetU32(&offset);
+ image_infos[i].flags = extractor.GetU32(&offset);
+ image_infos[i].reference_list = extractor.GetU64(&offset);
+ }
+ if (i < image_infos.size())
+ image_infos.resize(i);
+ }
+ else
+ {
+ image_infos.clear();
+ }
+ return image_infos.size();
+}
+
+bool
+DynamicLoaderMacOSXKernel::ReadAllKextSummaries (bool force)
+{
+ LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ Mutex::Locker locker(m_mutex);
+ if (!force)
+ {
+ if (m_process->GetStopID() == m_kext_summaries_stop_id || m_kext_summaries.size() != 0)
+ return false;
+ }
+
+ if (ReadKextSummaryHeader ())
+ {
+ if (m_kext_summary_header.entry_count > 0)
+ {
+ if (!ParseKextSummaries (m_kext_summary_header_addr + 16, m_kext_summary_header.entry_count))
+ {
+ DEBUG_PRINTF( "unable to read all data for all_dylib_infos.");
+ m_kext_summaries.clear();
+ }
+ return true;
+ }
+ }
+ 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
+DynamicLoaderMacOSXKernel::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))
+ {
+ uint32_t offset = 0;
+ ::memset (header, 0, sizeof(header));
+
+ // Get the magic byte unswapped so we can figure out what we are dealing with
+ DataExtractor data(header_bytes.GetBytes(), header_bytes.GetByteSize(), lldb::endian::InlHostByteOrder(), 4);
+ header->magic = data.GetU32(&offset);
+ lldb::addr_t load_cmd_addr = addr;
+ data.SetByteOrder(DynamicLoaderMacOSXKernel::GetByteOrderFromMagic(header->magic));
+ switch (header->magic)
+ {
+ case llvm::MachO::HeaderMagic32:
+ case llvm::MachO::HeaderMagic32Swapped:
+ data.SetAddressByteSize(4);
+ load_cmd_addr += sizeof(llvm::MachO::mach_header);
+ break;
+
+ case llvm::MachO::HeaderMagic64:
+ case llvm::MachO::HeaderMagic64Swapped:
+ 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
+DynamicLoaderMacOSXKernel::ParseLoadCommands (const DataExtractor& data, OSKextLoadedKextSummary& dylib_info)
+{
+ uint32_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;
+ uint32_t load_cmd_offset = offset;
+ load_cmd.cmd = data.GetU32 (&offset);
+ load_cmd.cmdsize = data.GetU32 (&offset);
+ switch (load_cmd.cmd)
+ {
+ case llvm::MachO::LoadCommandSegment32:
+ {
+ 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::LoadCommandSegment64:
+ {
+ 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::LoadCommandUUID:
+ 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;
+ }
+ }
+#if 0
+ // No slide in the kernel...
+
+ // 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.slide = dylib_info.address - dylib_info.segments[i].vmaddr;
+ // We have found the slide amount, so we can exit
+ // this for loop.
+ break;
+ }
+ }
+#endif
+ return cmd_idx;
+}
+
+//----------------------------------------------------------------------
+// Dump a Segment to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::Segment::PutToLog (Log *log, lldb::addr_t slide) const
+{
+ if (log)
+ {
+ if (slide == 0)
+ log->Printf ("\t\t%16s [0x%16.16llx - 0x%16.16llx)",
+ name.AsCString(""),
+ vmaddr + slide,
+ vmaddr + slide + vmsize);
+ else
+ log->Printf ("\t\t%16s [0x%16.16llx - 0x%16.16llx) slide = 0x%llx",
+ name.AsCString(""),
+ vmaddr + slide,
+ vmaddr + slide + vmsize,
+ slide);
+ }
+}
+
+const DynamicLoaderMacOSXKernel::Segment *
+DynamicLoaderMacOSXKernel::OSKextLoadedKextSummary::FindSegment (const ConstString &name) const
+{
+ const size_t num_segments = segments.size();
+ for (size_t i=0; i<num_segments; ++i)
+ {
+ if (segments[i].name == name)
+ return &segments[i];
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Dump an image info structure to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::OSKextLoadedKextSummary::PutToLog (Log *log) const
+{
+ if (log == NULL)
+ return;
+ uint8_t *u = (uint8_t *)uuid.GetBytes();
+//
+// char name[KERNEL_MODULE_MAX_NAME];
+// lldb::ModuleSP module_sp;
+// lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
+// uint64_t address;
+// uint64_t size;
+// uint64_t version;
+// uint32_t load_tag;
+// uint32_t flags;
+// uint64_t reference_list;
+// 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)
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ if (u)
+ {
+ log->Printf("\t uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name='%s' (UNLOADED)",
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ name);
+ }
+ else
+ log->Printf("\t name='%s' (UNLOADED)", name);
+ }
+ else
+ {
+ if (u)
+ {
+ log->Printf("\taddress=0x%16.16llx uuid=%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X name='%s'",
+ address,
+ u[ 0], u[ 1], u[ 2], u[ 3],
+ u[ 4], u[ 5], u[ 6], u[ 7],
+ u[ 8], u[ 9], u[10], u[11],
+ u[12], u[13], u[14], u[15],
+ name);
+ }
+ else
+ {
+ log->Printf("\taddress=0x%16.16llx path='%s/%s'", address, name);
+ }
+ for (uint32_t i=0; i<segments.size(); ++i)
+ segments[i].PutToLog(log, 0);
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump the _dyld_all_image_infos members and all current image infos
+// that we have parsed to the file handle provided.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::PutToLog(Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ Mutex::Locker locker(m_mutex);
+ log->Printf("gLoadedKextSummaries = 0x%16.16llx { version=%u, entry_size=%u, entry_count=%u, reserved=%u }",
+ m_kext_summary_header_addr,
+ m_kext_summary_header.version,
+ m_kext_summary_header.entry_size,
+ m_kext_summary_header.entry_count,
+ m_kext_summary_header.reserved);
+
+ size_t i;
+ const size_t count = m_kext_summaries.size();
+ if (count > 0)
+ {
+ log->PutCString("Loaded:");
+ for (i = 0; i<count; i++)
+ m_kext_summaries[i].PutToLog(log);
+ }
+}
+
+void
+DynamicLoaderMacOSXKernel::PrivateInitialize(Process *process)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+ Clear(true);
+ m_process = process;
+ m_process->GetTarget().GetSectionLoadList().Clear();
+}
+
+bool
+DynamicLoaderMacOSXKernel::SetNotificationBreakpoint ()
+{
+ // TODO: Add breakpoint to detected dynamic kext loads/unloads. We aren't
+ // doing any live dynamic checks for kernel kexts being loaded or unloaded
+ // on the fly yet.
+// DEBUG_PRINTF("DynamicLoaderMacOSXKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
+// if (m_break_id == LLDB_INVALID_BREAK_ID)
+// {
+// if (m_kext_summaries.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.
+//
+// if (m_process->GetTarget().GetSectionLoadList().ResolveLoadAddress(m_kext_summaries.notification, so_addr))
+// {
+// Breakpoint *dyld_break = m_process->GetTarget().CreateBreakpoint (so_addr, true).get();
+// dyld_break->SetCallback (DynamicLoaderMacOSXKernel::NotifyBreakpointHit, this, true);
+// m_break_id = dyld_break->GetID();
+// }
+// }
+// }
+ return m_break_id != LLDB_INVALID_BREAK_ID;
+}
+
+//----------------------------------------------------------------------
+// Member function that gets called when the process state changes.
+//----------------------------------------------------------------------
+void
+DynamicLoaderMacOSXKernel::PrivateProcessStateChanged (Process *process, StateType state)
+{
+ DEBUG_PRINTF("DynamicLoaderMacOSXKernel::%s(%s)\n", __FUNCTION__, StateAsCString(state));
+ switch (state)
+ {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ case eStateDetached:
+ Clear(false);
+ break;
+
+ case eStateStopped:
+ // Keep trying find dyld and set our notification breakpoint each time
+ // we stop until we succeed
+ if (!DidSetNotificationBreakpoint () && m_process->IsAlive())
+ {
+ if (LoadKernelModule())
+ {
+ }
+
+ SetNotificationBreakpoint ();
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ break;
+
+ default:
+ break;
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderMacOSXKernel::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ ThreadPlanSP thread_plan_sp;
+ StackFrame *current_frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext ¤t_context = current_frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *current_symbol = current_context.symbol;
+ LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (current_symbol != NULL)
+ {
+ if (current_symbol->IsTrampoline())
+ {
+ const ConstString &trampoline_name = current_symbol->GetMangled().GetName(Mangled::ePreferMangled);
+
+ if (trampoline_name)
+ {
+ SymbolContextList target_symbols;
+ ModuleList &images = thread.GetProcess().GetTarget().GetImages();
+ images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols);
+ // FIXME - Make the Run to Address take multiple addresses, and
+ // run to any of them.
+ uint32_t num_symbols = target_symbols.GetSize();
+ if (num_symbols == 1)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (target_symbols.GetContextAtIndex(0, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
+ thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addr_range.GetBaseAddress(), stop_others));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Couldn't resolve the symbol context.");
+ }
+ }
+ else if (num_symbols > 1)
+ {
+ std::vector<lldb::addr_t> addresses;
+ addresses.resize (num_symbols);
+ for (uint32_t i = 0; i < num_symbols; i++)
+ {
+ SymbolContext context;
+ AddressRange addr_range;
+ if (target_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range);
+ lldb::addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(&thread.GetProcess().GetTarget());
+ addresses[i] = load_addr;
+ }
+ }
+ if (addresses.size() > 0)
+ thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addresses, stop_others));
+ else
+ {
+ if (log)
+ log->Printf ("Couldn't resolve the symbol contexts.");
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("Could not find symbol for trampoline target: \"%s\"", trampoline_name.AsCString());
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Could not find symbol for step through.");
+ }
+
+ return thread_plan_sp;
+}
+
+Error
+DynamicLoaderMacOSXKernel::CanLoadImage ()
+{
+ Error error;
+ error.SetErrorString("always unsafe to load or unload shared libraries in the darwin kernel");
+ return error;
+}
+
+void
+DynamicLoaderMacOSXKernel::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderMacOSXKernel::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+const char *
+DynamicLoaderMacOSXKernel::GetPluginNameStatic()
+{
+ return "dynamic-loader.macosx-kernel";
+}
+
+const char *
+DynamicLoaderMacOSXKernel::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library loads/unloads in the MacOSX kernel.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+DynamicLoaderMacOSXKernel::GetPluginName()
+{
+ return "DynamicLoaderMacOSXKernel";
+}
+
+const char *
+DynamicLoaderMacOSXKernel::GetShortPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderMacOSXKernel::GetPluginVersion()
+{
+ return 1;
+}
+
Added: lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h?rev=134672&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h (added)
+++ lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/DynamicLoaderMacOSXKernel.h Thu Jul 7 19:48:09 2011
@@ -0,0 +1,418 @@
+//===-- DynamicLoaderMacOSXKernel.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLoaderMacOSXKernel_h_
+#define liblldb_DynamicLoaderMacOSXKernel_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+#include "llvm/Support/MachO.h"
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+class DynamicLoaderMacOSXKernel : public lldb_private::DynamicLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static const char *
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ DynamicLoaderMacOSXKernel (lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderMacOSXKernel ();
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual const char *
+ GetPluginName();
+
+ virtual const char *
+ GetShortPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ void
+ PrivateInitialize (lldb_private::Process *process);
+
+ void
+ PrivateProcessStateChanged (lldb_private::Process *process,
+ lldb::StateType state);
+ bool
+ LoadKernelModule ();
+
+ bool
+ DidSetNotificationBreakpoint () const;
+
+ void
+ Clear (bool clear_process);
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ static bool
+ NotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ uint32_t
+ AddrByteSize()
+ {
+ switch (m_kernel.header.magic)
+ {
+ case llvm::MachO::HeaderMagic32:
+ case llvm::MachO::HeaderMagic32Swapped:
+ return 4;
+
+ case llvm::MachO::HeaderMagic64:
+ case llvm::MachO::HeaderMagic64Swapped:
+ return 8;
+
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ static lldb::ByteOrder
+ GetByteOrderFromMagic (uint32_t magic)
+ {
+ switch (magic)
+ {
+ case llvm::MachO::HeaderMagic32:
+ case llvm::MachO::HeaderMagic64:
+ return lldb::endian::InlHostByteOrder();
+
+ case llvm::MachO::HeaderMagic32Swapped:
+ case llvm::MachO::HeaderMagic64Swapped:
+ if (lldb::endian::InlHostByteOrder() == lldb::eByteOrderBig)
+ return lldb::eByteOrderLittle;
+ else
+ return lldb::eByteOrderBig;
+
+ default:
+ break;
+ }
+ return lldb::eByteOrderInvalid;
+ }
+
+ bool
+ ReadMachHeader (lldb::addr_t addr,
+ llvm::MachO::mach_header *header,
+ lldb_private::DataExtractor *load_command_data);
+ class Segment
+ {
+ public:
+
+ Segment() :
+ name(),
+ vmaddr(LLDB_INVALID_ADDRESS),
+ vmsize(0),
+ fileoff(0),
+ filesize(0),
+ maxprot(0),
+ initprot(0),
+ nsects(0),
+ flags(0)
+ {
+ }
+
+ lldb_private::ConstString name;
+ lldb::addr_t vmaddr;
+ lldb::addr_t vmsize;
+ lldb::addr_t fileoff;
+ lldb::addr_t filesize;
+ uint32_t maxprot;
+ uint32_t initprot;
+ uint32_t nsects;
+ uint32_t flags;
+
+ bool
+ operator==(const Segment& rhs) const
+ {
+ return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize;
+ }
+
+ void
+ PutToLog (lldb_private::Log *log,
+ lldb::addr_t slide) const;
+
+ };
+
+ enum { KERNEL_MODULE_MAX_NAME = 64u };
+
+ struct OSKextLoadedKextSummary
+ {
+ char name[KERNEL_MODULE_MAX_NAME];
+ lldb::ModuleSP module_sp;
+ lldb_private::UUID uuid; // UUID for this dylib if it has one, else all zeros
+ uint64_t address;
+ uint64_t size;
+ uint64_t version;
+ uint32_t load_tag;
+ uint32_t flags;
+ uint64_t reference_list;
+ 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)
+
+ OSKextLoadedKextSummary() :
+ module_sp (),
+ uuid (),
+ address (LLDB_INVALID_ADDRESS),
+ size (0),
+ version (0),
+ load_tag (0),
+ flags (0),
+ reference_list (0),
+ header(),
+ segments()
+ {
+ name[0] = '\0';
+ }
+
+ void
+ Clear (bool load_cmd_data_only)
+ {
+ if (!load_cmd_data_only)
+ {
+ address = LLDB_INVALID_ADDRESS;
+ size = 0;
+ version = 0;
+ load_tag = 0;
+ flags = 0;
+ reference_list = 0;
+ name[0] = '\0';
+ ::memset (&header, 0, sizeof(header));
+ }
+ module_sp.reset();
+ uuid.Clear();
+ segments.clear();
+ }
+
+ bool
+ operator == (const OSKextLoadedKextSummary& rhs) const
+ {
+ return address == rhs.address
+ && size == rhs.size
+ //&& module_sp.get() == rhs.module_sp.get()
+ && uuid == rhs.uuid
+ && version == rhs.version
+ && load_tag == rhs.load_tag
+ && flags == rhs.flags
+ && reference_list == rhs.reference_list
+ && strncmp (name, rhs.name, KERNEL_MODULE_MAX_NAME) == 0
+ && memcmp(&header, &rhs.header, sizeof(header)) == 0
+ && segments == rhs.segments;
+ }
+
+ bool
+ UUIDValid() const
+ {
+ return uuid.IsValid();
+ }
+
+ uint32_t
+ GetAddressByteSize ()
+ {
+ if (header.cputype)
+ {
+ if (header.cputype & llvm::MachO::CPUArchABI64)
+ return 8;
+ else
+ return 4;
+ }
+ return 0;
+ }
+
+ lldb::ByteOrder
+ GetByteOrder()
+ {
+ switch (header.magic)
+ {
+ case llvm::MachO::HeaderMagic32: // MH_MAGIC
+ case llvm::MachO::HeaderMagic64: // MH_MAGIC_64
+ return lldb::endian::InlHostByteOrder();
+
+ case llvm::MachO::HeaderMagic32Swapped: // MH_CIGAM
+ case llvm::MachO::HeaderMagic64Swapped: // MH_CIGAM_64
+ if (lldb::endian::InlHostByteOrder() == lldb::eByteOrderLittle)
+ return lldb::eByteOrderBig;
+ else
+ return lldb::eByteOrderLittle;
+ default:
+ assert (!"invalid header.magic value");
+ break;
+ }
+ return lldb::endian::InlHostByteOrder();
+ }
+
+ lldb_private::ArchSpec
+ GetArchitecture () const
+ {
+ return lldb_private::ArchSpec (lldb_private::eArchTypeMachO, header.cputype, header.cpusubtype);
+ }
+
+ const Segment *
+ FindSegment (const lldb_private::ConstString &name) const;
+
+ void
+ PutToLog (lldb_private::Log *log) const;
+
+ typedef std::vector<OSKextLoadedKextSummary> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ struct OSKextLoadedKextSummaryHeader
+ {
+ uint32_t version;
+ uint32_t entry_size;
+ uint32_t entry_count;
+ uint32_t reserved; /* explicit alignment for gdb */
+ lldb::addr_t image_infos_addr;
+
+ OSKextLoadedKextSummaryHeader() :
+ version (0),
+ entry_size (0),
+ entry_count (0),
+ reserved (0),
+ image_infos_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ void
+ Clear()
+ {
+ version = 0;
+ entry_size = 0;
+ entry_count = 0;
+ reserved = 0;
+ image_infos_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ bool
+ IsValid() const
+ {
+ return version >= 1 || version <= 2;
+ }
+ };
+
+ void
+ RegisterNotificationCallbacks();
+
+ void
+ UnregisterNotificationCallbacks();
+
+ uint32_t
+ ParseLoadCommands (const lldb_private::DataExtractor& data,
+ OSKextLoadedKextSummary& dylib_info);
+
+ bool
+ UpdateImageLoadAddress(OSKextLoadedKextSummary& info);
+
+ bool
+ FindTargetModule (OSKextLoadedKextSummary &image_info,
+ bool can_create,
+ bool *did_create_ptr);
+
+ bool
+ SetNotificationBreakpoint ();
+
+ bool
+ ReadAllKextSummaries (bool force);
+
+ bool
+ ReadKextSummaryHeader ();
+
+ bool
+ ParseKextSummaries (lldb::addr_t kext_summary_addr, uint32_t count);
+
+ bool
+ AddModulesUsingImageInfos (OSKextLoadedKextSummary::collection &image_infos);
+
+ bool
+ RemoveModulesUsingImageInfosAddress (lldb::addr_t image_infos_addr, uint32_t image_infos_count);
+
+ void
+ UpdateImageInfosHeaderAndLoadCommands(OSKextLoadedKextSummary::collection &image_infos,
+ uint32_t infos_count,
+ bool update_executable);
+
+ bool
+ UpdateCommPageLoadAddress (lldb_private::Module *module);
+
+ uint32_t
+ ReadKextSummaries (lldb::addr_t image_infos_addr,
+ uint32_t image_infos_count,
+ OSKextLoadedKextSummary::collection &image_infos);
+
+ bool
+ UnloadImageLoadAddress (OSKextLoadedKextSummary& info);
+
+ OSKextLoadedKextSummary m_kernel; // Info about the current kernel image being used
+ lldb::addr_t m_kext_summary_header_addr;
+ OSKextLoadedKextSummaryHeader m_kext_summary_header;
+ uint32_t m_kext_summary_header_stop_id; // The process stop ID that "m_kext_summary_header" is valid for
+ lldb::user_id_t m_break_id;
+ OSKextLoadedKextSummary::collection m_kext_summaries;
+ uint32_t m_kext_summaries_stop_id; // The process stop ID that "m_kext_summaries" is valid for
+ mutable lldb_private::Mutex m_mutex;
+ lldb_private::Process::Notifications m_notification_callbacks;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderMacOSXKernel);
+};
+
+#endif // liblldb_DynamicLoaderMacOSXKernel_h_
Added: lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile?rev=134672&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile (added)
+++ lldb/trunk/source/Plugins/DynamicLoader/MacOSX-Kernel/Makefile Thu Jul 7 19:48:09 2011
@@ -0,0 +1,14 @@
+##===- source/Plugins/Disassembler/llvm/Makefile -------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginDynamicLoaderMacOSXKernel
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=134672&r1=134671&r2=134672&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Thu Jul 7 19:48:09 2011
@@ -1275,6 +1275,46 @@
result.GetImmediateErrorStream()->Flush();
}
+bool
+Target::LoadModuleWithSlide (Module *module, lldb::addr_t slide)
+{
+ bool changed = false;
+ if (module)
+ {
+ ObjectFile *object_file = module->GetObjectFile();
+ if (object_file)
+ {
+ SectionList *section_list = object_file->GetSectionList ();
+ if (section_list)
+ {
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ Section *section = section_list->GetSectionAtIndex (sect_idx).get();
+ if (section)
+ {
+ if (m_section_load_list.SetSectionLoadAddress (section, section->GetFileAddress() + slide))
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+
//--------------------------------------------------------------
// class Target::StopHook
//--------------------------------------------------------------
More information about the lldb-commits
mailing list