forked from OSchip/llvm-project
“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:
parent
bb9d4a5ca0
commit
dcb1d856d7
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue