[Lldb-commits] [lldb] r199945 - Move process launching into GDBRemoteCommunicationServer.

Todd Fiala tfiala at google.com
Thu Jan 23 14:05:44 PST 2014


Author: tfiala
Date: Thu Jan 23 16:05:44 2014
New Revision: 199945

URL: http://llvm.org/viewvc/llvm-project?rev=199945&view=rev
Log:
Move process launching into GDBRemoteCommunicationServer.

lldb-gdbserver was launching the commandline-specified launch process
directly, without GDBRemoteCommunicationServer knowing anything about
it.  As GDBRemoteCommunicationServer is the piece that manages and
knows about processes that the gdb remote protocol discusses with
the client end, it is important that it know about launched processes.

This change also implements the k gdb remote protocol message, having it
kill all known spawned processes when it is received.

(Note: in lldb-gdbserver, the spawned processes are not properly
monitored yet. The response to the k packet will complain that
spawned processes do not really appear to be getting killed even if
they are. This will get addressed soon.)


Modified:
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
    lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=199945&r1=199944&r2=199945&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Thu Jan 23 16:05:44 2014
@@ -143,6 +143,10 @@ GDBRemoteCommunicationServer::GetPacketA
             packet_result = Handle_qKillSpawnedProcess (packet);
             break;
 
+        case StringExtractorGDBRemote::eServerPacketType_k:
+            packet_result = Handle_k (packet);
+            break;
+
         case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
             packet_result = Handle_qLaunchSuccess (packet);
             break;
@@ -271,6 +275,38 @@ GDBRemoteCommunicationServer::GetPacketA
     return packet_result == PacketResult::Success;
 }
 
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchProcess (const char *const args[], int argc, unsigned int launch_flags)
+{
+    if ((argc < 1) || !args || !args[0] || !args[0][0])
+        lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+    // Launch the program specified in args
+    m_process_launch_info.Clear ();
+    m_process_launch_info.SetArguments (const_cast<const char**> (args), true);
+    m_process_launch_info.GetFlags ().Set (launch_flags);
+
+    lldb_private::Error error = Host::LaunchProcess (m_process_launch_info);
+    if (!error.Success ())
+    {
+        fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, args[0]);
+        return error;
+    }
+
+    printf ("Launched '%s' as process %" PRIu64 "...\n", args[0], m_process_launch_info.GetProcessID());
+
+    // add to list of spawned processes.  On an lldb-gdbserver, we
+    // would expect there to be only one.
+    lldb::pid_t pid;
+    if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID )
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        m_spawned_pids.insert(pid);
+    }
+
+    return error;
+}
+
 GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
 {
@@ -897,57 +933,122 @@ GDBRemoteCommunicationServer::Handle_qLa
 #endif
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+bool
+GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
 {
-    // Spawn a local debugserver as a platform so we can then attach or launch
-    // a process...
-
-    if (m_is_platform)
+    // make sure we know about this process
     {
-        packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return false;
+    }
 
-        lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+    // first try a SIGTERM (standard kill)
+    Host::Kill (pid, SIGTERM);
 
-        // Scope for locker
+    // check if that worked
+    for (size_t i=0; i<10; ++i)
+    {
         {
             Mutex::Locker locker (m_spawned_pids_mutex);
             if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-                return SendErrorResponse (10);
+            {
+                // it is now killed
+                return true;
+            }
         }
-        Host::Kill (pid, SIGTERM);
+        usleep (10000);
+    }
+
+    // check one more time after the final usleep
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return true;
+    }
 
-        for (size_t i=0; i<10; ++i)
+    // the launched process still lives.  Now try killling it again,
+    // this time with an unblockable signal.
+    Host::Kill (pid, SIGKILL);
+
+    for (size_t i=0; i<10; ++i)
+    {
         {
-            // Scope for locker
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
             {
-                Mutex::Locker locker (m_spawned_pids_mutex);
-                if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-                    return SendOKResponse();
+                // it is now killed
+                return true;
             }
-            usleep (10000);
         }
+        usleep (10000);
+    }
+
+    // check one more time after the final usleep
+    // Scope for locker
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return true;
+    }
 
-        // Scope for locker
+    // no luck - the process still lives
+    return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+    lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+    // verify that we know anything about this pid.
+    // Scope for locker
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
         {
-            Mutex::Locker locker (m_spawned_pids_mutex);
-            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-                return SendOKResponse();
+            // not a pid we know about
+            return SendErrorResponse (10);
         }
-        Host::Kill (pid, SIGKILL);
+    }
 
-        for (size_t i=0; i<10; ++i)
+    // go ahead and attempt to kill the spawned process
+    if (KillSpawnedProcess (pid))
+        return SendOKResponse ();
+    else
+        return SendErrorResponse (11);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
+{
+    // ignore for now if we're lldb_platform
+    if (m_is_platform)
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+    // shutdown all spawned processes
+    std::set<lldb::pid_t> spawned_pids_copy;
+
+    // copy pids
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+    }
+
+    // nuke the spawned processes
+    for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+    {
+        lldb::pid_t spawned_pid = *it;
+        if (!KillSpawnedProcess (spawned_pid))
         {
-            // Scope for locker
-            {
-                Mutex::Locker locker (m_spawned_pids_mutex);
-                if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-                    return SendOKResponse();
-            }
-            usleep (10000);
+            fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
         }
     }
-    return SendErrorResponse (11);
+
+    // TODO figure out how to shut down gracefully at this point
+    return SendOKResponse ();
 }
 
 GDBRemoteCommunication::PacketResult

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=199945&r1=199944&r2=199945&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Thu Jan 23 16:05:44 2014
@@ -138,6 +138,29 @@ public:
         m_port_offset = port_offset;
     }
 
+    //------------------------------------------------------------------
+    /// Launch a process.
+    ///
+    /// This method supports running an lldb-gdbserver or similar
+    /// server in a situation where the startup code has been provided
+    /// with all the information for a child process to be launched.
+    ///
+    /// @param[in] args
+    ///     The command line to launch.
+    ///
+    /// @param[in] argc
+    ///     The number of elements in the args array of cstring pointers.
+    ///
+    /// @param[in] launch_flags
+    ///     The launch flags to use when launching this process.
+    ///
+    /// @return
+    ///     An Error object indicating the success or failure of the
+    ///     launch.
+    //------------------------------------------------------------------
+    lldb_private::Error
+    LaunchProcess (const char *const args[], int argc, unsigned int launch_flags);
+
 protected:
     lldb::thread_t m_async_thread;
     lldb_private::ProcessLaunchInfo m_process_launch_info;
@@ -175,6 +198,9 @@ protected:
     Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
 
     PacketResult
+    Handle_k (StringExtractorGDBRemote &packet);
+
+    PacketResult
     Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
     
     PacketResult
@@ -275,6 +301,9 @@ private:
                             int signal,
                             int status);
 
+    bool
+    KillSpawnedProcess (lldb::pid_t pid);
+
     //------------------------------------------------------------------
     // For GDBRemoteCommunicationServer only
     //------------------------------------------------------------------

Modified: lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp?rev=199945&r1=199944&r2=199945&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp (original)
+++ lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp Thu Jan 23 16:05:44 2014
@@ -105,7 +105,7 @@ main (int argc, char *argv[])
     debugger_sp->SetOutputFileHandle(stdout, false);
     debugger_sp->SetErrorFileHandle(stderr, false);
 
-    ProcessLaunchInfo launch_info;
+    // ProcessLaunchInfo launch_info;
     ProcessAttachInfo attach_info;
 
     bool show_usage = false;
@@ -210,6 +210,9 @@ main (int argc, char *argv[])
             puts (output);
     }
 
+    const bool is_platform = false;
+    GDBRemoteCommunicationServer gdb_server (is_platform);
+
     const char *host_and_port = argv[0];
     argc -= 1;
     argv += 1;
@@ -218,31 +221,19 @@ main (int argc, char *argv[])
     // to launch a program, or a vAttach packet to attach to an existing process.
     if (argc > 0)
     {
-        // Launch the program specified on the command line
-        launch_info.SetArguments((const char **)argv, true);
-
         unsigned int launch_flags = eLaunchFlagStopAtEntry;
 #if !defined(__linux__)
         // linux doesn't yet handle eLaunchFlagDebug
         launch_flags |= eLaunchFlagDebug;
 #endif
-        launch_info.GetFlags ().Set (launch_flags);
-        error = Host::LaunchProcess (launch_info);
-
-        if (error.Success())
-        {
-            printf ("Launched '%s' as process %" PRIu64 "...\n", argv[0], launch_info.GetProcessID());
-        }
-        else
+        error = gdb_server.LaunchProcess (argv, argc, launch_flags);
+        if (error.Fail ())
         {
             fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
             exit(1);
         }
     }
-    
-    const bool is_platform = false;
-    GDBRemoteCommunicationServer gdb_server (is_platform);
-    
+
     if (host_and_port && host_and_port[0])
     {
         std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
@@ -271,7 +262,7 @@ main (int argc, char *argv[])
                     if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
                         break;
                 }
-                
+
                 if (error.Fail())
                 {
                     fprintf(stderr, "error: %s\n", error.AsCString());





More information about the lldb-commits mailing list