summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/source/Plugins/Process/NetBSD/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp948
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h90
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp47
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h13
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp477
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h70
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp123
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h39
9 files changed, 1803 insertions, 5 deletions
diff --git a/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt b/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt
index 6ff5f02be4e..5b2cef8b847 100644
--- a/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/NetBSD/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories(../Utility)
add_lldb_library(lldbPluginProcessNetBSD PLUGIN
NativeProcessNetBSD.cpp
NativeRegisterContextNetBSD.cpp
+ NativeRegisterContextNetBSD_x86_64.cpp
NativeThreadNetBSD.cpp
LINK_LIBS
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index 0a9c38edd63..9c09727588d 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -14,18 +14,77 @@
// C++ Includes
// Other libraries and framework includes
-
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/common/NativeBreakpoint.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
// System includes - They have to be included after framework includes because
// they define some
// macros which collide with variable names in other modules
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <uvm/uvm_prot.h>
+#include <elf.h>
+#include <util.h>
+// clang-format on
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_netbsd;
using namespace llvm;
+static ExitType convert_pid_status_to_exit_type(int status) {
+ if (WIFEXITED(status))
+ return ExitType::eExitTypeExit;
+ else if (WIFSIGNALED(status))
+ return ExitType::eExitTypeSignal;
+ else if (WIFSTOPPED(status))
+ return ExitType::eExitTypeStop;
+ else {
+ // We don't know what this is.
+ return ExitType::eExitTypeInvalid;
+ }
+}
+
+static int convert_pid_status_to_return_code(int status) {
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ return WTERMSIG(status);
+ else if (WIFSTOPPED(status))
+ return WSTOPSIG(status);
+ else {
+ // We don't know what this is.
+ return ExitType::eExitTypeInvalid;
+ }
+}
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Error EnsureFDFlags(int fd, int flags) {
+ Error error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
// -----------------------------------------------------------------------------
// Public Static Methods
// -----------------------------------------------------------------------------
@@ -34,13 +93,68 @@ Error NativeProcessProtocol::Launch(
ProcessLaunchInfo &launch_info,
NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
NativeProcessProtocolSP &native_process_sp) {
- return Error();
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ Error 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;
+ }
+
+ // 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;
+ }
+
+ error = std::static_pointer_cast<NativeProcessNetBSD>(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;
}
Error NativeProcessProtocol::Attach(
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) {
- return Error();
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ // Retrieve the architecture for the running process.
+ ArchSpec process_arch;
+ Error error = ResolveProcessArchitecture(pid, process_arch);
+ if (!error.Success())
+ return error;
+
+ std::shared_ptr<NativeProcessNetBSD> native_process_netbsd_sp(
+ new NativeProcessNetBSD());
+
+ if (!native_process_netbsd_sp->RegisterNativeDelegate(native_delegate)) {
+ error.SetErrorStringWithFormat("failed to register the native delegate");
+ return error;
+ }
+
+ native_process_netbsd_sp->AttachToInferior(mainloop, pid, error);
+ if (!error.Success())
+ return error;
+
+ native_process_sp = native_process_netbsd_sp;
+ return error;
}
// -----------------------------------------------------------------------------
@@ -48,4 +162,830 @@ Error NativeProcessProtocol::Attach(
// -----------------------------------------------------------------------------
NativeProcessNetBSD::NativeProcessNetBSD()
- : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID) {}
+ : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(),
+ m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache() {}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ case SIGSTOP:
+ return MonitorSIGSTOP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, int signal,
+ int status) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", signal, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(convert_pid_status_to_exit_type(status),
+ convert_pid_status_to_return_code(status), nullptr, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessNetBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Success()) {
+ // Handle SIGSTOP from LLGS (LLDB GDB Server)
+ if (info.psi_siginfo.si_code == SI_USER &&
+ info.psi_siginfo.si_pid == ::getpid()) {
+ /* Stop Tracking All Threads attached to Process */
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ SIGSTOP, &info.psi_siginfo);
+ }
+ }
+ }
+}
+
+void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ ptrace_siginfo_t info;
+
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ // Get details on the signal raised.
+ if (siginfo_err.Success()) {
+ switch (info.psi_siginfo.si_code) {
+ case TRAP_BRKPT:
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)
+ ->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(
+ *static_pointer_cast<NativeThreadNetBSD>(thread_sp));
+ }
+ SetState(StateType::eStateStopped, true);
+ break;
+ }
+ }
+}
+
+void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ ptrace_siginfo_t info;
+ const auto siginfo_err =
+ PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetStoppedBySignal(
+ info.psi_siginfo.si_signo, &info.psi_siginfo);
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+Error NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Error error;
+ int ret;
+
+ errno = 0;
+ ret = ptrace(req, static_cast<::pid_t>(pid), addr, data);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+Error NativeProcessNetBSD::GetSoftwareBreakpointPCOffset(
+ uint32_t &actual_opcode_size) {
+ // FIXME put this behind a breakpoint protocol class that can be
+ // set per architecture. Need ARM, MIPS support here.
+ static const uint8_t g_i386_opcode[] = {0xCC};
+ switch (m_arch.GetMachine()) {
+ case llvm::Triple::x86_64:
+ actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode));
+ return Error();
+ default:
+ assert(false && "CPU type not supported!");
+ return Error("CPU type not supported");
+ }
+}
+
+Error NativeProcessNetBSD::FixupBreakpointPCAsNeeded(
+ NativeThreadNetBSD &thread) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
+ Error error;
+ // Find out the size of a breakpoint (might depend on where we are in the
+ // code).
+ NativeRegisterContextSP context_sp = thread.GetRegisterContext();
+ if (!context_sp) {
+ error.SetErrorString("cannot get a NativeRegisterContext for the thread");
+ LLDB_LOG(log, "failed: {0}", error);
+ return error;
+ }
+ uint32_t breakpoint_size = 0;
+ error = GetSoftwareBreakpointPCOffset(breakpoint_size);
+ if (error.Fail()) {
+ LLDB_LOG(log, "GetBreakpointSize() failed: {0}", error);
+ return error;
+ } else
+ LLDB_LOG(log, "breakpoint size: {0}", breakpoint_size);
+ // First try probing for a breakpoint at a software breakpoint location: PC -
+ // breakpoint size.
+ const lldb::addr_t initial_pc_addr =
+ context_sp->GetPCfromBreakpointLocation();
+ lldb::addr_t breakpoint_addr = initial_pc_addr;
+ if (breakpoint_size > 0) {
+ // Do not allow breakpoint probe to wrap around.
+ if (breakpoint_addr >= breakpoint_size)
+ breakpoint_addr -= breakpoint_size;
+ }
+ // Check if we stopped because of a breakpoint.
+ NativeBreakpointSP breakpoint_sp;
+ error = m_breakpoint_list.GetBreakpoint(breakpoint_addr, breakpoint_sp);
+ if (!error.Success() || !breakpoint_sp) {
+ // We didn't find one at a software probe location. Nothing to do.
+ LLDB_LOG(log,
+ "pid {0} no lldb breakpoint found at current pc with "
+ "adjustment: {1}",
+ GetID(), breakpoint_addr);
+ return Error();
+ }
+ // If the breakpoint is not a software breakpoint, nothing to do.
+ if (!breakpoint_sp->IsSoftwareBreakpoint()) {
+ LLDB_LOG(
+ log,
+ "pid {0} breakpoint found at {1:x}, not software, nothing to adjust",
+ GetID(), breakpoint_addr);
+ return Error();
+ }
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+ // Sanity check.
+ if (breakpoint_size == 0) {
+ // Nothing to do! How did we get here?
+ LLDB_LOG(log,
+ "pid {0} breakpoint found at {1:x}, it is software, but the "
+ "size is zero, nothing to do (unexpected)",
+ GetID(), breakpoint_addr);
+ return Error();
+ }
+ //
+ // We have a software breakpoint and need to adjust the PC.
+ //
+ // Sanity check.
+ if (breakpoint_size == 0) {
+ // Nothing to do! How did we get here?
+ LLDB_LOG(log,
+ "pid {0} breakpoint found at {1:x}, it is software, but the "
+ "size is zero, nothing to do (unexpected)",
+ GetID(), breakpoint_addr);
+ return Error();
+ }
+ // Change the program counter.
+ LLDB_LOG(log, "pid {0} tid {1}: changing PC from {2:x} to {3:x}", GetID(),
+ thread.GetID(), initial_pc_addr, breakpoint_addr);
+ error = context_sp->SetPC(breakpoint_addr);
+ if (error.Fail()) {
+ LLDB_LOG(log, "pid {0} tid {1}: failed to set PC: {2}", GetID(),
+ thread.GetID(), error);
+ return error;
+ }
+ return error;
+}
+
+Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ const auto &thread_sp = m_threads[0];
+ const ResumeAction *const action =
+ resume_actions.GetActionForThread(thread_sp->GetID(), true);
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread_sp->GetID());
+ return Error();
+ }
+
+ switch (action->state) {
+ case eStateRunning: {
+ // Run the thread, possibly feeding it the signal.
+ Error error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(),
+ (void *)1, action->signal);
+ if (!error.Success())
+ return error;
+ for (const auto &thread_sp : m_threads) {
+ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->SetRunning();
+ }
+ SetState(eStateRunning, true);
+ break;
+ }
+ case eStateStepping:
+ return Error("Not implemented");
+ break;
+
+ case eStateSuspended:
+ case eStateStopped:
+ llvm_unreachable("Unexpected state");
+
+ default:
+ return Error("NativeProcessLinux::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(),
+ thread_sp->GetID());
+ }
+
+ return Error();
+}
+
+Error NativeProcessNetBSD::Halt() {
+ Error error;
+
+ if (kill(GetID(), SIGSTOP) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error NativeProcessNetBSD::Detach() {
+ Error error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID());
+}
+
+Error NativeProcessNetBSD::Signal(int signo) {
+ Error error;
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error NativeProcessNetBSD::Kill() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Error error;
+
+ switch (m_state) {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
+ StateAsCString(m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ if (kill(GetID(), SIGKILL) != 0) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+Error NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Error("unsupported");
+ }
+
+ Error error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ lldb::addr_t prev_base_address = 0;
+ // FIXME start by finding the last region that is <= target address using
+ // binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
+ ++it) {
+ MemoryRegionInfo &proc_entry_info = it->first;
+ // Sanity check assumption that memory map entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending memory map entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+ // If the target address comes before this entry, indicate distance to next
+ // region.
+ if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetByteSize(
+ proc_entry_info.GetRange().GetRangeBase() - load_addr);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+ } else if (proc_entry_info.GetRange().Contains(load_addr)) {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+ // The target memory address comes somewhere after the region we just
+ // parsed.
+ }
+ // If we made it here, we didn't find an entry that contained the given
+ // address. Return the
+ // load_addr as start and the amount of bytes betwwen load address and the end
+ // of the memory as
+ // size.
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Error NativeProcessNetBSD::PopulateMemoryRegionCache() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ // If our cache is empty, pull the latest. There should always be at least
+ // one memory region if memory region handling is supported.
+ if (!m_mem_region_cache.empty()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Error();
+ }
+
+ struct kinfo_vmentry *vm;
+ size_t count, i;
+ vm = kinfo_getvmmap(GetID(), &count);
+ if (vm == NULL) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Error error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ for (i = 0; i < count; i++) {
+ MemoryRegionInfo info;
+ info.Clear();
+ info.GetRange().SetRangeBase(vm[i].kve_start);
+ info.GetRange().SetRangeEnd(vm[i].kve_end);
+ info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ if (vm[i].kve_protection & VM_PROT_READ)
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_WRITE)
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_protection & VM_PROT_EXECUTE)
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (vm[i].kve_path[0])
+ info.SetName(vm[i].kve_path);
+
+ m_mem_region_cache.emplace_back(
+ info, FileSpec(info.GetName().GetCString(), true));
+ }
+ free(vm);
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen.
+ // Assume we don't support map entries.
+ LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
+ "for memory region metadata retrieval");
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ Error error;
+ error.SetErrorString("not supported");
+ return error;
+ }
+ LLDB_LOG(log, "read {0} memory region entries from process {1}",
+ m_mem_region_cache.size(), GetID());
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+ return Error();
+}
+
+Error NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) {
+ return Error("Unimplemented");
+}
+
+Error NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
+ return Error("Unimplemented");
+}
+
+lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
+ // punt on this for now
+ return LLDB_INVALID_ADDRESS;
+}
+
+size_t NativeProcessNetBSD::UpdateThreads() { return m_threads.size(); }
+
+bool NativeProcessNetBSD::GetArchitecture(ArchSpec &arch) const {
+ arch = m_arch;
+ return true;
+}
+
+Error NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return Error("NativeProcessNetBSD does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Error NativeProcessNetBSD::GetSoftwareBreakpointTrapOpcode(
+ size_t trap_opcode_size_hint, size_t &actual_opcode_size,
+ const uint8_t *&trap_opcode_bytes) {
+ static const uint8_t g_i386_opcode[] = {0xCC};
+
+ switch (m_arch.GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ trap_opcode_bytes = g_i386_opcode;
+ actual_opcode_size = sizeof(g_i386_opcode);
+ return Error();
+ default:
+ assert(false && "CPU type not supported!");
+ return Error("CPU type not supported");
+ }
+}
+
+Error NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ return Error("Unimplemented");
+}
+
+Error NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+ return Error();
+}
+
+Error NativeProcessNetBSD::LaunchInferior(MainLoop &mainloop,
+ ProcessLaunchInfo &launch_info) {
+ Error 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);
+
+ /* Initialize threads */
+ struct ptrace_lwpinfo info = {};
+ error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return error;
+ }
+ while (info.pl_lwpid != 0) {
+ NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
+ thread_sp->SetStoppedBySignal(SIGSTOP);
+ error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return error;
+ }
+ }
+
+ /* 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,
+ Error &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.
+ int status;
+ ::pid_t wait_pid = waitpid(GetID(), &status, WALLSIG | WNOHANG);
+
+ if (wait_pid == 0)
+ return; // We are done.
+
+ if (wait_pid == -1) {
+ if (errno == EINTR)
+ return;
+
+ Error error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ }
+
+ bool exited = false;
+ int signal = 0;
+ int exit_status = 0;
+ const char *status_cstr = nullptr;
+ if (WIFSTOPPED(status)) {
+ signal = WSTOPSIG(status);
+ status_cstr = "STOPPED";
+ } else if (WIFEXITED(status)) {
+ exit_status = WEXITSTATUS(status);
+ status_cstr = "EXITED";
+ exited = true;
+ } else if (WIFSIGNALED(status)) {
+ signal = WTERMSIG(status);
+ status_cstr = "SIGNALED";
+ if (wait_pid == static_cast<::pid_t>(GetID())) {
+ exited = true;
+ exit_status = -1;
+ }
+ } else
+ status_cstr = "(\?\?\?)";
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2:x} "
+ "({3}), signal = {4}, exit_state = {5}",
+ GetID(), wait_pid, status, status_cstr, signal, exit_status);
+
+ if (exited)
+ MonitorExited(wait_pid, signal, exit_status);
+ else
+ MonitorCallback(wait_pid, signal);
+}
+
+NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(!HasThreadNoLock(thread_id) &&
+ "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty())
+ SetCurrentThreadID(thread_id);
+
+ auto thread_sp = std::make_shared<NativeThreadNetBSD>(this, thread_id);
+ m_threads.push_back(thread_sp);
+ return thread_sp;
+}
+
+::pid_t NativeProcessNetBSD::Attach(lldb::pid_t pid, Error &error) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // 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;
+ }
+
+ // 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;
+
+ int status;
+ // 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;
+
+ /* Initialize threads */
+ struct ptrace_lwpinfo info = {};
+ error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return -1;
+ }
+ while (info.pl_lwpid != 0) {
+ NativeThreadNetBSDSP thread_sp = AddThread(info.pl_lwpid);
+ thread_sp->SetStoppedBySignal(SIGSTOP);
+ error = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return -1;
+ }
+ }
+
+ // Let our process instance know the thread has stopped.
+ SetState(StateType::eStateStopped);
+
+ return pid;
+}
+
+Error NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Error error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail())
+ return error;
+
+ bytes_read = io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Error();
+}
+
+Error NativeProcessNetBSD::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
+ size_t size,
+ size_t &bytes_read) {
+ Error error = ReadMemory(addr, buf, size, bytes_read);
+ if (error.Fail())
+ return error;
+ return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size);
+}
+
+Error NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ const unsigned char *src = static_cast<const unsigned char *>(buf);
+ Error error;
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr = (void *)(src + bytes_written);
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Error error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail())
+ return error;
+
+ bytes_written = io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return error;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessNetBSD::GetAuxvData() const {
+ /*
+ * ELF_AUX_ENTRIES is currently restricted to kernel
+ * (<sys/exec_elf.h> r. 1.155 specifies 15)
+ *
+ * ptrace(2) returns the whole AUXV including extra fiels after AT_NULL this
+ * information isn't needed.
+ */
+ size_t auxv_size = 100 * sizeof(AuxInfo);
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> buf =
+ llvm::MemoryBuffer::getNewMemBuffer(auxv_size);
+
+ struct ptrace_io_desc io = {.piod_op = PIOD_READ_AUXV,
+ .piod_offs = 0,
+ .piod_addr = (void *)buf.get()->getBufferStart(),
+ .piod_len = auxv_size};
+
+ Error error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
+
+ if (error.Fail())
+ return std::error_code(error.GetError(), std::generic_category());
+
+ if (io.piod_len < 1)
+ return std::error_code(ECANCELED, std::generic_category());
+
+ return buf;
+}
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 3d54c333f34..8463220e61e 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -39,8 +39,98 @@ class NativeProcessNetBSD : public NativeProcessProtocol {
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
+public:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol Interface
+ // ---------------------------------------------------------------------
+ Error Resume(const ResumeActionList &resume_actions) override;
+
+ Error Halt() override;
+
+ Error Detach() override;
+
+ Error Signal(int signo) override;
+
+ Error Kill() override;
+
+ Error GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Error ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Error ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Error WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ Error AllocateMemory(size_t size, uint32_t permissions,
+ lldb::addr_t &addr) override;
+
+ Error DeallocateMemory(lldb::addr_t addr) override;
+
+ lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+ size_t UpdateThreads() override;
+
+ bool GetArchitecture(ArchSpec &arch) const override;
+
+ Error SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override;
+
+ Error GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+
+ Error GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // ---------------------------------------------------------------------
+ // Interface used by NativeRegisterContext-derived classes.
+ // ---------------------------------------------------------------------
+ static Error PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+
+protected:
+ // ---------------------------------------------------------------------
+ // NativeProcessProtocol protected interface
+ // ---------------------------------------------------------------------
+
+ Error
+ GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
+ size_t &actual_opcode_size,
+ const uint8_t *&trap_opcode_bytes) override;
+
private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ LazyBool m_supports_mem_region;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ // ---------------------------------------------------------------------
+ // Private Instance Methods
+ // ---------------------------------------------------------------------
NativeProcessNetBSD();
+
+ NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id);
+
+ Error LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info);
+ void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error &error);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, int signal, int status);
+ void MonitorSIGSTOP(lldb::pid_t pid);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+
+ Error GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
+ Error FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread);
+ Error PopulateMemoryRegionCache();
+ void SigchldHandler();
+
+ ::pid_t Attach(lldb::pid_t pid, Error &error);
};
} // namespace process_netbsd
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
index 836004879f8..009f82b1737 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -9,11 +9,58 @@
#include "NativeRegisterContextNetBSD.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
using namespace lldb_private;
using namespace lldb_private::process_netbsd;
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx,
RegisterInfoInterface *reg_info_interface_p)
: NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx,
reg_info_interface_p) {}
+
+Error NativeRegisterContextNetBSD::ReadGPR() {
+ void *buf = GetGPRBuffer();
+ if (!buf)
+ return Error("GPR buffer is NULL");
+
+ return DoReadGPR(buf);
+}
+
+Error NativeRegisterContextNetBSD::WriteGPR() {
+ void *buf = GetGPRBuffer();
+ if (!buf)
+ return Error("GPR buffer is NULL");
+
+ return DoWriteGPR(buf);
+}
+
+Error NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+Error NativeRegisterContextNetBSD::DoWriteGPR(void *buf) {
+ return NativeProcessNetBSD::PtraceWrapper(PT_SETREGS, GetProcessPid(), buf,
+ m_thread.GetID());
+}
+
+NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
+ auto process_sp =
+ std::static_pointer_cast<NativeProcessNetBSD>(m_thread.GetProcess());
+ assert(process_sp);
+ return *process_sp;
+}
+
+::pid_t NativeRegisterContextNetBSD::GetProcessPid() {
+ NativeProcessNetBSD &process = GetProcess();
+ lldb::pid_t pid = process.GetID();
+
+ return pid;
+}
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
index 1de59db4dd9..9834acb6f93 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -33,6 +33,19 @@ public:
CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread,
uint32_t concrete_frame_idx);
+
+protected:
+ virtual Error ReadGPR();
+ virtual Error WriteGPR();
+ virtual void *GetGPRBuffer() { return nullptr; }
+ virtual size_t GetGPRSize() {
+ return GetRegisterInfoInterface().GetGPRSize();
+ }
+ virtual Error DoReadGPR(void *buf);
+ virtual Error DoWriteGPR(void *buf);
+
+ virtual NativeProcessNetBSD &GetProcess();
+ virtual ::pid_t GetProcessPid();
};
} // namespace process_netbsd
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
new file mode 100644
index 00000000000..0dcdcc9ca34
--- /dev/null
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -0,0 +1,477 @@
+//===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__x86_64__)
+
+#include "NativeRegisterContextNetBSD_x86_64.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Error.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
+
+#include <elf.h>
+
+using namespace lldb_private;
+using namespace lldb_private::process_netbsd;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace {
+// x86 64-bit general purpose registers.
+static const uint32_t g_gpr_regnums_x86_64[] = {
+ lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64,
+ lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64,
+ lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64,
+ lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64,
+ lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64,
+ lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64,
+ lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64,
+ lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits or r8
+ lldb_r9d_x86_64, // Low 32 bits or r9
+ lldb_r10d_x86_64, // Low 32 bits or r10
+ lldb_r11d_x86_64, // Low 32 bits or r11
+ lldb_r12d_x86_64, // Low 32 bits or r12
+ lldb_r13d_x86_64, // Low 32 bits or r13
+ lldb_r14d_x86_64, // Low 32 bits or r14
+ lldb_r15d_x86_64, // Low 32 bits or r15
+ lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64,
+ lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits or r8
+ lldb_r9w_x86_64, // Low 16 bits or r9
+ lldb_r10w_x86_64, // Low 16 bits or r10
+ lldb_r11w_x86_64, // Low 16 bits or r11
+ lldb_r12w_x86_64, // Low 16 bits or r12
+ lldb_r13w_x86_64, // Low 16 bits or r13
+ lldb_r14w_x86_64, // Low 16 bits or r14
+ lldb_r15w_x86_64, // Low 16 bits or r15
+ lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64,
+ lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64,
+ lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits or r8
+ lldb_r9l_x86_64, // Low 8 bits or r9
+ lldb_r10l_x86_64, // Low 8 bits or r10
+ lldb_r11l_x86_64, // Low 8 bits or r11
+ lldb_r12l_x86_64, // Low 8 bits or r12
+ lldb_r13l_x86_64, // Low 8 bits or r13
+ lldb_r14l_x86_64, // Low 8 bits or r14
+ lldb_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_gpr_registers_x86_64,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 };
+
+// Register sets for x86 64-bit.
+static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
+ g_gpr_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+
+} // namespace
+
+NativeRegisterContextNetBSD *
+NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx) {
+ return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread,
+ concrete_frame_idx);
+}
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextNetBSD_x86_64 members.
+// ----------------------------------------------------------------------------
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
+ // x86_64 register context.
+ return new RegisterContextNetBSD_x86_64(target_arch);
+}
+
+NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx)
+ : NativeRegisterContextNetBSD(native_thread, concrete_frame_idx,
+ CreateRegisterInfoInterface(target_arch)),
+ m_gpr_x86_64() {}
+
+// CONSIDER after local and llgs debugging are merged, register set support can
+// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
+uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
+ uint32_t sets = 0;
+ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
+ if (GetSetForNativeRegNum(set_index) != -1)
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set_index];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
+int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
+ int reg_num) const {
+ if (reg_num < lldb_fctrl_x86_64)
+ return GPRegSet;
+ else
+ return -1;
+}
+
+int NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
+ switch (set) {
+ case GPRegSet:
+ ReadGPR();
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+int NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
+ switch (set) {
+ case GPRegSet:
+ WriteGPR();
+ return 0;
+ default:
+ break;
+ }
+ return -1;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::ReadRegister(
+ const RegisterInfo *reg_info, RegisterValue &reg_value) {
+ Error error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ int set = GetSetForNativeRegNum(reg);
+ if (set == -1) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ if (ReadRegisterSet(set) != 0) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat(
+ "reading register set for register \"%s\" failed", reg_info->name);
+ return error;
+ }
+
+ switch (reg) {
+ case lldb_rax_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
+ break;
+ case lldb_rbx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
+ break;
+ case lldb_rcx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
+ break;
+ case lldb_rdx_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
+ break;
+ case lldb_rdi_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
+ break;
+ case lldb_rsi_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
+ break;
+ case lldb_rbp_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
+ break;
+ case lldb_rsp_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
+ break;
+ case lldb_r8_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
+ break;
+ case lldb_r9_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
+ break;
+ case lldb_r10_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
+ break;
+ case lldb_r11_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
+ break;
+ case lldb_r12_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
+ break;
+ case lldb_r13_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
+ break;
+ case lldb_r14_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
+ break;
+ case lldb_r15_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
+ break;
+ case lldb_rip_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
+ break;
+ case lldb_rflags_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
+ break;
+ case lldb_cs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
+ break;
+ case lldb_fs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
+ break;
+ case lldb_gs_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
+ break;
+ case lldb_ss_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
+ break;
+ case lldb_ds_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
+ break;
+ case lldb_es_x86_64:
+ reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
+ break;
+ }
+
+ return error;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+ Error error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ int set = GetSetForNativeRegNum(reg);
+ if (set == -1) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ if (ReadRegisterSet(set) != 0) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat(
+ "reading register set for register \"%s\" failed", reg_info->name);
+ return error;
+ }
+
+ switch (reg) {
+ case lldb_rax_x86_64:
+ m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbx_x86_64:
+ m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rcx_x86_64:
+ m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdx_x86_64:
+ m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rdi_x86_64:
+ m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsi_x86_64:
+ m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rbp_x86_64:
+ m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rsp_x86_64:
+ m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r8_x86_64:
+ m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r9_x86_64:
+ m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r10_x86_64:
+ m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r11_x86_64:
+ m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r12_x86_64:
+ m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r13_x86_64:
+ m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r14_x86_64:
+ m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
+ break;
+ case lldb_r15_x86_64:
+ m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rip_x86_64:
+ m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
+ break;
+ case lldb_rflags_x86_64:
+ m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_cs_x86_64:
+ m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_fs_x86_64:
+ m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_gs_x86_64:
+ m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_ss_x86_64:
+ m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_ds_x86_64:
+ m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
+ break;
+ case lldb_es_x86_64:
+ m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
+ break;
+ }
+
+ if (WriteRegisterSet(set) != 0)
+ error.SetErrorStringWithFormat("failed to write register set");
+
+ return error;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
+ lldb::DataBufferSP &data_sp) {
+ Error error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "failed to allocate DataBufferHeap instance of size %" PRIu64,
+ REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ error = ReadGPR();
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ if (dst == nullptr) {
+ error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
+ " returned a null pointer",
+ REG_CONTEXT_SIZE);
+ return error;
+ }
+
+ ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
+ dst += GetRegisterInfoInterface().GetGPRSize();
+
+ RegisterValue value((uint64_t)-1);
+ const RegisterInfo *reg_info =
+ GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
+ if (reg_info == nullptr)
+ reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
+ return error;
+}
+
+Error NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Error error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
+ "data size, expected %" PRIu64 ", actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
+
+ error = WriteGPR();
+ if (error.Fail())
+ return error;
+ src += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+#endif // defined(__x86_64__)
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
new file mode 100644
index 00000000000..3166d96d0a4
--- /dev/null
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -0,0 +1,70 @@
+//===-- NativeRegisterContextNetBSD_x86_64.h --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+#define lldb_NativeRegisterContextNetBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+namespace lldb_private {
+namespace process_netbsd {
+
+class NativeProcessNetBSD;
+
+class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD {
+public:
+ NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread,
+ uint32_t concrete_frame_idx);
+ uint32_t GetRegisterSetCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Error ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Error WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Error ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+ Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+protected:
+ void *GetGPRBuffer() override { return &m_gpr_x86_64; }
+
+private:
+ // Private member types.
+ enum { GPRegSet };
+
+ // Private member variables.
+ struct reg m_gpr_x86_64;
+
+ int GetSetForNativeRegNum(int reg_num) const;
+
+ int ReadRegisterSet(uint32_t set);
+ int WriteRegisterSet(uint32_t set);
+};
+
+} // namespace process_netbsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
+
+#endif // defined(__x86_64__)
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
index 1646337150b..8493e98e3d0 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -12,10 +12,131 @@
#include "NativeProcessNetBSD.h"
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_netbsd;
NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD *process,
lldb::tid_t tid)
- : NativeThreadProtocol(process, tid) {}
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(), m_reg_context_sp(), m_stop_description() {}
+
+void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = signo;
+
+ m_stop_description.clear();
+ if (info) {
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ const auto reason = GetCrashReason(*info);
+ m_stop_description = GetCrashReasonString(reason, *info);
+ break;
+ }
+ }
+}
+
+void NativeThreadNetBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadNetBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadNetBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadNetBSD::GetName() { return std::string(""); }
+
+lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
+
+bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextSP NativeThreadNetBSD::GetRegisterContext() {
+ // Return the register context if we already created it.
+ if (m_reg_context_sp)
+ return m_reg_context_sp;
+
+ NativeProcessProtocolSP m_process_sp = m_process_wp.lock();
+ if (!m_process_sp)
+ return NativeRegisterContextSP();
+
+ ArchSpec target_arch;
+ if (!m_process_sp->GetArchitecture(target_arch))
+ return NativeRegisterContextSP();
+
+ const uint32_t concrete_frame_idx = 0;
+ m_reg_context_sp.reset(
+ NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
+ target_arch, *this, concrete_frame_idx));
+
+ return m_reg_context_sp;
+}
+
+Error NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ return Error("Unimplemented");
+}
+
+Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ return Error("Unimplemented");
+}
+
+Error NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ return Error("Unimplemented");
+}
+
+Error NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ return Error("Unimplemented");
+}
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
index bf2d9a49477..94d3830894d 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -22,6 +22,45 @@ class NativeThreadNetBSD : public NativeThreadProtocol {
public:
NativeThreadNetBSD(NativeProcessNetBSD *process, lldb::tid_t tid);
+
+ // ---------------------------------------------------------------------
+ // NativeThreadProtocol Interface
+ // ---------------------------------------------------------------------
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextSP GetRegisterContext() override;
+
+ Error SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Error RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Error SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Error RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+ // ---------------------------------------------------------------------
+ // Interface for friend classes
+ // ---------------------------------------------------------------------
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+ void SetStoppedByBreakpoint();
+ void SetStopped();
+ void SetRunning();
+
+ // ---------------------------------------------------------------------
+ // Member Variables
+ // ---------------------------------------------------------------------
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ NativeRegisterContextSP m_reg_context_sp;
+ std::string m_stop_description;
};
typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
OpenPOWER on IntegriCloud