Centralized the launching of a process into Target::Launch()

While investigating test suite failures when running the test suite remotely, I noticed we had 3 copies of code that launched a process:
1 - in "process launch" command 
2 - SBTarget::Launch() with args
3 - SBTarget::Launch() with SBLaunchInfo

"process launch" was launching through the platform if it was supported (this is needed for remote debugging) and the 2 and 3 were not.

Now all code is in one place.

llvm-svn: 197247
This commit is contained in:
Greg Clayton 2013-12-13 17:20:18 +00:00
parent 3dcbca3719
commit b09c5384b0
5 changed files with 179 additions and 218 deletions

View File

@ -529,6 +529,10 @@ public:
void
Destroy();
Error
Launch (Listener &listener,
ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
// This part handles the breakpoints.

View File

@ -689,57 +689,26 @@ SBTarget::Launch
return sb_process;
}
}
if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
launch_flags |= eLaunchFlagDisableSTDIO;
ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
if (argv)
launch_info.GetArguments().AppendArguments (argv);
if (envp)
launch_info.GetEnvironmentEntries ().SetArguments (envp);
if (listener.IsValid())
error.SetError (target_sp->Launch(listener.ref(), launch_info));
else
{
if (listener.IsValid())
process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
else
process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
}
error.SetError (target_sp->Launch(target_sp->GetDebugger().GetListener(), launch_info));
if (process_sp)
{
sb_process.SetSP (process_sp);
if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
launch_flags |= eLaunchFlagDisableSTDIO;
ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
if (argv)
launch_info.GetArguments().AppendArguments (argv);
if (envp)
launch_info.GetEnvironmentEntries ().SetArguments (envp);
error.SetError (process_sp->Launch (launch_info));
if (error.Success())
{
// We we are stopping at the entry point, we can return now!
if (stop_at_entry)
return sb_process;
// Make sure we are stopped at the entry
StateType state = process_sp->WaitForProcessToStop (NULL);
if (state == eStateStopped)
{
// resume the process to skip the entry point
error.SetError (process_sp->Resume());
if (error.Success())
{
// If we are doing synchronous mode, then wait for the
// process to stop yet again!
if (target_sp->GetDebugger().GetAsyncExecution () == false)
process_sp->WaitForProcessToStop (NULL);
}
}
}
}
else
{
error.SetErrorString ("unable to create lldb_private::Process");
}
sb_process.SetSP(target_sp->GetProcessSP());
}
else
{
@ -750,7 +719,7 @@ SBTarget::Launch
if (log)
{
log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
target_sp.get(), process_sp.get());
target_sp.get(), sb_process.GetSP().get());
}
return sb_process;
@ -762,7 +731,6 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBProcess sb_process;
ProcessSP process_sp;
TargetSP target_sp(GetSP());
if (log)
@ -774,7 +742,8 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
{
Mutex::Locker api_locker (target_sp->GetAPIMutex());
StateType state = eStateInvalid;
process_sp = target_sp->GetProcessSP();
{
ProcessSP process_sp = target_sp->GetProcessSP();
if (process_sp)
{
state = process_sp->GetState();
@ -788,58 +757,20 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
return sb_process;
}
}
if (state != eStateConnected)
process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
if (process_sp)
{
sb_process.SetSP (process_sp);
lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref();
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
const ArchSpec &arch_spec = target_sp->GetArchitecture();
if (arch_spec.IsValid())
launch_info.GetArchitecture () = arch_spec;
error.SetError (process_sp->Launch (launch_info));
const bool synchronous_execution = target_sp->GetDebugger().GetAsyncExecution () == false;
if (error.Success())
{
if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
{
// If we are doing synchronous mode, then wait for the initial
// stop to happen, else, return and let the caller watch for
// the stop
if (synchronous_execution)
process_sp->WaitForProcessToStop (NULL);
// We we are stopping at the entry point, we can return now!
return sb_process;
}
// Make sure we are stopped at the entry
StateType state = process_sp->WaitForProcessToStop (NULL);
if (state == eStateStopped)
{
// resume the process to skip the entry point
error.SetError (process_sp->Resume());
if (error.Success())
{
// If we are doing synchronous mode, then wait for the
// process to stop yet again!
if (synchronous_execution)
process_sp->WaitForProcessToStop (NULL);
}
}
}
}
else
{
error.SetErrorString ("unable to create lldb_private::Process");
}
lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref();
Module *exe_module = target_sp->GetExecutableModulePointer();
if (exe_module)
launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
const ArchSpec &arch_spec = target_sp->GetArchitecture();
if (arch_spec.IsValid())
launch_info.GetArchitecture () = arch_spec;
error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info));
sb_process.SetSP(target_sp->GetProcessSP());
}
else
{
@ -849,8 +780,8 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
if (log)
{
log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
target_sp.get(), process_sp.get());
log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
target_sp.get(), sb_process.GetSP().get());
}
return sb_process;

View File

@ -49,7 +49,7 @@ public:
virtual ~CommandObjectProcessLaunchOrAttach () {}
protected:
bool
StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result)
StopProcessIfNecessary (Process *process, StateType &state, CommandReturnObject &result)
{
state = eStateInvalid;
if (process)
@ -187,12 +187,10 @@ protected:
{
Debugger &debugger = m_interpreter.GetDebugger();
Target *target = debugger.GetSelectedTarget().get();
Error error;
// If our listener is NULL, users aren't allows to launch
char filename[PATH_MAX];
const Module *exe_module = target->GetExecutableModulePointer();
ModuleSP exe_module_sp = target->GetExecutableModule();
if (exe_module == NULL)
if (exe_module_sp == NULL)
{
result.AppendError ("no file in target, create a debug target using the 'target create' command");
result.SetStatus (eReturnStatusFailed);
@ -200,23 +198,31 @@ protected:
}
StateType state = eStateInvalid;
Process *process = m_exe_ctx.GetProcessPtr();
if (!StopProcessIfNecessary(process, state, result))
if (!StopProcessIfNecessary(m_exe_ctx.GetProcessPtr(), state, result))
return false;
const char *target_settings_argv0 = target->GetArg0();
exe_module->GetFileSpec().GetPath (filename, sizeof(filename));
if (target->GetDisableASLR())
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
if (target->GetDisableSTDIO())
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
Args environment;
target->GetEnvironmentAsArgs (environment);
if (environment.GetArgumentCount() > 0)
m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
if (target_settings_argv0)
{
m_options.launch_info.GetArguments().AppendArgument (target_settings_argv0);
m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), false);
m_options.launch_info.SetExecutableFile(exe_module_sp->GetPlatformFileSpec(), false);
}
else
{
m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
m_options.launch_info.SetExecutableFile(exe_module_sp->GetPlatformFileSpec(), true);
}
if (launch_args.GetArgumentCount() == 0)
@ -228,122 +234,33 @@ protected:
else
{
m_options.launch_info.GetArguments().AppendArguments (launch_args);
// Save the arguments for subsequent runs in the current target.
target->SetRunArguments (launch_args);
}
if (target->GetDisableASLR())
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
if (target->GetDisableSTDIO())
m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
m_options.launch_info.GetFlags().Set (eLaunchFlagDebug);
Args environment;
target->GetEnvironmentAsArgs (environment);
if (environment.GetArgumentCount() > 0)
m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
// Get the value of synchronous execution here. If you wait till after you have started to
// run, then you could have hit a breakpoint, whose command might switch the value, and
// then you'll pick up that incorrect value.
bool synchronous_execution = m_interpreter.GetSynchronous ();
PlatformSP platform_sp (target->GetPlatform());
// Finalize the file actions, and if none were given, default to opening
// up a pseudo terminal
const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false;
m_options.launch_info.FinalizeFileActions (target, default_to_use_pty);
if (state == eStateConnected)
{
if (m_options.launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
{
result.AppendWarning("can't launch in tty when launching through a remote connection");
m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
}
}
Error error = target->Launch(debugger.GetListener(), m_options.launch_info);
if (!m_options.launch_info.GetArchitecture().IsValid())
m_options.launch_info.GetArchitecture() = target->GetArchitecture();
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 (error.Success())
{
const char *archname = exe_module->GetArchitecture().GetArchitectureName();
result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process->GetID(), filename, archname);
result.SetDidChangeProcessState (true);
if (m_options.launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName();
ProcessSP process_sp (target->GetProcessSP());
if (process_sp)
{
result.SetStatus (eReturnStatusSuccessContinuingNoResult);
StateType state = process->WaitForProcessToStop (NULL, NULL, false);
if (state == eStateStopped)
{
error = process->Resume();
if (error.Success())
{
if (synchronous_execution)
{
state = process->WaitForProcessToStop (NULL);
const bool must_be_alive = true;
if (!StateIsStoppedState(state, must_be_alive))
{
result.AppendErrorWithFormat ("process isn't stopped: %s", StateAsCString(state));
}
result.SetDidChangeProcessState (true);
result.SetStatus (eReturnStatusSuccessFinishResult);
}
else
{
result.SetStatus (eReturnStatusSuccessContinuingNoResult);
}
}
else
{
result.AppendErrorWithFormat ("process resume at entry point failed: %s", error.AsCString());
result.SetStatus (eReturnStatusFailed);
}
}
else
{
result.AppendErrorWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
result.SetStatus (eReturnStatusFailed);
}
result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
result.SetStatus (eReturnStatusSuccessFinishResult);
result.SetDidChangeProcessState (true);
}
else
{
result.AppendError("no error returned from Target::Launch, and target has no process");
result.SetStatus (eReturnStatusFailed);
}
}
else
{
result.AppendErrorWithFormat ("process launch failed: %s", error.AsCString());
result.AppendError(error.AsCString());
result.SetStatus (eReturnStatusFailed);
}
return result.Succeeded();
}

View File

@ -254,7 +254,7 @@ protected:
// Classes that inherit from GDBRemoteCommunication can see and modify these
//------------------------------------------------------------------
uint32_t m_packet_timeout;
#ifdef LLDB_CONFIGURATION_DEBUG
#ifdef ENABLE_MUTEX_ERROR_CHECKING
lldb_private::TrackingMutex m_sequence_mutex;
#else
lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time

View File

@ -28,6 +28,7 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
@ -2317,6 +2318,114 @@ Target::ClearAllLoadedSections ()
m_section_load_history.Clear();
}
Error
Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
{
Error error;
Error error2;
StateType state = eStateInvalid;
launch_info.GetFlags().Set (eLaunchFlagDebug);
// Get the value of synchronous execution here. If you wait till after you have started to
// run, then you could have hit a breakpoint, whose command might switch the value, and
// then you'll pick up that incorrect value.
Debugger &debugger = GetDebugger();
const bool synchronous_execution = debugger.GetCommandInterpreter().GetSynchronous ();
PlatformSP platform_sp (GetPlatform());
// Finalize the file actions, and if none were given, default to opening
// up a pseudo terminal
const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false;
launch_info.FinalizeFileActions (this, default_to_use_pty);
if (state == eStateConnected)
{
if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
{
error.SetErrorString("can't launch in tty when launching through a remote connection");
return error;
}
}
if (!launch_info.GetArchitecture().IsValid())
launch_info.GetArchitecture() = GetArchitecture();
if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ())
{
m_process_sp = GetPlatform()->DebugProcess (launch_info,
debugger,
this,
listener,
error);
}
else
{
if (state == eStateConnected)
{
assert(m_process_sp);
}
else
{
const char *plugin_name = launch_info.GetProcessPluginName();
CreateProcess (listener, plugin_name, NULL);
}
if (m_process_sp)
error = m_process_sp->Launch (launch_info);
}
if (!m_process_sp)
{
if (error.Success())
error.SetErrorString("failed to launch or debug process");
return error;
}
if (error.Success())
{
if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
{
StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false);
if (state == eStateStopped)
{
error = m_process_sp->Resume();
if (error.Success())
{
if (synchronous_execution)
{
state = m_process_sp->WaitForProcessToStop (NULL);
const bool must_be_alive = false; // eStateExited is ok, so this must be false
if (!StateIsStoppedState(state, must_be_alive))
{
error2.SetErrorStringWithFormat("process isn't stopped: %s", StateAsCString(state));
return error2;
}
}
}
else
{
error2.SetErrorStringWithFormat("process resume at entry point failed: %s", error.AsCString());
return error2;
}
}
else
{
error.SetErrorStringWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
}
}
}
else
{
error2.SetErrorStringWithFormat ("process launch failed: %s", error.AsCString());
return error2;
}
return error;
}
//--------------------------------------------------------------
// Target::StopHook
//--------------------------------------------------------------