Added an option to "process detach" to keep the process stopped, if the process plugin (or in the

case of ProcessGDBRemote the stub we are talking to) know how to do that.

rdar://problem/13680832

llvm-svn: 180831
This commit is contained in:
Jim Ingham 2013-04-30 23:46:08 +00:00
parent 3ca3cd1ed7
commit a23f73dbbc
14 changed files with 221 additions and 30 deletions

View File

@ -204,6 +204,9 @@ public:
lldb::SBError
Detach ();
lldb::SBError
Detach (bool keep_stopped);
lldb::SBError
Signal (int signal);

View File

@ -91,6 +91,12 @@ public:
void
SetStopOnSharedLibraryEvents (bool stop);
bool
GetDetachKeepsStopped () const;
void
SetDetachKeepsStopped (bool keep_stopped);
};
typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP;
@ -1943,11 +1949,14 @@ public:
/// This function is not meant to be overridden by Process
/// subclasses.
///
/// @param[in] keep_stopped
/// If true, don't resume the process on detach.
///
/// @return
/// Returns an error object.
//------------------------------------------------------------------
Error
Detach ();
Detach (bool keep_stopped);
//------------------------------------------------------------------
/// Kills the process and shuts down all threads that were spawned
@ -2334,7 +2343,7 @@ public:
/// false otherwise.
//------------------------------------------------------------------
virtual Error
DoDetach ()
DoDetach (bool keep_stopped)
{
Error error;
error.SetErrorStringWithFormat("error: %s does not support detaching from processes", GetShortPluginName());

View File

@ -785,13 +785,21 @@ SBProcess::Kill ()
SBError
SBProcess::Detach ()
{
// FIXME: This should come from a process default.
bool keep_stopped = false;
Detach (keep_stopped);
}
SBError
SBProcess::Detach (bool keep_stopped)
{
SBError sb_error;
ProcessSP process_sp(GetSP());
if (process_sp)
{
Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
sb_error.SetError (process_sp->Detach());
sb_error.SetError (process_sp->Detach(keep_stopped));
}
else
sb_error.SetErrorString ("SBProcess is invalid");

View File

@ -75,7 +75,8 @@ protected:
{
if (process->GetShouldDetach())
{
Error detach_error (process->Detach());
bool keep_stopped = false;
Error detach_error (process->Detach(keep_stopped));
if (detach_error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
@ -903,6 +904,68 @@ CommandObjectProcessContinue::CommandOptions::g_option_table[] =
class CommandObjectProcessDetach : public CommandObjectParsed
{
public:
class CommandOptions : public Options
{
public:
CommandOptions (CommandInterpreter &interpreter) :
Options (interpreter)
{
OptionParsingStarting ();
}
~CommandOptions ()
{
}
Error
SetOptionValue (uint32_t option_idx, const char *option_arg)
{
Error error;
const int short_option = m_getopt_table[option_idx].val;
switch (short_option)
{
case 's':
bool tmp_result;
bool success;
tmp_result = Args::StringToBoolean(option_arg, false, &success);
if (!success)
error.SetErrorStringWithFormat("invalid boolean option: \"%s\"", option_arg);
else
{
if (tmp_result)
m_keep_stopped = eLazyBoolYes;
else
m_keep_stopped = eLazyBoolNo;
}
break;
default:
error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
break;
}
return error;
}
void
OptionParsingStarting ()
{
m_keep_stopped = eLazyBoolCalculate;
}
const OptionDefinition*
GetDefinitions ()
{
return g_option_table;
}
// Options table: Required for subclasses of Options.
static OptionDefinition g_option_table[];
// Instance variables to hold the values for command options.
LazyBool m_keep_stopped;
};
CommandObjectProcessDetach (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
@ -911,7 +974,8 @@ public:
"process detach",
eFlagRequiresProcess |
eFlagTryTargetAPILock |
eFlagProcessMustBeLaunched)
eFlagProcessMustBeLaunched),
m_options(interpreter)
{
}
@ -919,13 +983,35 @@ public:
{
}
Options *
GetOptions ()
{
return &m_options;
}
protected:
bool
DoExecute (Args& command, CommandReturnObject &result)
{
Process *process = m_exe_ctx.GetProcessPtr();
result.AppendMessageWithFormat ("Detaching from process %" PRIu64 "\n", process->GetID());
Error error (process->Detach());
// FIXME: This will be a Command Option:
bool keep_stopped;
if (m_options.m_keep_stopped == eLazyBoolCalculate)
{
// Check the process default:
if (process->GetDetachKeepsStopped())
keep_stopped = true;
else
keep_stopped = false;
}
else if (m_options.m_keep_stopped == eLazyBoolYes)
keep_stopped = true;
else
keep_stopped = false;
Error error (process->Detach(keep_stopped));
if (error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
@ -938,6 +1024,15 @@ protected:
}
return result.Succeeded();
}
CommandOptions m_options;
};
OptionDefinition
CommandObjectProcessDetach::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "keep-stopped", 's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be kept stopped on detach (if possible)." },
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};
//-------------------------------------------------------------------------

View File

@ -295,7 +295,6 @@ CommandObject::CheckRequirements (CommandReturnObject &result)
else
{
StateType state = process->GetState();
switch (state)
{
case eStateInvalid:

View File

@ -507,12 +507,12 @@ ProcessKDP::DoHalt (bool &caused_stop)
}
Error
ProcessKDP::DoDetach()
ProcessKDP::DoDetach(bool keep_stopped)
{
Error error;
Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
if (log)
log->Printf ("ProcessKDP::DoDetach()");
log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped);
if (m_comm.IsRunning())
{
@ -525,7 +525,8 @@ ProcessKDP::DoDetach()
m_thread_list.DiscardThreadPlans();
if (m_comm.IsConnected())
// If we are going to keep the target stopped, then don't send the disconnect message.
if (!keep_stopped && m_comm.IsConnected())
{
m_comm.SendRequestDisconnect();
@ -554,7 +555,8 @@ Error
ProcessKDP::DoDestroy ()
{
// For KDP there really is no difference between destroy and detach
return DoDetach();
bool keep_stopped = false;
return DoDetach(keep_stopped);
}
//------------------------------------------------------------------

View File

@ -135,7 +135,7 @@ public:
DoHalt (bool &caused_stop);
virtual lldb_private::Error
DoDetach ();
DoDetach (bool keep_stopped);
virtual lldb_private::Error
DoSignal (int signal);

View File

@ -283,9 +283,16 @@ ProcessPOSIX::DoHalt(bool &caused_stop)
}
Error
ProcessPOSIX::DoDetach()
ProcessPOSIX::DoDetach(bool keep_stopped)
{
Error error;
if (keep_stopped)
{
// FIXME: If you want to implement keep_stopped on Linux,
// this would be the place to do it.
error.SetErrorString("Detaching with keep_stopped true is not currently supported on Linux.");
return error;
}
error = m_monitor->Detach();
if (error.Success())

View File

@ -65,7 +65,7 @@ public:
DoHalt(bool &caused_stop);
virtual lldb_private::Error
DoDetach();
DoDetach(bool keep_stopped);
virtual lldb_private::Error
DoSignal(int signal);

View File

@ -52,6 +52,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
m_supports_memory_region_info (eLazyBoolCalculate),
m_supports_watchpoint_support_info (eLazyBoolCalculate),
m_supports_detach_stay_stopped (eLazyBoolCalculate),
m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
m_attach_or_wait_reply(eLazyBoolCalculate),
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
@ -1396,10 +1397,48 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
return false;
}
bool
GDBRemoteCommunicationClient::Detach ()
Error
GDBRemoteCommunicationClient::Detach (bool keep_stopped)
{
return SendPacket ("D", 1) > 0;
Error error;
if (keep_stopped)
{
if (m_supports_detach_stay_stopped == eLazyBoolCalculate)
{
char packet[64];
const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");
assert (packet_len < sizeof(packet));
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
{
m_supports_detach_stay_stopped = eLazyBoolYes;
}
else
{
m_supports_detach_stay_stopped = eLazyBoolNo;
}
}
if (m_supports_detach_stay_stopped == eLazyBoolNo)
{
error.SetErrorString("Stays stopped not supported by this target.");
return error;
}
else
{
size_t num_sent = SendPacket ("D1", 2);
if (num_sent == 0)
error.SetErrorString ("Sending extended disconnect packet failed.");
}
}
else
{
size_t num_sent = SendPacket ("D", 1);
if (num_sent == 0)
error.SetErrorString ("Sending disconnect packet failed.");
}
return error;
}
Error

View File

@ -199,8 +199,8 @@ public:
bool
DeallocateMemory (lldb::addr_t addr);
bool
Detach ();
lldb_private::Error
Detach (bool keep_stopped);
lldb_private::Error
GetMemoryRegionInfo (lldb::addr_t addr,
@ -381,6 +381,7 @@ protected:
lldb_private::LazyBool m_supports_alloc_dealloc_memory;
lldb_private::LazyBool m_supports_memory_region_info;
lldb_private::LazyBool m_supports_watchpoint_support_info;
lldb_private::LazyBool m_supports_detach_stay_stopped;
lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
lldb_private::LazyBool m_attach_or_wait_reply;
lldb_private::LazyBool m_prepare_for_reg_writing_reply;

View File

@ -1703,25 +1703,29 @@ ProcessGDBRemote::DoHalt (bool &caused_stop)
}
Error
ProcessGDBRemote::DoDetach()
ProcessGDBRemote::DoDetach(bool keep_stopped)
{
Error error;
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf ("ProcessGDBRemote::DoDetach()");
log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
DisableAllBreakpointSites ();
m_thread_list.DiscardThreadPlans();
bool success = m_gdb_comm.Detach ();
error = m_gdb_comm.Detach (keep_stopped);
if (log)
{
if (success)
if (error.Success())
log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully");
else
log->PutCString ("ProcessGDBRemote::DoDetach() detach packet send failed");
log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>");
}
if (!error.Success())
return error;
// Sleep for one second to let the process get all detached...
StopAsyncThread ();

View File

@ -141,7 +141,7 @@ public:
DoHalt (bool &caused_stop);
virtual lldb_private::Error
DoDetach ();
DoDetach (bool keep_stopped);
virtual bool
DetachRequiresHalt() { return true; }

View File

@ -101,6 +101,7 @@ g_properties[] =
{ "unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, errors in expression evaluation will unwind the stack back to the state before the call." },
{ "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, NULL, NULL, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
{ "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, stop when a shared library is loaded or unloaded." },
{ "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, detach will attempt to keep the process stopped." },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
@ -110,7 +111,8 @@ enum {
ePropertyIgnoreBreakpointsInExpressions,
ePropertyUnwindOnErrorInExpressions,
ePropertyPythonOSPluginPath,
ePropertyStopOnSharedLibraryEvents
ePropertyStopOnSharedLibraryEvents,
ePropertyDetachKeepsStopped
};
ProcessProperties::ProcessProperties (bool is_global) :
@ -213,6 +215,20 @@ ProcessProperties::SetStopOnSharedLibraryEvents (bool stop)
m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, stop);
}
bool
ProcessProperties::GetDetachKeepsStopped () const
{
const uint32_t idx = ePropertyDetachKeepsStopped;
return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
}
void
ProcessProperties::SetDetachKeepsStopped (bool stop)
{
const uint32_t idx = ePropertyDetachKeepsStopped;
m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, stop);
}
void
ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
{
@ -1096,7 +1112,11 @@ Process::Finalize()
case eStateCrashed:
case eStateSuspended:
if (GetShouldDetach())
Detach();
{
// FIXME: This will have to be a process setting:
bool keep_stopped = false;
Detach(keep_stopped);
}
else
Destroy();
break;
@ -3431,7 +3451,7 @@ Process::HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp)
}
Error
Process::Detach ()
Process::Detach (bool keep_stopped)
{
EventSP exit_event_sp;
Error error;
@ -3458,12 +3478,16 @@ Process::Detach ()
}
}
error = DoDetach();
error = DoDetach(keep_stopped);
if (error.Success())
{
DidDetach();
StopPrivateStateThread();
}
else
{
return error;
}
}
m_destroy_in_process = false;