[Lldb-commits] [PATCH] fix debugging on linux
dawn at burble.org
dawn at burble.org
Wed Nov 23 23:31:22 PST 2011
This patch was created using clang/llvm rev 144569, lldb rev 144919 but has
been updated to clang/llvm rev 144982, lldb rev 145118. It gets debugging on
Linux back to the state it was in in llvm/clang rev 143631, lldb rev 143774.
Debugging on Linux broke when the assumption was made that a process could be
launched by spawning it in a suspended state and then attaching to it. That
support does not exist on Linux. To work around this, I added a new method
"CanLaunchViaAttach" which tests whether the platform supports being launched
in this way. I wanted to add a flag to ProcessLaunchInfo, but could not find
an easy way to set it from within the Linux plugins.
Commit message:
Fix debugging on Linux.
Implement remote vs. host platform code as was done with PlatformDarwin.
Platform::CanLaunchViaAttach(): new: return true if the process can be launched
via spawn and attach. Default is true. Override in PlatformLinux to false.
Platform::DebugProcess(): if (!target->GetPlatform()->CanLaunchViaAttach())
then launch the process via CreateProcess and Launch.
Please review and commit if acceptable.
Thanks!
-Dawn
-------------- next part --------------
Index: include/lldb/Target/Platform.h
===================================================================
--- include/lldb/Target/Platform.h (revision 145118)
+++ include/lldb/Target/Platform.h (working copy)
@@ -146,6 +146,10 @@
virtual const char *
GetDescription () = 0;
+ /// By default, launch the process by spawning and attaching.
+ virtual bool
+ CanLaunchViaAttach () { return true; }
+
//------------------------------------------------------------------
/// Report the current status for this platform.
///
Index: include/lldb/Core/MappedHash.h
===================================================================
--- include/lldb/Core/MappedHash.h (revision 145118)
+++ include/lldb/Core/MappedHash.h (working copy)
@@ -98,7 +98,7 @@
virtual size_t
GetByteSize (const HeaderData &header_data) = 0;
- size_t
+ void
SetHeaderDataByteSize (uint32_t header_data_byte_size)
{
header_data_len = header_data_byte_size;
Index: source/Plugins/Platform/Linux/PlatformLinux.cpp
===================================================================
--- source/Plugins/Platform/Linux/PlatformLinux.cpp (revision 145118)
+++ source/Plugins/Platform/Linux/PlatformLinux.cpp (working copy)
@@ -17,6 +17,7 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Error.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
@@ -29,10 +30,12 @@
using namespace lldb;
using namespace lldb_private;
+static uint32_t g_initialize_count = 0;
+
Platform *
PlatformLinux::CreateInstance ()
{
- return new PlatformLinux();
+ return new PlatformLinux(true);
}
const char *
@@ -42,33 +45,51 @@
}
const char *
-PlatformLinux::GetPluginDescriptionStatic()
+PlatformLinux::GetShortPluginNameStatic (bool is_host)
{
- return "Default platform plugin for Linux";
+ if (is_host)
+ return Platform::GetHostPlatformName ();
+ else
+ return "remote-linux";
}
+const char *
+PlatformLinux::GetPluginDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local Linux user platform plug-in.";
+ else
+ return "Remote Linux user platform plug-in.";
+}
+
void
PlatformLinux::Initialize ()
{
- static bool g_initialized = false;
-
- if (!g_initialized)
+ if (g_initialize_count++ == 0)
{
- PlatformSP default_platform_sp (CreateInstance());
+#if defined(__linux__)
+ PlatformSP default_platform_sp (new PlatformLinux(true));
+ default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
Platform::SetDefaultPlatform (default_platform_sp);
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(),
- CreateInstance);
- g_initialized = true;
+#endif
+ PluginManager::RegisterPlugin(PlatformLinux::GetShortPluginNameStatic(false),
+ PlatformLinux::GetPluginDescriptionStatic(false),
+ PlatformLinux::CreateInstance);
}
}
void
PlatformLinux::Terminate ()
{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformLinux::CreateInstance);
+ }
+ }
}
-
Error
PlatformLinux::ResolveExecutable (const FileSpec &exe_file,
const ArchSpec &exe_arch,
@@ -77,18 +98,51 @@
Error error;
// Nothing special to do here, just use the actual file and architecture
+ char exe_path[PATH_MAX];
FileSpec resolved_exe_file (exe_file);
- // If we have "ls" as the exe_file, resolve the executable loation based on
- // the current path variables
- if (!resolved_exe_file.Exists())
- resolved_exe_file.ResolveExecutableLocation ();
+ if (IsHost())
+ {
+ // If we have "ls" as the exe_file, resolve the executable location based on
+ // the current path variables
+ if (!resolved_exe_file.Exists())
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ resolved_exe_file.SetFile(exe_path, true);
+ }
- // Resolve any executable within a bundle on MacOSX
- Host::ResolveExecutableInBundle (resolved_exe_file);
+ if (!resolved_exe_file.Exists())
+ resolved_exe_file.ResolveExecutableLocation ();
- if (resolved_exe_file.Exists())
+ if (resolved_exe_file.Exists())
+ error.Clear();
+ else
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ }
+ }
+ else
{
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ResolveExecutable (exe_file,
+ exe_arch,
+ exe_module_sp);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+
+ if (resolved_exe_file.Exists())
+ error.Clear();
+ else
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
+ }
+ }
+
+ if (error.Success())
+ {
if (exe_arch.IsValid())
{
error = ModuleList::GetSharedModule (resolved_exe_file,
@@ -152,21 +206,20 @@
}
}
}
- else
- {
- error.SetErrorStringWithFormat ("'%s%s%s' does not exist",
- exe_file.GetDirectory().AsCString(""),
- exe_file.GetDirectory() ? "/" : "",
- exe_file.GetFilename().AsCString(""));
- }
return error;
}
Error
PlatformLinux::GetFile (const FileSpec &platform_file,
- const UUID *uuid, FileSpec &local_file)
+ const UUID *uuid_ptr, FileSpec &local_file)
{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file);
+ }
+
// Default to the local case
local_file = platform_file;
return Error();
@@ -176,8 +229,9 @@
//------------------------------------------------------------------
/// Default Constructor
//------------------------------------------------------------------
-PlatformLinux::PlatformLinux () :
- Platform(true)
+PlatformLinux::PlatformLinux (bool is_host) :
+ Platform(is_host), // This is the local host platform
+ m_remote_platform_sp ()
{
}
@@ -194,7 +248,17 @@
bool
PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
{
- return Host::GetProcessInfo (pid, process_info);
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
}
bool
@@ -225,11 +289,9 @@
PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target,
BreakpointSite *bp_site)
{
- static const uint8_t g_i386_opcode[] = { 0xCC };
-
ArchSpec arch = target.GetArchitecture();
- const uint8_t *opcode = NULL;
- size_t opcode_size = 0;
+ const uint8_t *trap_opcode = NULL;
+ size_t trap_opcode_size = 0;
switch (arch.GetCore())
{
@@ -239,15 +301,41 @@
case ArchSpec::eCore_x86_32_i386:
case ArchSpec::eCore_x86_64_x86_64:
- opcode = g_i386_opcode;
- opcode_size = sizeof(g_i386_opcode);
+ {
+ static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
+ trap_opcode = g_i386_breakpoint_opcode;
+ trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
+ }
break;
}
- bp_site->SetTrapOpcode(opcode, opcode_size);
- return opcode_size;
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+ return 0;
}
+Error
+PlatformLinux::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+
+ if (IsHost())
+ {
+ if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
+ {
+ const bool is_localhost = true;
+ if (!launch_info.ConvertArgumentsForLaunchingInShell (error, is_localhost))
+ return error;
+ }
+ error = Platform::LaunchProcess (launch_info);
+ }
+ else
+ {
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
lldb::ProcessSP
PlatformLinux::Attach(ProcessAttachInfo &attach_info,
Debugger &debugger,
@@ -255,7 +343,42 @@
Listener &listener,
Error &error)
{
- ProcessSP processSP;
- assert(!"Not implemented yet!");
- return processSP;
+ lldb::ProcessSP process_sp;
+ if (IsHost())
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+ FileSpec emptyFileSpec;
+ ArchSpec emptyArchSpec;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ emptyFileSpec,
+ emptyArchSpec,
+ false,
+ m_remote_platform_sp,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ process_sp = target->CreateProcess (listener, attach_info.GetProcessPluginName());
+
+ if (process_sp)
+ error = process_sp->Attach (attach_info);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
}
Index: source/Plugins/Platform/Linux/PlatformLinux.h
===================================================================
--- source/Plugins/Platform/Linux/PlatformLinux.h (revision 145118)
+++ source/Plugins/Platform/Linux/PlatformLinux.h (working copy)
@@ -28,7 +28,7 @@
static void
Terminate ();
- PlatformLinux ();
+ PlatformLinux (bool is_host);
virtual
~PlatformLinux();
@@ -43,8 +43,11 @@
GetPluginNameStatic();
static const char *
- GetPluginDescriptionStatic();
+ GetShortPluginNameStatic(bool is_host);
+ static const char *
+ GetPluginDescriptionStatic(bool is_host);
+
virtual const char *
GetPluginName()
{
@@ -71,10 +74,14 @@
const ArchSpec &arch,
lldb::ModuleSP &module_sp);
+ /// Linux processes can not be launched by spawning and attaching.
+ virtual bool
+ CanLaunchViaAttach () { return false; }
+
virtual const char *
GetDescription ()
{
- return GetPluginDescriptionStatic();
+ return GetPluginDescriptionStatic(IsHost());
}
virtual void
@@ -94,13 +101,16 @@
GetSoftwareBreakpointTrapOpcode (Target &target,
BreakpointSite *bp_site);
+ virtual lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+
virtual lldb::ProcessSP
Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
Target *target, Listener &listener, Error &error);
protected:
+ lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS
-
private:
DISALLOW_COPY_AND_ASSIGN (PlatformLinux);
};
Index: source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp (revision 145118)
+++ source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp (working copy)
@@ -34,7 +34,7 @@
s.PutCString("\n ");
s.Indent();
- s.AddressRange(start_addr + base_addr, end_addr + base_addr, NULL, ": ");
+ s.AddressRange(start_addr + base_addr, end_addr + base_addr, 0, ": ");
uint32_t loc_length = debug_loc_data.GetU16(&offset);
DataExtractor locationData(debug_loc_data, offset, loc_length);
Index: source/Plugins/Process/Linux/ProcessLinux.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessLinux.cpp (revision 145118)
+++ source/Plugins/Process/Linux/ProcessLinux.cpp (working copy)
@@ -87,7 +87,6 @@
m_in_limbo(false),
m_exit_now(false)
{
-
#if 0
// FIXME: Putting this code in the ctor and saving the byte order in a
// member variable is a hack to avoid const qual issues in GetByteOrder.
@@ -152,7 +151,6 @@
SetPrivateState(eStateLaunching);
- uint32_t launch_flags = launch_info.GetFlags().Get();
const char *stdin_path = NULL;
const char *stdout_path = NULL;
const char *stderr_path = NULL;
@@ -270,7 +268,13 @@
Error
ProcessLinux::DoDetach()
{
- return Error(1, eErrorTypeGeneric);
+ Error error;
+
+ error = m_monitor->Detach();
+ if (error.Success())
+ SetPrivateState(eStateDetached);
+
+ return error;
}
Error
@@ -388,7 +392,7 @@
ProcessLinux::IsAlive()
{
StateType state = GetPrivateState();
- return state != eStateExited && state != eStateInvalid;
+ return state != eStateDetached && state != eStateExited && state != eStateInvalid;
}
size_t
Index: source/Plugins/Process/Linux/ProcessMonitor.cpp
===================================================================
--- source/Plugins/Process/Linux/ProcessMonitor.cpp (revision 145118)
+++ source/Plugins/Process/Linux/ProcessMonitor.cpp (working copy)
@@ -722,6 +722,30 @@
m_result = true;
}
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class DetachOperation : public Operation
+{
+public:
+ DetachOperation(Error &result) : m_error(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ Error &m_error;
+};
+
+void
+DetachOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (ptrace(PT_DETACH, pid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+
+}
+
ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
: m_monitor(monitor)
{
@@ -1220,7 +1244,7 @@
ProcessMessage
ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
- const struct siginfo *info, lldb::pid_t pid)
+ const siginfo_t *info, lldb::pid_t pid)
{
ProcessMessage message;
@@ -1261,7 +1285,7 @@
ProcessMessage
ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
- const struct siginfo *info, lldb::pid_t pid)
+ const siginfo_t *info, lldb::pid_t pid)
{
ProcessMessage message;
int signo = info->si_signo;
@@ -1312,7 +1336,7 @@
}
ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGSEGV(const struct siginfo *info)
+ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
{
ProcessMessage::CrashReason reason;
assert(info->si_signo == SIGSEGV);
@@ -1336,7 +1360,7 @@
}
ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGILL(const struct siginfo *info)
+ProcessMonitor::GetCrashReasonForSIGILL(const siginfo_t *info)
{
ProcessMessage::CrashReason reason;
assert(info->si_signo == SIGILL);
@@ -1378,7 +1402,7 @@
}
ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGFPE(const struct siginfo *info)
+ProcessMonitor::GetCrashReasonForSIGFPE(const siginfo_t *info)
{
ProcessMessage::CrashReason reason;
assert(info->si_signo == SIGFPE);
@@ -1420,7 +1444,7 @@
}
ProcessMessage::CrashReason
-ProcessMonitor::GetCrashReasonForSIGBUS(const struct siginfo *info)
+ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info)
{
ProcessMessage::CrashReason reason;
assert(info->si_signo == SIGBUS);
@@ -1646,7 +1670,9 @@
ProcessMonitor::Detach()
{
bool result;
- KillOperation op(result);
+ lldb_private::Error error;
+ DetachOperation op(error);
+ result = error.Success();
DoOperation(&op);
StopMonitor();
return result;
Index: source/Plugins/Process/Linux/ProcessMonitor.h
===================================================================
--- source/Plugins/Process/Linux/ProcessMonitor.h (revision 145118)
+++ source/Plugins/Process/Linux/ProcessMonitor.h (working copy)
@@ -257,23 +257,23 @@
static ProcessMessage
MonitorSIGTRAP(ProcessMonitor *monitor,
- const struct siginfo *info, lldb::pid_t pid);
+ const siginfo_t *info, lldb::pid_t pid);
static ProcessMessage
MonitorSignal(ProcessMonitor *monitor,
- const struct siginfo *info, lldb::pid_t pid);
+ const siginfo_t *info, lldb::pid_t pid);
static ProcessMessage::CrashReason
- GetCrashReasonForSIGSEGV(const struct siginfo *info);
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
static ProcessMessage::CrashReason
- GetCrashReasonForSIGILL(const struct siginfo *info);
+ GetCrashReasonForSIGILL(const siginfo_t *info);
static ProcessMessage::CrashReason
- GetCrashReasonForSIGFPE(const struct siginfo *info);
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
static ProcessMessage::CrashReason
- GetCrashReasonForSIGBUS(const struct siginfo *info);
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
void
DoOperation(Operation *op);
Index: source/Target/Platform.cpp
===================================================================
--- source/Target/Platform.cpp (revision 145118)
+++ source/Target/Platform.cpp (working copy)
@@ -574,20 +574,31 @@
ProcessSP process_sp;
// Make sure we stop at the entry point
launch_info.GetFlags ().Set (eLaunchFlagDebug);
- error = LaunchProcess (launch_info);
- if (error.Success())
+
+ if (!target->GetPlatform()->CanLaunchViaAttach())
{
- if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ const char *plugin_name = launch_info.GetProcessPluginName();
+ process_sp = target->CreateProcess (listener, plugin_name).get();
+ error = process_sp->Launch (launch_info);
+ }
+ else
+ {
+ // We can launch the process using spawn and attach.
+ error = LaunchProcess (launch_info);
+ if (error.Success())
{
- ProcessAttachInfo attach_info (launch_info);
- process_sp = Attach (attach_info, debugger, target, listener, error);
- if (process_sp)
+ if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
{
- // Since we attached to the process, it will think it needs to detach
- // if the process object just goes away without an explicit call to
- // Process::Kill() or Process::Detach(), so let it know to kill the
- // process if this happens.
- process_sp->SetShouldDetach (false);
+ ProcessAttachInfo attach_info (launch_info);
+ process_sp = Attach (attach_info, debugger, target, listener, error);
+ if (process_sp)
+ {
+ // Since we attached to the process, it will think it needs to detach
+ // if the process object just goes away without an explicit call to
+ // Process::Kill() or Process::Detach(), so let it know to kill the
+ // process if this happens.
+ process_sp->SetShouldDetach (false);
+ }
// If we didn't have any file actions, the pseudo terminal might
// have been used where the slave side was given as the file to
More information about the lldb-commits
mailing list