“process launch” should “detach” not “kill” if the current process was one we attached to.

“process attach” should ask the same questions as process launch if there is a current process.
“process connect” then “process launch” or “process attach” should actually work.

<rdar://problem/13524210>
<rdar://problem/13524208>
<rdar://problem/13488919>

llvm-svn: 178324
This commit is contained in:
Jim Ingham 2013-03-29 00:56:30 +00:00
parent bb9d4a5ca0
commit dcb1d856d7
1 changed files with 120 additions and 81 deletions

View File

@ -34,20 +34,95 @@
using namespace lldb; using namespace lldb;
using namespace lldb_private; using namespace lldb_private;
class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed
{
public:
CommandObjectProcessLaunchOrAttach (CommandInterpreter &interpreter,
const char *name,
const char *help,
const char *syntax,
uint32_t flags,
const char *new_process_action) :
CommandObjectParsed (interpreter, name, help, syntax, flags),
m_new_process_action (new_process_action) {}
virtual ~CommandObjectProcessLaunchOrAttach () {}
protected:
bool
StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result)
{
state = eStateInvalid;
if (process)
{
state = process->GetState();
if (process->IsAlive() && state != eStateConnected)
{
char message[1024];
if (process->GetState() == eStateAttaching)
::snprintf (message, sizeof(message), "There is a pending attach, abort it and %s?", m_new_process_action.c_str());
else if (process->GetShouldDetach())
::snprintf (message, sizeof(message), "There is a running process, detach from it and %s?", m_new_process_action.c_str());
else
::snprintf (message, sizeof(message), "There is a running process, kill it and %s?", m_new_process_action.c_str());
if (!m_interpreter.Confirm (message, true))
{
result.SetStatus (eReturnStatusFailed);
return false;
}
else
{
if (process->GetShouldDetach())
{
Error detach_error (process->Detach());
if (detach_error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
process = NULL;
}
else
{
result.AppendErrorWithFormat ("Failed to detach from process: %s\n", detach_error.AsCString());
result.SetStatus (eReturnStatusFailed);
}
}
else
{
Error destroy_error (process->Destroy());
if (destroy_error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
process = NULL;
}
else
{
result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
result.SetStatus (eReturnStatusFailed);
}
}
}
}
}
return result.Succeeded();
}
std::string m_new_process_action;
};
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// CommandObjectProcessLaunch // CommandObjectProcessLaunch
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#pragma mark CommandObjectProcessLaunch #pragma mark CommandObjectProcessLaunch
class CommandObjectProcessLaunch : public CommandObjectParsed class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach
{ {
public: public:
CommandObjectProcessLaunch (CommandInterpreter &interpreter) : CommandObjectProcessLaunch (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter, CommandObjectProcessLaunchOrAttach (interpreter,
"process launch", "process launch",
"Launch the executable in the debugger.", "Launch the executable in the debugger.",
NULL, NULL,
eFlagRequiresTarget), eFlagRequiresTarget,
"restart"),
m_options (interpreter) m_options (interpreter)
{ {
CommandArgumentEntry arg; CommandArgumentEntry arg;
@ -125,38 +200,9 @@ protected:
StateType state = eStateInvalid; StateType state = eStateInvalid;
Process *process = m_exe_ctx.GetProcessPtr(); Process *process = m_exe_ctx.GetProcessPtr();
if (process)
{
state = process->GetState();
if (process->IsAlive() && state != eStateConnected) if (!StopProcessIfNecessary(process, state, result))
{ return false;
char message[1024];
if (process->GetState() == eStateAttaching)
::strncpy (message, "There is a pending attach, abort it and launch a new process?", sizeof(message));
else
::strncpy (message, "There is a running process, kill it and restart?", sizeof(message));
if (!m_interpreter.Confirm (message, true))
{
result.SetStatus (eReturnStatusFailed);
return false;
}
else
{
Error destroy_error (process->Destroy());
if (destroy_error.Success())
{
result.SetStatus (eReturnStatusSuccessFinishResult);
}
else
{
result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
result.SetStatus (eReturnStatusFailed);
}
}
}
}
const char *target_settings_argv0 = target->GetArg0(); const char *target_settings_argv0 = target->GetArg0();
@ -217,36 +263,35 @@ protected:
m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY); m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
} }
} }
if (!m_options.launch_info.GetArchitecture().IsValid())
m_options.launch_info.GetArchitecture() = target->GetArchitecture();
PlatformSP platform_sp (target->GetPlatform());
if (platform_sp && platform_sp->CanDebugProcess ())
{
process = target->GetPlatform()->DebugProcess (m_options.launch_info,
debugger,
target,
debugger.GetListener(),
error).get();
}
else else
{ {
if (!m_options.launch_info.GetArchitecture().IsValid()) const char *plugin_name = m_options.launch_info.GetProcessPluginName();
m_options.launch_info.GetArchitecture() = target->GetArchitecture(); process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
if (process)
PlatformSP platform_sp (target->GetPlatform()); error = process->Launch (m_options.launch_info);
if (platform_sp && platform_sp->CanDebugProcess ())
{
process = target->GetPlatform()->DebugProcess (m_options.launch_info,
debugger,
target,
debugger.GetListener(),
error).get();
}
else
{
const char *plugin_name = m_options.launch_info.GetProcessPluginName();
process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
if (process)
error = process->Launch (m_options.launch_info);
}
if (process == NULL)
{
result.SetError (error, "failed to launch or debug process");
return false;
}
} }
if (process == NULL)
{
result.SetError (error, "failed to launch or debug process");
return false;
}
if (error.Success()) if (error.Success())
{ {
const char *archname = exe_module->GetArchitecture().GetArchitectureName(); const char *archname = exe_module->GetArchitecture().GetArchitectureName();
@ -332,7 +377,7 @@ protected:
// CommandObjectProcessAttach // CommandObjectProcessAttach
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
#pragma mark CommandObjectProcessAttach #pragma mark CommandObjectProcessAttach
class CommandObjectProcessAttach : public CommandObjectParsed class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach
{ {
public: public:
@ -475,10 +520,12 @@ public:
}; };
CommandObjectProcessAttach (CommandInterpreter &interpreter) : CommandObjectProcessAttach (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter, CommandObjectProcessLaunchOrAttach (interpreter,
"process attach", "process attach",
"Attach to a process.", "Attach to a process.",
"process attach <cmd-options>"), "process attach <cmd-options>",
0,
"attach"),
m_options (interpreter) m_options (interpreter)
{ {
} }
@ -503,19 +550,11 @@ protected:
// and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop // and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop
// ourselves here. // ourselves here.
Process *process = m_exe_ctx.GetProcessPtr();
StateType state = eStateInvalid; StateType state = eStateInvalid;
if (process) Process *process = m_exe_ctx.GetProcessPtr();
{
state = process->GetState(); if (!StopProcessIfNecessary (process, state, result))
if (process->IsAlive() && state != eStateConnected) return false;
{
result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before attaching.\n",
process->GetID());
result.SetStatus (eReturnStatusFailed);
return false;
}
}
if (target == NULL) if (target == NULL)
{ {