Added an option to turn OFF the "detach on error" behavior that was added
authorJim Ingham <jingham@apple.com>
Wed, 25 Jun 2014 02:32:56 +0000 (02:32 +0000)
committerJim Ingham <jingham@apple.com>
Wed, 25 Jun 2014 02:32:56 +0000 (02:32 +0000)
to debugserver when launching processes.

<rdar://problem/16216199>

llvm-svn: 211658

20 files changed:
lldb/include/lldb/API/SBTarget.h
lldb/include/lldb/Target/Process.h
lldb/include/lldb/Target/Target.h
lldb/include/lldb/lldb-enumerations.h
lldb/scripts/Python/interface/SBTarget.i
lldb/source/API/SBTarget.cpp
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Host/macosx/Host.mm
lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Target/Target.cpp
lldb/source/Utility/StringExtractorGDBRemote.cpp
lldb/source/Utility/StringExtractorGDBRemote.h
lldb/tools/debugserver/source/RNBRemote.cpp
lldb/tools/debugserver/source/RNBRemote.h

index e0ac4f8..f5bb8b4 100644 (file)
@@ -145,6 +145,12 @@ public:
     const char *
     GetLaunchEventData () const;
     
+    bool
+    GetDetachOnError() const;
+    
+    void
+    SetDetachOnError(bool enable);
+    
 protected:
     friend class SBTarget;
     
index 94bc958..69a2c4e 100644 (file)
@@ -866,6 +866,21 @@ public:
         return m_event_data.c_str();
     }
     
+    void
+    SetDetachOnError (bool enable)
+    {
+        if (enable)
+            m_flags.Set(lldb::eLaunchFlagDetachOnError);
+        else
+            m_flags.Clear(lldb::eLaunchFlagDetachOnError);
+    }
+    
+    bool
+    GetDetachOnError () const
+    {
+        return m_flags.Test(lldb::eLaunchFlagDetachOnError);
+    }
+    
 protected:
     std::string m_working_dir;
     std::string m_plugin_name;
@@ -882,9 +897,9 @@ protected:
 };
 
 //----------------------------------------------------------------------
-// ProcessLaunchInfo
+// ProcessAttachInfo
 //
-// Describes any information that is required to launch a process.
+// Describes any information that is required to attach to a process.
 //----------------------------------------------------------------------
     
 class ProcessAttachInfo : public ProcessInstanceInfo
@@ -896,7 +911,8 @@ public:
         m_resume_count (0),
         m_wait_for_launch (false),
         m_ignore_existing (true),
-        m_continue_once_attached (false)
+        m_continue_once_attached (false),
+        m_detach_on_error (true)
     {
     }
 
@@ -906,12 +922,14 @@ public:
         m_resume_count (0),
         m_wait_for_launch (false),
         m_ignore_existing (true),
-        m_continue_once_attached (false)
+        m_continue_once_attached (false),
+        m_detach_on_error(true)
     {
         ProcessInfo::operator= (launch_info);
         SetProcessPluginName (launch_info.GetProcessPluginName());
         SetResumeCount (launch_info.GetResumeCount());
         SetHijackListener(launch_info.GetHijackListener());
+        m_detach_on_error = launch_info.GetDetachOnError();
     }
     
     bool
@@ -1014,7 +1032,18 @@ public:
         m_hijack_listener_sp = listener_sp;
     }
     
-
+    bool
+    GetDetachOnError () const
+    {
+        return m_detach_on_error;
+    }
+    
+    void
+    SetDetachOnError (bool enable)
+    {
+        m_detach_on_error = enable;
+    }
+    
 protected:
     lldb::ListenerSP m_hijack_listener_sp;
     std::string m_plugin_name;
@@ -1022,6 +1051,7 @@ protected:
     bool m_wait_for_launch;
     bool m_ignore_existing;
     bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached.
+    bool m_detach_on_error;  // If we are debugging remotely, instruct the stub to detach rather than killing the target on error.
 };
 
 class ProcessLaunchCommandOptions : public Options
index 25e0eaa..3393bb6 100644 (file)
@@ -82,6 +82,12 @@ public:
     SetDisableASLR (bool b);
     
     bool
+    GetDetachOnError () const;
+    
+    void
+    SetDetachOnError (bool b);
+    
+    bool
     GetDisableSTDIO () const;
     
     void
index 8596f6d..33e34df 100644 (file)
@@ -39,16 +39,18 @@ namespace lldb {
     typedef enum LaunchFlags
     {
         eLaunchFlagNone         = 0u,
-        eLaunchFlagExec         = (1u << 0),  ///< Exec when launching and turn the calling process into a new process
-        eLaunchFlagDebug        = (1u << 1),  ///< Stop as soon as the process launches to allow the process to be debugged
-        eLaunchFlagStopAtEntry  = (1u << 2),  ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point
-        eLaunchFlagDisableASLR  = (1u << 3),  ///< Disable Address Space Layout Randomization
-        eLaunchFlagDisableSTDIO = (1u << 4),  ///< Disable stdio for inferior process (e.g. for a GUI app)
-        eLaunchFlagLaunchInTTY  = (1u << 5),  ///< Launch the process in a new TTY if supported by the host 
-        eLaunchFlagLaunchInShell= (1u << 6),   ///< Launch the process inside a shell to get shell expansion
+        eLaunchFlagExec         = (1u << 0),       ///< Exec when launching and turn the calling process into a new process
+        eLaunchFlagDebug        = (1u << 1),       ///< Stop as soon as the process launches to allow the process to be debugged
+        eLaunchFlagStopAtEntry  = (1u << 2),       ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point
+        eLaunchFlagDisableASLR  = (1u << 3),       ///< Disable Address Space Layout Randomization
+        eLaunchFlagDisableSTDIO = (1u << 4),       ///< Disable stdio for inferior process (e.g. for a GUI app)
+        eLaunchFlagLaunchInTTY  = (1u << 5),       ///< Launch the process in a new TTY if supported by the host
+        eLaunchFlagLaunchInShell= (1u << 6),       ///< Launch the process inside a shell to get shell expansion
         eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7), ///< Launch the process in a separate process group
-        eLaunchFlagsDontSetExitStatus = (1u << 8)  ///< If you are going to hand the process off (e.g. to debugserver)
-                                                    ///< set this flag so lldb & the handee don't race to set its exit status.
+        eLaunchFlagDontSetExitStatus = (1u << 8), ///< If you are going to hand the process off (e.g. to debugserver)
+                                                   ///< set this flag so lldb & the handee don't race to set its exit status.
+        eLaunchFlagDetachOnError = (1u << 9)      ///< If set, then the client stub should detach rather than killing the debugee
+                                                   ///< if it loses connection with lldb.
     } LaunchFlags;
         
     //----------------------------------------------------------------------
index 1f697ba..bbf1f74 100644 (file)
@@ -107,6 +107,12 @@ public:
     const char *
     GetLaunchEventData () const;
     
+    bool
+    GetDetachOnError() const;
+    
+    void
+    SetDetachOnError(bool enable);
+    
 };
 
 class SBAttachInfo
index 900ccaf..5826ee6 100644 (file)
@@ -292,6 +292,18 @@ SBLaunchInfo::GetLaunchEventData () const
     return m_opaque_sp->GetLaunchEventData ();
 }
 
+void
+SBLaunchInfo::SetDetachOnError (bool enable)
+{
+    m_opaque_sp->SetDetachOnError (enable);
+}
+
+bool
+SBLaunchInfo::GetDetachOnError () const
+{
+    return m_opaque_sp->GetDetachOnError ();
+}
+
 SBAttachInfo::SBAttachInfo () :
     m_opaque_sp (new ProcessAttachInfo())
 {
index 92735ec..4952ed5 100644 (file)
@@ -208,6 +208,9 @@ protected:
         if (target->GetDisableASLR())
             m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
         
+        if (target->GetDetachOnError())
+            m_options.launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
+        
         if (target->GetDisableSTDIO())
             m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
         
index f4932ef..375f9e4 100644 (file)
@@ -1669,7 +1669,7 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info)
             const bool monitor_signals = false;
             Host::MonitorChildProcessCallback callback = nullptr;
             
-            if (!launch_info.GetFlags().Test(lldb::eLaunchFlagsDontSetExitStatus))
+            if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
                 callback = Process::SetProcessExitStatus;
 
             StartMonitoringChildProcess (callback,
index 3ff28e1..29d8bc8 100644 (file)
@@ -788,7 +788,7 @@ PlatformDarwin::DebugProcess (ProcessLaunchInfo &launch_info,
         // We are going to hand this process off to debugserver which will be in charge of setting the exit status.
         // We still need to reap it from lldb but if we let the monitor thread also set the exit status, we set up a
         // race between debugserver & us for who will find out about the debugged process's death.
-        launch_info.GetFlags().Set(eLaunchFlagsDontSetExitStatus);
+        launch_info.GetFlags().Set(eLaunchFlagDontSetExitStatus);
         process_sp = Platform::DebugProcess (launch_info, debugger, target, listener, error);
     }
     else
index aa1b6ee..6641998 100644 (file)
@@ -353,6 +353,7 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
     m_gdb_client.SetSTDOUT ("/dev/null");
     m_gdb_client.SetSTDERR ("/dev/null");
     m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
+    m_gdb_client.SetDetachOnError (launch_info.GetFlags().Test (eLaunchFlagDetachOnError));
     
     const char *working_dir = launch_info.GetWorkingDirectory();
     if (working_dir && working_dir[0])
index f7beac2..c3c2c67 100644 (file)
@@ -2256,6 +2256,25 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
     return -1;
 }
 
+int
+GDBRemoteCommunicationClient::SetDetachOnError (bool enable)
+{
+    char packet[32];
+    const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0);
+    assert (packet_len < (int)sizeof(packet));
+    StringExtractorGDBRemote response;
+    if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+    {
+        if (response.IsOKResponse())
+            return 0;
+        uint8_t error = response.GetError();
+        if (error)
+            return error;
+    }
+    return -1;
+}
+
+
 bool
 GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info)
 {
index 1166a6f..556465d 100644 (file)
@@ -205,13 +205,25 @@ public:
     /// be launched with the 'A' packet.
     ///
     /// @param[in] enable
-    ///     A boolean value indicating wether to disable ASLR or not.
+    ///     A boolean value indicating whether to disable ASLR or not.
     ///
     /// @return
     ///     Zero if the for success, or an error code for failure.
     //------------------------------------------------------------------
     int
     SetDisableASLR (bool enable);
+    
+    //------------------------------------------------------------------
+    /// Sets the DetachOnError flag to \a enable for the process controlled by the stub.
+    ///
+    /// @param[in] enable
+    ///     A boolean value indicating whether to detach on error or not.
+    ///
+    /// @return
+    ///     Zero if the for success, or an error code for failure.
+    //------------------------------------------------------------------
+    int
+    SetDetachOnError (bool enable);
 
     //------------------------------------------------------------------
     /// Sets the working directory to \a path for a process that will 
index 2fadf33..21f9eda 100644 (file)
@@ -202,6 +202,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
             packet_result = Handle_QSetDisableASLR (packet);
             break;
 
+        case StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError:
+            packet_result = Handle_QSetDetachOnError (packet);
+            break;
+
         case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
             packet_result = Handle_QSetSTDIN (packet);
             break;
@@ -1140,6 +1144,17 @@ GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &
 }
 
 GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetDetachOnError:"));
+    if (packet.GetU32(0))
+        m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
+    else
+        m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
+    return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
 {
     packet.SetFilePos(::strlen ("QSetWorkingDir:"));
index 913c6b6..4bc0857 100644 (file)
@@ -265,6 +265,9 @@ protected:
     Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
 
     PacketResult
+    Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
+
+    PacketResult
     Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
     
     PacketResult
index 7adf916..521e354 100644 (file)
@@ -799,6 +799,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
                 m_gdb_comm.SetSTDERR (stderr_path);
 
             m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
+            m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
 
             m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
             
@@ -1071,6 +1072,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
     
         if (error.Success())
         {
+            m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+            
             char packet[64];
             const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
             SetID (attach_pid);            
@@ -1108,6 +1111,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const Pro
         {
             StreamString packet;
             
+            m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+            
             if (attach_info.GetWaitForLaunch())
             {
                 if (!m_gdb_comm.GetVAttachOrWaitSupported())
index 35b4112..9deafa9 100644 (file)
@@ -2642,6 +2642,7 @@ g_properties[] =
     { "input-path"                         , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for reading its standard input." },
     { "output-path"                        , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for writing its standard output." },
     { "error-path"                         , OptionValue::eTypeFileSpec  , false, 0                         , NULL, NULL, "The file/path to be used by the executable program for writing its standard error." },
+    { "detach-on-error"                    , OptionValue::eTypeBoolean   , false, true                      , NULL, NULL, "debugserver will detach (rather than killing) a process if it loses connection with lldb." },
     { "disable-aslr"                       , OptionValue::eTypeBoolean   , false, true                      , NULL, NULL, "Disable Address Space Layout Randomization (ASLR)" },
     { "disable-stdio"                      , OptionValue::eTypeBoolean   , false, false                     , NULL, NULL, "Disable stdin/stdout for process (e.g. for a GUI application)" },
     { "inline-breakpoint-strategy"         , OptionValue::eTypeEnum      , false, eInlineBreakpointsHeaders , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
@@ -2688,6 +2689,7 @@ enum
     ePropertyInputPath,
     ePropertyOutputPath,
     ePropertyErrorPath,
+    ePropertyDetachOnError,
     ePropertyDisableASLR,
     ePropertyDisableSTDIO,
     ePropertyInlineStrategy,
@@ -2871,6 +2873,20 @@ TargetProperties::SetDisableASLR (bool b)
 }
 
 bool
+TargetProperties::GetDetachOnError () const
+{
+    const uint32_t idx = ePropertyDetachOnError;
+    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+TargetProperties::SetDetachOnError (bool b)
+{
+    const uint32_t idx = ePropertyDetachOnError;
+    m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
 TargetProperties::GetDisableSTDIO () const
 {
     const uint32_t idx = ePropertyDisableSTDIO;
index eccb813..c8633d7 100644 (file)
@@ -92,6 +92,7 @@ StringExtractorGDBRemote::GetServerPacketType () const
             if (PACKET_MATCHES ("QStartNoAckMode"))               return eServerPacketType_QStartNoAckMode;
             if (PACKET_STARTS_WITH ("QSaveRegisterState"))        return eServerPacketType_QSaveRegisterState;
             if (PACKET_STARTS_WITH ("QSetDisableASLR:"))          return eServerPacketType_QSetDisableASLR;
+            if (PACKET_STARTS_WITH ("QSetDetachOnError:"))        return eServerPacketType_QSetDetachOnError;
             if (PACKET_STARTS_WITH ("QSetSTDIN:"))                return eServerPacketType_QSetSTDIN;
             if (PACKET_STARTS_WITH ("QSetSTDOUT:"))               return eServerPacketType_QSetSTDOUT;
             if (PACKET_STARTS_WITH ("QSetSTDERR:"))               return eServerPacketType_QSetSTDERR;
index f8af3ca..e73dd97 100644 (file)
@@ -62,6 +62,7 @@ public:
         eServerPacketType_QEnvironment,
         eServerPacketType_QLaunchArch,
         eServerPacketType_QSetDisableASLR,
+        eServerPacketType_QSetDetachOnError,
         eServerPacketType_QSetSTDIN,
         eServerPacketType_QSetSTDOUT,
         eServerPacketType_QSetSTDERR,
index e8fb114..f2b1171 100644 (file)
@@ -203,6 +203,7 @@ RNBRemote::CreatePacketTable  ()
     t.push_back (Packet (set_enable_profiling,          &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, "QSetEnableAsyncProfiling", "Enable or disable the profiling of current target."));
     t.push_back (Packet (watchpoint_support_info,       &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL, "qWatchpointSupportInfo", "Return the number of supported hardware watchpoints"));
     t.push_back (Packet (set_process_event,             &RNBRemote::HandlePacket_QSetProcessEvent, NULL, "QSetProcessEvent:", "Set a process event, to be passed to the process, can be set before the process is started, or after."));
+    t.push_back (Packet (set_detach_on_error,           &RNBRemote::HandlePacket_QSetDetachOnError, NULL, "QSetDetachOnError:", "Set whether debugserver will detach (1) or kill (0) from the process it is controlling if it loses connection to lldb."));
     t.push_back (Packet (speed_test,                    &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:", "Test the maximum speed at which packet can be sent/received."));
 }
 
@@ -2018,6 +2019,24 @@ RNBRemote::HandlePacket_QSyncThreadState (const char *p)
 }
 
 rnb_err_t
+RNBRemote::HandlePacket_QSetDetachOnError (const char *p)
+{
+    p += sizeof ("QSetDetachOnError:") - 1;
+    bool should_detach = true;
+    switch (*p)
+    {
+        case '0': should_detach = false; break;
+        case '1': should_detach = true; break;
+        default:
+          return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid value for QSetDetachOnError - should be 0 or 1");
+          break;
+    }
+    
+    m_ctx.SetDetachOnError(should_detach);
+    return SendPacket ("OK");
+}
+
+rnb_err_t
 RNBRemote::HandlePacket_QListThreadsInStopReply (const char *p)
 {
     // If this packet is received, it allows us to send an extra key/value
index fb2ec12..1622ba1 100644 (file)
@@ -126,6 +126,7 @@ public:
         save_register_state,            // '_g'
         restore_register_state,         // '_G'
         speed_test,                     // 'qSpeedTest:'
+        set_detach_on_error,            // 'QSetDetachOnError:'
         unknown_type
     } PacketEnum;
 
@@ -234,6 +235,7 @@ public:
     rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p);
     rnb_err_t HandlePacket_qSpeedTest (const char *p);
     rnb_err_t HandlePacket_stop_process (const char *p);
+    rnb_err_t HandlePacket_QSetDetachOnError (const char *p);
 
     rnb_err_t SendStopReplyPacketForThread (nub_thread_t tid);
     rnb_err_t SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer);