[lldb] [Platform] Move common ::DebugProcess() to PlatformPOSIX

Move common ::DebugProcess() implementation shared by Linux and NetBSD
(and to be shared by FreeBSD shortly) into PlatformPOSIX, and move
the old base implementation used only by Darwin to PlatformDarwin.

Differential Revision: https://reviews.llvm.org/D88852
This commit is contained in:
Michał Górny 2020-10-05 23:07:00 +02:00
parent 21100f885d
commit a825eaa90e
7 changed files with 134 additions and 248 deletions

View File

@ -262,121 +262,6 @@ bool PlatformLinux::CanDebugProcess() {
}
}
// For local debugging, Linux will override the debug logic to use llgs-launch
// rather than lldb-launch, llgs-attach. This differs from current lldb-
// launch, debugserver-attach approach on MacOSX.
lldb::ProcessSP
PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new
// target, else use existing one
Status &error) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
LLDB_LOG(log, "target {0}", target);
// If we're a remote host, use standard behavior from parent class.
if (!IsHost())
return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error);
//
// For local debugging, we'll insist on having ProcessGDBRemote create the
// process.
//
ProcessSP process_sp;
// Make sure we stop at the entry point
launch_info.GetFlags().Set(eLaunchFlagDebug);
// We always launch the process we are going to debug in a separate process
// group, since then we can handle ^C interrupts ourselves w/o having to
// worry about the target getting them as well.
launch_info.SetLaunchInSeparateProcessGroup(true);
// Ensure we have a target.
if (target == nullptr) {
LLDB_LOG(log, "creating new target");
TargetSP new_target_sp;
error = debugger.GetTargetList().CreateTarget(
debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
if (error.Fail()) {
LLDB_LOG(log, "failed to create new target: {0}", error);
return process_sp;
}
target = new_target_sp.get();
if (!target) {
error.SetErrorString("CreateTarget() returned nullptr");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
}
// Mark target as currently selected target.
debugger.GetTargetList().SetSelectedTarget(target);
// Now create the gdb-remote process.
LLDB_LOG(log, "having target create process with gdb-remote plugin");
process_sp =
target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr);
if (!process_sp) {
error.SetErrorString("CreateProcess() failed for gdb-remote process");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
LLDB_LOG(log, "successfully created process");
// Adjust launch for a hijacker.
ListenerSP listener_sp;
if (!launch_info.GetHijackListener()) {
LLDB_LOG(log, "setting up hijacker");
listener_sp =
Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack");
launch_info.SetHijackListener(listener_sp);
process_sp->HijackProcessEvents(listener_sp);
}
// Log file actions.
if (log) {
LLDB_LOG(log, "launching process with the following file actions:");
StreamString stream;
size_t i = 0;
const FileAction *file_action;
while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
file_action->Dump(stream);
LLDB_LOG(log, "{0}", stream.GetData());
stream.Clear();
}
}
// Do the launch.
error = process_sp->Launch(launch_info);
if (error.Success()) {
// Handle the hijacking of process events.
if (listener_sp) {
const StateType state = process_sp->WaitForProcessToStop(
llvm::None, nullptr, false, listener_sp);
LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state);
}
// Hook up process PTY if we have one (which we should for local debugging
// with llgs).
int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
if (pty_fd != PseudoTerminal::invalid_fd) {
process_sp->SetSTDIOFileDescriptor(pty_fd);
LLDB_LOG(log, "hooked up STDIO pty to process");
} else
LLDB_LOG(log, "not using process STDIO pty");
} else {
LLDB_LOG(log, "{0}", error);
// FIXME figure out appropriate cleanup here. Do we delete the target? Do
// we delete the process? Does our caller do that?
}
return process_sp;
}
void PlatformLinux::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));

View File

@ -48,10 +48,6 @@ public:
bool CanDebugProcess() override;
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
Debugger &debugger, Target *target,
Status &error) override;
void CalculateTrapHandlerSymbolNames() override;
MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,

View File

@ -1226,6 +1226,33 @@ PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
return 1;
}
lldb::ProcessSP
PlatformDarwin::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create
// a new target, else use existing
// one
Status &error) {
ProcessSP process_sp;
if (IsHost()) {
// We are going to hand this process off to debugserver which will be in
// charge of setting the exit status. However, we still need to reap it
// from lldb. So, make sure we use a exit callback which does not set exit
// status.
const bool monitor_signals = false;
launch_info.SetMonitorProcessCallback(
&ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals);
process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
} else {
if (m_remote_platform_sp)
process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
target, error);
else
error.SetErrorString("the platform is not currently connected");
}
return process_sp;
}
void PlatformDarwin::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
}

View File

@ -11,6 +11,7 @@
#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/ProcessLaunchInfo.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/StructuredData.h"
@ -68,6 +69,11 @@ public:
int32_t GetResumeCountForLaunchInfo(
lldb_private::ProcessLaunchInfo &launch_info) override;
lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Debugger &debugger,
lldb_private::Target *target,
lldb_private::Status &error) override;
void CalculateTrapHandlerSymbolNames() override;
llvm::VersionTuple

View File

@ -231,121 +231,6 @@ bool PlatformNetBSD::CanDebugProcess() {
}
}
// For local debugging, NetBSD will override the debug logic to use llgs-launch
// rather than lldb-launch, llgs-attach. This differs from current lldb-
// launch, debugserver-attach approach on MacOSX.
lldb::ProcessSP
PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new
// target, else use existing one
Status &error) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
LLDB_LOG(log, "target {0}", target);
// If we're a remote host, use standard behavior from parent class.
if (!IsHost())
return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error);
//
// For local debugging, we'll insist on having ProcessGDBRemote create the
// process.
//
ProcessSP process_sp;
// Make sure we stop at the entry point
launch_info.GetFlags().Set(eLaunchFlagDebug);
// We always launch the process we are going to debug in a separate process
// group, since then we can handle ^C interrupts ourselves w/o having to
// worry about the target getting them as well.
launch_info.SetLaunchInSeparateProcessGroup(true);
// Ensure we have a target.
if (target == nullptr) {
LLDB_LOG(log, "creating new target");
TargetSP new_target_sp;
error = debugger.GetTargetList().CreateTarget(
debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
if (error.Fail()) {
LLDB_LOG(log, "failed to create new target: {0}", error);
return process_sp;
}
target = new_target_sp.get();
if (!target) {
error.SetErrorString("CreateTarget() returned nullptr");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
}
// Mark target as currently selected target.
debugger.GetTargetList().SetSelectedTarget(target);
// Now create the gdb-remote process.
LLDB_LOG(log, "having target create process with gdb-remote plugin");
process_sp =
target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr);
if (!process_sp) {
error.SetErrorString("CreateProcess() failed for gdb-remote process");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
LLDB_LOG(log, "successfully created process");
// Adjust launch for a hijacker.
ListenerSP listener_sp;
if (!launch_info.GetHijackListener()) {
LLDB_LOG(log, "setting up hijacker");
listener_sp =
Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack");
launch_info.SetHijackListener(listener_sp);
process_sp->HijackProcessEvents(listener_sp);
}
// Log file actions.
if (log) {
LLDB_LOG(log, "launching process with the following file actions:");
StreamString stream;
size_t i = 0;
const FileAction *file_action;
while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
file_action->Dump(stream);
LLDB_LOG(log, "{0}", stream.GetData());
stream.Clear();
}
}
// Do the launch.
error = process_sp->Launch(launch_info);
if (error.Success()) {
// Handle the hijacking of process events.
if (listener_sp) {
const StateType state = process_sp->WaitForProcessToStop(
llvm::None, nullptr, false, listener_sp);
LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state);
}
// Hook up process PTY if we have one (which we should for local debugging
// with llgs).
int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
if (pty_fd != PseudoTerminal::invalid_fd) {
process_sp->SetSTDIOFileDescriptor(pty_fd);
LLDB_LOG(log, "hooked up STDIO pty to process");
} else
LLDB_LOG(log, "not using process STDIO pty");
} else {
LLDB_LOG(log, "{0}", error);
// FIXME figure out appropriate cleanup here. Do we delete the target? Do
// we delete the process? Does our caller do that?
}
return process_sp;
}
void PlatformNetBSD::CalculateTrapHandlerSymbolNames() {
m_trap_handlers.push_back(ConstString("_sigtramp"));
}

View File

@ -48,10 +48,6 @@ public:
bool CanDebugProcess() override;
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
Debugger &debugger, Target *target,
Status &error) override;
void CalculateTrapHandlerSymbolNames() override;
MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,

View File

@ -416,24 +416,115 @@ PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new
// target, else use existing one
Status &error) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
LLDB_LOG(log, "target {0}", target);
ProcessSP process_sp;
if (IsHost()) {
// We are going to hand this process off to debugserver which will be in
// charge of setting the exit status. However, we still need to reap it
// from lldb. So, make sure we use a exit callback which does not set exit
// status.
const bool monitor_signals = false;
launch_info.SetMonitorProcessCallback(
&ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals);
process_sp = Platform::DebugProcess(launch_info, debugger, target, error);
} else {
if (!IsHost()) {
if (m_remote_platform_sp)
process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger,
target, error);
else
error.SetErrorString("the platform is not currently connected");
return process_sp;
}
//
// For local debugging, we'll insist on having ProcessGDBRemote create the
// process.
//
// Make sure we stop at the entry point
launch_info.GetFlags().Set(eLaunchFlagDebug);
// We always launch the process we are going to debug in a separate process
// group, since then we can handle ^C interrupts ourselves w/o having to
// worry about the target getting them as well.
launch_info.SetLaunchInSeparateProcessGroup(true);
// Ensure we have a target.
if (target == nullptr) {
LLDB_LOG(log, "creating new target");
TargetSP new_target_sp;
error = debugger.GetTargetList().CreateTarget(
debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
if (error.Fail()) {
LLDB_LOG(log, "failed to create new target: {0}", error);
return process_sp;
}
target = new_target_sp.get();
if (!target) {
error.SetErrorString("CreateTarget() returned nullptr");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
}
// Mark target as currently selected target.
debugger.GetTargetList().SetSelectedTarget(target);
// Now create the gdb-remote process.
LLDB_LOG(log, "having target create process with gdb-remote plugin");
process_sp =
target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr);
if (!process_sp) {
error.SetErrorString("CreateProcess() failed for gdb-remote process");
LLDB_LOG(log, "error: {0}", error);
return process_sp;
}
LLDB_LOG(log, "successfully created process");
// Adjust launch for a hijacker.
ListenerSP listener_sp;
if (!launch_info.GetHijackListener()) {
LLDB_LOG(log, "setting up hijacker");
listener_sp =
Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack");
launch_info.SetHijackListener(listener_sp);
process_sp->HijackProcessEvents(listener_sp);
}
// Log file actions.
if (log) {
LLDB_LOG(log, "launching process with the following file actions:");
StreamString stream;
size_t i = 0;
const FileAction *file_action;
while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
file_action->Dump(stream);
LLDB_LOG(log, "{0}", stream.GetData());
stream.Clear();
}
}
// Do the launch.
error = process_sp->Launch(launch_info);
if (error.Success()) {
// Handle the hijacking of process events.
if (listener_sp) {
const StateType state = process_sp->WaitForProcessToStop(
llvm::None, nullptr, false, listener_sp);
LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state);
}
// Hook up process PTY if we have one (which we should for local debugging
// with llgs).
int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
if (pty_fd != PseudoTerminal::invalid_fd) {
process_sp->SetSTDIOFileDescriptor(pty_fd);
LLDB_LOG(log, "hooked up STDIO pty to process");
} else
LLDB_LOG(log, "not using process STDIO pty");
} else {
LLDB_LOG(log, "{0}", error);
// FIXME figure out appropriate cleanup here. Do we delete the target? Do
// we delete the process? Does our caller do that?
}
return process_sp;
}