user process dyld binary and/or a mach kernel binary image. By default, it prefers the kernel if it finds both. But if it finds two kernel binary images (which can happen when random things are mapped into memory), it may pick the wrong kernel image. DynamicLoaderDarwinKernel has heuristics to find a kernel in memory; once we've established that there is a kernel binary in memory, call over to that class to see if it can find a kernel address via its search methods. If it does, use that. Some minor cleanups to DynamicLoaderDarwinKernel while I was at it. <rdar://problem/24446112> llvm-svn: 259983
372 lines
11 KiB
C++
372 lines
11 KiB
C++
//===-- DynamicLoaderDarwinKernel.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_DynamicLoaderDarwinKernel_h_
|
|
#define liblldb_DynamicLoaderDarwinKernel_h_
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/Target/DynamicLoader.h"
|
|
#include "lldb/Host/FileSpec.h"
|
|
#include "lldb/Host/TimeValue.h"
|
|
#include "lldb/Core/UUID.h"
|
|
#include "lldb/Host/Mutex.h"
|
|
#include "lldb/Target/Process.h"
|
|
|
|
class DynamicLoaderDarwinKernel : public lldb_private::DynamicLoader
|
|
{
|
|
public:
|
|
DynamicLoaderDarwinKernel(lldb_private::Process *process, lldb::addr_t kernel_addr);
|
|
|
|
~DynamicLoaderDarwinKernel() override;
|
|
|
|
//------------------------------------------------------------------
|
|
// Static Functions
|
|
//------------------------------------------------------------------
|
|
static void
|
|
Initialize();
|
|
|
|
static void
|
|
Terminate();
|
|
|
|
static lldb_private::ConstString
|
|
GetPluginNameStatic();
|
|
|
|
static const char *
|
|
GetPluginDescriptionStatic();
|
|
|
|
static lldb_private::DynamicLoader *
|
|
CreateInstance (lldb_private::Process *process, bool force);
|
|
|
|
static void
|
|
DebuggerInitialize (lldb_private::Debugger &debugger);
|
|
|
|
static lldb::addr_t
|
|
SearchForDarwinKernel (lldb_private::Process *process);
|
|
|
|
//------------------------------------------------------------------
|
|
/// Called after attaching a process.
|
|
///
|
|
/// Allow DynamicLoader plug-ins to execute some code after
|
|
/// attaching to a process.
|
|
//------------------------------------------------------------------
|
|
void
|
|
DidAttach() override;
|
|
|
|
void
|
|
DidLaunch() override;
|
|
|
|
lldb::ThreadPlanSP
|
|
GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
|
|
bool stop_others) override;
|
|
|
|
lldb_private::Error
|
|
CanLoadImage() override;
|
|
|
|
//------------------------------------------------------------------
|
|
// PluginInterface protocol
|
|
//------------------------------------------------------------------
|
|
lldb_private::ConstString
|
|
GetPluginName() override;
|
|
|
|
uint32_t
|
|
GetPluginVersion() override;
|
|
|
|
protected:
|
|
void
|
|
PrivateInitialize (lldb_private::Process *process);
|
|
|
|
void
|
|
PrivateProcessStateChanged (lldb_private::Process *process,
|
|
lldb::StateType state);
|
|
|
|
void
|
|
UpdateIfNeeded();
|
|
|
|
void
|
|
LoadKernelModuleIfNeeded ();
|
|
|
|
void
|
|
Clear (bool clear_process);
|
|
|
|
void
|
|
PutToLog (lldb_private::Log *log) const;
|
|
|
|
static bool
|
|
BreakpointHitCallback (void *baton,
|
|
lldb_private::StoppointCallbackContext *context,
|
|
lldb::user_id_t break_id,
|
|
lldb::user_id_t break_loc_id);
|
|
|
|
bool
|
|
BreakpointHit (lldb_private::StoppointCallbackContext *context,
|
|
lldb::user_id_t break_id,
|
|
lldb::user_id_t break_loc_id);
|
|
uint32_t
|
|
GetAddrByteSize()
|
|
{
|
|
return m_kernel.GetAddressByteSize();
|
|
}
|
|
|
|
static lldb::ByteOrder
|
|
GetByteOrderFromMagic (uint32_t magic);
|
|
|
|
enum
|
|
{
|
|
KERNEL_MODULE_MAX_NAME = 64u,
|
|
// Versions less than 2 didn't have an entry size,
|
|
// they had a 64 bit name, 16 byte UUID, 8 byte addr,
|
|
// 8 byte size, 8 byte version, 4 byte load tag, and
|
|
// 4 byte flags
|
|
KERNEL_MODULE_ENTRY_SIZE_VERSION_1 = 64u + 16u + 8u + 8u + 8u + 4u + 4u
|
|
};
|
|
|
|
// class KextImageInfo represents a single kext or kernel binary image.
|
|
// The class was designed to hold the information from the OSKextLoadedKextSummary
|
|
// structure (in libkern/libkern/OSKextLibPrivate.h from xnu). The kernel maintains
|
|
// a list of loded kexts in memory (the OSKextLoadedKextSummaryHeader structure,
|
|
// which points to an array of OSKextLoadedKextSummary's).
|
|
//
|
|
// A KextImageInfos may have -
|
|
//
|
|
// 1. The load address, name, UUID, and size of a kext/kernel binary in memory
|
|
// (read straight out of the kernel's list-of-kexts loaded)
|
|
// 2. A ModuleSP based on a MemoryModule read out of the kernel's memory
|
|
// (very unlikely to have any symbolic information)
|
|
// 3. A ModuleSP for an on-disk copy of the kext binary, possibly with debug info
|
|
// or a dSYM
|
|
//
|
|
// For performance reasons, the developer may prefer that lldb not load the kexts out
|
|
// of memory at the start of a kernel session. But we should build up / maintain a
|
|
// list of kexts that the kernel has told us about so we can relocate a kext module
|
|
// later if the user explicitly adds it to the target.
|
|
|
|
class KextImageInfo
|
|
{
|
|
public:
|
|
KextImageInfo () :
|
|
m_name (),
|
|
m_module_sp (),
|
|
m_memory_module_sp (),
|
|
m_load_process_stop_id (UINT32_MAX),
|
|
m_uuid (),
|
|
m_load_address (LLDB_INVALID_ADDRESS),
|
|
m_size (0),
|
|
m_kernel_image (false)
|
|
{ }
|
|
|
|
void
|
|
Clear ()
|
|
{
|
|
m_load_address = LLDB_INVALID_ADDRESS;
|
|
m_size = 0;
|
|
m_name.clear ();
|
|
m_uuid.Clear();
|
|
m_module_sp.reset();
|
|
m_memory_module_sp.reset();
|
|
m_load_process_stop_id = UINT32_MAX;
|
|
}
|
|
|
|
bool
|
|
LoadImageAtFileAddress (lldb_private::Process *process);
|
|
|
|
bool
|
|
LoadImageUsingMemoryModule (lldb_private::Process *process);
|
|
|
|
bool
|
|
IsLoaded ()
|
|
{
|
|
return m_load_process_stop_id != UINT32_MAX;
|
|
}
|
|
|
|
void
|
|
SetLoadAddress (lldb::addr_t load_addr); // Address of the Mach-O header for this binary
|
|
|
|
lldb::addr_t
|
|
GetLoadAddress () const; // Address of the Mach-O header for this binary
|
|
|
|
lldb_private::UUID
|
|
GetUUID () const;
|
|
|
|
void
|
|
SetUUID (const lldb_private::UUID &uuid);
|
|
|
|
void
|
|
SetName (const char *);
|
|
|
|
std::string
|
|
GetName () const;
|
|
|
|
void
|
|
SetModule (lldb::ModuleSP module);
|
|
|
|
lldb::ModuleSP
|
|
GetModule ();
|
|
|
|
// try to fill in m_memory_module_sp from memory based on the m_load_address
|
|
bool
|
|
ReadMemoryModule (lldb_private::Process *process);
|
|
|
|
bool
|
|
IsKernel () const; // true if this is the mach_kernel; false if this is a kext
|
|
|
|
void
|
|
SetIsKernel (bool is_kernel);
|
|
|
|
uint64_t
|
|
GetSize () const;
|
|
|
|
void
|
|
SetSize (uint64_t size);
|
|
|
|
uint32_t
|
|
GetProcessStopId () const; // the stop-id when this binary was first noticed
|
|
|
|
void
|
|
SetProcessStopId (uint32_t stop_id);
|
|
|
|
bool
|
|
operator== (const KextImageInfo &rhs);
|
|
|
|
uint32_t
|
|
GetAddressByteSize (); // as determined by Mach-O header
|
|
|
|
lldb::ByteOrder
|
|
GetByteOrder(); // as determined by Mach-O header
|
|
|
|
lldb_private::ArchSpec
|
|
GetArchitecture () const; // as determined by Mach-O header
|
|
|
|
void
|
|
PutToLog (lldb_private::Log *log) const;
|
|
|
|
typedef std::vector<KextImageInfo> collection;
|
|
typedef collection::iterator iterator;
|
|
typedef collection::const_iterator const_iterator;
|
|
|
|
private:
|
|
std::string m_name;
|
|
lldb::ModuleSP m_module_sp;
|
|
lldb::ModuleSP m_memory_module_sp;
|
|
uint32_t m_load_process_stop_id; // the stop-id when this module was added to the Target
|
|
lldb_private::UUID m_uuid; // UUID for this dylib if it has one, else all zeros
|
|
lldb::addr_t m_load_address;
|
|
uint64_t m_size;
|
|
bool m_kernel_image; // true if this is the kernel, false if this is a kext
|
|
};
|
|
|
|
struct OSKextLoadedKextSummaryHeader
|
|
{
|
|
uint32_t version;
|
|
uint32_t entry_size;
|
|
uint32_t entry_count;
|
|
lldb::addr_t image_infos_addr;
|
|
|
|
OSKextLoadedKextSummaryHeader() :
|
|
version (0),
|
|
entry_size (0),
|
|
entry_count (0),
|
|
image_infos_addr (LLDB_INVALID_ADDRESS)
|
|
{
|
|
}
|
|
|
|
uint32_t
|
|
GetSize()
|
|
{
|
|
switch (version)
|
|
{
|
|
case 0: return 0; // Can't know the size without a valid version
|
|
case 1: return 8; // Version 1 only had a version + entry_count
|
|
default: break;
|
|
}
|
|
// Version 2 and above has version, entry_size, entry_count, and reserved
|
|
return 16;
|
|
}
|
|
|
|
void
|
|
Clear()
|
|
{
|
|
version = 0;
|
|
entry_size = 0;
|
|
entry_count = 0;
|
|
image_infos_addr = LLDB_INVALID_ADDRESS;
|
|
}
|
|
|
|
bool
|
|
IsValid() const
|
|
{
|
|
return version >= 1 || version <= 2;
|
|
}
|
|
};
|
|
|
|
void
|
|
RegisterNotificationCallbacks();
|
|
|
|
void
|
|
UnregisterNotificationCallbacks();
|
|
|
|
void
|
|
SetNotificationBreakpointIfNeeded ();
|
|
|
|
bool
|
|
ReadAllKextSummaries ();
|
|
|
|
bool
|
|
ReadKextSummaryHeader ();
|
|
|
|
bool
|
|
ParseKextSummaries (const lldb_private::Address &kext_summary_addr,
|
|
uint32_t count);
|
|
|
|
void
|
|
UpdateImageInfosHeaderAndLoadCommands(KextImageInfo::collection &image_infos,
|
|
uint32_t infos_count,
|
|
bool update_executable);
|
|
|
|
uint32_t
|
|
ReadKextSummaries (const lldb_private::Address &kext_summary_addr,
|
|
uint32_t image_infos_count,
|
|
KextImageInfo::collection &image_infos);
|
|
|
|
static lldb::addr_t
|
|
SearchForKernelAtSameLoadAddr (lldb_private::Process *process);
|
|
|
|
static lldb::addr_t
|
|
SearchForKernelWithDebugHints (lldb_private::Process *process);
|
|
|
|
static lldb::addr_t
|
|
SearchForKernelNearPC (lldb_private::Process *process);
|
|
|
|
static lldb::addr_t
|
|
SearchForKernelViaExhaustiveSearch (lldb_private::Process *process);
|
|
|
|
static lldb_private::UUID
|
|
CheckForKernelImageAtAddress (lldb::addr_t addr, lldb_private::Process *process);
|
|
|
|
lldb::addr_t m_kernel_load_address;
|
|
KextImageInfo m_kernel; // Info about the current kernel image being used
|
|
|
|
lldb_private::Address m_kext_summary_header_ptr_addr;
|
|
lldb_private::Address m_kext_summary_header_addr;
|
|
OSKextLoadedKextSummaryHeader m_kext_summary_header;
|
|
KextImageInfo::collection m_known_kexts;
|
|
mutable lldb_private::Mutex m_mutex;
|
|
lldb::user_id_t m_break_id;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN (DynamicLoaderDarwinKernel);
|
|
};
|
|
|
|
#endif // liblldb_DynamicLoaderDarwinKernel_h_
|