[Lldb-commits] [lldb] 92eaad2 - Revert "Revert "Make it possible for lldb to launch a remote binary with no local file.""
Jim Ingham via lldb-commits
lldb-commits at lists.llvm.org
Wed Nov 17 18:00:32 PST 2021
Author: Jim Ingham
Date: 2021-11-17T17:59:47-08:00
New Revision: 92eaad2dd7adb5ee92f397cef85ab11f2612294e
URL: https://github.com/llvm/llvm-project/commit/92eaad2dd7adb5ee92f397cef85ab11f2612294e
DIFF: https://github.com/llvm/llvm-project/commit/92eaad2dd7adb5ee92f397cef85ab11f2612294e.diff
LOG: 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.
Added:
lldb/test/API/functionalities/gdb_remote_client/TestNoLocalFile.py
Modified:
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Target/Process.cpp
Removed:
################################################################################
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 8ce14f2a96d5e..5fd1718e84840 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -159,7 +159,12 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
// 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 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
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 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
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 {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index a666aeb8bb3f6..2233bf6758190 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -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;
-
- 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());
-
- 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>");
- }
+ error = EstablishConnectionIfNeeded(launch_info);
+ if (error.Success()) {
+ PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
- 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);
-
- m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
- m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
+ 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());
- m_gdb_comm.SendLaunchArchPacket(
- GetTarget().GetArchitecture().GetArchitectureName());
+ if (!stdin_file_spec)
+ stdin_file_spec = secondary_name;
- 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 (!stdout_file_spec)
+ stdout_file_spec = secondary_name;
- if (working_dir) {
- m_gdb_comm.SetWorkingDir(working_dir);
+ 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>");
+ }
- // Send the environment and the program + arguments after we connect
- m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
+ 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);
+
+ m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
+ m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
+
+ 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);
+
+ if (working_dir) {
+ m_gdb_comm.SetWorkingDir(working_dir);
+ }
- {
- // Scope for the scoped timeout object
- GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
- std::chrono::seconds(10));
+ // Send the environment and the program + arguments after we connect
+ m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
- 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());
- }
+ {
+ // 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.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;
- }
+ 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);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response)) {
+ SetLastStopPacket(response);
- const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
+ 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 (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));
+ SetPrivateState(SetThreadStopInfo(response));
- if (!disable_stdio) {
- if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
- SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
- }
+ 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;
}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 519db0482e4ba..3fbd6434e8683 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -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));
-
- 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();
-
- GetJITLoaders().DidLaunch();
-
- SystemRuntime *system_runtime = GetSystemRuntime();
- if (system_runtime)
- system_runtime->DidLaunch();
-
- 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();
-
- // 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();
+ // 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();
+
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld)
+ dyld->DidLaunch();
+
+ GetJITLoaders().DidLaunch();
+
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime)
+ system_runtime->DidLaunch();
+
+ 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();
+
+ // 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();
- // 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;
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestNoLocalFile.py b/lldb/test/API/functionalities/gdb_remote_client/TestNoLocalFile.py
new file mode 100644
index 0000000000000..8cc10133783f0
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestNoLocalFile.py
@@ -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")
More information about the lldb-commits
mailing list