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:
Pavel Labath
2017-07-07 11:02:19 +00:00
parent d4550baf3b
commit 96e600fcf5
12 changed files with 361 additions and 557 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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,

View File

@@ -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();
};

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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(

View File

@@ -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);

View File

@@ -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

View File

@@ -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;