[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