Skip to content

Commit b715b79

Browse files
committed
Make it possible for lldb to launch a remote binary with no local file.
We don't actually need a local copy of the main executable to debug a remote process. So instead of treating "no local module" as an error, see if the LaunchInfo has an executable it wants lldb to use, and if so use it. Then report whatever error the remote server returns. Differential Revision: https://reviews.llvm.org/D113521
1 parent a0dc600 commit b715b79

File tree

4 files changed

+325
-220
lines changed

4 files changed

+325
-220
lines changed

lldb/source/Commands/CommandObjectProcess.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
159159
// If our listener is nullptr, users aren't allows to launch
160160
ModuleSP exe_module_sp = target->GetExecutableModule();
161161

162-
if (exe_module_sp == nullptr) {
162+
// If the target already has an executable module, then use that. If it
163+
// doesn't then someone must be trying to launch using a path that will
164+
// make sense to the remote stub, but doesn't exist on the local host.
165+
// In that case use the ExecutableFile that was set in the target's
166+
// ProcessLaunchInfo.
167+
if (exe_module_sp == nullptr && !target->GetProcessLaunchInfo().GetExecutableFile()) {
163168
result.AppendError("no file in target, create a debug target using the "
164169
"'target create' command");
165170
return false;
@@ -219,11 +224,17 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
219224
if (!target_settings_argv0.empty()) {
220225
m_options.launch_info.GetArguments().AppendArgument(
221226
target_settings_argv0);
222-
m_options.launch_info.SetExecutableFile(
223-
exe_module_sp->GetPlatformFileSpec(), false);
227+
if (exe_module_sp)
228+
m_options.launch_info.SetExecutableFile(
229+
exe_module_sp->GetPlatformFileSpec(), false);
230+
else
231+
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), false);
224232
} else {
225-
m_options.launch_info.SetExecutableFile(
226-
exe_module_sp->GetPlatformFileSpec(), true);
233+
if (exe_module_sp)
234+
m_options.launch_info.SetExecutableFile(
235+
exe_module_sp->GetPlatformFileSpec(), true);
236+
else
237+
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), true);
227238
}
228239

229240
if (launch_args.GetArgumentCount() == 0) {
@@ -250,11 +261,20 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
250261
llvm::StringRef data = stream.GetString();
251262
if (!data.empty())
252263
result.AppendMessage(data);
253-
const char *archname =
254-
exe_module_sp->GetArchitecture().GetArchitectureName();
255-
result.AppendMessageWithFormat(
256-
"Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
257-
exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
264+
// If we didn't have a local executable, then we wouldn't have had an
265+
// executable module before launch.
266+
if (!exe_module_sp)
267+
exe_module_sp = target->GetExecutableModule();
268+
if (!exe_module_sp) {
269+
result.AppendWarning("Could not get executable module after launch.");
270+
} else {
271+
272+
const char *archname =
273+
exe_module_sp->GetArchitecture().GetArchitectureName();
274+
result.AppendMessageWithFormat(
275+
"Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
276+
exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
277+
}
258278
result.SetStatus(eReturnStatusSuccessFinishResult);
259279
result.SetDidChangeProcessState(true);
260280
} else {

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 107 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -677,143 +677,133 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
677677
// LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
678678
// ::LogSetLogFile ("/dev/stdout");
679679

680-
ObjectFile *object_file = exe_module->GetObjectFile();
681-
if (object_file) {
682-
error = EstablishConnectionIfNeeded(launch_info);
683-
if (error.Success()) {
684-
PseudoTerminal pty;
685-
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
686-
687-
PlatformSP platform_sp(GetTarget().GetPlatform());
688-
if (disable_stdio) {
689-
// set to /dev/null unless redirected to a file above
690-
if (!stdin_file_spec)
691-
stdin_file_spec.SetFile(FileSystem::DEV_NULL,
692-
FileSpec::Style::native);
693-
if (!stdout_file_spec)
694-
stdout_file_spec.SetFile(FileSystem::DEV_NULL,
695-
FileSpec::Style::native);
696-
if (!stderr_file_spec)
697-
stderr_file_spec.SetFile(FileSystem::DEV_NULL,
698-
FileSpec::Style::native);
699-
} else if (platform_sp && platform_sp->IsHost()) {
700-
// If the debugserver is local and we aren't disabling STDIO, lets use
701-
// a pseudo terminal to instead of relying on the 'O' packets for stdio
702-
// since 'O' packets can really slow down debugging if the inferior
703-
// does a lot of output.
704-
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
705-
!errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
706-
FileSpec secondary_name(pty.GetSecondaryName());
707-
708-
if (!stdin_file_spec)
709-
stdin_file_spec = secondary_name;
710-
711-
if (!stdout_file_spec)
712-
stdout_file_spec = secondary_name;
713-
714-
if (!stderr_file_spec)
715-
stderr_file_spec = secondary_name;
716-
}
717-
LLDB_LOGF(
718-
log,
719-
"ProcessGDBRemote::%s adjusted STDIO paths for local platform "
720-
"(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
721-
"stderr=%s",
722-
__FUNCTION__,
723-
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
724-
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
725-
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
726-
}
680+
error = EstablishConnectionIfNeeded(launch_info);
681+
if (error.Success()) {
682+
PseudoTerminal pty;
683+
const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
727684

728-
LLDB_LOGF(log,
729-
"ProcessGDBRemote::%s final STDIO paths after all "
730-
"adjustments: stdin=%s, stdout=%s, stderr=%s",
731-
__FUNCTION__,
732-
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
733-
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
734-
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
735-
736-
if (stdin_file_spec)
737-
m_gdb_comm.SetSTDIN(stdin_file_spec);
738-
if (stdout_file_spec)
739-
m_gdb_comm.SetSTDOUT(stdout_file_spec);
740-
if (stderr_file_spec)
741-
m_gdb_comm.SetSTDERR(stderr_file_spec);
742-
743-
m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
744-
m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
685+
PlatformSP platform_sp(GetTarget().GetPlatform());
686+
if (disable_stdio) {
687+
// set to /dev/null unless redirected to a file above
688+
if (!stdin_file_spec)
689+
stdin_file_spec.SetFile(FileSystem::DEV_NULL,
690+
FileSpec::Style::native);
691+
if (!stdout_file_spec)
692+
stdout_file_spec.SetFile(FileSystem::DEV_NULL,
693+
FileSpec::Style::native);
694+
if (!stderr_file_spec)
695+
stderr_file_spec.SetFile(FileSystem::DEV_NULL,
696+
FileSpec::Style::native);
697+
} else if (platform_sp && platform_sp->IsHost()) {
698+
// If the debugserver is local and we aren't disabling STDIO, lets use
699+
// a pseudo terminal to instead of relying on the 'O' packets for stdio
700+
// since 'O' packets can really slow down debugging if the inferior
701+
// does a lot of output.
702+
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
703+
!errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
704+
FileSpec secondary_name(pty.GetSecondaryName());
745705

746-
m_gdb_comm.SendLaunchArchPacket(
747-
GetTarget().GetArchitecture().GetArchitectureName());
706+
if (!stdin_file_spec)
707+
stdin_file_spec = secondary_name;
748708

749-
const char *launch_event_data = launch_info.GetLaunchEventData();
750-
if (launch_event_data != nullptr && *launch_event_data != '\0')
751-
m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
709+
if (!stdout_file_spec)
710+
stdout_file_spec = secondary_name;
752711

753-
if (working_dir) {
754-
m_gdb_comm.SetWorkingDir(working_dir);
712+
if (!stderr_file_spec)
713+
stderr_file_spec = secondary_name;
755714
}
715+
LLDB_LOGF(
716+
log,
717+
"ProcessGDBRemote::%s adjusted STDIO paths for local platform "
718+
"(IsHost() is true) using secondary: stdin=%s, stdout=%s, "
719+
"stderr=%s",
720+
__FUNCTION__,
721+
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
722+
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
723+
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
724+
}
756725

757-
// Send the environment and the program + arguments after we connect
758-
m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
726+
LLDB_LOGF(log,
727+
"ProcessGDBRemote::%s final STDIO paths after all "
728+
"adjustments: stdin=%s, stdout=%s, stderr=%s",
729+
__FUNCTION__,
730+
stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
731+
stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
732+
stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
733+
734+
if (stdin_file_spec)
735+
m_gdb_comm.SetSTDIN(stdin_file_spec);
736+
if (stdout_file_spec)
737+
m_gdb_comm.SetSTDOUT(stdout_file_spec);
738+
if (stderr_file_spec)
739+
m_gdb_comm.SetSTDERR(stderr_file_spec);
740+
741+
m_gdb_comm.SetDisableASLR(launch_flags & eLaunchFlagDisableASLR);
742+
m_gdb_comm.SetDetachOnError(launch_flags & eLaunchFlagDetachOnError);
743+
744+
m_gdb_comm.SendLaunchArchPacket(
745+
GetTarget().GetArchitecture().GetArchitectureName());
746+
747+
const char *launch_event_data = launch_info.GetLaunchEventData();
748+
if (launch_event_data != nullptr && *launch_event_data != '\0')
749+
m_gdb_comm.SendLaunchEventDataPacket(launch_event_data);
750+
751+
if (working_dir) {
752+
m_gdb_comm.SetWorkingDir(working_dir);
753+
}
759754

760-
{
761-
// Scope for the scoped timeout object
762-
GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
763-
std::chrono::seconds(10));
755+
// Send the environment and the program + arguments after we connect
756+
m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
764757

765-
int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
766-
if (arg_packet_err == 0) {
767-
std::string error_str;
768-
if (m_gdb_comm.GetLaunchSuccess(error_str)) {
769-
SetID(m_gdb_comm.GetCurrentProcessID());
770-
} else {
771-
error.SetErrorString(error_str.c_str());
772-
}
758+
{
759+
// Scope for the scoped timeout object
760+
GDBRemoteCommunication::ScopedTimeout timeout(m_gdb_comm,
761+
std::chrono::seconds(10));
762+
763+
int arg_packet_err = m_gdb_comm.SendArgumentsPacket(launch_info);
764+
if (arg_packet_err == 0) {
765+
std::string error_str;
766+
if (m_gdb_comm.GetLaunchSuccess(error_str)) {
767+
SetID(m_gdb_comm.GetCurrentProcessID());
773768
} else {
774-
error.SetErrorStringWithFormat("'A' packet returned an error: %i",
775-
arg_packet_err);
769+
error.SetErrorString(error_str.c_str());
776770
}
771+
} else {
772+
error.SetErrorStringWithFormat("'A' packet returned an error: %i",
773+
arg_packet_err);
777774
}
775+
}
778776

779-
if (GetID() == LLDB_INVALID_PROCESS_ID) {
780-
LLDB_LOGF(log, "failed to connect to debugserver: %s",
781-
error.AsCString());
782-
KillDebugserverProcess();
783-
return error;
784-
}
777+
if (GetID() == LLDB_INVALID_PROCESS_ID) {
778+
LLDB_LOGF(log, "failed to connect to debugserver: %s",
779+
error.AsCString());
780+
KillDebugserverProcess();
781+
return error;
782+
}
785783

786-
StringExtractorGDBRemote response;
787-
if (m_gdb_comm.GetStopReply(response)) {
788-
SetLastStopPacket(response);
784+
StringExtractorGDBRemote response;
785+
if (m_gdb_comm.GetStopReply(response)) {
786+
SetLastStopPacket(response);
789787

790-
const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
788+
const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
791789

792-
if (process_arch.IsValid()) {
793-
GetTarget().MergeArchitecture(process_arch);
794-
} else {
795-
const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
796-
if (host_arch.IsValid())
797-
GetTarget().MergeArchitecture(host_arch);
798-
}
790+
if (process_arch.IsValid()) {
791+
GetTarget().MergeArchitecture(process_arch);
792+
} else {
793+
const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
794+
if (host_arch.IsValid())
795+
GetTarget().MergeArchitecture(host_arch);
796+
}
799797

800-
SetPrivateState(SetThreadStopInfo(response));
798+
SetPrivateState(SetThreadStopInfo(response));
801799

802-
if (!disable_stdio) {
803-
if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
804-
SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
805-
}
800+
if (!disable_stdio) {
801+
if (pty.GetPrimaryFileDescriptor() != PseudoTerminal::invalid_fd)
802+
SetSTDIOFileDescriptor(pty.ReleasePrimaryFileDescriptor());
806803
}
807-
} else {
808-
LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
809804
}
810805
} else {
811-
// Set our user ID to an invalid process ID.
812-
SetID(LLDB_INVALID_PROCESS_ID);
813-
error.SetErrorStringWithFormat(
814-
"failed to get object file from '%s' for arch %s",
815-
exe_module->GetFileSpec().GetFilename().AsCString(),
816-
exe_module->GetArchitecture().GetArchitectureName());
806+
LLDB_LOGF(log, "failed to connect to debugserver: %s", error.AsCString());
817807
}
818808
return error;
819809
}

0 commit comments

Comments
 (0)