mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 21:55:39 +08:00
Add a NativeProcessProtocol Factory class
Summary: This replaces the static functions used for creating NativeProcessProtocol instances with a factory pattern, and modernizes the interface of the new class in the process -- I use llvm::Expected instead of the Status+value combo. I also move some of the common code (like the Delegate registration into the base class). The new arrangement has multiple benefits: - it removes the NativeProcess*** dependency from Process/gdb-remote (which for example means that liblldb no longer pulls in this code). - it enables unit testing of the GDBRemoteCommunicationServerLLGS class (by providing a mock Native Process). - serves as another example on how to use the llvm::Expected class (I couldn't get rid of the Initialize-type functions completely here because of the use of shared_from_this, but that's the next thing on my list here) Tests still pass on Linux and I've made sure NetBSD compiles after this. Reviewers: zturner, eugene, krytarowski Subscribers: srhines, lldb-commits, mgorny Differential Revision: https://reviews.llvm.org/D33778 llvm-svn: 307390
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <vector>
|
||||
|
||||
@@ -244,68 +245,57 @@ public:
|
||||
virtual Status GetFileLoadAddress(const llvm::StringRef &file_name,
|
||||
lldb::addr_t &load_addr) = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Launch a process for debugging. This method will create an concrete
|
||||
/// instance of NativeProcessProtocol, based on the host platform.
|
||||
/// (e.g. NativeProcessLinux on linux, etc.)
|
||||
///
|
||||
/// @param[in] launch_info
|
||||
/// Information required to launch the process.
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[in] mainloop
|
||||
/// The mainloop instance with which the process can register
|
||||
/// callbacks. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
static Status Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate, MainLoop &mainloop,
|
||||
NativeProcessProtocolSP &process_sp);
|
||||
class Factory {
|
||||
public:
|
||||
virtual ~Factory();
|
||||
//------------------------------------------------------------------
|
||||
/// Launch a process for debugging.
|
||||
///
|
||||
/// @param[in] launch_info
|
||||
/// Information required to launch the process.
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[in] mainloop
|
||||
/// The mainloop instance with which the process can register
|
||||
/// callbacks. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @return
|
||||
/// A NativeProcessProtocol shared pointer if the operation succeeded or
|
||||
/// an error object if it failed.
|
||||
//------------------------------------------------------------------
|
||||
virtual llvm::Expected<NativeProcessProtocolSP>
|
||||
Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to an existing process. This method will create an concrete
|
||||
/// instance of NativeProcessProtocol, based on the host platform.
|
||||
/// (e.g. NativeProcessLinux on linux, etc.)
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// pid of the process locatable
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[in] mainloop
|
||||
/// The mainloop instance with which the process can register
|
||||
/// callbacks. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[out] process_sp
|
||||
/// On successful return from the method, this parameter
|
||||
/// contains the shared pointer to the
|
||||
/// NativeProcessProtocol that can be used to manipulate
|
||||
/// the native process.
|
||||
///
|
||||
/// @return
|
||||
/// An error object indicating if the operation succeeded,
|
||||
/// and if not, what error occurred.
|
||||
//------------------------------------------------------------------
|
||||
static Status Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||
//------------------------------------------------------------------
|
||||
/// Attach to an existing process.
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// pid of the process locatable
|
||||
///
|
||||
/// @param[in] native_delegate
|
||||
/// The delegate that will receive messages regarding the
|
||||
/// inferior. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @param[in] mainloop
|
||||
/// The mainloop instance with which the process can register
|
||||
/// callbacks. Must outlive the NativeProcessProtocol
|
||||
/// instance.
|
||||
///
|
||||
/// @return
|
||||
/// A NativeProcessProtocol shared pointer if the operation succeeded or
|
||||
/// an error object if it failed.
|
||||
//------------------------------------------------------------------
|
||||
virtual llvm::Expected<NativeProcessProtocolSP>
|
||||
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// StartTracing API for starting a tracing instance with the
|
||||
@@ -413,10 +403,10 @@ protected:
|
||||
lldb::pid_t m_pid;
|
||||
|
||||
std::vector<NativeThreadProtocolSP> m_threads;
|
||||
lldb::tid_t m_current_thread_id;
|
||||
lldb::tid_t m_current_thread_id = LLDB_INVALID_THREAD_ID;
|
||||
mutable std::recursive_mutex m_threads_mutex;
|
||||
|
||||
lldb::StateType m_state;
|
||||
lldb::StateType m_state = lldb::eStateInvalid;
|
||||
mutable std::recursive_mutex m_state_mutex;
|
||||
|
||||
llvm::Optional<WaitStatus> m_exit_status;
|
||||
@@ -427,7 +417,7 @@ protected:
|
||||
NativeWatchpointList m_watchpoint_list;
|
||||
HardwareBreakpointMap m_hw_breakpoints_map;
|
||||
int m_terminal_fd;
|
||||
uint32_t m_stop_id;
|
||||
uint32_t m_stop_id = 0;
|
||||
|
||||
// Set of signal numbers that LLDB directly injects back to inferior
|
||||
// without stopping it.
|
||||
@@ -438,7 +428,8 @@ protected:
|
||||
// then the process should be attached to. When attaching to a process
|
||||
// lldb_private::Host calls should be used to locate the process to attach to,
|
||||
// and then this function should be called.
|
||||
NativeProcessProtocol(lldb::pid_t pid);
|
||||
NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
|
||||
NativeDelegate &delegate);
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Internal interface for state handling
|
||||
|
||||
@@ -29,11 +29,13 @@ using namespace lldb_private;
|
||||
// NativeProcessProtocol Members
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid)
|
||||
: m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID),
|
||||
m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(),
|
||||
m_delegates_mutex(), m_delegates(), m_breakpoint_list(),
|
||||
m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {}
|
||||
NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
|
||||
NativeDelegate &delegate)
|
||||
: m_pid(pid), m_terminal_fd(terminal_fd) {
|
||||
bool registered = RegisterNativeDelegate(delegate);
|
||||
assert(registered);
|
||||
(void)registered;
|
||||
}
|
||||
|
||||
lldb_private::Status NativeProcessProtocol::Interrupt() {
|
||||
Status error;
|
||||
@@ -488,23 +490,4 @@ Status NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
|
||||
"failed to retrieve a valid architecture from the exe module");
|
||||
}
|
||||
|
||||
#if !defined(__linux__) && !defined(__NetBSD__)
|
||||
// These need to be implemented to support lldb-gdb-server on a given platform.
|
||||
// Stubs are
|
||||
// provided to make the rest of the code link on non-supported platforms.
|
||||
|
||||
Status NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop,
|
||||
NativeProcessProtocolSP &process_sp) {
|
||||
llvm_unreachable("Platform has no NativeProcessProtocol support");
|
||||
}
|
||||
|
||||
Status NativeProcessProtocol::Attach(lldb::pid_t pid,
|
||||
NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop,
|
||||
NativeProcessProtocolSP &process_sp) {
|
||||
llvm_unreachable("Platform has no NativeProcessProtocol support");
|
||||
}
|
||||
|
||||
#endif
|
||||
NativeProcessProtocol::Factory::~Factory() = default;
|
||||
|
||||
@@ -214,207 +214,122 @@ static Status EnsureFDFlags(int fd, int flags) {
|
||||
// Public Static Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Status NativeProcessProtocol::Launch(
|
||||
ProcessLaunchInfo &launch_info,
|
||||
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
|
||||
NativeProcessProtocolSP &native_process_sp) {
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
NativeProcessLinux::Factory::Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
|
||||
Status error;
|
||||
MaybeLogLaunchInfo(launch_info);
|
||||
|
||||
// Verify the working directory is valid if one was specified.
|
||||
FileSpec working_dir{launch_info.GetWorkingDirectory()};
|
||||
if (working_dir && (!working_dir.ResolvePath() ||
|
||||
!llvm::sys::fs::is_directory(working_dir.GetPath()))) {
|
||||
error.SetErrorStringWithFormat("No such file or directory: %s",
|
||||
working_dir.GetCString());
|
||||
return error;
|
||||
Status status;
|
||||
::pid_t pid = ProcessLauncherPosixFork()
|
||||
.LaunchProcess(launch_info, status)
|
||||
.GetProcessId();
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
if (status.Fail()) {
|
||||
LLDB_LOG(log, "failed to launch process: {0}", status);
|
||||
return status.ToError();
|
||||
}
|
||||
|
||||
// Create the NativeProcessLinux in launch mode.
|
||||
native_process_sp.reset(new NativeProcessLinux());
|
||||
// Wait for the child process to trap on its call to execve.
|
||||
int wstatus;
|
||||
::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
|
||||
assert(wpid == pid);
|
||||
(void)wpid;
|
||||
if (!WIFSTOPPED(wstatus)) {
|
||||
LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
|
||||
WaitStatus::Decode(wstatus));
|
||||
return llvm::make_error<StringError>("Could not sync with inferior process",
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||
|
||||
if (!native_process_sp->RegisterNativeDelegate(native_delegate)) {
|
||||
native_process_sp.reset();
|
||||
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||
return error;
|
||||
ArchSpec arch;
|
||||
if ((status = ResolveProcessArchitecture(pid, arch)).Fail())
|
||||
return status.ToError();
|
||||
|
||||
// Set the architecture to the exe architecture.
|
||||
LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
|
||||
arch.GetArchitectureName());
|
||||
|
||||
status = SetDefaultPtraceOpts(pid);
|
||||
if (status.Fail()) {
|
||||
LLDB_LOG(log, "failed to set default ptrace options: {0}", status);
|
||||
return status.ToError();
|
||||
}
|
||||
|
||||
error = std::static_pointer_cast<NativeProcessLinux>(native_process_sp)
|
||||
->LaunchInferior(mainloop, launch_info);
|
||||
|
||||
if (error.Fail()) {
|
||||
native_process_sp.reset();
|
||||
LLDB_LOG(log, "failed to launch process: {0}", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
launch_info.SetProcessID(native_process_sp->GetID());
|
||||
|
||||
return error;
|
||||
std::shared_ptr<NativeProcessLinux> process_sp(new NativeProcessLinux(
|
||||
pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate,
|
||||
arch, mainloop));
|
||||
process_sp->InitializeThreads({pid});
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
Status NativeProcessProtocol::Attach(
|
||||
llvm::Expected<NativeProcessProtocolSP> NativeProcessLinux::Factory::Attach(
|
||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
|
||||
MainLoop &mainloop) const {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
|
||||
// Retrieve the architecture for the running process.
|
||||
ArchSpec process_arch;
|
||||
Status error = ResolveProcessArchitecture(pid, process_arch);
|
||||
if (!error.Success())
|
||||
return error;
|
||||
ArchSpec arch;
|
||||
Status status = ResolveProcessArchitecture(pid, arch);
|
||||
if (!status.Success())
|
||||
return status.ToError();
|
||||
|
||||
std::shared_ptr<NativeProcessLinux> native_process_linux_sp(
|
||||
new NativeProcessLinux());
|
||||
auto tids_or = NativeProcessLinux::Attach(pid);
|
||||
if (!tids_or)
|
||||
return tids_or.takeError();
|
||||
|
||||
if (!native_process_linux_sp->RegisterNativeDelegate(native_delegate)) {
|
||||
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||
return error;
|
||||
}
|
||||
|
||||
native_process_linux_sp->AttachToInferior(mainloop, pid, error);
|
||||
if (!error.Success())
|
||||
return error;
|
||||
|
||||
native_process_sp = native_process_linux_sp;
|
||||
return error;
|
||||
std::shared_ptr<NativeProcessLinux> process_sp(
|
||||
new NativeProcessLinux(pid, -1, native_delegate, arch, mainloop));
|
||||
process_sp->InitializeThreads(*tids_or);
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Instance Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NativeProcessLinux::NativeProcessLinux()
|
||||
: NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(),
|
||||
m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache(),
|
||||
m_pending_notification_tid(LLDB_INVALID_THREAD_ID),
|
||||
m_pt_proces_trace_id(LLDB_INVALID_UID) {}
|
||||
|
||||
void NativeProcessLinux::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
|
||||
Status &error) {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
|
||||
NativeDelegate &delegate,
|
||||
const ArchSpec &arch, MainLoop &mainloop)
|
||||
: NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) {
|
||||
if (m_terminal_fd != -1) {
|
||||
Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
|
||||
assert(status.Success());
|
||||
}
|
||||
|
||||
Status status;
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||
if (!m_sigchld_handle)
|
||||
return;
|
||||
|
||||
error = ResolveProcessArchitecture(pid, m_arch);
|
||||
if (!error.Success())
|
||||
return;
|
||||
|
||||
// Set the architecture to the exe architecture.
|
||||
LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
|
||||
m_arch.GetArchitectureName());
|
||||
m_pid = pid;
|
||||
SetState(eStateAttaching);
|
||||
|
||||
Attach(pid, error);
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
|
||||
assert(m_sigchld_handle && status.Success());
|
||||
}
|
||||
|
||||
Status NativeProcessLinux::LaunchInferior(MainLoop &mainloop,
|
||||
ProcessLaunchInfo &launch_info) {
|
||||
Status error;
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||
if (!m_sigchld_handle)
|
||||
return error;
|
||||
|
||||
SetState(eStateLaunching);
|
||||
|
||||
MaybeLogLaunchInfo(launch_info);
|
||||
|
||||
::pid_t pid =
|
||||
ProcessLauncherPosixFork().LaunchProcess(launch_info, error).GetProcessId();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
|
||||
// Wait for the child process to trap on its call to execve.
|
||||
::pid_t wpid;
|
||||
int status;
|
||||
if ((wpid = waitpid(pid, &status, 0)) < 0) {
|
||||
error.SetErrorToErrno();
|
||||
LLDB_LOG(log, "waitpid for inferior failed with %s", error);
|
||||
|
||||
// Mark the inferior as invalid.
|
||||
// FIXME this could really use a new state - eStateLaunchFailure. For now,
|
||||
// using eStateInvalid.
|
||||
SetState(StateType::eStateInvalid);
|
||||
|
||||
return error;
|
||||
void NativeProcessLinux::InitializeThreads(llvm::ArrayRef<::pid_t> tids) {
|
||||
for (const auto &tid : tids) {
|
||||
NativeThreadLinuxSP thread_sp = AddThread(tid);
|
||||
assert(thread_sp && "AddThread() returned a nullptr thread");
|
||||
thread_sp->SetStoppedBySignal(SIGSTOP);
|
||||
ThreadWasCreated(*thread_sp);
|
||||
}
|
||||
assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t>(pid)) &&
|
||||
"Could not sync with inferior process.");
|
||||
|
||||
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||
error = SetDefaultPtraceOpts(pid);
|
||||
if (error.Fail()) {
|
||||
LLDB_LOG(log, "failed to set default ptrace options: {0}", error);
|
||||
|
||||
// Mark the inferior as invalid.
|
||||
// FIXME this could really use a new state - eStateLaunchFailure. For now,
|
||||
// using eStateInvalid.
|
||||
SetState(StateType::eStateInvalid);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// Release the master terminal descriptor and pass it off to the
|
||||
// NativeProcessLinux instance. Similarly stash the inferior pid.
|
||||
m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
|
||||
m_pid = pid;
|
||||
launch_info.SetProcessID(pid);
|
||||
|
||||
if (m_terminal_fd != -1) {
|
||||
error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
|
||||
if (error.Fail()) {
|
||||
LLDB_LOG(log,
|
||||
"inferior EnsureFDFlags failed for ensuring terminal "
|
||||
"O_NONBLOCK setting: {0}",
|
||||
error);
|
||||
|
||||
// Mark the inferior as invalid.
|
||||
// FIXME this could really use a new state - eStateLaunchFailure. For
|
||||
// now, using eStateInvalid.
|
||||
SetState(StateType::eStateInvalid);
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
LLDB_LOG(log, "adding pid = {0}", pid);
|
||||
ResolveProcessArchitecture(m_pid, m_arch);
|
||||
NativeThreadLinuxSP thread_sp = AddThread(pid);
|
||||
assert(thread_sp && "AddThread() returned a nullptr thread");
|
||||
thread_sp->SetStoppedBySignal(SIGSTOP);
|
||||
ThreadWasCreated(*thread_sp);
|
||||
|
||||
// Let our process instance know the thread has stopped.
|
||||
SetCurrentThreadID(thread_sp->GetID());
|
||||
SetState(StateType::eStateStopped);
|
||||
SetCurrentThreadID(tids[0]);
|
||||
SetState(StateType::eStateStopped, false);
|
||||
|
||||
if (error.Fail())
|
||||
LLDB_LOG(log, "inferior launching failed {0}", error);
|
||||
return error;
|
||||
// Proccess any signals we received before installing our handler
|
||||
SigchldHandler();
|
||||
}
|
||||
|
||||
::pid_t NativeProcessLinux::Attach(lldb::pid_t pid, Status &error) {
|
||||
llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
|
||||
Status status;
|
||||
// Use a map to keep track of the threads which we have attached/need to
|
||||
// attach.
|
||||
Host::TidMap tids_to_attach;
|
||||
if (pid <= 1) {
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("Attaching to process 1 is not allowed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (Host::FindProcessThreads(pid, tids_to_attach)) {
|
||||
for (Host::TidMap::iterator it = tids_to_attach.begin();
|
||||
it != tids_to_attach.end();) {
|
||||
@@ -423,48 +338,36 @@ Status NativeProcessLinux::LaunchInferior(MainLoop &mainloop,
|
||||
|
||||
// Attach to the requested process.
|
||||
// An attach will cause the thread to stop with a SIGSTOP.
|
||||
error = PtraceWrapper(PTRACE_ATTACH, tid);
|
||||
if (error.Fail()) {
|
||||
if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) {
|
||||
// No such thread. The thread may have exited.
|
||||
// More error handling may be needed.
|
||||
if (error.GetError() == ESRCH) {
|
||||
if (status.GetError() == ESRCH) {
|
||||
it = tids_to_attach.erase(it);
|
||||
continue;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
return status.ToError();
|
||||
}
|
||||
|
||||
int status;
|
||||
int wpid =
|
||||
llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL);
|
||||
// Need to use __WALL otherwise we receive an error with errno=ECHLD
|
||||
// At this point we should have a thread stopped if waitpid succeeds.
|
||||
if ((status = waitpid(tid, NULL, __WALL)) < 0) {
|
||||
if (wpid < 0) {
|
||||
// No such thread. The thread may have exited.
|
||||
// More error handling may be needed.
|
||||
if (errno == ESRCH) {
|
||||
it = tids_to_attach.erase(it);
|
||||
continue;
|
||||
} else {
|
||||
error.SetErrorToErrno();
|
||||
return -1;
|
||||
}
|
||||
return llvm::errorCodeToError(
|
||||
std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
|
||||
error = SetDefaultPtraceOpts(tid);
|
||||
if (error.Fail())
|
||||
return -1;
|
||||
if ((status = SetDefaultPtraceOpts(tid)).Fail())
|
||||
return status.ToError();
|
||||
|
||||
LLDB_LOG(log, "adding tid = {0}", tid);
|
||||
it->second = true;
|
||||
|
||||
// Create the thread, mark it as stopped.
|
||||
NativeThreadLinuxSP thread_sp(AddThread(static_cast<lldb::tid_t>(tid)));
|
||||
assert(thread_sp && "AddThread() returned a nullptr");
|
||||
|
||||
// This will notify this is a new thread and tell the system it is
|
||||
// stopped.
|
||||
thread_sp->SetStoppedBySignal(SIGSTOP);
|
||||
ThreadWasCreated(*thread_sp);
|
||||
SetCurrentThreadID(thread_sp->GetID());
|
||||
}
|
||||
|
||||
// move the loop forward
|
||||
@@ -472,17 +375,16 @@ Status NativeProcessLinux::LaunchInferior(MainLoop &mainloop,
|
||||
}
|
||||
}
|
||||
|
||||
if (tids_to_attach.size() > 0) {
|
||||
m_pid = pid;
|
||||
// Let our process instance know the thread has stopped.
|
||||
SetState(StateType::eStateStopped);
|
||||
} else {
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("No such process.");
|
||||
return -1;
|
||||
}
|
||||
size_t tid_count = tids_to_attach.size();
|
||||
if (tid_count == 0)
|
||||
return llvm::make_error<StringError>("No such process",
|
||||
llvm::inconvertibleErrorCode());
|
||||
|
||||
return pid;
|
||||
std::vector<::pid_t> tids;
|
||||
tids.reserve(tid_count);
|
||||
for (const auto &p : tids_to_attach)
|
||||
tids.push_back(p.first);
|
||||
return std::move(tids);
|
||||
}
|
||||
|
||||
Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
|
||||
|
||||
@@ -39,15 +39,18 @@ namespace process_linux {
|
||||
///
|
||||
/// Changes in the inferior process state are broadcasted.
|
||||
class NativeProcessLinux : public NativeProcessProtocol {
|
||||
friend Status NativeProcessProtocol::Launch(
|
||||
ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||
|
||||
friend Status NativeProcessProtocol::Attach(
|
||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||
|
||||
public:
|
||||
class Factory : public NativeProcessProtocol::Factory {
|
||||
public:
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const override;
|
||||
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const override;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// NativeProcessProtocol Interface
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -144,10 +147,10 @@ private:
|
||||
MainLoop::SignalHandleUP m_sigchld_handle;
|
||||
ArchSpec m_arch;
|
||||
|
||||
LazyBool m_supports_mem_region;
|
||||
LazyBool m_supports_mem_region = eLazyBoolCalculate;
|
||||
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
|
||||
|
||||
lldb::tid_t m_pending_notification_tid;
|
||||
lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
|
||||
|
||||
// List of thread ids stepping with a breakpoint with the address of
|
||||
// the relevan breakpoint
|
||||
@@ -156,19 +159,15 @@ private:
|
||||
// ---------------------------------------------------------------------
|
||||
// Private Instance Methods
|
||||
// ---------------------------------------------------------------------
|
||||
NativeProcessLinux();
|
||||
NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
|
||||
const ArchSpec &arch, MainLoop &mainloop);
|
||||
|
||||
Status LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info);
|
||||
|
||||
/// Attaches to an existing process. Forms the
|
||||
/// implementation of Process::DoAttach
|
||||
void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error);
|
||||
|
||||
::pid_t Attach(lldb::pid_t pid, Status &error);
|
||||
// Returns a list of process threads that we have attached to.
|
||||
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
|
||||
|
||||
static Status SetDefaultPtraceOpts(const lldb::pid_t);
|
||||
|
||||
static void *MonitorThread(void *baton);
|
||||
void InitializeThreads(llvm::ArrayRef<::pid_t> tids);
|
||||
|
||||
void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status);
|
||||
|
||||
@@ -280,7 +279,7 @@ private:
|
||||
// same process user id.
|
||||
llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group;
|
||||
|
||||
lldb::user_id_t m_pt_proces_trace_id;
|
||||
lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID;
|
||||
TraceOptions m_pt_process_trace_config;
|
||||
};
|
||||
|
||||
|
||||
@@ -64,81 +64,101 @@ static Status EnsureFDFlags(int fd, int flags) {
|
||||
// Public Static Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
Status NativeProcessProtocol::Launch(
|
||||
ProcessLaunchInfo &launch_info,
|
||||
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
|
||||
NativeProcessProtocolSP &native_process_sp) {
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
|
||||
Status error;
|
||||
|
||||
// Verify the working directory is valid if one was specified.
|
||||
FileSpec working_dir{launch_info.GetWorkingDirectory()};
|
||||
if (working_dir && (!working_dir.ResolvePath() ||
|
||||
!llvm::sys::fs::is_directory(working_dir.GetPath()))) {
|
||||
error.SetErrorStringWithFormat("No such file or directory: %s",
|
||||
working_dir.GetCString());
|
||||
return error;
|
||||
Status status;
|
||||
::pid_t pid = ProcessLauncherPosixFork()
|
||||
.LaunchProcess(launch_info, status)
|
||||
.GetProcessId();
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
if (status.Fail()) {
|
||||
LLDB_LOG(log, "failed to launch process: {0}", status);
|
||||
return status.ToError();
|
||||
}
|
||||
|
||||
// Create the NativeProcessNetBSD in launch mode.
|
||||
native_process_sp.reset(new NativeProcessNetBSD());
|
||||
|
||||
if (!native_process_sp->RegisterNativeDelegate(native_delegate)) {
|
||||
native_process_sp.reset();
|
||||
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||
return error;
|
||||
// Wait for the child process to trap on its call to execve.
|
||||
int wstatus;
|
||||
::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
|
||||
assert(wpid == pid);
|
||||
(void)wpid;
|
||||
if (!WIFSTOPPED(wstatus)) {
|
||||
LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
|
||||
WaitStatus::Decode(wstatus));
|
||||
return llvm::make_error<StringError>("Could not sync with inferior process",
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||
|
||||
error = std::static_pointer_cast<NativeProcessNetBSD>(native_process_sp)
|
||||
->LaunchInferior(mainloop, launch_info);
|
||||
ArchSpec arch;
|
||||
if ((status = ResolveProcessArchitecture(pid, arch)).Fail())
|
||||
return status.ToError();
|
||||
|
||||
if (error.Fail()) {
|
||||
native_process_sp.reset();
|
||||
LLDB_LOG(log, "failed to launch process: {0}", error);
|
||||
return error;
|
||||
// Set the architecture to the exe architecture.
|
||||
LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
|
||||
arch.GetArchitectureName());
|
||||
|
||||
std::shared_ptr<NativeProcessNetBSD> process_sp(new NativeProcessNetBSD(
|
||||
pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate,
|
||||
arch, mainloop));
|
||||
|
||||
status = process_sp->ReinitializeThreads();
|
||||
if (status.Fail())
|
||||
return status.ToError();
|
||||
|
||||
for (const auto &thread_sp : process_sp->m_threads) {
|
||||
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||
SIGSTOP);
|
||||
}
|
||||
process_sp->SetState(StateType::eStateStopped);
|
||||
|
||||
launch_info.SetProcessID(native_process_sp->GetID());
|
||||
|
||||
return error;
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
Status NativeProcessProtocol::Attach(
|
||||
llvm::Expected<NativeProcessProtocolSP> NativeProcessNetBSD::Factory::Attach(
|
||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
|
||||
MainLoop &mainloop) const {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
|
||||
// Retrieve the architecture for the running process.
|
||||
ArchSpec process_arch;
|
||||
Status error = ResolveProcessArchitecture(pid, process_arch);
|
||||
if (!error.Success())
|
||||
return error;
|
||||
ArchSpec arch;
|
||||
Status status = ResolveProcessArchitecture(pid, arch);
|
||||
if (!status.Success())
|
||||
return status.ToError();
|
||||
|
||||
std::shared_ptr<NativeProcessNetBSD> native_process_netbsd_sp(
|
||||
new NativeProcessNetBSD());
|
||||
std::shared_ptr<NativeProcessNetBSD> process_sp(
|
||||
new NativeProcessNetBSD(pid, -1, native_delegate, arch, mainloop));
|
||||
|
||||
if (!native_process_netbsd_sp->RegisterNativeDelegate(native_delegate)) {
|
||||
error.SetErrorStringWithFormat("failed to register the native delegate");
|
||||
return error;
|
||||
}
|
||||
status = process_sp->Attach();
|
||||
if (!status.Success())
|
||||
return status.ToError();
|
||||
|
||||
native_process_netbsd_sp->AttachToInferior(mainloop, pid, error);
|
||||
if (!error.Success())
|
||||
return error;
|
||||
|
||||
native_process_sp = native_process_netbsd_sp;
|
||||
return error;
|
||||
return process_sp;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Instance Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NativeProcessNetBSD::NativeProcessNetBSD()
|
||||
: NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(),
|
||||
m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache() {}
|
||||
NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd,
|
||||
NativeDelegate &delegate,
|
||||
const ArchSpec &arch,
|
||||
MainLoop &mainloop)
|
||||
: NativeProcessProtocol(pid, terminal_fd, delegate), m_arch(arch) {
|
||||
if (m_terminal_fd != -1) {
|
||||
Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
|
||||
assert(status.Success());
|
||||
}
|
||||
|
||||
Status status;
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
|
||||
assert(m_sigchld_handle && status.Success());
|
||||
}
|
||||
|
||||
// Handles all waitpid events from the inferior process.
|
||||
void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
|
||||
@@ -710,113 +730,6 @@ Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
|
||||
return Status();
|
||||
}
|
||||
|
||||
Status NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
|
||||
ProcessLaunchInfo &launch_info) {
|
||||
Status error;
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||
if (!m_sigchld_handle)
|
||||
return error;
|
||||
|
||||
SetState(eStateLaunching);
|
||||
|
||||
::pid_t pid = ProcessLauncherPosixFork()
|
||||
.LaunchProcess(launch_info, error)
|
||||
.GetProcessId();
|
||||
if (error.Fail())
|
||||
return error;
|
||||
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
|
||||
// Wait for the child process to trap on its call to execve.
|
||||
::pid_t wpid;
|
||||
int status;
|
||||
if ((wpid = waitpid(pid, &status, 0)) < 0) {
|
||||
error.SetErrorToErrno();
|
||||
LLDB_LOG(log, "waitpid for inferior failed with %s", error);
|
||||
|
||||
// Mark the inferior as invalid.
|
||||
// FIXME this could really use a new state - eStateLaunchFailure. For
|
||||
// now, using eStateInvalid.
|
||||
SetState(StateType::eStateInvalid);
|
||||
|
||||
return error;
|
||||
}
|
||||
assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t>(pid)) &&
|
||||
"Could not sync with inferior process.");
|
||||
|
||||
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||
|
||||
// Release the master terminal descriptor and pass it off to the
|
||||
// NativeProcessNetBSD instance. Similarly stash the inferior pid.
|
||||
m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
|
||||
m_pid = pid;
|
||||
launch_info.SetProcessID(pid);
|
||||
|
||||
if (m_terminal_fd != -1) {
|
||||
error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
|
||||
if (error.Fail()) {
|
||||
LLDB_LOG(log,
|
||||
"inferior EnsureFDFlags failed for ensuring terminal "
|
||||
"O_NONBLOCK setting: {0}",
|
||||
error);
|
||||
|
||||
// Mark the inferior as invalid.
|
||||
// FIXME this could really use a new state - eStateLaunchFailure. For
|
||||
// now, using eStateInvalid.
|
||||
SetState(StateType::eStateInvalid);
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
LLDB_LOG(log, "adding pid = {0}", pid);
|
||||
|
||||
ResolveProcessArchitecture(m_pid, m_arch);
|
||||
|
||||
error = ReinitializeThreads();
|
||||
if (error.Fail()) {
|
||||
SetState(StateType::eStateInvalid);
|
||||
return error;
|
||||
}
|
||||
|
||||
for (const auto &thread_sp : m_threads) {
|
||||
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||
SIGSTOP);
|
||||
}
|
||||
|
||||
/* Set process stopped */
|
||||
SetState(StateType::eStateStopped);
|
||||
|
||||
if (error.Fail())
|
||||
LLDB_LOG(log, "inferior launching failed {0}", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
void NativeProcessNetBSD::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
|
||||
Status &error) {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error);
|
||||
if (!m_sigchld_handle)
|
||||
return;
|
||||
|
||||
error = ResolveProcessArchitecture(pid, m_arch);
|
||||
if (!error.Success())
|
||||
return;
|
||||
|
||||
// Set the architecture to the exe architecture.
|
||||
LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
|
||||
m_arch.GetArchitectureName());
|
||||
|
||||
m_pid = pid;
|
||||
SetState(eStateAttaching);
|
||||
|
||||
Attach(pid, error);
|
||||
}
|
||||
|
||||
void NativeProcessNetBSD::SigchldHandler() {
|
||||
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
|
||||
// Process all pending waitpid notifications.
|
||||
@@ -879,33 +792,23 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
|
||||
return thread_sp;
|
||||
}
|
||||
|
||||
::pid_t NativeProcessNetBSD::Attach(lldb::pid_t pid, Status &error) {
|
||||
if (pid <= 1) {
|
||||
error.SetErrorToGenericError();
|
||||
error.SetErrorString("Attaching to process 1 is not allowed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Status NativeProcessNetBSD::Attach() {
|
||||
// Attach to the requested process.
|
||||
// An attach will cause the thread to stop with a SIGSTOP.
|
||||
error = PtraceWrapper(PT_ATTACH, pid);
|
||||
if (error.Fail())
|
||||
return -1;
|
||||
Status status = PtraceWrapper(PT_ATTACH, m_pid);
|
||||
if (status.Fail())
|
||||
return status;
|
||||
|
||||
int status;
|
||||
int wstatus;
|
||||
// Need to use WALLSIG otherwise we receive an error with errno=ECHLD
|
||||
// At this point we should have a thread stopped if waitpid succeeds.
|
||||
if ((status = waitpid(pid, NULL, WALLSIG)) < 0)
|
||||
return -1;
|
||||
|
||||
m_pid = pid;
|
||||
if ((wstatus = waitpid(m_pid, NULL, WALLSIG)) < 0)
|
||||
return Status(errno, eErrorTypePOSIX);
|
||||
|
||||
/* Initialize threads */
|
||||
error = ReinitializeThreads();
|
||||
if (error.Fail()) {
|
||||
SetState(StateType::eStateInvalid);
|
||||
return -1;
|
||||
}
|
||||
status = ReinitializeThreads();
|
||||
if (status.Fail())
|
||||
return status;
|
||||
|
||||
for (const auto &thread_sp : m_threads) {
|
||||
static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
|
||||
@@ -914,8 +817,7 @@ NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
|
||||
|
||||
// Let our process instance know the thread has stopped.
|
||||
SetState(StateType::eStateStopped);
|
||||
|
||||
return pid;
|
||||
return Status();
|
||||
}
|
||||
|
||||
Status NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf,
|
||||
|
||||
@@ -31,15 +31,18 @@ namespace process_netbsd {
|
||||
///
|
||||
/// Changes in the inferior process state are broadcasted.
|
||||
class NativeProcessNetBSD : public NativeProcessProtocol {
|
||||
friend Status NativeProcessProtocol::Launch(
|
||||
ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||
|
||||
friend Status NativeProcessProtocol::Attach(
|
||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
|
||||
|
||||
public:
|
||||
class Factory : public NativeProcessProtocol::Factory {
|
||||
public:
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const override;
|
||||
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
|
||||
MainLoop &mainloop) const override;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// NativeProcessProtocol Interface
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -107,21 +110,19 @@ protected:
|
||||
private:
|
||||
MainLoop::SignalHandleUP m_sigchld_handle;
|
||||
ArchSpec m_arch;
|
||||
LazyBool m_supports_mem_region;
|
||||
LazyBool m_supports_mem_region = eLazyBoolCalculate;
|
||||
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Private Instance Methods
|
||||
// ---------------------------------------------------------------------
|
||||
NativeProcessNetBSD();
|
||||
NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
|
||||
const ArchSpec &arch, MainLoop &mainloop);
|
||||
|
||||
bool HasThreadNoLock(lldb::tid_t thread_id);
|
||||
|
||||
NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id);
|
||||
|
||||
Status LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info);
|
||||
void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error);
|
||||
|
||||
void MonitorCallback(lldb::pid_t pid, int signal);
|
||||
void MonitorExited(lldb::pid_t pid, WaitStatus status);
|
||||
void MonitorSIGSTOP(lldb::pid_t pid);
|
||||
@@ -133,8 +134,7 @@ private:
|
||||
Status PopulateMemoryRegionCache();
|
||||
void SigchldHandler();
|
||||
|
||||
::pid_t Attach(lldb::pid_t pid, Status &error);
|
||||
|
||||
Status Attach();
|
||||
Status ReinitializeThreads();
|
||||
};
|
||||
|
||||
|
||||
@@ -7,14 +7,6 @@ set(LLDB_PLUGINS
|
||||
lldbPluginPlatformMacOSX
|
||||
)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD)
|
||||
endif()
|
||||
|
||||
add_lldb_library(lldbPluginProcessGDBRemote PLUGIN
|
||||
GDBRemoteClientBase.cpp
|
||||
GDBRemoteCommunication.cpp
|
||||
|
||||
@@ -1046,14 +1046,9 @@ GDBRemoteCommunicationServerCommon::Handle_A(StringExtractorGDBRemote &packet) {
|
||||
|
||||
if (success) {
|
||||
m_process_launch_error = LaunchProcess();
|
||||
if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
|
||||
if (m_process_launch_error.Success())
|
||||
return SendOKResponse();
|
||||
} else {
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf("LLGSPacketHandler::%s failed to launch exe: %s",
|
||||
__FUNCTION__, m_process_launch_error.AsCString());
|
||||
}
|
||||
LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error);
|
||||
}
|
||||
return SendErrorResponse(8);
|
||||
}
|
||||
|
||||
@@ -73,15 +73,11 @@ enum GDBRemoteServerError {
|
||||
// GDBRemoteCommunicationServerLLGS constructor
|
||||
//----------------------------------------------------------------------
|
||||
GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
|
||||
MainLoop &mainloop)
|
||||
MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory)
|
||||
: GDBRemoteCommunicationServerCommon("gdb-remote.server",
|
||||
"gdb-remote.server.rx_packet"),
|
||||
m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID),
|
||||
m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(),
|
||||
m_debugged_process_sp(), m_stdio_communication("process.stdio"),
|
||||
m_inferior_prev_state(StateType::eStateInvalid),
|
||||
m_saved_registers_map(), m_next_saved_registers_id(1),
|
||||
m_handshake_completed(false) {
|
||||
m_mainloop(mainloop), m_process_factory(process_factory),
|
||||
m_stdio_communication("process.stdio") {
|
||||
RegisterPacketHandlers();
|
||||
}
|
||||
|
||||
@@ -241,19 +237,20 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
|
||||
const bool default_to_use_pty = true;
|
||||
m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty);
|
||||
|
||||
Status error;
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex);
|
||||
assert(!m_debugged_process_sp && "lldb-server creating debugged "
|
||||
"process but one already exists");
|
||||
error = NativeProcessProtocol::Launch(m_process_launch_info, *this,
|
||||
m_mainloop, m_debugged_process_sp);
|
||||
}
|
||||
|
||||
if (!error.Success()) {
|
||||
fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__,
|
||||
m_process_launch_info.GetArguments().GetArgumentAtIndex(0));
|
||||
return error;
|
||||
auto process_or =
|
||||
m_process_factory.Launch(m_process_launch_info, *this, m_mainloop);
|
||||
if (!process_or) {
|
||||
Status status(process_or.takeError());
|
||||
llvm::errs() << llvm::formatv(
|
||||
"failed to launch executable `{0}`: {1}",
|
||||
m_process_launch_info.GetArguments().GetArgumentAtIndex(0), status);
|
||||
return status;
|
||||
}
|
||||
m_debugged_process_sp = *process_or;
|
||||
}
|
||||
|
||||
// Handle mirroring of inferior stdout/stderr over the gdb-remote protocol
|
||||
@@ -279,9 +276,9 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
|
||||
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting "
|
||||
"inferior STDIO fd to %d",
|
||||
__FUNCTION__, terminal_fd);
|
||||
error = SetSTDIOFileDescriptor(terminal_fd);
|
||||
if (error.Fail())
|
||||
return error;
|
||||
Status status = SetSTDIOFileDescriptor(terminal_fd);
|
||||
if (status.Fail())
|
||||
return status;
|
||||
} else {
|
||||
if (log)
|
||||
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
|
||||
@@ -298,14 +295,12 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() {
|
||||
|
||||
printf("Launched '%s' as process %" PRIu64 "...\n",
|
||||
m_process_launch_info.GetArguments().GetArgumentAtIndex(0),
|
||||
m_process_launch_info.GetProcessID());
|
||||
m_debugged_process_sp->GetID());
|
||||
|
||||
return error;
|
||||
return Status();
|
||||
}
|
||||
|
||||
Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
|
||||
Status error;
|
||||
|
||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64,
|
||||
@@ -321,13 +316,14 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
|
||||
pid, m_debugged_process_sp->GetID());
|
||||
|
||||
// Try to attach.
|
||||
error = NativeProcessProtocol::Attach(pid, *this, m_mainloop,
|
||||
m_debugged_process_sp);
|
||||
if (!error.Success()) {
|
||||
fprintf(stderr, "%s: failed to attach to process %" PRIu64 ": %s",
|
||||
__FUNCTION__, pid, error.AsCString());
|
||||
return error;
|
||||
auto process_or = m_process_factory.Attach(pid, *this, m_mainloop);
|
||||
if (!process_or) {
|
||||
Status status(process_or.takeError());
|
||||
llvm::errs() << llvm::formatv("failed to attach to process {0}: {1}", pid,
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
m_debugged_process_sp = *process_or;
|
||||
|
||||
// Setup stdout/stderr mapping from inferior.
|
||||
auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor();
|
||||
@@ -336,9 +332,9 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
|
||||
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s setting "
|
||||
"inferior STDIO fd to %d",
|
||||
__FUNCTION__, terminal_fd);
|
||||
error = SetSTDIOFileDescriptor(terminal_fd);
|
||||
if (error.Fail())
|
||||
return error;
|
||||
Status status = SetSTDIOFileDescriptor(terminal_fd);
|
||||
if (status.Fail())
|
||||
return status;
|
||||
} else {
|
||||
if (log)
|
||||
log->Printf("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring "
|
||||
@@ -347,8 +343,7 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
|
||||
}
|
||||
|
||||
printf("Attached to process %" PRIu64 "...\n", pid);
|
||||
|
||||
return error;
|
||||
return Status();
|
||||
}
|
||||
|
||||
void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
|
||||
|
||||
@@ -39,7 +39,9 @@ public:
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
GDBRemoteCommunicationServerLLGS(MainLoop &mainloop);
|
||||
GDBRemoteCommunicationServerLLGS(
|
||||
MainLoop &mainloop,
|
||||
const NativeProcessProtocol::Factory &process_factory);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Specify the program to launch and its arguments.
|
||||
@@ -108,20 +110,21 @@ public:
|
||||
protected:
|
||||
MainLoop &m_mainloop;
|
||||
MainLoop::ReadHandleUP m_network_handle_up;
|
||||
lldb::tid_t m_current_tid;
|
||||
lldb::tid_t m_continue_tid;
|
||||
const NativeProcessProtocol::Factory &m_process_factory;
|
||||
lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID;
|
||||
lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID;
|
||||
std::recursive_mutex m_debugged_process_mutex;
|
||||
NativeProcessProtocolSP m_debugged_process_sp;
|
||||
|
||||
Communication m_stdio_communication;
|
||||
MainLoop::ReadHandleUP m_stdio_handle_up;
|
||||
|
||||
lldb::StateType m_inferior_prev_state;
|
||||
lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid;
|
||||
std::unique_ptr<llvm::MemoryBuffer> m_active_auxv_buffer_up;
|
||||
std::mutex m_saved_registers_mutex;
|
||||
std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
|
||||
uint32_t m_next_saved_registers_id;
|
||||
bool m_handshake_completed : 1;
|
||||
uint32_t m_next_saved_registers_id = 1;
|
||||
bool m_handshake_completed = false;
|
||||
|
||||
PacketResult SendONotification(const char *buffer, uint32_t len);
|
||||
|
||||
|
||||
@@ -59,6 +59,16 @@ if (LLVM_BUILD_STATIC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LLDB_PLUGINS)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD)
|
||||
endif()
|
||||
|
||||
add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK
|
||||
Acceptor.cpp
|
||||
lldb-gdbserver.cpp
|
||||
@@ -72,7 +82,7 @@ add_lldb_tool(lldb-server INCLUDE_IN_FRAMEWORK
|
||||
lldbHost
|
||||
lldbInitialization
|
||||
lldbInterpreter
|
||||
${EXTRA_LLDB_LIBS}
|
||||
${LLDB_PLUGINS}
|
||||
${LLDB_SYSTEM_LIBS}
|
||||
|
||||
LINK_COMPONENTS
|
||||
|
||||
@@ -33,10 +33,17 @@
|
||||
#include "lldb/Host/Pipe.h"
|
||||
#include "lldb/Host/Socket.h"
|
||||
#include "lldb/Host/StringConvert.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Utility/Status.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Errno.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include "Plugins/Process/Linux/NativeProcessLinux.h"
|
||||
#elif defined(__NetBSD__)
|
||||
#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
|
||||
#endif
|
||||
|
||||
#ifndef LLGS_PROGRAM_NAME
|
||||
#define LLGS_PROGRAM_NAME "lldb-server"
|
||||
#endif
|
||||
@@ -51,6 +58,30 @@ using namespace lldb_private;
|
||||
using namespace lldb_private::lldb_server;
|
||||
using namespace lldb_private::process_gdb_remote;
|
||||
|
||||
namespace {
|
||||
#if defined(__linux__)
|
||||
typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
|
||||
#elif defined(__NetBSD__)
|
||||
typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
|
||||
#else
|
||||
// Dummy implementation to make sure the code compiles
|
||||
class NativeProcessFactory : public NativeProcessProtocol::Factory {
|
||||
public:
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeProcessProtocol::NativeDelegate &delegate,
|
||||
MainLoop &mainloop) const override {
|
||||
llvm_unreachable("Not implemented");
|
||||
}
|
||||
llvm::Expected<NativeProcessProtocolSP>
|
||||
Attach(lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &delegate,
|
||||
MainLoop &mainloop) const override {
|
||||
llvm_unreachable("Not implemented");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// option descriptors for getopt_long_only()
|
||||
//----------------------------------------------------------------------
|
||||
@@ -446,7 +477,8 @@ int main_gdbserver(int argc, char *argv[]) {
|
||||
exit(255);
|
||||
}
|
||||
|
||||
GDBRemoteCommunicationServerLLGS gdb_server(mainloop);
|
||||
NativeProcessFactory factory;
|
||||
GDBRemoteCommunicationServerLLGS gdb_server(mainloop, factory);
|
||||
|
||||
const char *const host_and_port = argv[0];
|
||||
argc -= 1;
|
||||
|
||||
Reference in New Issue
Block a user