blob: 7dbd98db2ab1b5fc86f7439618eebd13d06c7102 [file] [log] [blame]
//===-- 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_