forked from OSchip/llvm-project
Add support for debugging KASLR kernels via kdp (the kernel being
loaded at a random offset). To get the kernel's UUID and load address I need to send a kdp packet so I had to implement the kernel relocation (and attempt to find the kernel if none was provided to lldb already) in ProcessKDP -- but this code really properly belongs in DynamicLoaderDarwinKernel. I also had to add an optional Stream to ConnectRemote so ProcessKDP::DoConnectRemote can print feedback about the remote kernel's UUID, load address, and notify the user if we auto-loaded the kernel via the UUID. <rdar://problem/7714201> llvm-svn: 164881
This commit is contained in:
parent
913b876329
commit
4bd4e7e3ba
|
@ -1673,8 +1673,22 @@ public:
|
|||
virtual Error
|
||||
Attach (ProcessAttachInfo &attach_info);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to a remote system via a URL
|
||||
///
|
||||
/// @param[in] strm
|
||||
/// A stream where output intended for the user
|
||||
/// (if the driver has a way to display that) generated during
|
||||
/// the connection. This may be NULL if no output is needed.A
|
||||
///
|
||||
/// @param[in] remote_url
|
||||
/// The URL format that we are connecting to.
|
||||
///
|
||||
/// @return
|
||||
/// Returns an error object.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
ConnectRemote (const char *remote_url);
|
||||
ConnectRemote (Stream *strm, const char *remote_url);
|
||||
|
||||
bool
|
||||
GetShouldDetach () const
|
||||
|
@ -1896,8 +1910,22 @@ public:
|
|||
return Error();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to a remote system via a URL
|
||||
///
|
||||
/// @param[in] strm
|
||||
/// A stream where output intended for the user
|
||||
/// (if the driver has a way to display that) generated during
|
||||
/// the connection. This may be NULL if no output is needed.A
|
||||
///
|
||||
/// @param[in] remote_url
|
||||
/// The URL format that we are connecting to.
|
||||
///
|
||||
/// @return
|
||||
/// Returns an error object.
|
||||
//------------------------------------------------------------------
|
||||
virtual Error
|
||||
DoConnectRemote (const char *remote_url)
|
||||
DoConnectRemote (Stream *strm, const char *remote_url)
|
||||
{
|
||||
Error error;
|
||||
error.SetErrorString ("remote connections are not supported");
|
||||
|
|
|
@ -1087,7 +1087,7 @@ SBTarget::ConnectRemote
|
|||
if (process_sp)
|
||||
{
|
||||
sb_process.SetSP (process_sp);
|
||||
error.SetError (process_sp->ConnectRemote (url));
|
||||
error.SetError (process_sp->ConnectRemote (NULL, url));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1041,7 +1041,7 @@ protected:
|
|||
|
||||
if (process)
|
||||
{
|
||||
error = process->ConnectRemote (remote_url);
|
||||
error = process->ConnectRemote (&process->GetTarget().GetDebugger().GetOutputStream(), remote_url);
|
||||
|
||||
if (error.Fail())
|
||||
{
|
||||
|
|
|
@ -342,7 +342,16 @@ DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded()
|
|||
{
|
||||
m_kernel.Clear(false);
|
||||
m_kernel.module_sp = m_process->GetTarget().GetExecutableModule();
|
||||
strncpy(m_kernel.name, "mach_kernel", sizeof(m_kernel.name));
|
||||
|
||||
ConstString kernel_name("mach_kernel");
|
||||
if (m_kernel.module_sp.get()
|
||||
&& m_kernel.module_sp->GetObjectFile()
|
||||
&& !m_kernel.module_sp->GetObjectFile()->GetFileSpec().GetFilename().IsEmpty())
|
||||
{
|
||||
kernel_name = m_kernel.module_sp->GetObjectFile()->GetFileSpec().GetFilename();
|
||||
}
|
||||
strlcpy (m_kernel.name, kernel_name.AsCString(), sizeof(m_kernel.name));
|
||||
|
||||
if (m_kernel.address == LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
m_kernel.address = m_process->GetImageInfoAddress ();
|
||||
|
@ -353,7 +362,25 @@ DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded()
|
|||
// the file if we have one
|
||||
ObjectFile *kernel_object_file = m_kernel.module_sp->GetObjectFile();
|
||||
if (kernel_object_file)
|
||||
m_kernel.address = kernel_object_file->GetHeaderAddress().GetFileAddress();
|
||||
{
|
||||
addr_t load_address = kernel_object_file->GetHeaderAddress().GetLoadAddress(&m_process->GetTarget());
|
||||
addr_t file_address = kernel_object_file->GetHeaderAddress().GetFileAddress();
|
||||
if (load_address != LLDB_INVALID_ADDRESS && load_address != 0)
|
||||
{
|
||||
m_kernel.address = load_address;
|
||||
if (load_address != file_address)
|
||||
{
|
||||
// Don't accidentally relocate the kernel to the File address --
|
||||
// the Load address has already been set to its actual in-memory address.
|
||||
// Mark it as IsLoaded.
|
||||
m_kernel.load_process_stop_id = m_process->GetStopID();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kernel.address = file_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,7 +752,6 @@ DynamicLoaderDarwinKernel::PrivateInitialize(Process *process)
|
|||
DEBUG_PRINTF("DynamicLoaderDarwinKernel::%s() process state = %s\n", __FUNCTION__, StateAsCString(m_process->GetState()));
|
||||
Clear(true);
|
||||
m_process = process;
|
||||
m_process->GetTarget().GetSectionLoadList().Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -398,7 +398,7 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
|
|||
GetHostname (),
|
||||
port);
|
||||
assert (connect_url_len < sizeof(connect_url));
|
||||
error = process_sp->ConnectRemote (connect_url);
|
||||
error = process_sp->ConnectRemote (NULL, connect_url);
|
||||
if (error.Success())
|
||||
error = process_sp->Attach(attach_info);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "CommunicationKDP.h"
|
||||
|
||||
// C Includes
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "lldb/Core/DataExtractor.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/UUID.h"
|
||||
#include "lldb/Host/FileSpec.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/TimeValue.h"
|
||||
|
@ -499,6 +501,51 @@ CommunicationKDP::GetCPUSubtype ()
|
|||
return m_kdp_hostinfo_cpu_subtype;
|
||||
}
|
||||
|
||||
lldb_private::UUID
|
||||
CommunicationKDP::GetUUID ()
|
||||
{
|
||||
UUID uuid;
|
||||
if (GetKernelVersion() == NULL)
|
||||
return uuid;
|
||||
|
||||
if (m_kernel_version.find("UUID=") == std::string::npos)
|
||||
return uuid;
|
||||
|
||||
size_t p = m_kernel_version.find("UUID=") + strlen ("UUID=");
|
||||
std::string uuid_str = m_kernel_version.substr(p, 36);
|
||||
if (uuid_str.size() < 32)
|
||||
return uuid;
|
||||
|
||||
if (uuid.SetFromCString (uuid_str.c_str()) == 0)
|
||||
{
|
||||
UUID invalid_uuid;
|
||||
return invalid_uuid;
|
||||
}
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
CommunicationKDP::GetLoadAddress ()
|
||||
{
|
||||
if (GetKernelVersion() == NULL)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
if (m_kernel_version.find("stext=") == std::string::npos)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
size_t p = m_kernel_version.find("stext=") + strlen ("stext=");
|
||||
if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x')
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
addr_t kernel_load_address;
|
||||
errno = 0;
|
||||
kernel_load_address = ::strtoul (m_kernel_version.c_str() + p, NULL, 16);
|
||||
if (errno != 0 || kernel_load_address == 0)
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
return kernel_load_address;
|
||||
}
|
||||
|
||||
bool
|
||||
CommunicationKDP::SendRequestHostInfo ()
|
||||
{
|
||||
|
|
|
@ -213,6 +213,12 @@ public:
|
|||
uint32_t
|
||||
GetCPUSubtype ();
|
||||
|
||||
lldb_private::UUID
|
||||
GetUUID ();
|
||||
|
||||
lldb::addr_t
|
||||
GetLoadAddress ();
|
||||
|
||||
bool
|
||||
SendRequestResume ();
|
||||
|
||||
|
|
|
@ -17,8 +17,11 @@
|
|||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/ModuleSpec.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/UUID.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/Symbols.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
@ -167,7 +170,7 @@ ProcessKDP::WillAttachToProcessWithName (const char *process_name, bool wait_for
|
|||
}
|
||||
|
||||
Error
|
||||
ProcessKDP::DoConnectRemote (const char *remote_url)
|
||||
ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url)
|
||||
{
|
||||
Error error;
|
||||
|
||||
|
@ -214,6 +217,90 @@ ProcessKDP::DoConnectRemote (const char *remote_url)
|
|||
ArchSpec kernel_arch;
|
||||
kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
|
||||
m_target.SetArchitecture(kernel_arch);
|
||||
|
||||
/* Get the kernel's UUID and load address via kdp-kernelversion packet. */
|
||||
|
||||
UUID kernel_uuid = m_comm.GetUUID ();
|
||||
addr_t kernel_load_addr = m_comm.GetLoadAddress ();
|
||||
if (strm)
|
||||
{
|
||||
char uuidbuf[64];
|
||||
strm->Printf ("Kernel UUID: %s\n", kernel_uuid.GetAsCString (uuidbuf, sizeof (uuidbuf)));
|
||||
strm->Printf ("Load Address: 0x%llx\n", kernel_load_addr);
|
||||
strm->Flush ();
|
||||
}
|
||||
|
||||
/* Set the kernel's LoadAddress based on the information from kdp.
|
||||
This would normally be handled by the DynamicLoaderDarwinKernel plugin but there's no easy
|
||||
way to communicate the UUID / load addr from kdp back up to that plugin so we'll set it here. */
|
||||
ModuleSP exe_module_sp = m_target.GetExecutableModule ();
|
||||
bool find_and_load_kernel = true;
|
||||
if (exe_module_sp.get ())
|
||||
{
|
||||
ObjectFile *exe_objfile = exe_module_sp->GetObjectFile();
|
||||
if (exe_objfile->GetType() == ObjectFile::eTypeExecutable &&
|
||||
exe_objfile->GetStrata() == ObjectFile::eStrataKernel)
|
||||
{
|
||||
UUID exe_objfile_uuid;
|
||||
if (exe_objfile->GetUUID (&exe_objfile_uuid) && kernel_uuid == exe_objfile_uuid
|
||||
&& exe_objfile->GetHeaderAddress().IsValid())
|
||||
{
|
||||
find_and_load_kernel = false;
|
||||
addr_t slide = kernel_load_addr - exe_objfile->GetHeaderAddress().GetFileAddress();
|
||||
if (slide != 0)
|
||||
{
|
||||
bool changed = false;
|
||||
exe_module_sp->SetLoadAddress (m_target, slide, changed);
|
||||
if (changed)
|
||||
{
|
||||
ModuleList modlist;
|
||||
modlist.Append (exe_module_sp);
|
||||
m_target.ModulesDidLoad (modlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the executable binary is not the same as the kernel being run on the remote host,
|
||||
// see if Symbols::DownloadObjectAndSymbolFile can find us a symbol file based on the UUID
|
||||
// and if so, load it at the correct address.
|
||||
if (find_and_load_kernel && kernel_load_addr != LLDB_INVALID_ADDRESS && kernel_uuid.IsValid())
|
||||
{
|
||||
ModuleSpec sym_spec;
|
||||
sym_spec.GetUUID() = kernel_uuid;
|
||||
if (Symbols::DownloadObjectAndSymbolFile (sym_spec)
|
||||
&& sym_spec.GetArchitecture().IsValid()
|
||||
&& sym_spec.GetSymbolFileSpec().Exists())
|
||||
{
|
||||
ModuleSP kernel_sp = m_target.GetSharedModule (sym_spec);
|
||||
if (kernel_sp.get())
|
||||
{
|
||||
m_target.SetExecutableModule(kernel_sp, false);
|
||||
if (kernel_sp->GetObjectFile() && kernel_sp->GetObjectFile()->GetHeaderAddress().IsValid())
|
||||
{
|
||||
addr_t slide = kernel_load_addr - kernel_sp->GetObjectFile()->GetHeaderAddress().GetFileAddress();
|
||||
bool changed = false;
|
||||
kernel_sp->SetLoadAddress (m_target, slide, changed);
|
||||
if (changed)
|
||||
{
|
||||
ModuleList modlist;
|
||||
modlist.Append (kernel_sp);
|
||||
m_target.ModulesDidLoad (modlist);
|
||||
}
|
||||
if (strm)
|
||||
{
|
||||
strm->Printf ("Loaded kernel file %s/%s\n",
|
||||
kernel_sp->GetFileSpec().GetDirectory().AsCString(),
|
||||
kernel_sp->GetFileSpec().GetFilename().AsCString());
|
||||
strm->Flush ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set the thread ID
|
||||
UpdateThreadListIfNeeded ();
|
||||
SetID (1);
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoConnectRemote (const char *remote_url);
|
||||
DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoAttachToProcessWithID (lldb::pid_t pid);
|
||||
|
|
|
@ -414,7 +414,7 @@ ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wa
|
|||
}
|
||||
|
||||
Error
|
||||
ProcessGDBRemote::DoConnectRemote (const char *remote_url)
|
||||
ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
|
||||
{
|
||||
Error error (WillLaunchOrAttach ());
|
||||
|
||||
|
@ -427,6 +427,25 @@ ProcessGDBRemote::DoConnectRemote (const char *remote_url)
|
|||
return error;
|
||||
StartAsyncThread ();
|
||||
|
||||
const ArchSpec &gdb_remote_arch = m_gdb_comm.GetHostArchitecture();
|
||||
if (gdb_remote_arch.IsValid() && gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
|
||||
{
|
||||
Module *exe_module = GetTarget().GetExecutableModulePointer();
|
||||
|
||||
ObjectFile *exe_objfile = exe_module->GetObjectFile();
|
||||
|
||||
// If the remote system is an Apple device and we don't have an exec file
|
||||
// OR we have an exec file and it is a kernel, look for the kernel's load address
|
||||
// in memory and load/relocate the kernel symbols as appropriate.
|
||||
if (exe_objfile == NULL
|
||||
|| (exe_objfile->GetType() == ObjectFile::eTypeExecutable &&
|
||||
exe_objfile->GetStrata() == ObjectFile::eStrataKernel))
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
|
||||
if (pid == LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoConnectRemote (const char *remote_url);
|
||||
DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
|
||||
|
||||
lldb_private::Error
|
||||
WillLaunchOrAttach ();
|
||||
|
|
|
@ -2906,7 +2906,7 @@ Process::CompleteAttach ()
|
|||
}
|
||||
|
||||
Error
|
||||
Process::ConnectRemote (const char *remote_url)
|
||||
Process::ConnectRemote (Stream *strm, const char *remote_url)
|
||||
{
|
||||
m_abi_sp.reset();
|
||||
m_process_input_reader.reset();
|
||||
|
@ -2914,7 +2914,7 @@ Process::ConnectRemote (const char *remote_url)
|
|||
// Find the process and its architecture. Make sure it matches the architecture
|
||||
// of the current Target, and if not adjust it.
|
||||
|
||||
Error error (DoConnectRemote (remote_url));
|
||||
Error error (DoConnectRemote (strm, remote_url));
|
||||
if (error.Success())
|
||||
{
|
||||
if (GetID() != LLDB_INVALID_PROCESS_ID)
|
||||
|
|
Loading…
Reference in New Issue