mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-26 05:18:46 +00:00
Revert "Revert "Make it possible for lldb to launch a remote binary with no local file.""
This reverts commit dd5505a8f2c75a903ec944b6e46aed2042610673. I picked the wrong class for the test, should have been GDBRemoteTestBase.
This commit is contained in:
parent
02eca53a50
commit
92eaad2dd7
@ -159,7 +159,12 @@ protected:
|
||||
// If our listener is nullptr, users aren't allows to launch
|
||||
ModuleSP exe_module_sp = target->GetExecutableModule();
|
||||
|
||||
if (exe_module_sp == nullptr) {
|
||||
// If the target already has an executable module, then use that. If it
|
||||
// doesn't then someone must be trying to launch using a path that will
|
||||
// make sense to the remote stub, but doesn't exist on the local host.
|
||||
// In that case use the ExecutableFile that was set in the target's
|
||||
// ProcessLaunchInfo.
|
||||
if (exe_module_sp == nullptr && !target->GetProcessLaunchInfo().GetExecutableFile()) {
|
||||
result.AppendError("no file in target, create a debug target using the "
|
||||
"'target create' command");
|
||||
return false;
|
||||
@ -219,11 +224,17 @@ protected:
|
||||
if (!target_settings_argv0.empty()) {
|
||||
m_options.launch_info.GetArguments().AppendArgument(
|
||||
target_settings_argv0);
|
||||
m_options.launch_info.SetExecutableFile(
|
||||
exe_module_sp->GetPlatformFileSpec(), false);
|
||||
if (exe_module_sp)
|
||||
m_options.launch_info.SetExecutableFile(
|
||||
exe_module_sp->GetPlatformFileSpec(), false);
|
||||
else
|
||||
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), false);
|
||||
} else {
|
||||
m_options.launch_info.SetExecutableFile(
|
||||
exe_module_sp->GetPlatformFileSpec(), true);
|
||||
if (exe_module_sp)
|
||||
m_options.launch_info.SetExecutableFile(
|
||||
exe_module_sp->GetPlatformFileSpec(), true);
|
||||
else
|
||||
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), true);
|
||||
}
|
||||
|
||||
if (launch_args.GetArgumentCount() == 0) {
|
||||
@ -250,11 +261,20 @@ protected:
|
||||
llvm::StringRef data = stream.GetString();
|
||||
if (!data.empty())
|
||||
result.AppendMessage(data);
|
||||
const char *archname =
|
||||
exe_module_sp->GetArchitecture().GetArchitectureName();
|
||||
result.AppendMessageWithFormat(
|
||||
"Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
|
||||
exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
|
||||
// If we didn't have a local executable, then we wouldn't have had an
|
||||
// executable module before launch.
|
||||
if (!exe_module_sp)
|
||||
exe_module_sp = target->GetExecutableModule();
|
||||
if (!exe_module_sp) {
|
||||
result.AppendWarning("Could not get executable module after launch.");
|
||||
} else {
|
||||
|
||||
const char *archname =
|
||||
exe_module_sp->GetArchitecture().GetArchitectureName();
|
||||
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 {
|
||||
|
@ -677,143 +677,133 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
|
||||
// LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
|
||||
// ::LogSetLogFile ("/dev/stdout");
|
||||
|
||||
ObjectFile *object_file = exe_module->GetObjectFile();
|
||||
if (object_file) {
|
||||
error = EstablishConnectionIfNeeded(launch_info);
|
||||
if (error.Success()) {
|
||||
PseudoTerminal pty;
|
||||
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
|
||||
error = EstablishConnectionIfNeeded(launch_info);
|
||||
if (error.Success()) {
|
||||
PseudoTerminal pty;
|
||||
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
|
||||
|
||||
PlatformSP platform_sp(GetTarget().GetPlatform());
|
||||
if (disable_stdio) {
|
||||
// set to /dev/null unless redirected to a file above
|
||||
if (!stdin_file_spec)
|
||||
stdin_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
if (!stdout_file_spec)
|
||||
stdout_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
if (!stderr_file_spec)
|
||||
stderr_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
} else if (platform_sp && platform_sp->IsHost()) {
|
||||
// If the debugserver is local and we aren't disabling STDIO, lets use
|
||||
// a pseudo terminal to instead of relying on the 'O' packets for stdio
|
||||
// since 'O' packets can really slow down debugging if the inferior
|
||||
// does a lot of output.
|
||||
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
|
||||
!errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
|
||||
FileSpec secondary_name(pty.GetSecondaryName());
|
||||
|
||||
PlatformSP platform_sp(GetTarget().GetPlatform());
|
||||
if (disable_stdio) {
|
||||
// set to /dev/null unless redirected to a file above
|
||||
if (!stdin_file_spec)
|
||||
stdin_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
stdin_file_spec = secondary_name;
|
||||
|
||||
if (!stdout_file_spec)
|
||||
stdout_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
stdout_file_spec = secondary_name;
|
||||
|
||||
if (!stderr_file_spec)
|
||||
stderr_file_spec.SetFile(FileSystem::DEV_NULL,
|
||||
FileSpec::Style::native);
|
||||
} else if (platform_sp && platform_sp->IsHost()) {
|
||||
// If the debugserver is local and we aren't disabling STDIO, lets use
|
||||
// a pseudo terminal to instead of relying on the 'O' packets for stdio
|
||||
// since 'O' packets can really slow down debugging if the inferior
|
||||
// does a lot of output.
|
||||
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
|
||||
!errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
|
||||
FileSpec secondary_name(pty.GetSecondaryName());
|
||||
|
||||
if (!stdin_file_spec)
|
||||
stdin_file_spec = secondary_name;
|
||||
|
||||
if (!stdout_file_spec)
|
||||
stdout_file_spec = secondary_name;
|
||||
|
||||
if (!stderr_file_spec)
|
||||
stderr_file_spec = secondary_name;
|
||||
}
|
||||
LLDB_LOGF(
|
||||
log,
|
||||
"ProcessGDBRemote::%s adjusted STDIO paths for local platform "
|
||||
"(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
|
||||
"stderr=%s",
|
||||
__FUNCTION__,
|
||||
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
|
||||
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
|
||||
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
|
||||
stderr_file_spec = secondary_name;
|
||||
}
|
||||
LLDB_LOGF(
|
||||
log,
|
||||
"ProcessGDBRemote::%s adjusted STDIO paths for local platform "
|
||||
"(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
|
||||
"stderr=%s",
|
||||
__FUNCTION__,
|
||||
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
|
||||
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
|
||||
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
|
||||
}
|
||||
|
||||
LLDB_LOGF(log,
|
||||
"ProcessGDBRemote::%s final STDIO paths after all "
|
||||
"adjustments: stdin=%s, stdout=%s, stderr=%s",
|
||||
__FUNCTION__,
|
||||
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
|
||||
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
|
||||
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
|
||||
LLDB_LOGF(log,
|
||||
"ProcessGDBRemote::%s final STDIO paths after all "
|
||||
"adjustments: stdin=%s, stdout=%s, stderr=%s",
|
||||
__FUNCTION__,
|
||||
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
|
||||
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
|
||||
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
|
||||
|
||||
if (stdin_file_spec)
|
||||
m_gdb_comm.SetSTDIN(stdin_file_spec);
|
||||
if (stdout_file_spec)
|
||||
m_gdb_comm.SetSTDOUT(stdout_file_spec);
|
||||
if (stderr_file_spec)
|
||||
m_gdb_comm.SetSTDERR(stderr_file_spec);
|
||||
if (stdin_file_spec)
|
||||
m_gdb_comm.SetSTDIN(stdin_file_spec);
|
||||
if (stdout_file_spec)
|
||||
m_gdb_comm.SetSTDOUT(stdout_file_spec);
|
||||
if (stderr_file_spec)
|
||||
m_gdb_comm.SetSTDERR(stderr_file_spec);
|
||||
|
||||
m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
|
||||
m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
|
||||
m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
|
||||
m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
|
||||
|
||||
m_gdb_comm.SendLaunchArchPacket(
|
||||
GetTarget().GetArchitecture().GetArchitectureName());
|
||||
m_gdb_comm.SendLaunchArchPacket(
|
||||
GetTarget().GetArchitecture().GetArchitectureName());
|
||||
|
||||
const char *launch_event_data = launch_info.GetLaunchEventData();
|
||||
if (launch_event_data != nullptr && *launch_event_data != '\0')
|
||||
m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
|
||||
const char *launch_event_data = launch_info.GetLaunchEventData();
|
||||
if (launch_event_data != nullptr && *launch_event_data != '\0')
|
||||
m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
|
||||
|
||||
if (working_dir) {
|
||||
m_gdb_comm.SetWorkingDir(working_dir);
|
||||
}
|
||||
if (working_dir) {
|
||||
m_gdb_comm.SetWorkingDir(working_dir);
|
||||
}
|
||||
|
||||
// Send the environment and the program + arguments after we connect
|
||||
m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
|
||||
// Send the environment and the program + arguments after we connect
|
||||
m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
|
||||
|
||||
{
|
||||
// Scope for the scoped timeout object
|
||||
GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
|
||||
std::chrono::seconds(10));
|
||||
{
|
||||
// Scope for the scoped timeout object
|
||||
GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
|
||||
std::chrono::seconds(10));
|
||||
|
||||
int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
|
||||
if (arg_packet_err == 0) {
|
||||
std::string error_str;
|
||||
if (m_gdb_comm.GetLaunchSuccess(error_str)) {
|
||||
SetID(m_gdb_comm.GetCurrentProcessID());
|
||||
} else {
|
||||
error.SetErrorString(error_str.c_str());
|
||||
}
|
||||
int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
|
||||
if (arg_packet_err == 0) {
|
||||
std::string error_str;
|
||||
if (m_gdb_comm.GetLaunchSuccess(error_str)) {
|
||||
SetID(m_gdb_comm.GetCurrentProcessID());
|
||||
} else {
|
||||
error.SetErrorStringWithFormat("'A' packet returned an error: %i",
|
||||
arg_packet_err);
|
||||
error.SetErrorString(error_str.c_str());
|
||||
}
|
||||
} else {
|
||||
error.SetErrorStringWithFormat("'A' packet returned an error: %i",
|
||||
arg_packet_err);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetID() == LLDB_INVALID_PROCESS_ID) {
|
||||
LLDB_LOGF(log, "failed to connect to debugserver: %s",
|
||||
error.AsCString());
|
||||
KillDebugserverProcess();
|
||||
return error;
|
||||
}
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.GetStopReply(response)) {
|
||||
SetLastStopPacket(response);
|
||||
|
||||
const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
|
||||
|
||||
if (process_arch.IsValid()) {
|
||||
GetTarget().MergeArchitecture(process_arch);
|
||||
} else {
|
||||
const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
|
||||
if (host_arch.IsValid())
|
||||
GetTarget().MergeArchitecture(host_arch);
|
||||
}
|
||||
|
||||
if (GetID() == LLDB_INVALID_PROCESS_ID) {
|
||||
LLDB_LOGF(log, "failed to connect to debugserver: %s",
|
||||
error.AsCString());
|
||||
KillDebugserverProcess();
|
||||
return error;
|
||||
SetPrivateState(SetThreadStopInfo(response));
|
||||
|
||||
if (!disable_stdio) {
|
||||
if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
|
||||
SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
|
||||
}
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.GetStopReply(response)) {
|
||||
SetLastStopPacket(response);
|
||||
|
||||
const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
|
||||
|
||||
if (process_arch.IsValid()) {
|
||||
GetTarget().MergeArchitecture(process_arch);
|
||||
} else {
|
||||
const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
|
||||
if (host_arch.IsValid())
|
||||
GetTarget().MergeArchitecture(host_arch);
|
||||
}
|
||||
|
||||
SetPrivateState(SetThreadStopInfo(response));
|
||||
|
||||
if (!disable_stdio) {
|
||||
if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
|
||||
SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
|
||||
}
|
||||
} else {
|
||||
// Set our user ID to an invalid process ID.
|
||||
SetID(LLDB_INVALID_PROCESS_ID);
|
||||
error.SetErrorStringWithFormat(
|
||||
"failed to get object file from '%s' for arch %s",
|
||||
exe_module->GetFileSpec().GetFilename().AsCString(),
|
||||
exe_module->GetArchitecture().GetArchitectureName());
|
||||
LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
@ -2493,118 +2493,125 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) {
|
||||
m_process_input_reader.reset();
|
||||
|
||||
Module *exe_module = GetTarget().GetExecutableModulePointer();
|
||||
if (!exe_module) {
|
||||
error.SetErrorString("executable module does not exist");
|
||||
return error;
|
||||
}
|
||||
|
||||
char local_exec_file_path[PATH_MAX];
|
||||
char platform_exec_file_path[PATH_MAX];
|
||||
exe_module->GetFileSpec().GetPath(local_exec_file_path,
|
||||
sizeof(local_exec_file_path));
|
||||
exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path,
|
||||
sizeof(platform_exec_file_path));
|
||||
if (FileSystem::Instance().Exists(exe_module->GetFileSpec())) {
|
||||
// The "remote executable path" is hooked up to the local Executable
|
||||
// module. But we should be able to debug a remote process even if the
|
||||
// executable module only exists on the remote. However, there needs to
|
||||
// be a way to express this path, without actually having a module.
|
||||
// The way to do that is to set the ExecutableFile in the LaunchInfo.
|
||||
// Figure that out here:
|
||||
|
||||
FileSpec exe_spec_to_use;
|
||||
if (!exe_module) {
|
||||
if (!launch_info.GetExecutableFile()) {
|
||||
error.SetErrorString("executable module does not exist");
|
||||
return error;
|
||||
}
|
||||
exe_spec_to_use = launch_info.GetExecutableFile();
|
||||
} else
|
||||
exe_spec_to_use = exe_module->GetFileSpec();
|
||||
|
||||
if (exe_module && FileSystem::Instance().Exists(exe_module->GetFileSpec())) {
|
||||
// Install anything that might need to be installed prior to launching.
|
||||
// For host systems, this will do nothing, but if we are connected to a
|
||||
// remote platform it will install any needed binaries
|
||||
error = GetTarget().Install(&launch_info);
|
||||
if (error.Fail())
|
||||
return error;
|
||||
}
|
||||
// Listen and queue events that are broadcasted during the process launch.
|
||||
ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack"));
|
||||
HijackProcessEvents(listener_sp);
|
||||
auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); });
|
||||
|
||||
// Listen and queue events that are broadcasted during the process launch.
|
||||
ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack"));
|
||||
HijackProcessEvents(listener_sp);
|
||||
auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); });
|
||||
if (PrivateStateThreadIsValid())
|
||||
PausePrivateStateThread();
|
||||
|
||||
if (PrivateStateThreadIsValid())
|
||||
PausePrivateStateThread();
|
||||
error = WillLaunch(exe_module);
|
||||
if (error.Success()) {
|
||||
const bool restarted = false;
|
||||
SetPublicState(eStateLaunching, restarted);
|
||||
m_should_detach = false;
|
||||
|
||||
error = WillLaunch(exe_module);
|
||||
if (error.Success()) {
|
||||
const bool restarted = false;
|
||||
SetPublicState(eStateLaunching, restarted);
|
||||
m_should_detach = false;
|
||||
if (m_public_run_lock.TrySetRunning()) {
|
||||
// Now launch using these arguments.
|
||||
error = DoLaunch(exe_module, launch_info);
|
||||
} else {
|
||||
// This shouldn't happen
|
||||
error.SetErrorString("failed to acquire process run lock");
|
||||
}
|
||||
|
||||
if (m_public_run_lock.TrySetRunning()) {
|
||||
// Now launch using these arguments.
|
||||
error = DoLaunch(exe_module, launch_info);
|
||||
} else {
|
||||
// This shouldn't happen
|
||||
error.SetErrorString("failed to acquire process run lock");
|
||||
if (error.Fail()) {
|
||||
if (GetID() != LLDB_INVALID_PROCESS_ID) {
|
||||
SetID(LLDB_INVALID_PROCESS_ID);
|
||||
const char *error_string = error.AsCString();
|
||||
if (error_string == nullptr)
|
||||
error_string = "launch failed";
|
||||
SetExitStatus(-1, error_string);
|
||||
}
|
||||
} else {
|
||||
EventSP event_sp;
|
||||
|
||||
if (error.Fail()) {
|
||||
if (GetID() != LLDB_INVALID_PROCESS_ID) {
|
||||
SetID(LLDB_INVALID_PROCESS_ID);
|
||||
const char *error_string = error.AsCString();
|
||||
if (error_string == nullptr)
|
||||
error_string = "launch failed";
|
||||
SetExitStatus(-1, error_string);
|
||||
}
|
||||
} else {
|
||||
EventSP event_sp;
|
||||
// Now wait for the process to launch and return control to us, and then
|
||||
// call DidLaunch:
|
||||
StateType state = WaitForProcessStopPrivate(event_sp, seconds(10));
|
||||
|
||||
// Now wait for the process to launch and return control to us, and then
|
||||
// call DidLaunch:
|
||||
StateType state = WaitForProcessStopPrivate(event_sp, seconds(10));
|
||||
if (state == eStateInvalid || !event_sp) {
|
||||
// We were able to launch the process, but we failed to catch the
|
||||
// initial stop.
|
||||
error.SetErrorString("failed to catch stop after launch");
|
||||
SetExitStatus(0, "failed to catch stop after launch");
|
||||
Destroy(false);
|
||||
} else if (state == eStateStopped || state == eStateCrashed) {
|
||||
DidLaunch();
|
||||
|
||||
if (state == eStateInvalid || !event_sp) {
|
||||
// We were able to launch the process, but we failed to catch the
|
||||
// initial stop.
|
||||
error.SetErrorString("failed to catch stop after launch");
|
||||
SetExitStatus(0, "failed to catch stop after launch");
|
||||
Destroy(false);
|
||||
} else if (state == eStateStopped || state == eStateCrashed) {
|
||||
DidLaunch();
|
||||
DynamicLoader *dyld = GetDynamicLoader();
|
||||
if (dyld)
|
||||
dyld->DidLaunch();
|
||||
|
||||
DynamicLoader *dyld = GetDynamicLoader();
|
||||
if (dyld)
|
||||
dyld->DidLaunch();
|
||||
GetJITLoaders().DidLaunch();
|
||||
|
||||
GetJITLoaders().DidLaunch();
|
||||
SystemRuntime *system_runtime = GetSystemRuntime();
|
||||
if (system_runtime)
|
||||
system_runtime->DidLaunch();
|
||||
|
||||
SystemRuntime *system_runtime = GetSystemRuntime();
|
||||
if (system_runtime)
|
||||
system_runtime->DidLaunch();
|
||||
if (!m_os_up)
|
||||
LoadOperatingSystemPlugin(false);
|
||||
|
||||
if (!m_os_up)
|
||||
LoadOperatingSystemPlugin(false);
|
||||
// We successfully launched the process and stopped, now it the
|
||||
// right time to set up signal filters before resuming.
|
||||
UpdateAutomaticSignalFiltering();
|
||||
|
||||
// We successfully launched the process and stopped, now it the
|
||||
// right time to set up signal filters before resuming.
|
||||
UpdateAutomaticSignalFiltering();
|
||||
// Note, the stop event was consumed above, but not handled. This
|
||||
// was done to give DidLaunch a chance to run. The target is either
|
||||
// stopped or crashed. Directly set the state. This is done to
|
||||
// prevent a stop message with a bunch of spurious output on thread
|
||||
// status, as well as not pop a ProcessIOHandler.
|
||||
// We are done with the launch hijack listener, and this stop should
|
||||
// go to the public state listener:
|
||||
RestoreProcessEvents();
|
||||
SetPublicState(state, false);
|
||||
|
||||
// Note, the stop event was consumed above, but not handled. This
|
||||
// was done to give DidLaunch a chance to run. The target is either
|
||||
// stopped or crashed. Directly set the state. This is done to
|
||||
// prevent a stop message with a bunch of spurious output on thread
|
||||
// status, as well as not pop a ProcessIOHandler.
|
||||
// We are done with the launch hijack listener, and this stop should
|
||||
// go to the public state listener:
|
||||
RestoreProcessEvents();
|
||||
SetPublicState(state, false);
|
||||
if (PrivateStateThreadIsValid())
|
||||
ResumePrivateStateThread();
|
||||
else
|
||||
StartPrivateStateThread();
|
||||
|
||||
if (PrivateStateThreadIsValid())
|
||||
ResumePrivateStateThread();
|
||||
else
|
||||
StartPrivateStateThread();
|
||||
|
||||
// Target was stopped at entry as was intended. Need to notify the
|
||||
// listeners about it.
|
||||
if (state == eStateStopped &&
|
||||
launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
|
||||
HandlePrivateEvent(event_sp);
|
||||
} else if (state == eStateExited) {
|
||||
// We exited while trying to launch somehow. Don't call DidLaunch
|
||||
// as that's not likely to work, and return an invalid pid.
|
||||
// Target was stopped at entry as was intended. Need to notify the
|
||||
// listeners about it.
|
||||
if (state == eStateStopped &&
|
||||
launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
|
||||
HandlePrivateEvent(event_sp);
|
||||
}
|
||||
} else if (state == eStateExited) {
|
||||
// We exited while trying to launch somehow. Don't call DidLaunch
|
||||
// as that's not likely to work, and return an invalid pid.
|
||||
HandlePrivateEvent(event_sp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::string local_exec_file_path = exe_spec_to_use.GetPath();
|
||||
error.SetErrorStringWithFormat("file doesn't exist: '%s'",
|
||||
local_exec_file_path);
|
||||
local_exec_file_path.c_str());
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -0,0 +1,91 @@
|
||||
import lldb
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.gdbclientutils import *
|
||||
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
|
||||
|
||||
class TestNoLocalFile(GDBRemoteTestBase):
|
||||
""" Test the case where there is NO local copy of the file
|
||||
being debugged. We shouldn't immediately error out, but
|
||||
rather lldb should ask debugserver if it knows about the file. """
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@skipIfXmlSupportMissing
|
||||
def test(self):
|
||||
self.absent_file = '/nosuch_dir/nosuch_subdir/nosuch_executable'
|
||||
self.a_packet_file = None
|
||||
class MyResponder(MockGDBServerResponder):
|
||||
def __init__(self, testcase):
|
||||
MockGDBServerResponder.__init__(self)
|
||||
self.after_launch = False
|
||||
self.testcase = testcase
|
||||
self.current_thread = 0
|
||||
|
||||
def A(self, packet):
|
||||
# This is the main test, we want to see that lldb DID send the
|
||||
# A packet to get debugserver to load the file.
|
||||
# Skip the length and second length:
|
||||
print("Got A packet: {0}".format(packet))
|
||||
a_arr = packet.split(",")
|
||||
self.testcase.a_packet_file = bytearray.fromhex(a_arr[2]).decode()
|
||||
return "OK"
|
||||
|
||||
def qXferRead(self, obj, annex, offset, length):
|
||||
if annex == "target.xml":
|
||||
return """<?xml version="1.0"?>
|
||||
<target version="1.0">
|
||||
<architecture>i386:x86-64</architecture>
|
||||
<feature name="org.gnu.gdb.i386.core">
|
||||
<reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/>
|
||||
</feature>
|
||||
</target>""", False
|
||||
else:
|
||||
return None, False
|
||||
|
||||
def qC(self):
|
||||
if not self.after_launch:
|
||||
return "QC0"
|
||||
return "0"
|
||||
|
||||
def qfThreadInfo(self):
|
||||
if not self.after_launch:
|
||||
return "OK"
|
||||
return "m0"
|
||||
|
||||
def qsThreadInfo(self):
|
||||
if not self.after_launch:
|
||||
return "OK"
|
||||
return "l"
|
||||
|
||||
def qLaunchSuccess(self):
|
||||
return "OK"
|
||||
|
||||
def qProcessInfo(self):
|
||||
return "$pid:10b70;parent-pid:10b20;real-uid:1f6;real-gid:14;effective-uid:1f6;effective-gid:14;cputype:1000007;cpusubtype:8;ptrsize:8;ostype:macosx;vendor:apple;endian:little;"
|
||||
|
||||
|
||||
error = lldb.SBError()
|
||||
self.server.responder = MyResponder(self)
|
||||
target = self.dbg.CreateTarget(None, "x86_64-apple-macosx", "remote-macosx", False, error)
|
||||
self.assertSuccess(error, "Made a valid target")
|
||||
launch_info = target.GetLaunchInfo()
|
||||
launch_info.SetExecutableFile(lldb.SBFileSpec(self.absent_file), True)
|
||||
flags = launch_info.GetLaunchFlags()
|
||||
flags |= lldb.eLaunchFlagStopAtEntry
|
||||
launch_info.SetLaunchFlags(flags)
|
||||
|
||||
process = self.connect(target)
|
||||
self.assertTrue(process.IsValid(), "Process is valid")
|
||||
|
||||
# We need to fetch the connected event:
|
||||
lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected])
|
||||
|
||||
self.server.responder.after_launch = True
|
||||
|
||||
process = target.Launch(launch_info, error)
|
||||
|
||||
self.assertSuccess(error, "Successfully launched.")
|
||||
self.assertEqual(process.GetState(), lldb.eStateStopped, "Should be stopped at entry")
|
||||
self.assertIsNotNone(self.a_packet_file, "A packet was sent")
|
||||
self.assertEqual(self.absent_file, self.a_packet_file, "The A packet file was correct")
|
Loading…
x
Reference in New Issue
Block a user