pkgsrc-WIP-changes archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lldb-netbsd: Add NetBSDProcess, a clone of LinuxProcessPlugin
Module Name: pkgsrc-wip
Committed By: Kamil Rytarowski <n54%gmx.com@localhost>
Pushed By: kamil
Date: Sat Dec 17 14:03:15 2016 +0100
Changeset: 45ac397da8dcac1a37fbb79d91e4e13683ce70fc
Modified Files:
lldb-netbsd/distinfo
Added Files:
lldb-netbsd/patches/patch-cmake_LLDBDependencies.cmake
lldb-netbsd/patches/patch-source_CMakeLists.txt
lldb-netbsd/patches/patch-source_Plugins_Process_CMakeLists.txt
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_Procfs.h
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.cpp
lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.h
lldb-netbsd/patches/patch-tools_lldb-server_CMakeLists.txt
Log Message:
lldb-netbsd: Add NetBSDProcess, a clone of LinuxProcessPlugin
Nothing builds so far, it's a commit with a starting point to port it to
NetBSD, as it's a raw copy of the Linux Process Plugin files.
Include only the x86_64 CPU now.
Sponsored by <The NetBSD Foundation>
To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=45ac397da8dcac1a37fbb79d91e4e13683ce70fc
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
diffstat:
lldb-netbsd/distinfo | 18 +
.../patches/patch-cmake_LLDBDependencies.cmake | 12 +
lldb-netbsd/patches/patch-source_CMakeLists.txt | 12 +
.../patch-source_Plugins_Process_CMakeLists.txt | 12 +
...ch-source_Plugins_Process_NetBSD_CMakeLists.txt | 17 +
..._Plugins_Process_NetBSD_NativeProcessNetBSD.cpp | 2761 ++++++++++++++++++++
...ce_Plugins_Process_NetBSD_NativeProcessNetBSD.h | 230 ++
..._Process_NetBSD_NativeRegisterContextNetBSD.cpp | 218 ++
...ns_Process_NetBSD_NativeRegisterContextNetBSD.h | 97 +
...NetBSD_NativeRegisterContextNetBSD__x86__64.cpp | 1226 +++++++++
...s_NetBSD_NativeRegisterContextNetBSD__x86__64.h | 151 ++
...e_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp | 486 ++++
...rce_Plugins_Process_NetBSD_NativeThreadNetBSD.h | 122 +
...ource_Plugins_Process_NetBSD_ProcFileReader.cpp | 108 +
...-source_Plugins_Process_NetBSD_ProcFileReader.h | 42 +
.../patch-source_Plugins_Process_NetBSD_Procfs.h | 36 +
...urce_Plugins_Process_NetBSD_SingleStepCheck.cpp | 171 ++
...source_Plugins_Process_NetBSD_SingleStepCheck.h | 45 +
.../patches/patch-tools_lldb-server_CMakeLists.txt | 27 +
19 files changed, 5791 insertions(+)
diffs:
diff --git a/lldb-netbsd/distinfo b/lldb-netbsd/distinfo
index a4de524..9472177 100644
--- a/lldb-netbsd/distinfo
+++ b/lldb-netbsd/distinfo
@@ -12,8 +12,26 @@ Size (libcxx-3.6.2.src.tar.xz) = 944020 bytes
SHA1 (llvm-3.6.2.src.tar.xz) = 7a00257eb2bc9431e4c77c3a36b033072c54bc7e
RMD160 (llvm-3.6.2.src.tar.xz) = 521cbc5fe2925ea3c6e90c7a31f752a04045c972
Size (llvm-3.6.2.src.tar.xz) = 12802380 bytes
+SHA1 (patch-cmake_LLDBDependencies.cmake) = 81673d8624ca7a9ad60bcaf530587fbfbd695dca
+SHA1 (patch-source_CMakeLists.txt) = 5dacabc3f39c23bdfd432b5a4895866157b97aa0
+SHA1 (patch-source_Plugins_Process_CMakeLists.txt) = c0168f81da56d9896eb414e6b8bb7262de04ac33
+SHA1 (patch-source_Plugins_Process_NetBSD_CMakeLists.txt) = 91366fe224db18c87d0f00d0b1617ad97b6523c6
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.cpp) = b2b7f04a9287fda1b4208dbd669a3fdf76dce94a
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.h) = 6cdb3ff974c63f8a22027e25e8a4991629948707
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.cpp) = 39aa59226470589fdab5d2f62a7297f580328ebb
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.h) = 9be389183d8dbb588f29a283811781d13c2f049c
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.cpp) = 765a54e7c31108297316f8b8ffb2c5f0fb243aac
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.h) = 5dc6da570d43f5c832ec13f6487305f1feda5e93
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp) = dcc5a330c4fdfdd48d7ae1d317f11f24c287bd02
+SHA1 (patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.h) = d0536fd2d157e360cd4949fc1b1212a55833a5a9
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcFileReader.cpp) = 10d9511387fe5be20d8a0560fbee8d49ad00b255
+SHA1 (patch-source_Plugins_Process_NetBSD_ProcFileReader.h) = 88dd0aa5b61344458f759346211541bf5f660525
+SHA1 (patch-source_Plugins_Process_NetBSD_Procfs.h) = 464221c6e839ecd3b06d612f3e815933f7f11789
+SHA1 (patch-source_Plugins_Process_NetBSD_SingleStepCheck.cpp) = 7abe72717518912256fc80d72c6102ead505b6ee
+SHA1 (patch-source_Plugins_Process_NetBSD_SingleStepCheck.h) = 79752a7a54b1aef5951b7dc92ab7df0396c1b412
SHA1 (patch-tools_lldb-mi_MICmnBase.cpp) = 851c82ac61e1241018755fbd7236af00379ac986
SHA1 (patch-tools_lldb-mi_MICmnBase.h) = f550d5e10bcf02fb46472733acdbb820791f22e5
SHA1 (patch-tools_lldb-mi_MIDriver.cpp) = bf1b5399e82bcfe54d6d852f64ed155328f2064d
SHA1 (patch-tools_lldb-mi_MIUtilString.cpp) = 200d9712753b5559da79c2e16fa0889fea1e9432
SHA1 (patch-tools_lldb-mi_MIUtilString.h) = 7e7befec383f88502a97aec509ba39477efde37d
+SHA1 (patch-tools_lldb-server_CMakeLists.txt) = 39a390a7598bc0028a8a93cb512af2050ee7718f
diff --git a/lldb-netbsd/patches/patch-cmake_LLDBDependencies.cmake b/lldb-netbsd/patches/patch-cmake_LLDBDependencies.cmake
new file mode 100644
index 0000000..5ff4868
--- /dev/null
+++ b/lldb-netbsd/patches/patch-cmake_LLDBDependencies.cmake
@@ -0,0 +1,12 @@
+$NetBSD$
+
+--- cmake/LLDBDependencies.cmake.orig 2016-12-17 10:34:01.000000000 +0000
++++ cmake/LLDBDependencies.cmake
+@@ -115,6 +115,7 @@ endif ()
+ # NetBSD-only libraries
+ if ( CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
+ list(APPEND LLDB_USED_LIBS
++ lldbPluginProcessNetBSD
+ lldbPluginProcessPOSIX
+ )
+ endif ()
diff --git a/lldb-netbsd/patches/patch-source_CMakeLists.txt b/lldb-netbsd/patches/patch-source_CMakeLists.txt
new file mode 100644
index 0000000..4ddfea5
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_CMakeLists.txt
@@ -0,0 +1,12 @@
+$NetBSD$
+
+--- source/CMakeLists.txt.orig 2016-12-17 10:30:34.000000000 +0000
++++ source/CMakeLists.txt
+@@ -16,6 +16,7 @@ endif ()
+
+ if ( CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
+ include_directories(
++ Plugins/Process/NetBSD
+ Plugins/Process/POSIX
+ )
+ endif ()
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_CMakeLists.txt b/lldb-netbsd/patches/patch-source_Plugins_Process_CMakeLists.txt
new file mode 100644
index 0000000..af967f1
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_CMakeLists.txt
@@ -0,0 +1,12 @@
+$NetBSD$
+
+--- source/Plugins/Process/CMakeLists.txt.orig 2016-12-17 10:30:06.000000000 +0000
++++ source/Plugins/Process/CMakeLists.txt
+@@ -5,6 +5,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeB
+ add_subdirectory(FreeBSD)
+ add_subdirectory(POSIX)
+ elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
++ add_subdirectory(NetBSD)
+ add_subdirectory(POSIX)
+ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
+ add_subdirectory(Windows/Common)
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
new file mode 100644
index 0000000..b862bd8
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_CMakeLists.txt
@@ -0,0 +1,17 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/CMakeLists.txt.orig 2016-12-17 13:00:53.140016397 +0000
++++ source/Plugins/Process/NetBSD/CMakeLists.txt
+@@ -0,0 +1,12 @@
++include_directories(.)
++include_directories(../POSIX)
++include_directories(../Utility)
++
++add_lldb_library(lldbPluginProcessNetBSD
++ NativeProcessNetBSD.cpp
++ NativeRegisterContextNetBSD.cpp
++ NativeRegisterContextNetBSD_x86_64.cpp
++ NativeThreadNetBSD.cpp
++ ProcFileReader.cpp
++ SingleStepCheck.cpp
++ )
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.cpp
new file mode 100644
index 0000000..508b7a9
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.cpp
@@ -0,0 +1,2761 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp.orig 2016-12-17 13:00:53.143603907 +0000
++++ source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+@@ -0,0 +1,2756 @@
++//===-- NativeProcessNetBSD.cpp -------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#include "NativeProcessNetBSD.h"
++
++// C Includes
++#include <errno.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++
++// C++ Includes
++#include <fstream>
++#include <mutex>
++#include <sstream>
++#include <string>
++#include <unordered_map>
++
++// Other libraries and framework includes
++#include "lldb/Core/EmulateInstruction.h"
++#include "lldb/Core/Error.h"
++#include "lldb/Core/ModuleSpec.h"
++#include "lldb/Core/RegisterValue.h"
++#include "lldb/Core/State.h"
++#include "lldb/Host/Host.h"
++#include "lldb/Host/HostProcess.h"
++#include "lldb/Host/ThreadLauncher.h"
++#include "lldb/Host/common/NativeBreakpoint.h"
++#include "lldb/Host/common/NativeRegisterContext.h"
++#include "lldb/Host/linux/ProcessLauncherNetBSD.h"
++#include "lldb/Symbol/ObjectFile.h"
++#include "lldb/Target/Process.h"
++#include "lldb/Target/ProcessLaunchInfo.h"
++#include "lldb/Target/Target.h"
++#include "lldb/Utility/LLDBAssert.h"
++#include "lldb/Utility/PseudoTerminal.h"
++#include "lldb/Utility/StringExtractor.h"
++
++#include "NativeThreadNetBSD.h"
++#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
++#include "ProcFileReader.h"
++#include "Procfs.h"
++
++// System includes - They have to be included after framework includes because
++// they define some
++// macros which collide with variable names in other modules
++#include <linux/unistd.h>
++#include <sys/socket.h>
++
++#include <sys/syscall.h>
++#include <sys/types.h>
++#include <sys/user.h>
++#include <sys/wait.h>
++
++#include "lldb/Host/linux/Ptrace.h"
++#include "lldb/Host/linux/Uio.h"
++
++// Support hardware breakpoints in case it has not been defined
++#ifndef TRAP_HWBKPT
++#define TRAP_HWBKPT 4
++#endif
++
++using namespace lldb;
++using namespace lldb_private;
++using namespace lldb_private::process_linux;
++using namespace llvm;
++
++// Private bits we only need internally.
++
++static bool ProcessVmReadvSupported() {
++ static bool is_supported;
++ static std::once_flag flag;
++
++ std::call_once(flag, [] {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++
++ uint32_t source = 0x47424742;
++ uint32_t dest = 0;
++
++ struct iovec local, remote;
++ remote.iov_base = &source;
++ local.iov_base = &dest;
++ remote.iov_len = local.iov_len = sizeof source;
++
++ // We shall try if cross-process-memory reads work by attempting to read a
++ // value from our own process.
++ ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
++ is_supported = (res == sizeof(source) && source == dest);
++ if (log) {
++ if (is_supported)
++ log->Printf("%s: Detected kernel support for process_vm_readv syscall. "
++ "Fast memory reads enabled.",
++ __FUNCTION__);
++ else
++ log->Printf("%s: syscall process_vm_readv failed (error: %s). Fast "
++ "memory reads disabled.",
++ __FUNCTION__, strerror(errno));
++ }
++ });
++
++ return is_supported;
++}
++
++namespace {
++void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (!log)
++ return;
++
++ if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO))
++ log->Printf("%s: setting STDIN to '%s'", __FUNCTION__,
++ action->GetFileSpec().GetCString());
++ else
++ log->Printf("%s leaving STDIN as is", __FUNCTION__);
++
++ if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO))
++ log->Printf("%s setting STDOUT to '%s'", __FUNCTION__,
++ action->GetFileSpec().GetCString());
++ else
++ log->Printf("%s leaving STDOUT as is", __FUNCTION__);
++
++ if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO))
++ log->Printf("%s setting STDERR to '%s'", __FUNCTION__,
++ action->GetFileSpec().GetCString());
++ else
++ log->Printf("%s leaving STDERR as is", __FUNCTION__);
++
++ int i = 0;
++ for (const char **args = info.GetArguments().GetConstArgumentVector(); *args;
++ ++args, ++i)
++ log->Printf("%s arg %d: \"%s\"", __FUNCTION__, i,
++ *args ? *args : "nullptr");
++}
++
++void DisplayBytes(StreamString &s, void *bytes, uint32_t count) {
++ uint8_t *ptr = (uint8_t *)bytes;
++ const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count);
++ for (uint32_t i = 0; i < loop_count; i++) {
++ s.Printf("[%x]", *ptr);
++ ptr++;
++ }
++}
++
++void PtraceDisplayBytes(int &req, void *data, size_t data_size) {
++ StreamString buf;
++ Log *verbose_log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(
++ POSIX_LOG_PTRACE | POSIX_LOG_VERBOSE));
++
++ if (verbose_log) {
++ switch (req) {
++ case PTRACE_POKETEXT: {
++ DisplayBytes(buf, &data, 8);
++ verbose_log->Printf("PTRACE_POKETEXT %s", buf.GetData());
++ break;
++ }
++ case PTRACE_POKEDATA: {
++ DisplayBytes(buf, &data, 8);
++ verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData());
++ break;
++ }
++ case PTRACE_POKEUSER: {
++ DisplayBytes(buf, &data, 8);
++ verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData());
++ break;
++ }
++ case PTRACE_SETREGS: {
++ DisplayBytes(buf, data, data_size);
++ verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData());
++ break;
++ }
++ case PTRACE_SETFPREGS: {
++ DisplayBytes(buf, data, data_size);
++ verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData());
++ break;
++ }
++ case PTRACE_SETSIGINFO: {
++ DisplayBytes(buf, data, sizeof(siginfo_t));
++ verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData());
++ break;
++ }
++ case PTRACE_SETREGSET: {
++ // Extract iov_base from data, which is a pointer to the struct IOVEC
++ DisplayBytes(buf, *(void **)data, data_size);
++ verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData());
++ break;
++ }
++ default: {}
++ }
++ }
++}
++
++static constexpr unsigned k_ptrace_word_size = sizeof(void *);
++static_assert(sizeof(long) >= k_ptrace_word_size,
++ "Size of long must be larger than ptrace word size");
++} // end of anonymous namespace
++
++// 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
++// -----------------------------------------------------------------------------
++
++Error NativeProcessProtocol::Launch(
++ ProcessLaunchInfo &launch_info,
++ NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop,
++ NativeProcessProtocolSP &native_process_sp) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_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() ||
++ working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) {
++ 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();
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s failed to launch process: %s",
++ __FUNCTION__, error.AsCString());
++ 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) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
++ log->Printf("NativeProcessNetBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, 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_linux_sp(
++ new NativeProcessNetBSD());
++
++ 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;
++}
++
++// -----------------------------------------------------------------------------
++// Public Instance Methods
++// -----------------------------------------------------------------------------
++
++NativeProcessNetBSD::NativeProcessNetBSD()
++ : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID), m_arch(),
++ m_supports_mem_region(eLazyBoolCalculate), m_mem_region_cache(),
++ m_pending_notification_tid(LLDB_INVALID_THREAD_ID) {}
++
++void NativeProcessNetBSD::AttachToInferior(MainLoop &mainloop, lldb::pid_t pid,
++ Error &error) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (pid = %" PRIi64 ")", __FUNCTION__,
++ 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.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (pid = %" PRIi64
++ ") detected architecture %s",
++ __FUNCTION__, pid, m_arch.GetArchitectureName());
++
++ m_pid = pid;
++ SetState(eStateAttaching);
++
++ Attach(pid, 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);
++
++ MaybeLogLaunchInfo(launch_info);
++
++ ::pid_t pid =
++ ProcessLauncherNetBSD().LaunchProcess(launch_info, error).GetProcessId();
++ if (error.Fail())
++ return error;
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_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();
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s waitpid for inferior failed with %s",
++ __FUNCTION__, error.AsCString());
++
++ // 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.");
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s inferior started, now in stopped state",
++ __FUNCTION__);
++
++ error = SetDefaultPtraceOpts(pid);
++ if (error.Fail()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s inferior failed to set default "
++ "ptrace options: %s",
++ __FUNCTION__, error.AsCString());
++
++ // 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
++ // 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()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s inferior EnsureFDFlags failed for "
++ "ensuring terminal O_NONBLOCK setting: %s",
++ __FUNCTION__, error.AsCString());
++
++ // Mark the inferior as invalid.
++ // FIXME this could really use a new state - eStateLaunchFailure. For
++ // now, using eStateInvalid.
++ SetState(StateType::eStateInvalid);
++
++ return error;
++ }
++ }
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() adding pid = %" PRIu64, __FUNCTION__,
++ uint64_t(pid));
++
++ ResolveProcessArchitecture(m_pid, m_arch);
++ NativeThreadNetBSDSP 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);
++
++ if (log) {
++ if (error.Success())
++ log->Printf("NativeProcessNetBSD::%s inferior launching succeeded",
++ __FUNCTION__);
++ else
++ log->Printf("NativeProcessNetBSD::%s inferior launching failed: %s",
++ __FUNCTION__, error.AsCString());
++ }
++ return error;
++}
++
++::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;
++ }
++
++ while (Host::FindProcessThreads(pid, tids_to_attach)) {
++ for (Host::TidMap::iterator it = tids_to_attach.begin();
++ it != tids_to_attach.end();) {
++ if (it->second == false) {
++ lldb::tid_t tid = it->first;
++
++ // Attach to the requested process.
++ // An attach will cause the thread to stop with a SIGSTOP.
++ error = PtraceWrapper(PTRACE_ATTACH, tid);
++ if (error.Fail()) {
++ // No such thread. The thread may have exited.
++ // More error handling may be needed.
++ if (error.GetError() == ESRCH) {
++ it = tids_to_attach.erase(it);
++ continue;
++ } else
++ return -1;
++ }
++
++ int status;
++ // 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) {
++ // 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;
++ }
++ }
++
++ error = SetDefaultPtraceOpts(tid);
++ if (error.Fail())
++ return -1;
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() adding tid = %" PRIu64,
++ __FUNCTION__, tid);
++
++ it->second = true;
++
++ // Create the thread, mark it as stopped.
++ NativeThreadNetBSDSP 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
++ ++it;
++ }
++ }
++
++ 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;
++ }
++
++ return pid;
++}
++
++Error NativeProcessNetBSD::SetDefaultPtraceOpts(lldb::pid_t pid) {
++ long ptrace_opts = 0;
++
++ // Have the child raise an event on exit. This is used to keep the child in
++ // limbo until it is destroyed.
++ ptrace_opts |= PTRACE_O_TRACEEXIT;
++
++ // Have the tracer trace threads which spawn in the inferior process.
++ // TODO: if we want to support tracing the inferiors' child, add the
++ // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
++ ptrace_opts |= PTRACE_O_TRACECLONE;
++
++ // Have the tracer notify us before execve returns
++ // (needed to disable legacy SIGTRAP generation)
++ ptrace_opts |= PTRACE_O_TRACEEXEC;
++
++ return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts);
++}
++
++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;
++ }
++}
++
++// Handles all waitpid events from the inferior process.
++void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, bool exited,
++ int signal, int status) {
++ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
++
++ // Certain activities differ based on whether the pid is the tid of the main
++ // thread.
++ const bool is_main_thread = (pid == GetID());
++
++ // Handle when the thread exits.
++ if (exited) {
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s() got exit signal(%d) , tid = %" PRIu64
++ " (%s main thread)",
++ __FUNCTION__, signal, pid, is_main_thread ? "is" : "is not");
++
++ // This is a thread that exited. Ensure we're not tracking it anymore.
++ const bool thread_found = StopTrackingThread(pid);
++
++ if (is_main_thread) {
++ // We only set the exit status and notify the delegate if we haven't
++ // already set the process
++ // state to an exited state. We normally should have received a SIGTRAP |
++ // (PTRACE_EVENT_EXIT << 8)
++ // for the main thread.
++ const bool already_notified = (GetState() == StateType::eStateExited) ||
++ (GetState() == StateType::eStateCrashed);
++ if (!already_notified) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() tid = %" PRIu64
++ " handling main thread exit (%s), expected exit state "
++ "already set but state was %s instead, setting exit "
++ "state now",
++ __FUNCTION__, pid,
++ thread_found ? "stopped tracking thread metadata"
++ : "thread metadata not found",
++ StateAsCString(GetState()));
++ // The main thread exited. We're done monitoring. Report to delegate.
++ 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);
++ } else {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() tid = %" PRIu64
++ " main thread now exited (%s)",
++ __FUNCTION__, pid,
++ thread_found ? "stopped tracking thread metadata"
++ : "thread metadata not found");
++ }
++ } else {
++ // Do we want to report to the delegate in this case? I think not. If
++ // this was an orderly
++ // thread exit, we would already have received the SIGTRAP |
++ // (PTRACE_EVENT_EXIT << 8) signal,
++ // and we would have done an all-stop then.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() tid = %" PRIu64
++ " handling non-main thread exit (%s)",
++ __FUNCTION__, pid,
++ thread_found ? "stopped tracking thread metadata"
++ : "thread metadata not found");
++ }
++ return;
++ }
++
++ siginfo_t info;
++ const auto info_err = GetSignalInfo(pid, &info);
++ auto thread_sp = GetThreadByID(pid);
++
++ if (!thread_sp) {
++ // Normally, the only situation when we cannot find the thread is if we have
++ // just
++ // received a new thread notification. This is indicated by GetSignalInfo()
++ // returning
++ // si_code == SI_USER and si_pid == 0
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s received notification about an "
++ "unknown tid %" PRIu64 ".",
++ __FUNCTION__, pid);
++
++ if (info_err.Fail()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (tid %" PRIu64
++ ") GetSignalInfo failed (%s). Ingoring this notification.",
++ __FUNCTION__, pid, info_err.AsCString());
++ return;
++ }
++
++ if (log && (info.si_code != SI_USER || info.si_pid != 0))
++ log->Printf("NativeProcessNetBSD::%s (tid %" PRIu64
++ ") unexpected signal info (si_code: %d, si_pid: %d). "
++ "Treating as a new thread notification anyway.",
++ __FUNCTION__, pid, info.si_code, info.si_pid);
++
++ auto thread_sp = AddThread(pid);
++ // Resume the newly created thread.
++ ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
++ ThreadWasCreated(*thread_sp);
++ return;
++ }
++
++ // Get details on the signal raised.
++ if (info_err.Success()) {
++ // We have retrieved the signal info. Dispatch appropriately.
++ if (info.si_signo == SIGTRAP)
++ MonitorSIGTRAP(info, *thread_sp);
++ else
++ MonitorSignal(info, *thread_sp, exited);
++ } else {
++ if (info_err.GetError() == EINVAL) {
++ // This is a group stop reception for this tid.
++ // We can reach here if we reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU
++ // into the
++ // tracee, triggering the group-stop mechanism. Normally receiving these
++ // would stop
++ // the process, pending a SIGCONT. Simulating this state in a debugger is
++ // hard and is
++ // generally not needed (one use case is debugging background task being
++ // managed by a
++ // shell). For general use, it is sufficient to stop the process in a
++ // signal-delivery
++ // stop which happens before the group stop. This done by MonitorSignal
++ // and works
++ // correctly for all signals.
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s received a group stop for pid %" PRIu64
++ " tid %" PRIu64 ". Transparent handling of group stops not "
++ "supported, resuming the thread.",
++ __FUNCTION__, GetID(), pid);
++ ResumeThread(*thread_sp, thread_sp->GetState(),
++ LLDB_INVALID_SIGNAL_NUMBER);
++ } else {
++ // ptrace(GETSIGINFO) failed (but not due to group-stop).
++
++ // A return value of ESRCH means the thread/process is no longer on the
++ // system,
++ // so it was killed somehow outside of our control. Either way, we can't
++ // do anything
++ // with it anymore.
++
++ // Stop tracking the metadata for the thread since it's entirely off the
++ // system now.
++ const bool thread_found = StopTrackingThread(pid);
++
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s GetSignalInfo failed: %s, tid = %" PRIu64
++ ", signal = %d, status = %d (%s, %s, %s)",
++ __FUNCTION__, info_err.AsCString(), pid, signal, status,
++ info_err.GetError() == ESRCH ? "thread/process killed"
++ : "unknown reason",
++ is_main_thread ? "is main thread" : "is not main thread",
++ thread_found ? "thread metadata removed"
++ : "thread metadata not found");
++
++ if (is_main_thread) {
++ // Notify the delegate - our process is not available but appears to
++ // have been killed outside
++ // our control. Is eStateExited the right exit state in this case?
++ SetExitStatus(convert_pid_status_to_exit_type(status),
++ convert_pid_status_to_return_code(status), nullptr, true);
++ SetState(StateType::eStateExited, true);
++ } else {
++ // This thread was pulled out from underneath us. Anything to do here?
++ // Do we want to do an all stop?
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64 " tid %" PRIu64
++ " non-main thread exit occurred, didn't tell delegate "
++ "anything since thread disappeared out from underneath "
++ "us",
++ __FUNCTION__, GetID(), pid);
++ }
++ }
++ }
++}
++
++void NativeProcessNetBSD::WaitForNewThread(::pid_t tid) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++
++ NativeThreadNetBSDSP new_thread_sp = GetThreadByID(tid);
++
++ if (new_thread_sp) {
++ // We are already tracking the thread - we got the event on the new thread
++ // (see
++ // MonitorSignal) before this one. We are done.
++ return;
++ }
++
++ // The thread is not tracked yet, let's wait for it to appear.
++ int status = -1;
++ ::pid_t wait_pid;
++ do {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received thread creation event for "
++ "tid %" PRIu32
++ ". tid not tracked yet, waiting for thread to appear...",
++ __FUNCTION__, tid);
++ wait_pid = waitpid(tid, &status, __WALL);
++ } while (wait_pid == -1 && errno == EINTR);
++ // Since we are waiting on a specific tid, this must be the creation event.
++ // But let's do
++ // some checks just in case.
++ if (wait_pid != tid) {
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s() waiting for tid %" PRIu32
++ " failed. Assuming the thread has disappeared in the meantime",
++ __FUNCTION__, tid);
++ // The only way I know of this could happen is if the whole process was
++ // SIGKILLed in the mean time. In any case, we can't do anything about that
++ // now.
++ return;
++ }
++ if (WIFEXITED(status)) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() waiting for tid %" PRIu32
++ " returned an 'exited' event. Not tracking the thread.",
++ __FUNCTION__, tid);
++ // Also a very improbable event.
++ return;
++ }
++
++ siginfo_t info;
++ Error error = GetSignalInfo(tid, &info);
++ if (error.Fail()) {
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s() GetSignalInfo for tid %" PRIu32
++ " failed. Assuming the thread has disappeared in the meantime.",
++ __FUNCTION__, tid);
++ return;
++ }
++
++ if (((info.si_pid != 0) || (info.si_code != SI_USER)) && log) {
++ // We should be getting a thread creation signal here, but we received
++ // something
++ // else. There isn't much we can do about it now, so we will just log that.
++ // Since the
++ // thread is alive and we are receiving events from it, we shall pretend
++ // that it was
++ // created properly.
++ log->Printf("NativeProcessNetBSD::%s() GetSignalInfo for tid %" PRIu32
++ " received unexpected signal with code %d from pid %d.",
++ __FUNCTION__, tid, info.si_code, info.si_pid);
++ }
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid = %" PRIu64
++ ": tracking new thread tid %" PRIu32,
++ __FUNCTION__, GetID(), tid);
++
++ new_thread_sp = AddThread(tid);
++ ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
++ ThreadWasCreated(*new_thread_sp);
++}
++
++void NativeProcessNetBSD::MonitorSIGTRAP(const siginfo_t &info,
++ NativeThreadNetBSD &thread) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ const bool is_main_thread = (thread.GetID() == GetID());
++
++ assert(info.si_signo == SIGTRAP && "Unexpected child signal!");
++
++ switch (info.si_code) {
++ // TODO: these two cases are required if we want to support tracing of the
++ // inferiors' children. We'd need this to debug a monitor.
++ // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)):
++ // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)):
++
++ case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): {
++ // This is the notification on the parent thread which informs us of new
++ // thread
++ // creation.
++ // We don't want to do anything with the parent thread so we just resume it.
++ // In case we
++ // want to implement "break on thread creation" functionality, we would need
++ // to stop
++ // here.
++
++ unsigned long event_message = 0;
++ if (GetEventMessage(thread.GetID(), &event_message).Fail()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid %" PRIu64
++ " received thread creation event but GetEventMessage "
++ "failed so we don't know the new tid",
++ __FUNCTION__, thread.GetID());
++ } else
++ WaitForNewThread(event_message);
++
++ ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
++ break;
++ }
++
++ case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)): {
++ NativeThreadNetBSDSP main_thread_sp;
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received exec event, code = %d",
++ __FUNCTION__, info.si_code ^ SIGTRAP);
++
++ // Exec clears any pending notifications.
++ m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
++
++ // Remove all but the main thread here. NetBSD fork creates a new process
++ // which only copies the main thread.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s exec received, stop tracking all but "
++ "main thread",
++ __FUNCTION__);
++
++ for (auto thread_sp : m_threads) {
++ const bool is_main_thread = thread_sp && thread_sp->GetID() == GetID();
++ if (is_main_thread) {
++ main_thread_sp = std::static_pointer_cast<NativeThreadNetBSD>(thread_sp);
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s found main thread with tid %" PRIu64
++ ", keeping",
++ __FUNCTION__, main_thread_sp->GetID());
++ } else {
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s discarding non-main-thread tid %" PRIu64
++ " due to exec",
++ __FUNCTION__, thread_sp->GetID());
++ }
++ }
++
++ m_threads.clear();
++
++ if (main_thread_sp) {
++ m_threads.push_back(main_thread_sp);
++ SetCurrentThreadID(main_thread_sp->GetID());
++ main_thread_sp->SetStoppedByExec();
++ } else {
++ SetCurrentThreadID(LLDB_INVALID_THREAD_ID);
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64
++ "no main thread found, discarded all threads, we're in a "
++ "no-thread state!",
++ __FUNCTION__, GetID());
++ }
++
++ // Tell coordinator about about the "new" (since exec) stopped main thread.
++ ThreadWasCreated(*main_thread_sp);
++
++ // Let our delegate know we have just exec'd.
++ NotifyDidExec();
++
++ // If we have a main thread, indicate we are stopped.
++ assert(main_thread_sp && "exec called during ptraced process but no main "
++ "thread metadata tracked");
++
++ // Let the process know we're stopped.
++ StopRunningThreads(main_thread_sp->GetID());
++
++ break;
++ }
++
++ case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): {
++ // The inferior process or one of its threads is about to exit.
++ // We don't want to do anything with the thread so we just resume it. In
++ // case we
++ // want to implement "break on thread exit" functionality, we would need to
++ // stop
++ // here.
++
++ unsigned long data = 0;
++ if (GetEventMessage(thread.GetID(), &data).Fail())
++ data = -1;
++
++ if (log) {
++ log->Printf("NativeProcessNetBSD::%s() received PTRACE_EVENT_EXIT, data = "
++ "%lx (WIFEXITED=%s,WIFSIGNALED=%s), pid = %" PRIu64 " (%s)",
++ __FUNCTION__, data, WIFEXITED(data) ? "true" : "false",
++ WIFSIGNALED(data) ? "true" : "false", thread.GetID(),
++ is_main_thread ? "is main thread" : "not main thread");
++ }
++
++ if (is_main_thread) {
++ SetExitStatus(convert_pid_status_to_exit_type(data),
++ convert_pid_status_to_return_code(data), nullptr, true);
++ }
++
++ StateType state = thread.GetState();
++ if (!StateIsRunningState(state)) {
++ // Due to a kernel bug, we may sometimes get this stop after the inferior
++ // gets a
++ // SIGKILL. This confuses our state tracking logic in ResumeThread(),
++ // since normally,
++ // we should not be receiving any ptrace events while the inferior is
++ // stopped. This
++ // makes sure that the inferior is resumed and exits normally.
++ state = eStateRunning;
++ }
++ ResumeThread(thread, state, LLDB_INVALID_SIGNAL_NUMBER);
++
++ break;
++ }
++
++ case 0:
++ case TRAP_TRACE: // We receive this on single stepping.
++ case TRAP_HWBKPT: // We receive this on watchpoint hit
++ {
++ // If a watchpoint was hit, report it
++ uint32_t wp_index;
++ Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(
++ wp_index, (uintptr_t)info.si_addr);
++ if (error.Fail() && log)
++ log->Printf("NativeProcessNetBSD::%s() "
++ "received error while checking for watchpoint hits, "
++ "pid = %" PRIu64 " error = %s",
++ __FUNCTION__, thread.GetID(), error.AsCString());
++ if (wp_index != LLDB_INVALID_INDEX32) {
++ MonitorWatchpoint(thread, wp_index);
++ break;
++ }
++
++ // Otherwise, report step over
++ MonitorTrace(thread);
++ break;
++ }
++
++ case SI_KERNEL:
++#if defined __mips__
++ // For mips there is no special signal for watchpoint
++ // So we check for watchpoint in kernel trap
++ {
++ // If a watchpoint was hit, report it
++ uint32_t wp_index;
++ Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(
++ wp_index, LLDB_INVALID_ADDRESS);
++ if (error.Fail() && log)
++ log->Printf("NativeProcessNetBSD::%s() "
++ "received error while checking for watchpoint hits, "
++ "pid = %" PRIu64 " error = %s",
++ __FUNCTION__, thread.GetID(), error.AsCString());
++ if (wp_index != LLDB_INVALID_INDEX32) {
++ MonitorWatchpoint(thread, wp_index);
++ break;
++ }
++ }
++// NO BREAK
++#endif
++ case TRAP_BRKPT:
++ MonitorBreakpoint(thread);
++ break;
++
++ case SIGTRAP:
++ case (SIGTRAP | 0x80):
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received unknown SIGTRAP system "
++ "call stop event, pid %" PRIu64 "tid %" PRIu64 ", resuming",
++ __FUNCTION__, GetID(), thread.GetID());
++
++ // Ignore these signals until we know more about them.
++ ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER);
++ break;
++
++ default:
++ assert(false && "Unexpected SIGTRAP code!");
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid %" PRIu64 "tid %" PRIu64
++ " received unhandled SIGTRAP code: 0x%d",
++ __FUNCTION__, GetID(), thread.GetID(), info.si_code);
++ break;
++ }
++}
++
++void NativeProcessNetBSD::MonitorTrace(NativeThreadNetBSD &thread) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received trace event, pid = %" PRIu64
++ " (single stepping)",
++ __FUNCTION__, thread.GetID());
++
++ // This thread is currently stopped.
++ thread.SetStoppedByTrace();
++
++ StopRunningThreads(thread.GetID());
++}
++
++void NativeProcessNetBSD::MonitorBreakpoint(NativeThreadNetBSD &thread) {
++ Log *log(
++ GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS));
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s() received breakpoint event, pid = %" PRIu64,
++ __FUNCTION__, thread.GetID());
++
++ // Mark the thread as stopped at breakpoint.
++ thread.SetStoppedByBreakpoint();
++ Error error = FixupBreakpointPCAsNeeded(thread);
++ if (error.Fail())
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid = %" PRIu64 " fixup: %s",
++ __FUNCTION__, thread.GetID(), error.AsCString());
++
++ if (m_threads_stepping_with_breakpoint.find(thread.GetID()) !=
++ m_threads_stepping_with_breakpoint.end())
++ thread.SetStoppedByTrace();
++
++ StopRunningThreads(thread.GetID());
++}
++
++void NativeProcessNetBSD::MonitorWatchpoint(NativeThreadNetBSD &thread,
++ uint32_t wp_index) {
++ Log *log(
++ GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_WATCHPOINTS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received watchpoint event, "
++ "pid = %" PRIu64 ", wp_index = %" PRIu32,
++ __FUNCTION__, thread.GetID(), wp_index);
++
++ // Mark the thread as stopped at watchpoint.
++ // The address is at (lldb::addr_t)info->si_addr if we need it.
++ thread.SetStoppedByWatchpoint(wp_index);
++
++ // We need to tell all other running threads before we notify the delegate
++ // about this stop.
++ StopRunningThreads(thread.GetID());
++}
++
++void NativeProcessNetBSD::MonitorSignal(const siginfo_t &info,
++ NativeThreadNetBSD &thread, bool exited) {
++ const int signo = info.si_signo;
++ const bool is_from_llgs = info.si_pid == getpid();
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++
++ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
++ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
++ // kill(2) or raise(3). Similarly for tgkill(2) on NetBSD.
++ //
++ // IOW, user generated signals never generate what we consider to be a
++ // "crash".
++ //
++ // Similarly, ACK signals generated by this monitor.
++
++ // Handle the signal.
++ if (info.si_code == SI_TKILL || info.si_code == SI_USER) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received signal %s (%d) with code "
++ "%s, (siginfo pid = %d (%s), waitpid pid = %" PRIu64 ")",
++ __FUNCTION__, Host::GetSignalAsCString(signo), signo,
++ (info.si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
++ info.si_pid, is_from_llgs ? "from llgs" : "not from llgs",
++ thread.GetID());
++ }
++
++ // Check for thread stop notification.
++ if (is_from_llgs && (info.si_code == SI_TKILL) && (signo == SIGSTOP)) {
++ // This is a tgkill()-based stop.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid %" PRIu64 " tid %" PRIu64
++ ", thread stopped",
++ __FUNCTION__, GetID(), thread.GetID());
++
++ // Check that we're not already marked with a stop reason.
++ // Note this thread really shouldn't already be marked as stopped - if we
++ // were, that would imply that
++ // the kernel signaled us with the thread stopping which we handled and
++ // marked as stopped,
++ // and that, without an intervening resume, we received another stop. It is
++ // more likely
++ // that we are missing the marking of a run state somewhere if we find that
++ // the thread was
++ // marked as stopped.
++ const StateType thread_state = thread.GetState();
++ if (!StateIsStoppedState(thread_state, false)) {
++ // An inferior thread has stopped because of a SIGSTOP we have sent it.
++ // Generally, these are not important stops and we don't want to report
++ // them as
++ // they are just used to stop other threads when one thread (the one with
++ // the
++ // *real* stop reason) hits a breakpoint (watchpoint, etc...). However, in
++ // the
++ // case of an asynchronous Interrupt(), this *is* the real stop reason, so
++ // we
++ // leave the signal intact if this is the thread that was chosen as the
++ // triggering thread.
++ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) {
++ if (m_pending_notification_tid == thread.GetID())
++ thread.SetStoppedBySignal(SIGSTOP, &info);
++ else
++ thread.SetStoppedWithNoReason();
++
++ SetCurrentThreadID(thread.GetID());
++ SignalIfAllThreadsStopped();
++ } else {
++ // We can end up here if stop was initiated by LLGS but by this time a
++ // thread stop has occurred - maybe initiated by another event.
++ Error error = ResumeThread(thread, thread.GetState(), 0);
++ if (error.Fail() && log) {
++ log->Printf(
++ "NativeProcessNetBSD::%s failed to resume thread tid %" PRIu64
++ ": %s",
++ __FUNCTION__, thread.GetID(), error.AsCString());
++ }
++ }
++ } else {
++ if (log) {
++ // Retrieve the signal name if the thread was stopped by a signal.
++ int stop_signo = 0;
++ const bool stopped_by_signal = thread.IsStopped(&stop_signo);
++ const char *signal_name = stopped_by_signal
++ ? Host::GetSignalAsCString(stop_signo)
++ : "<not stopped by signal>";
++ if (!signal_name)
++ signal_name = "<no-signal-name>";
++
++ log->Printf("NativeProcessNetBSD::%s() pid %" PRIu64 " tid %" PRIu64
++ ", thread was already marked as a stopped state (state=%s, "
++ "signal=%d (%s)), leaving stop signal as is",
++ __FUNCTION__, GetID(), thread.GetID(),
++ StateAsCString(thread_state), stop_signo, signal_name);
++ }
++ SignalIfAllThreadsStopped();
++ }
++
++ // Done handling.
++ return;
++ }
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() received signal %s", __FUNCTION__,
++ Host::GetSignalAsCString(signo));
++
++ // This thread is stopped.
++ thread.SetStoppedBySignal(signo, &info);
++
++ // Send a stop to the debugger after we get all other threads to stop.
++ StopRunningThreads(thread.GetID());
++}
++
++namespace {
++
++struct EmulatorBaton {
++ NativeProcessNetBSD *m_process;
++ NativeRegisterContext *m_reg_context;
++
++ // eRegisterKindDWARF -> RegsiterValue
++ std::unordered_map<uint32_t, RegisterValue> m_register_values;
++
++ EmulatorBaton(NativeProcessNetBSD *process, NativeRegisterContext *reg_context)
++ : m_process(process), m_reg_context(reg_context) {}
++};
++
++} // anonymous namespace
++
++static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
++ const EmulateInstruction::Context &context,
++ lldb::addr_t addr, void *dst, size_t length) {
++ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
++
++ size_t bytes_read;
++ emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
++ return bytes_read;
++}
++
++static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
++ const RegisterInfo *reg_info,
++ RegisterValue ®_value) {
++ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
++
++ auto it = emulator_baton->m_register_values.find(
++ reg_info->kinds[eRegisterKindDWARF]);
++ if (it != emulator_baton->m_register_values.end()) {
++ reg_value = it->second;
++ return true;
++ }
++
++ // The emulator only fill in the dwarf regsiter numbers (and in some case
++ // the generic register numbers). Get the full register info from the
++ // register context based on the dwarf register numbers.
++ const RegisterInfo *full_reg_info =
++ emulator_baton->m_reg_context->GetRegisterInfo(
++ eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
++
++ Error error =
++ emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
++ if (error.Success())
++ return true;
++
++ return false;
++}
++
++static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
++ const EmulateInstruction::Context &context,
++ const RegisterInfo *reg_info,
++ const RegisterValue ®_value) {
++ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
++ emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
++ reg_value;
++ return true;
++}
++
++static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
++ const EmulateInstruction::Context &context,
++ lldb::addr_t addr, const void *dst,
++ size_t length) {
++ return length;
++}
++
++static lldb::addr_t ReadFlags(NativeRegisterContext *regsiter_context) {
++ const RegisterInfo *flags_info = regsiter_context->GetRegisterInfo(
++ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
++ return regsiter_context->ReadRegisterAsUnsigned(flags_info,
++ LLDB_INVALID_ADDRESS);
++}
++
++Error NativeProcessNetBSD::SetupSoftwareSingleStepping(
++ NativeThreadNetBSD &thread) {
++ Error error;
++ NativeRegisterContextSP register_context_sp = thread.GetRegisterContext();
++
++ std::unique_ptr<EmulateInstruction> emulator_ap(
++ EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying,
++ nullptr));
++
++ if (emulator_ap == nullptr)
++ return Error("Instruction emulator not found!");
++
++ EmulatorBaton baton(this, register_context_sp.get());
++ emulator_ap->SetBaton(&baton);
++ emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
++ emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
++ emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
++ emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
++
++ if (!emulator_ap->ReadInstruction())
++ return Error("Read instruction failed!");
++
++ bool emulation_result =
++ emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
++
++ const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo(
++ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
++ const RegisterInfo *reg_info_flags = register_context_sp->GetRegisterInfo(
++ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
++
++ auto pc_it =
++ baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
++ auto flags_it =
++ baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]);
++
++ lldb::addr_t next_pc;
++ lldb::addr_t next_flags;
++ if (emulation_result) {
++ assert(pc_it != baton.m_register_values.end() &&
++ "Emulation was successfull but PC wasn't updated");
++ next_pc = pc_it->second.GetAsUInt64();
++
++ if (flags_it != baton.m_register_values.end())
++ next_flags = flags_it->second.GetAsUInt64();
++ else
++ next_flags = ReadFlags(register_context_sp.get());
++ } else if (pc_it == baton.m_register_values.end()) {
++ // Emulate instruction failed and it haven't changed PC. Advance PC
++ // with the size of the current opcode because the emulation of all
++ // PC modifying instruction should be successful. The failure most
++ // likely caused by a not supported instruction which don't modify PC.
++ next_pc =
++ register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
++ next_flags = ReadFlags(register_context_sp.get());
++ } else {
++ // The instruction emulation failed after it modified the PC. It is an
++ // unknown error where we can't continue because the next instruction is
++ // modifying the PC but we don't know how.
++ return Error("Instruction emulation failed unexpectedly.");
++ }
++
++ if (m_arch.GetMachine() == llvm::Triple::arm) {
++ if (next_flags & 0x20) {
++ // Thumb mode
++ error = SetSoftwareBreakpoint(next_pc, 2);
++ } else {
++ // Arm mode
++ error = SetSoftwareBreakpoint(next_pc, 4);
++ }
++ } else if (m_arch.GetMachine() == llvm::Triple::mips64 ||
++ m_arch.GetMachine() == llvm::Triple::mips64el ||
++ m_arch.GetMachine() == llvm::Triple::mips ||
++ m_arch.GetMachine() == llvm::Triple::mipsel)
++ error = SetSoftwareBreakpoint(next_pc, 4);
++ else {
++ // No size hint is given for the next breakpoint
++ error = SetSoftwareBreakpoint(next_pc, 0);
++ }
++
++ // If setting the breakpoint fails because next_pc is out of
++ // the address space, ignore it and let the debugee segfault.
++ if (error.GetError() == EIO || error.GetError() == EFAULT) {
++ return Error();
++ } else if (error.Fail())
++ return error;
++
++ m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
++
++ return Error();
++}
++
++bool NativeProcessNetBSD::SupportHardwareSingleStepping() const {
++ if (m_arch.GetMachine() == llvm::Triple::arm ||
++ m_arch.GetMachine() == llvm::Triple::mips64 ||
++ m_arch.GetMachine() == llvm::Triple::mips64el ||
++ m_arch.GetMachine() == llvm::Triple::mips ||
++ m_arch.GetMachine() == llvm::Triple::mipsel)
++ return false;
++ return true;
++}
++
++Error NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s called: pid %" PRIu64, __FUNCTION__,
++ GetID());
++
++ bool software_single_step = !SupportHardwareSingleStepping();
++
++ if (software_single_step) {
++ for (auto thread_sp : m_threads) {
++ assert(thread_sp && "thread list should not contain NULL threads");
++
++ const ResumeAction *const action =
++ resume_actions.GetActionForThread(thread_sp->GetID(), true);
++ if (action == nullptr)
++ continue;
++
++ if (action->state == eStateStepping) {
++ Error error = SetupSoftwareSingleStepping(
++ static_cast<NativeThreadNetBSD &>(*thread_sp));
++ if (error.Fail())
++ return error;
++ }
++ }
++ }
++
++ for (auto thread_sp : m_threads) {
++ assert(thread_sp && "thread list should not contain NULL threads");
++
++ const ResumeAction *const action =
++ resume_actions.GetActionForThread(thread_sp->GetID(), true);
++
++ if (action == nullptr) {
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s no action specified for pid %" PRIu64
++ " tid %" PRIu64,
++ __FUNCTION__, GetID(), thread_sp->GetID());
++ continue;
++ }
++
++ if (log) {
++ log->Printf("NativeProcessNetBSD::%s processing resume action state %s "
++ "for pid %" PRIu64 " tid %" PRIu64,
++ __FUNCTION__, StateAsCString(action->state), GetID(),
++ thread_sp->GetID());
++ }
++
++ switch (action->state) {
++ case eStateRunning:
++ case eStateStepping: {
++ // Run the thread, possibly feeding it the signal.
++ const int signo = action->signal;
++ ResumeThread(static_cast<NativeThreadNetBSD &>(*thread_sp), action->state,
++ signo);
++ break;
++ }
++
++ case eStateSuspended:
++ case eStateStopped:
++ lldbassert(0 && "Unexpected state");
++
++ default:
++ return Error("NativeProcessNetBSD::%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;
++
++ for (auto thread_sp : m_threads) {
++ Error e = Detach(thread_sp->GetID());
++ if (e.Fail())
++ error =
++ e; // Save the error, but still attempt to detach from other threads.
++ }
++
++ return error;
++}
++
++Error NativeProcessNetBSD::Signal(int signo) {
++ Error error;
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s: sending signal %d (%s) to pid %" PRIu64,
++ __FUNCTION__, signo, Host::GetSignalAsCString(signo), GetID());
++
++ if (kill(GetID(), signo))
++ error.SetErrorToErrno();
++
++ return error;
++}
++
++Error NativeProcessNetBSD::Interrupt() {
++ // Pick a running thread (or if none, a not-dead stopped thread) as
++ // the chosen thread that will be the stop-reason thread.
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++
++ NativeThreadProtocolSP running_thread_sp;
++ NativeThreadProtocolSP stopped_thread_sp;
++
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s selecting running thread for interrupt target",
++ __FUNCTION__);
++
++ for (auto thread_sp : m_threads) {
++ // The thread shouldn't be null but lets just cover that here.
++ if (!thread_sp)
++ continue;
++
++ // If we have a running or stepping thread, we'll call that the
++ // target of the interrupt.
++ const auto thread_state = thread_sp->GetState();
++ if (thread_state == eStateRunning || thread_state == eStateStepping) {
++ running_thread_sp = thread_sp;
++ break;
++ } else if (!stopped_thread_sp && StateIsStoppedState(thread_state, true)) {
++ // Remember the first non-dead stopped thread. We'll use that as a backup
++ // if there are no running threads.
++ stopped_thread_sp = thread_sp;
++ }
++ }
++
++ if (!running_thread_sp && !stopped_thread_sp) {
++ Error error("found no running/stepping or live stopped threads as target "
++ "for interrupt");
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s skipping due to error: %s",
++ __FUNCTION__, error.AsCString());
++
++ return error;
++ }
++
++ NativeThreadProtocolSP deferred_signal_thread_sp =
++ running_thread_sp ? running_thread_sp : stopped_thread_sp;
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64 " %s tid %" PRIu64
++ " chosen for interrupt target",
++ __FUNCTION__, GetID(),
++ running_thread_sp ? "running" : "stopped",
++ deferred_signal_thread_sp->GetID());
++
++ StopRunningThreads(deferred_signal_thread_sp->GetID());
++
++ return Error();
++}
++
++Error NativeProcessNetBSD::Kill() {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s called for PID %" PRIu64, __FUNCTION__,
++ 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.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s ignored for PID %" PRIu64
++ " due to current state: %s",
++ __FUNCTION__, 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;
++}
++
++static Error
++ParseMemoryRegionInfoFromProcMapsLine(const std::string &maps_line,
++ MemoryRegionInfo &memory_region_info) {
++ memory_region_info.Clear();
++
++ StringExtractor line_extractor(maps_line.c_str());
++
++ // Format: {address_start_hex}-{address_end_hex} perms offset dev inode
++ // pathname
++ // perms: rwxp (letter is present if set, '-' if not, final character is
++ // p=private, s=shared).
++
++ // Parse out the starting address
++ lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
++
++ // Parse out hyphen separating start and end address from range.
++ if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
++ return Error(
++ "malformed /proc/{pid}/maps entry, missing dash between address range");
++
++ // Parse out the ending address
++ lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
++
++ // Parse out the space after the address.
++ if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
++ return Error("malformed /proc/{pid}/maps entry, missing space after range");
++
++ // Save the range.
++ memory_region_info.GetRange().SetRangeBase(start_address);
++ memory_region_info.GetRange().SetRangeEnd(end_address);
++
++ // Any memory region in /proc/{pid}/maps is by definition mapped into the
++ // process.
++ memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
++
++ // Parse out each permission entry.
++ if (line_extractor.GetBytesLeft() < 4)
++ return Error("malformed /proc/{pid}/maps entry, missing some portion of "
++ "permissions");
++
++ // Handle read permission.
++ const char read_perm_char = line_extractor.GetChar();
++ if (read_perm_char == 'r')
++ memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
++ else if (read_perm_char == '-')
++ memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
++ else
++ return Error("unexpected /proc/{pid}/maps read permission char");
++
++ // Handle write permission.
++ const char write_perm_char = line_extractor.GetChar();
++ if (write_perm_char == 'w')
++ memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
++ else if (write_perm_char == '-')
++ memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
++ else
++ return Error("unexpected /proc/{pid}/maps write permission char");
++
++ // Handle execute permission.
++ const char exec_perm_char = line_extractor.GetChar();
++ if (exec_perm_char == 'x')
++ memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
++ else if (exec_perm_char == '-')
++ memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
++ else
++ return Error("unexpected /proc/{pid}/maps exec permission char");
++
++ line_extractor.GetChar(); // Read the private bit
++ line_extractor.SkipSpaces(); // Skip the separator
++ line_extractor.GetHexMaxU64(false, 0); // Read the offset
++ line_extractor.GetHexMaxU64(false, 0); // Read the major device number
++ line_extractor.GetChar(); // Read the device id separator
++ line_extractor.GetHexMaxU64(false, 0); // Read the major device number
++ line_extractor.SkipSpaces(); // Skip the separator
++ line_extractor.GetU64(0, 10); // Read the inode number
++
++ line_extractor.SkipSpaces();
++ const char *name = line_extractor.Peek();
++ if (name)
++ memory_region_info.SetName(name);
++
++ return Error();
++}
++
++Error NativeProcessNetBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
++ MemoryRegionInfo &range_info) {
++ // FIXME review that the final memory region returned extends to the end of
++ // the virtual address space,
++ // with no perms if it is not mapped.
++
++ // Use an approach that reads memory regions from /proc/{pid}/maps.
++ // Assume proc maps entries are in ascending order.
++ // FIXME assert if we find differently.
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ Error error;
++
++ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
++ // We're done.
++ error.SetErrorString("unsupported");
++ return error;
++ }
++
++ // 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()) {
++ error = ProcFileReader::ProcessLineByLine(
++ GetID(), "maps", [&](const std::string &line) -> bool {
++ MemoryRegionInfo info;
++ const Error parse_error =
++ ParseMemoryRegionInfoFromProcMapsLine(line, info);
++ if (parse_error.Success()) {
++ m_mem_region_cache.push_back(info);
++ return true;
++ } else {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s failed to parse proc maps "
++ "line '%s': %s",
++ __FUNCTION__, line.c_str(), error.AsCString());
++ return false;
++ }
++ });
++
++ // If we had an error, we'll mark unsupported.
++ if (error.Fail()) {
++ m_supports_mem_region = LazyBool::eLazyBoolNo;
++ return error;
++ } else if (m_mem_region_cache.empty()) {
++ // No entries after attempting to read them. This shouldn't happen if
++ // /proc/{pid}/maps
++ // is supported. Assume we don't support map entries via procfs.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s failed to find any procfs maps "
++ "entries, assuming no support for memory region metadata "
++ "retrieval",
++ __FUNCTION__);
++ m_supports_mem_region = LazyBool::eLazyBoolNo;
++ error.SetErrorString("not supported");
++ return error;
++ }
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s read %" PRIu64
++ " memory region entries from /proc/%" PRIu64 "/maps",
++ __FUNCTION__,
++ static_cast<uint64_t>(m_mem_region_cache.size()), GetID());
++
++ // We support memory retrieval, remember that.
++ m_supports_mem_region = LazyBool::eLazyBoolYes;
++ } else {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s reusing %" PRIu64
++ " cached memory region entries",
++ __FUNCTION__,
++ static_cast<uint64_t>(m_mem_region_cache.size()));
++ }
++
++ 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;
++
++ // Sanity check assumption that /proc/{pid}/maps entries are ascending.
++ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
++ "descending /proc/pid/maps entries detected, unexpected");
++ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
++
++ // 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;
++}
++
++void NativeProcessNetBSD::DoStopIDBumped(uint32_t newBumpId) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s(newBumpId=%" PRIu32 ") called",
++ __FUNCTION__, newBumpId);
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s clearing %" PRIu64
++ " entries from the cache",
++ __FUNCTION__, static_cast<uint64_t>(m_mem_region_cache.size()));
++ m_mem_region_cache.clear();
++}
++
++Error NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
++ lldb::addr_t &addr) {
++// FIXME implementing this requires the equivalent of
++// InferiorCallPOSIX::InferiorCallMmap, which depends on
++// functional ThreadPlans working with Native*Protocol.
++#if 1
++ return Error("not implemented yet");
++#else
++ addr = LLDB_INVALID_ADDRESS;
++
++ unsigned prot = 0;
++ if (permissions & lldb::ePermissionsReadable)
++ prot |= eMmapProtRead;
++ if (permissions & lldb::ePermissionsWritable)
++ prot |= eMmapProtWrite;
++ if (permissions & lldb::ePermissionsExecutable)
++ prot |= eMmapProtExec;
++
++ // TODO implement this directly in NativeProcessNetBSD
++ // (and lift to NativeProcessPOSIX if/when that class is
++ // refactored out).
++ if (InferiorCallMmap(this, addr, 0, size, prot,
++ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
++ m_addr_to_mmap_size[addr] = size;
++ return Error();
++ } else {
++ addr = LLDB_INVALID_ADDRESS;
++ return Error("unable to allocate %" PRIu64
++ " bytes of memory with permissions %s",
++ size, GetPermissionsAsCString(permissions));
++ }
++#endif
++}
++
++Error NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
++ // FIXME see comments in AllocateMemory - required lower-level
++ // bits not in place yet (ThreadPlans)
++ return Error("not implemented");
++}
++
++lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
++ // punt on this for now
++ return LLDB_INVALID_ADDRESS;
++}
++
++size_t NativeProcessNetBSD::UpdateThreads() {
++ // The NativeProcessNetBSD monitoring threads are always up to date
++ // with respect to thread state and they keep the thread list
++ // populated properly. All this method needs to do is return the
++ // thread count.
++ return m_threads.size();
++}
++
++bool NativeProcessNetBSD::GetArchitecture(ArchSpec &arch) const {
++ arch = m_arch;
++ return true;
++}
++
++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};
++ static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
++
++ switch (m_arch.GetMachine()) {
++ case llvm::Triple::x86:
++ case llvm::Triple::x86_64:
++ actual_opcode_size = static_cast<uint32_t>(sizeof(g_i386_opcode));
++ return Error();
++
++ case llvm::Triple::systemz:
++ actual_opcode_size = static_cast<uint32_t>(sizeof(g_s390x_opcode));
++ return Error();
++
++ case llvm::Triple::arm:
++ case llvm::Triple::aarch64:
++ case llvm::Triple::mips64:
++ case llvm::Triple::mips64el:
++ case llvm::Triple::mips:
++ case llvm::Triple::mipsel:
++ // On these architectures the PC don't get updated for breakpoint hits
++ actual_opcode_size = 0;
++ return Error();
++
++ default:
++ assert(false && "CPU type not supported!");
++ return Error("CPU type not supported");
++ }
++}
++
++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) {
++ // FIXME put this behind a breakpoint protocol class that can be set per
++ // architecture. Need MIPS support here.
++ static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4};
++ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the
++ // linux kernel does otherwise.
++ static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};
++ static const uint8_t g_i386_opcode[] = {0xCC};
++ static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d};
++ static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00};
++ static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
++ static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};
++
++ switch (m_arch.GetMachine()) {
++ case llvm::Triple::aarch64:
++ trap_opcode_bytes = g_aarch64_opcode;
++ actual_opcode_size = sizeof(g_aarch64_opcode);
++ return Error();
++
++ case llvm::Triple::arm:
++ switch (trap_opcode_size_hint) {
++ case 2:
++ trap_opcode_bytes = g_thumb_breakpoint_opcode;
++ actual_opcode_size = sizeof(g_thumb_breakpoint_opcode);
++ return Error();
++ case 4:
++ trap_opcode_bytes = g_arm_breakpoint_opcode;
++ actual_opcode_size = sizeof(g_arm_breakpoint_opcode);
++ return Error();
++ default:
++ assert(false && "Unrecognised trap opcode size hint!");
++ return Error("Unrecognised trap opcode size hint!");
++ }
++
++ case llvm::Triple::x86:
++ case llvm::Triple::x86_64:
++ trap_opcode_bytes = g_i386_opcode;
++ actual_opcode_size = sizeof(g_i386_opcode);
++ return Error();
++
++ case llvm::Triple::mips:
++ case llvm::Triple::mips64:
++ trap_opcode_bytes = g_mips64_opcode;
++ actual_opcode_size = sizeof(g_mips64_opcode);
++ return Error();
++
++ case llvm::Triple::mipsel:
++ case llvm::Triple::mips64el:
++ trap_opcode_bytes = g_mips64el_opcode;
++ actual_opcode_size = sizeof(g_mips64el_opcode);
++ return Error();
++
++ case llvm::Triple::systemz:
++ trap_opcode_bytes = g_s390x_opcode;
++ actual_opcode_size = sizeof(g_s390x_opcode);
++ return Error();
++
++ default:
++ assert(false && "CPU type not supported!");
++ return Error("CPU type not supported");
++ }
++}
++
++#if 0
++ProcessMessage::CrashReason
++NativeProcessNetBSD::GetCrashReasonForSIGSEGV(const siginfo_t *info)
++{
++ ProcessMessage::CrashReason reason;
++ assert(info->si_signo == SIGSEGV);
++
++ reason = ProcessMessage::eInvalidCrashReason;
++
++ switch (info->si_code)
++ {
++ default:
++ assert(false && "unexpected si_code for SIGSEGV");
++ break;
++ case SI_KERNEL:
++ // NetBSD will occasionally send spurious SI_KERNEL codes.
++ // (this is poorly documented in sigaction)
++ // One way to get this is via unaligned SIMD loads.
++ reason = ProcessMessage::eInvalidAddress; // for lack of anything better
++ break;
++ case SEGV_MAPERR:
++ reason = ProcessMessage::eInvalidAddress;
++ break;
++ case SEGV_ACCERR:
++ reason = ProcessMessage::ePrivilegedAddress;
++ break;
++ }
++
++ return reason;
++}
++#endif
++
++#if 0
++ProcessMessage::CrashReason
++NativeProcessNetBSD::GetCrashReasonForSIGILL(const siginfo_t *info)
++{
++ ProcessMessage::CrashReason reason;
++ assert(info->si_signo == SIGILL);
++
++ reason = ProcessMessage::eInvalidCrashReason;
++
++ switch (info->si_code)
++ {
++ default:
++ assert(false && "unexpected si_code for SIGILL");
++ break;
++ case ILL_ILLOPC:
++ reason = ProcessMessage::eIllegalOpcode;
++ break;
++ case ILL_ILLOPN:
++ reason = ProcessMessage::eIllegalOperand;
++ break;
++ case ILL_ILLADR:
++ reason = ProcessMessage::eIllegalAddressingMode;
++ break;
++ case ILL_ILLTRP:
++ reason = ProcessMessage::eIllegalTrap;
++ break;
++ case ILL_PRVOPC:
++ reason = ProcessMessage::ePrivilegedOpcode;
++ break;
++ case ILL_PRVREG:
++ reason = ProcessMessage::ePrivilegedRegister;
++ break;
++ case ILL_COPROC:
++ reason = ProcessMessage::eCoprocessorError;
++ break;
++ case ILL_BADSTK:
++ reason = ProcessMessage::eInternalStackError;
++ break;
++ }
++
++ return reason;
++}
++#endif
++
++#if 0
++ProcessMessage::CrashReason
++NativeProcessNetBSD::GetCrashReasonForSIGFPE(const siginfo_t *info)
++{
++ ProcessMessage::CrashReason reason;
++ assert(info->si_signo == SIGFPE);
++
++ reason = ProcessMessage::eInvalidCrashReason;
++
++ switch (info->si_code)
++ {
++ default:
++ assert(false && "unexpected si_code for SIGFPE");
++ break;
++ case FPE_INTDIV:
++ reason = ProcessMessage::eIntegerDivideByZero;
++ break;
++ case FPE_INTOVF:
++ reason = ProcessMessage::eIntegerOverflow;
++ break;
++ case FPE_FLTDIV:
++ reason = ProcessMessage::eFloatDivideByZero;
++ break;
++ case FPE_FLTOVF:
++ reason = ProcessMessage::eFloatOverflow;
++ break;
++ case FPE_FLTUND:
++ reason = ProcessMessage::eFloatUnderflow;
++ break;
++ case FPE_FLTRES:
++ reason = ProcessMessage::eFloatInexactResult;
++ break;
++ case FPE_FLTINV:
++ reason = ProcessMessage::eFloatInvalidOperation;
++ break;
++ case FPE_FLTSUB:
++ reason = ProcessMessage::eFloatSubscriptRange;
++ break;
++ }
++
++ return reason;
++}
++#endif
++
++#if 0
++ProcessMessage::CrashReason
++NativeProcessNetBSD::GetCrashReasonForSIGBUS(const siginfo_t *info)
++{
++ ProcessMessage::CrashReason reason;
++ assert(info->si_signo == SIGBUS);
++
++ reason = ProcessMessage::eInvalidCrashReason;
++
++ switch (info->si_code)
++ {
++ default:
++ assert(false && "unexpected si_code for SIGBUS");
++ break;
++ case BUS_ADRALN:
++ reason = ProcessMessage::eIllegalAlignment;
++ break;
++ case BUS_ADRERR:
++ reason = ProcessMessage::eIllegalAddress;
++ break;
++ case BUS_OBJERR:
++ reason = ProcessMessage::eHardwareError;
++ break;
++ }
++
++ return reason;
++}
++#endif
++
++Error NativeProcessNetBSD::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
++ size_t &bytes_read) {
++ if (ProcessVmReadvSupported()) {
++ // The process_vm_readv path is about 50 times faster than ptrace api. We
++ // want to use
++ // this syscall if it is supported.
++
++ const ::pid_t pid = GetID();
++
++ struct iovec local_iov, remote_iov;
++ local_iov.iov_base = buf;
++ local_iov.iov_len = size;
++ remote_iov.iov_base = reinterpret_cast<void *>(addr);
++ remote_iov.iov_len = size;
++
++ bytes_read = process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0);
++ const bool success = bytes_read == size;
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s using process_vm_readv to read %zd "
++ "bytes from inferior address 0x%" PRIx64 ": %s",
++ __FUNCTION__, size, addr,
++ success ? "Success" : strerror(errno));
++
++ if (success)
++ return Error();
++ // else
++ // the call failed for some reason, let's retry the read using ptrace
++ // api.
++ }
++
++ unsigned char *dst = static_cast<unsigned char *>(buf);
++ size_t remainder;
++ long data;
++
++ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
++ if (log)
++ ProcessPOSIXLog::IncNestLevel();
++ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
++ log->GetMask().Test(POSIX_LOG_MEMORY))
++ log->Printf("NativeProcessNetBSD::%s(%p, %p, %zd, _)", __FUNCTION__,
++ (void *)addr, buf, size);
++
++ for (bytes_read = 0; bytes_read < size; bytes_read += remainder) {
++ Error error = NativeProcessNetBSD::PtraceWrapper(
++ PTRACE_PEEKDATA, GetID(), (void *)addr, nullptr, 0, &data);
++ if (error.Fail()) {
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ return error;
++ }
++
++ remainder = size - bytes_read;
++ remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder;
++
++ // Copy the data into our buffer
++ memcpy(dst, &data, remainder);
++
++ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
++ size <= POSIX_LOG_MEMORY_SHORT_BYTES))) {
++ uintptr_t print_dst = 0;
++ // Format bytes from data by moving into print_dst for log output
++ for (unsigned i = 0; i < remainder; ++i)
++ print_dst |= (((data >> i * 8) & 0xFF) << i * 8);
++ log->Printf("NativeProcessNetBSD::%s() [0x%" PRIx64 "]:0x%" PRIx64
++ " (0x%" PRIx64 ")",
++ __FUNCTION__, addr, uint64_t(print_dst), uint64_t(data));
++ }
++ addr += k_ptrace_word_size;
++ dst += k_ptrace_word_size;
++ }
++
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ 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);
++ size_t remainder;
++ Error error;
++
++ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
++ if (log)
++ ProcessPOSIXLog::IncNestLevel();
++ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
++ log->GetMask().Test(POSIX_LOG_MEMORY))
++ log->Printf("NativeProcessNetBSD::%s(0x%" PRIx64 ", %p, %zu)", __FUNCTION__,
++ addr, buf, size);
++
++ for (bytes_written = 0; bytes_written < size; bytes_written += remainder) {
++ remainder = size - bytes_written;
++ remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder;
++
++ if (remainder == k_ptrace_word_size) {
++ unsigned long data = 0;
++ memcpy(&data, src, k_ptrace_word_size);
++
++ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
++ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
++ log->Printf("NativeProcessNetBSD::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
++ (void *)addr, *(const unsigned long *)src, data);
++
++ error = NativeProcessNetBSD::PtraceWrapper(PTRACE_POKEDATA, GetID(),
++ (void *)addr, (void *)data);
++ if (error.Fail()) {
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ return error;
++ }
++ } else {
++ unsigned char buff[8];
++ size_t bytes_read;
++ error = ReadMemory(addr, buff, k_ptrace_word_size, bytes_read);
++ if (error.Fail()) {
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ return error;
++ }
++
++ memcpy(buff, src, remainder);
++
++ size_t bytes_written_rec;
++ error = WriteMemory(addr, buff, k_ptrace_word_size, bytes_written_rec);
++ if (error.Fail()) {
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ return error;
++ }
++
++ if (log && ProcessPOSIXLog::AtTopNestLevel() &&
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
++ (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
++ size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
++ log->Printf("NativeProcessNetBSD::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
++ (void *)addr, *(const unsigned long *)src,
++ *(unsigned long *)buff);
++ }
++
++ addr += k_ptrace_word_size;
++ src += k_ptrace_word_size;
++ }
++ if (log)
++ ProcessPOSIXLog::DecNestLevel();
++ return error;
++}
++
++Error NativeProcessNetBSD::GetSignalInfo(lldb::tid_t tid, void *siginfo) {
++ return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo);
++}
++
++Error NativeProcessNetBSD::GetEventMessage(lldb::tid_t tid,
++ unsigned long *message) {
++ return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message);
++}
++
++Error NativeProcessNetBSD::Detach(lldb::tid_t tid) {
++ if (tid == LLDB_INVALID_THREAD_ID)
++ return Error();
++
++ return PtraceWrapper(PTRACE_DETACH, tid);
++}
++
++bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {
++ for (auto thread_sp : m_threads) {
++ assert(thread_sp && "thread list should not contain NULL threads");
++ if (thread_sp->GetID() == thread_id) {
++ // We have this thread.
++ return true;
++ }
++ }
++
++ // We don't have this thread.
++ return false;
++}
++
++bool NativeProcessNetBSD::StopTrackingThread(lldb::tid_t thread_id) {
++ Log *const log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (tid: %" PRIu64 ")", __FUNCTION__,
++ thread_id);
++
++ bool found = false;
++
++ for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
++ if (*it && ((*it)->GetID() == thread_id)) {
++ m_threads.erase(it);
++ found = true;
++ break;
++ }
++ }
++
++ SignalIfAllThreadsStopped();
++
++ return found;
++}
++
++NativeThreadNetBSDSP NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++
++ if (log) {
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64
++ " adding thread with tid %" PRIu64,
++ __FUNCTION__, 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;
++}
++
++Error NativeProcessNetBSD::FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_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");
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s failed: %s", __FUNCTION__,
++ error.AsCString());
++ return error;
++ }
++
++ uint32_t breakpoint_size = 0;
++ error = GetSoftwareBreakpointPCOffset(breakpoint_size);
++ if (error.Fail()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s GetBreakpointSize() failed: %s",
++ __FUNCTION__, error.AsCString());
++ return error;
++ } else {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s breakpoint size: %" PRIu32,
++ __FUNCTION__, 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.
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s pid %" PRIu64
++ " no lldb breakpoint found at current pc with adjustment: 0x%" PRIx64,
++ __FUNCTION__, GetID(), breakpoint_addr);
++ return Error();
++ }
++
++ // If the breakpoint is not a software breakpoint, nothing to do.
++ if (!breakpoint_sp->IsSoftwareBreakpoint()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64
++ " breakpoint found at 0x%" PRIx64
++ ", not software, nothing to adjust",
++ __FUNCTION__, 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?
++ if (log)
++ log->Printf(
++ "NativeProcessNetBSD::%s pid %" PRIu64
++ " breakpoint found at 0x%" PRIx64
++ ", it is software, but the size is zero, nothing to do (unexpected)",
++ __FUNCTION__, GetID(), breakpoint_addr);
++ return Error();
++ }
++
++ // Change the program counter.
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64 " tid %" PRIu64
++ ": changing PC from 0x%" PRIx64 " to 0x%" PRIx64,
++ __FUNCTION__, GetID(), thread.GetID(), initial_pc_addr,
++ breakpoint_addr);
++
++ error = context_sp->SetPC(breakpoint_addr);
++ if (error.Fail()) {
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s pid %" PRIu64 " tid %" PRIu64
++ ": failed to set PC: %s",
++ __FUNCTION__, GetID(), thread.GetID(), error.AsCString());
++ return error;
++ }
++
++ return error;
++}
++
++Error NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
++ FileSpec &file_spec) {
++ FileSpec module_file_spec(module_path, true);
++
++ bool found = false;
++ file_spec.Clear();
++ ProcFileReader::ProcessLineByLine(
++ GetID(), "maps", [&](const std::string &line) {
++ SmallVector<StringRef, 16> columns;
++ StringRef(line).split(columns, " ", -1, false);
++ if (columns.size() < 6)
++ return true; // continue searching
++
++ FileSpec this_file_spec(columns[5].str(), false);
++ if (this_file_spec.GetFilename() != module_file_spec.GetFilename())
++ return true; // continue searching
++
++ file_spec = this_file_spec;
++ found = true;
++ return false; // we are done
++ });
++
++ if (!found)
++ return Error("Module file (%s) not found in /proc/%" PRIu64 "/maps file!",
++ module_file_spec.GetFilename().AsCString(), GetID());
++
++ return Error();
++}
++
++Error NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
++ lldb::addr_t &load_addr) {
++ load_addr = LLDB_INVALID_ADDRESS;
++ Error error = ProcFileReader::ProcessLineByLine(
++ GetID(), "maps", [&](const std::string &line) -> bool {
++ StringRef maps_row(line);
++
++ SmallVector<StringRef, 16> maps_columns;
++ maps_row.split(maps_columns, StringRef(" "), -1, false);
++
++ if (maps_columns.size() < 6) {
++ // Return true to continue reading the proc file
++ return true;
++ }
++
++ if (maps_columns[5] == file_name) {
++ StringExtractor addr_extractor(maps_columns[0].str().c_str());
++ load_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
++
++ // Return false to stop reading the proc file further
++ return false;
++ }
++
++ // Return true to continue reading the proc file
++ return true;
++ });
++ return error;
++}
++
++NativeThreadNetBSDSP NativeProcessNetBSD::GetThreadByID(lldb::tid_t tid) {
++ return std::static_pointer_cast<NativeThreadNetBSD>(
++ NativeProcessProtocol::GetThreadByID(tid));
++}
++
++Error NativeProcessNetBSD::ResumeThread(NativeThreadNetBSD &thread,
++ lldb::StateType state, int signo) {
++ Log *const log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (tid: %" PRIu64 ")", __FUNCTION__,
++ thread.GetID());
++
++ // Before we do the resume below, first check if we have a pending
++ // stop notification that is currently waiting for
++ // all threads to stop. This is potentially a buggy situation since
++ // we're ostensibly waiting for threads to stop before we send out the
++ // pending notification, and here we are resuming one before we send
++ // out the pending stop notification.
++ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && log) {
++ log->Printf("NativeProcessNetBSD::%s about to resume tid %" PRIu64
++ " per explicit request but we have a pending stop notification "
++ "(tid %" PRIu64 ") that is actively waiting for this thread to "
++ "stop. Valid sequence of events?",
++ __FUNCTION__, thread.GetID(), m_pending_notification_tid);
++ }
++
++ // Request a resume. We expect this to be synchronous and the system
++ // to reflect it is running after this completes.
++ switch (state) {
++ case eStateRunning: {
++ const auto resume_result = thread.Resume(signo);
++ if (resume_result.Success())
++ SetState(eStateRunning, true);
++ return resume_result;
++ }
++ case eStateStepping: {
++ const auto step_result = thread.SingleStep(signo);
++ if (step_result.Success())
++ SetState(eStateRunning, true);
++ return step_result;
++ }
++ default:
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s Unhandled state %s.", __FUNCTION__,
++ StateAsCString(state));
++ llvm_unreachable("Unhandled state for resume");
++ }
++}
++
++//===----------------------------------------------------------------------===//
++
++void NativeProcessNetBSD::StopRunningThreads(const lldb::tid_t triggering_tid) {
++ Log *const log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
++
++ if (log) {
++ log->Printf("NativeProcessNetBSD::%s about to process event: "
++ "(triggering_tid: %" PRIu64 ")",
++ __FUNCTION__, triggering_tid);
++ }
++
++ m_pending_notification_tid = triggering_tid;
++
++ // Request a stop for all the thread stops that need to be stopped
++ // and are not already known to be stopped.
++ for (const auto &thread_sp : m_threads) {
++ if (StateIsRunningState(thread_sp->GetState()))
++ static_pointer_cast<NativeThreadNetBSD>(thread_sp)->RequestStop();
++ }
++
++ SignalIfAllThreadsStopped();
++
++ if (log) {
++ log->Printf("NativeProcessNetBSD::%s event processing done", __FUNCTION__);
++ }
++}
++
++void NativeProcessNetBSD::SignalIfAllThreadsStopped() {
++ if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID)
++ return; // No pending notification. Nothing to do.
++
++ for (const auto &thread_sp : m_threads) {
++ if (StateIsRunningState(thread_sp->GetState()))
++ return; // Some threads are still running. Don't signal yet.
++ }
++
++ // We have a pending notification and all threads have stopped.
++ Log *log(
++ GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS));
++
++ // Clear any temporary breakpoints we used to implement software single
++ // stepping.
++ for (const auto &thread_info : m_threads_stepping_with_breakpoint) {
++ Error error = RemoveBreakpoint(thread_info.second);
++ if (error.Fail())
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s() pid = %" PRIu64
++ " remove stepping breakpoint: %s",
++ __FUNCTION__, thread_info.first, error.AsCString());
++ }
++ m_threads_stepping_with_breakpoint.clear();
++
++ // Notify the delegate about the stop
++ SetCurrentThreadID(m_pending_notification_tid);
++ SetState(StateType::eStateStopped, true);
++ m_pending_notification_tid = LLDB_INVALID_THREAD_ID;
++}
++
++void NativeProcessNetBSD::ThreadWasCreated(NativeThreadNetBSD &thread) {
++ Log *const log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD);
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s (tid: %" PRIu64 ")", __FUNCTION__,
++ thread.GetID());
++
++ if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID &&
++ StateIsRunningState(thread.GetState())) {
++ // We will need to wait for this new thread to stop as well before firing
++ // the
++ // notification.
++ thread.RequestStop();
++ }
++}
++
++void NativeProcessNetBSD::SigchldHandler() {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
++ // Process all pending waitpid notifications.
++ while (true) {
++ int status = -1;
++ ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG);
++
++ if (wait_pid == 0)
++ break; // We are done.
++
++ if (wait_pid == -1) {
++ if (errno == EINTR)
++ continue;
++
++ Error error(errno, eErrorTypePOSIX);
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s waitpid (-1, &status, __WALL | "
++ "__WNOTHREAD | WNOHANG) failed: %s",
++ __FUNCTION__, error.AsCString());
++ break;
++ }
++
++ 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 = "(\?\?\?)";
++
++ if (log)
++ log->Printf("NativeProcessNetBSD::%s: waitpid (-1, &status, __WALL | "
++ "__WNOTHREAD | WNOHANG)"
++ "=> pid = %" PRIi32
++ ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",
++ __FUNCTION__, wait_pid, status, status_cstr, signal,
++ exit_status);
++
++ MonitorCallback(wait_pid, exited, signal, exit_status);
++ }
++}
++
++// Wrapper for ptrace to catch errors and log calls.
++// Note that ptrace sets errno on error because -1 can be a valid result (i.e.
++// for PTRACE_PEEK*)
++Error NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
++ void *data, size_t data_size,
++ long *result) {
++ Error error;
++ long int ret;
++
++ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
++
++ PtraceDisplayBytes(req, data, data_size);
++
++ errno = 0;
++ if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
++ ret = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid),
++ *(unsigned int *)addr, data);
++ else
++ ret = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid),
++ addr, data);
++
++ if (ret == -1)
++ error.SetErrorToErrno();
++
++ if (result)
++ *result = ret;
++
++ if (log)
++ log->Printf("ptrace(%d, %" PRIu64 ", %p, %p, %zu)=%lX", req, pid, addr,
++ data, data_size, ret);
++
++ PtraceDisplayBytes(req, data, data_size);
++
++ if (log && error.GetError() != 0) {
++ const char *str;
++ switch (error.GetError()) {
++ case ESRCH:
++ str = "ESRCH";
++ break;
++ case EINVAL:
++ str = "EINVAL";
++ break;
++ case EBUSY:
++ str = "EBUSY";
++ break;
++ case EPERM:
++ str = "EPERM";
++ break;
++ default:
++ str = error.AsCString();
++ }
++ log->Printf("ptrace() failed; errno=%d (%s)", error.GetError(), str);
++ }
++
++ return error;
++}
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.h
new file mode 100644
index 0000000..9e8d9e2
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeProcessNetBSD.h
@@ -0,0 +1,230 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeProcessNetBSD.h.orig 2016-12-17 13:00:53.145447707 +0000
++++ source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+@@ -0,0 +1,225 @@
++//===-- NativeProcessNetBSD.h ---------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef liblldb_NativeProcessNetBSD_H_
++#define liblldb_NativeProcessNetBSD_H_
++
++// C++ Includes
++#include <unordered_set>
++
++// Other libraries and framework includes
++#include "lldb/Core/ArchSpec.h"
++#include "lldb/Host/Debug.h"
++#include "lldb/Host/FileSpec.h"
++#include "lldb/Host/HostThread.h"
++#include "lldb/Target/MemoryRegionInfo.h"
++#include "lldb/lldb-types.h"
++
++#include "NativeThreadNetBSD.h"
++#include "lldb/Host/common/NativeProcessProtocol.h"
++
++namespace lldb_private {
++class Error;
++class Scalar;
++
++namespace process_linux {
++/// @class NativeProcessNetBSD
++/// @brief Manages communication with the inferior (debugee) process.
++///
++/// Upon construction, this class prepares and launches an inferior process for
++/// debugging.
++///
++/// Changes in the inferior process state are broadcasted.
++class NativeProcessNetBSD : public NativeProcessProtocol {
++ friend Error NativeProcessProtocol::Launch(
++ ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
++ MainLoop &mainloop, NativeProcessProtocolSP &process_sp);
++
++ friend Error NativeProcessProtocol::Attach(
++ 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 Interrupt() 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;
++
++ void DoStopIDBumped(uint32_t newBumpId) override;
++
++ Error GetLoadedModuleFileSpec(const char *module_path,
++ FileSpec &file_spec) override;
++
++ Error GetFileLoadAddress(const llvm::StringRef &file_name,
++ lldb::addr_t &load_addr) override;
++
++ NativeThreadNetBSDSP GetThreadByID(lldb::tid_t id);
++
++ // ---------------------------------------------------------------------
++ // Interface used by NativeRegisterContext-derived classes.
++ // ---------------------------------------------------------------------
++ static Error PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
++ void *data = nullptr, size_t data_size = 0,
++ long *result = nullptr);
++
++ bool SupportHardwareSingleStepping() const;
++
++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<MemoryRegionInfo> m_mem_region_cache;
++
++ lldb::tid_t m_pending_notification_tid;
++
++ // List of thread ids stepping with a breakpoint with the address of
++ // the relevan breakpoint
++ std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
++
++ // ---------------------------------------------------------------------
++ // Private Instance Methods
++ // ---------------------------------------------------------------------
++ NativeProcessNetBSD();
++
++ Error 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, Error &error);
++
++ ::pid_t Attach(lldb::pid_t pid, Error &error);
++
++ static Error SetDefaultPtraceOpts(const lldb::pid_t);
++
++ static void *MonitorThread(void *baton);
++
++ void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status);
++
++ void WaitForNewThread(::pid_t tid);
++
++ void MonitorSIGTRAP(const siginfo_t &info, NativeThreadNetBSD &thread);
++
++ void MonitorTrace(NativeThreadNetBSD &thread);
++
++ void MonitorBreakpoint(NativeThreadNetBSD &thread);
++
++ void MonitorWatchpoint(NativeThreadNetBSD &thread, uint32_t wp_index);
++
++ void MonitorSignal(const siginfo_t &info, NativeThreadNetBSD &thread,
++ bool exited);
++
++ Error SetupSoftwareSingleStepping(NativeThreadNetBSD &thread);
++
++#if 0
++ static ::ProcessMessage::CrashReason
++ GetCrashReasonForSIGSEGV(const siginfo_t *info);
++
++ static ::ProcessMessage::CrashReason
++ GetCrashReasonForSIGILL(const siginfo_t *info);
++
++ static ::ProcessMessage::CrashReason
++ GetCrashReasonForSIGFPE(const siginfo_t *info);
++
++ static ::ProcessMessage::CrashReason
++ GetCrashReasonForSIGBUS(const siginfo_t *info);
++#endif
++
++ bool HasThreadNoLock(lldb::tid_t thread_id);
++
++ bool StopTrackingThread(lldb::tid_t thread_id);
++
++ NativeThreadNetBSDSP AddThread(lldb::tid_t thread_id);
++
++ Error GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
++
++ Error FixupBreakpointPCAsNeeded(NativeThreadNetBSD &thread);
++
++ /// Writes a siginfo_t structure corresponding to the given thread ID to the
++ /// memory region pointed to by @p siginfo.
++ Error GetSignalInfo(lldb::tid_t tid, void *siginfo);
++
++ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
++ /// corresponding to the given thread ID to the memory pointed to by @p
++ /// message.
++ Error GetEventMessage(lldb::tid_t tid, unsigned long *message);
++
++ void NotifyThreadDeath(lldb::tid_t tid);
++
++ Error Detach(lldb::tid_t tid);
++
++ // This method is requests a stop on all threads which are still running. It
++ // sets up a
++ // deferred delegate notification, which will fire once threads report as
++ // stopped. The
++ // triggerring_tid will be set as the current thread (main stop reason).
++ void StopRunningThreads(lldb::tid_t triggering_tid);
++
++ // Notify the delegate if all threads have stopped.
++ void SignalIfAllThreadsStopped();
++
++ // Resume the given thread, optionally passing it the given signal. The type
++ // of resume
++ // operation (continue, single-step) depends on the state parameter.
++ Error ResumeThread(NativeThreadNetBSD &thread, lldb::StateType state,
++ int signo);
++
++ void ThreadWasCreated(NativeThreadNetBSD &thread);
++
++ void SigchldHandler();
++};
++
++} // namespace process_linux
++} // namespace lldb_private
++
++#endif // #ifndef liblldb_NativeProcessNetBSD_H_
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.cpp
new file mode 100644
index 0000000..95a6d03
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.cpp
@@ -0,0 +1,218 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp.orig 2016-12-17 13:00:53.147290220 +0000
++++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
+@@ -0,0 +1,213 @@
++//===-- NativeRegisterContextNetBSD.cpp --------------------------*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#include "NativeRegisterContextNetBSD.h"
++
++#include "lldb/Core/RegisterValue.h"
++#include "lldb/Host/common/NativeProcessProtocol.h"
++#include "lldb/Host/common/NativeThreadProtocol.h"
++#include "lldb/Host/linux/Ptrace.h"
++
++#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
++
++using namespace lldb_private;
++using namespace lldb_private::process_linux;
++
++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) {}
++
++lldb::ByteOrder NativeRegisterContextNetBSD::GetByteOrder() const {
++ // Get the target process whose privileged thread was used for the register
++ // read.
++ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
++
++ NativeProcessProtocolSP process_sp(m_thread.GetProcess());
++ if (!process_sp)
++ return byte_order;
++
++ if (!process_sp->GetByteOrder(byte_order)) {
++ // FIXME log here
++ }
++
++ return byte_order;
++}
++
++Error NativeRegisterContextNetBSD::ReadRegisterRaw(uint32_t reg_index,
++ RegisterValue ®_value) {
++ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
++ if (!reg_info)
++ return Error("register %" PRIu32 " not found", reg_index);
++
++ return DoReadRegisterValue(reg_info->byte_offset, reg_info->name,
++ reg_info->byte_size, reg_value);
++}
++
++Error NativeRegisterContextNetBSD::WriteRegisterRaw(
++ uint32_t reg_index, const RegisterValue ®_value) {
++ uint32_t reg_to_write = reg_index;
++ RegisterValue value_to_write = reg_value;
++
++ // Check if this is a subregister of a full register.
++ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
++ if (reg_info->invalidate_regs &&
++ (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
++ Error error;
++
++ RegisterValue full_value;
++ uint32_t full_reg = reg_info->invalidate_regs[0];
++ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
++
++ // Read the full register.
++ error = ReadRegister(full_reg_info, full_value);
++ if (error.Fail())
++ return error;
++
++ lldb::ByteOrder byte_order = GetByteOrder();
++ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
++
++ // Get the bytes for the full register.
++ const uint32_t dest_size = full_value.GetAsMemoryData(
++ full_reg_info, dst, sizeof(dst), byte_order, error);
++ if (error.Success() && dest_size) {
++ uint8_t src[RegisterValue::kMaxRegisterByteSize];
++
++ // Get the bytes for the source data.
++ const uint32_t src_size = reg_value.GetAsMemoryData(
++ reg_info, src, sizeof(src), byte_order, error);
++ if (error.Success() && src_size && (src_size < dest_size)) {
++ // Copy the src bytes to the destination.
++ memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
++ // Set this full register as the value to write.
++ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
++ value_to_write.SetType(full_reg_info);
++ reg_to_write = full_reg;
++ }
++ }
++ }
++
++ const RegisterInfo *const register_to_write_info_p =
++ GetRegisterInfoAtIndex(reg_to_write);
++ assert(register_to_write_info_p &&
++ "register to write does not have valid RegisterInfo");
++ if (!register_to_write_info_p)
++ return Error("NativeRegisterContextNetBSD::%s failed to get RegisterInfo "
++ "for write register index %" PRIu32,
++ __FUNCTION__, reg_to_write);
++
++ return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
++}
++
++Error NativeRegisterContextNetBSD::ReadGPR() {
++ void *buf = GetGPRBuffer();
++ if (!buf)
++ return Error("GPR buffer is NULL");
++ size_t buf_size = GetGPRSize();
++
++ return DoReadGPR(buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::WriteGPR() {
++ void *buf = GetGPRBuffer();
++ if (!buf)
++ return Error("GPR buffer is NULL");
++ size_t buf_size = GetGPRSize();
++
++ return DoWriteGPR(buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::ReadFPR() {
++ void *buf = GetFPRBuffer();
++ if (!buf)
++ return Error("FPR buffer is NULL");
++ size_t buf_size = GetFPRSize();
++
++ return DoReadFPR(buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::WriteFPR() {
++ void *buf = GetFPRBuffer();
++ if (!buf)
++ return Error("FPR buffer is NULL");
++ size_t buf_size = GetFPRSize();
++
++ return DoWriteFPR(buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::ReadRegisterSet(void *buf, size_t buf_size,
++ unsigned int regset) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
++ static_cast<void *>(®set), buf,
++ buf_size);
++}
++
++Error NativeRegisterContextNetBSD::WriteRegisterSet(void *buf, size_t buf_size,
++ unsigned int regset) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
++ static_cast<void *>(®set), buf,
++ buf_size);
++}
++
++Error NativeRegisterContextNetBSD::DoReadRegisterValue(uint32_t offset,
++ const char *reg_name,
++ uint32_t size,
++ RegisterValue &value) {
++ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
++
++ long data;
++ Error error = NativeProcessNetBSD::PtraceWrapper(
++ PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset),
++ nullptr, 0, &data);
++
++ if (error.Success())
++ // First cast to an unsigned of the same size to avoid sign extension.
++ value.SetUInt(static_cast<unsigned long>(data), size);
++
++ if (log)
++ log->Printf("NativeRegisterContextNetBSD::%s() reg %s: 0x%lx", __FUNCTION__,
++ reg_name, data);
++
++ return error;
++}
++
++Error NativeRegisterContextNetBSD::DoWriteRegisterValue(
++ uint32_t offset, const char *reg_name, const RegisterValue &value) {
++ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
++
++ void *buf = reinterpret_cast<void *>(value.GetAsUInt64());
++
++ if (log)
++ log->Printf("NativeRegisterContextNetBSD::%s() reg %s: %p", __FUNCTION__,
++ reg_name, buf);
++
++ return NativeProcessNetBSD::PtraceWrapper(
++ PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
++}
++
++Error NativeRegisterContextNetBSD::DoReadGPR(void *buf, size_t buf_size) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
++ nullptr, buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::DoWriteGPR(void *buf, size_t buf_size) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
++ nullptr, buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::DoReadFPR(void *buf, size_t buf_size) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
++ nullptr, buf, buf_size);
++}
++
++Error NativeRegisterContextNetBSD::DoWriteFPR(void *buf, size_t buf_size) {
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
++ nullptr, buf, buf_size);
++}
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.h
new file mode 100644
index 0000000..aa0d15e
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD.h
@@ -0,0 +1,97 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h.orig 2016-12-17 13:00:53.149085298 +0000
++++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
+@@ -0,0 +1,92 @@
++//===-- NativeRegisterContextNetBSD.h ----------------------------*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef lldb_NativeRegisterContextNetBSD_h
++#define lldb_NativeRegisterContextNetBSD_h
++
++#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
++#include "lldb/Host/common/NativeThreadProtocol.h"
++
++#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
++
++namespace lldb_private {
++namespace process_linux {
++
++class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo {
++public:
++ NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread,
++ uint32_t concrete_frame_idx,
++ RegisterInfoInterface *reg_info_interface_p);
++
++ // This function is implemented in the NativeRegisterContextNetBSD_* subclasses
++ // to create a new
++ // instance of the host specific NativeRegisterContextNetBSD. The
++ // implementations can't collide
++ // as only one NativeRegisterContextNetBSD_* variant should be compiled into
++ // the final
++ // executable.
++ static NativeRegisterContextNetBSD *
++ CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
++ NativeThreadProtocol &native_thread,
++ uint32_t concrete_frame_idx);
++
++protected:
++ lldb::ByteOrder GetByteOrder() const;
++
++ virtual Error ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value);
++
++ virtual Error WriteRegisterRaw(uint32_t reg_index,
++ const RegisterValue ®_value);
++
++ virtual Error ReadRegisterSet(void *buf, size_t buf_size,
++ unsigned int regset);
++
++ virtual Error WriteRegisterSet(void *buf, size_t buf_size,
++ unsigned int regset);
++
++ virtual Error ReadGPR();
++
++ virtual Error WriteGPR();
++
++ virtual Error ReadFPR();
++
++ virtual Error WriteFPR();
++
++ virtual void *GetGPRBuffer() { return nullptr; }
++
++ virtual size_t GetGPRSize() {
++ return GetRegisterInfoInterface().GetGPRSize();
++ }
++
++ virtual void *GetFPRBuffer() { return nullptr; }
++
++ virtual size_t GetFPRSize() { return 0; }
++
++ // The Do*** functions are executed on the privileged thread and can perform
++ // ptrace
++ // operations directly.
++ virtual Error DoReadRegisterValue(uint32_t offset, const char *reg_name,
++ uint32_t size, RegisterValue &value);
++
++ virtual Error DoWriteRegisterValue(uint32_t offset, const char *reg_name,
++ const RegisterValue &value);
++
++ virtual Error DoReadGPR(void *buf, size_t buf_size);
++
++ virtual Error DoWriteGPR(void *buf, size_t buf_size);
++
++ virtual Error DoReadFPR(void *buf, size_t buf_size);
++
++ virtual Error DoWriteFPR(void *buf, size_t buf_size);
++};
++
++} // namespace process_linux
++} // namespace lldb_private
++
++#endif // #ifndef lldb_NativeRegisterContextNetBSD_h
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.cpp
new file mode 100644
index 0000000..454ccc4
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.cpp
@@ -0,0 +1,1226 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp.orig 2016-12-17 13:00:53.151215810 +0000
++++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
+@@ -0,0 +1,1221 @@
++//===-- 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(__i386__) || defined(__x86_64__)
++
++#include "NativeRegisterContextNetBSD_x86_64.h"
++
++#include "lldb/Core/DataBufferHeap.h"
++#include "lldb/Core/Error.h"
++#include "lldb/Core/Log.h"
++#include "lldb/Core/RegisterValue.h"
++#include "lldb/Host/HostInfo.h"
++
++#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h"
++#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
++
++#include <linux/elf.h>
++
++using namespace lldb_private;
++using namespace lldb_private::process_linux;
++
++// ----------------------------------------------------------------------------
++// Private namespace.
++// ----------------------------------------------------------------------------
++
++namespace {
++// x86 32-bit general purpose registers.
++const uint32_t g_gpr_regnums_i386[] = {
++ lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386,
++ lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386,
++ lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386,
++ lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386,
++ lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386,
++ lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386,
++ lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386,
++ lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
++ 1 ==
++ k_num_gpr_registers_i386,
++ "g_gpr_regnums_i386 has wrong number of register infos");
++
++// x86 32-bit floating point registers.
++const uint32_t g_fpu_regnums_i386[] = {
++ lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386,
++ lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386,
++ lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386,
++ lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386,
++ lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386,
++ lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386,
++ lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386,
++ lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386,
++ lldb_xmm6_i386, lldb_xmm7_i386,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) -
++ 1 ==
++ k_num_fpr_registers_i386,
++ "g_fpu_regnums_i386 has wrong number of register infos");
++
++// x86 32-bit AVX registers.
++const uint32_t g_avx_regnums_i386[] = {
++ lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
++ lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
++ 1 ==
++ k_num_avx_registers_i386,
++ " g_avx_regnums_i386 has wrong number of register infos");
++
++// x64 32-bit MPX registers.
++static const uint32_t g_mpx_regnums_i386[] = {
++ lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, lldb_bnd3_i386,
++ lldb_bndcfgu_i386, lldb_bndstatus_i386,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
++ 1 ==
++ k_num_mpx_registers_i386,
++ "g_mpx_regnums_x86_64 has wrong number of register infos");
++
++// 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");
++
++// x86 64-bit floating point registers.
++static const uint32_t g_fpu_regnums_x86_64[] = {
++ lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
++ lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
++ lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64,
++ lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64,
++ lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64,
++ lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64,
++ lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64,
++ lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64,
++ lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64,
++ lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64,
++ lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64,
++ lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64,
++ lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64,
++ lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
++ 1 ==
++ k_num_fpr_registers_x86_64,
++ "g_fpu_regnums_x86_64 has wrong number of register infos");
++
++// x86 64-bit AVX registers.
++static const uint32_t g_avx_regnums_x86_64[] = {
++ lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64,
++ lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64,
++ lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64,
++ lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
++ 1 ==
++ k_num_avx_registers_x86_64,
++ "g_avx_regnums_x86_64 has wrong number of register infos");
++
++// x86 64-bit MPX registers.
++static const uint32_t g_mpx_regnums_x86_64[] = {
++ lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
++ lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
++ LLDB_INVALID_REGNUM // register sets need to end with this flag
++};
++static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
++ 1 ==
++ k_num_mpx_registers_x86_64,
++ "g_mpx_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 32-bit.
++static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
++ {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
++ g_gpr_regnums_i386},
++ {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
++ g_fpu_regnums_i386},
++ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
++ g_avx_regnums_i386},
++ { "Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
++ g_mpx_regnums_i386}};
++
++// 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},
++ {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
++ g_fpu_regnums_x86_64},
++ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
++ g_avx_regnums_x86_64},
++ { "Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
++ g_mpx_regnums_x86_64}};
++}
++
++#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR))
++
++// ----------------------------------------------------------------------------
++// Required ptrace defines.
++// ----------------------------------------------------------------------------
++
++// Support ptrace extensions even when compiled without required kernel support
++#ifndef NT_X86_XSTATE
++#define NT_X86_XSTATE 0x202
++#endif
++#ifndef NT_PRXFPREG
++#define NT_PRXFPREG 0x46e62b7f
++#endif
++
++// On x86_64 NT_PRFPREG is used to access the FXSAVE area. On i386, we need to
++// use NT_PRXFPREG.
++static inline unsigned int fxsr_regset(const ArchSpec &arch) {
++ return arch.GetAddressByteSize() == 8 ? NT_PRFPREG : NT_PRXFPREG;
++}
++
++// ----------------------------------------------------------------------------
++// Required MPX define.
++// ----------------------------------------------------------------------------
++
++// Support MPX extensions also if compiled with compiler without MPX support.
++#ifndef bit_MPX
++#define bit_MPX 0x4000
++#endif
++
++// ----------------------------------------------------------------------------
++// XCR0 extended register sets masks.
++// ----------------------------------------------------------------------------
++#define mask_XSTATE_AVX (1ULL << 2)
++#define mask_XSTATE_BNDREGS (1ULL << 3)
++#define mask_XSTATE_BNDCFG (1ULL << 4)
++#define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG)
++
++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) {
++ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
++ // 32-bit hosts run with a RegisterContextNetBSD_i386 context.
++ return new RegisterContextNetBSD_i386(target_arch);
++ } else {
++ 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_xstate_type(XStateType::Invalid), m_fpr(), m_iovec(), m_ymm_set(),
++ m_mpx_set(), m_reg_info(), m_gpr_x86_64() {
++ // Set up data about ranges of valid registers.
++ switch (target_arch.GetMachine()) {
++ case llvm::Triple::x86:
++ m_reg_info.num_registers = k_num_registers_i386;
++ m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
++ m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
++ m_reg_info.num_avx_registers = k_num_avx_registers_i386;
++ m_reg_info.num_mpx_registers = k_num_mpx_registers_i386;
++ m_reg_info.last_gpr = k_last_gpr_i386;
++ m_reg_info.first_fpr = k_first_fpr_i386;
++ m_reg_info.last_fpr = k_last_fpr_i386;
++ m_reg_info.first_st = lldb_st0_i386;
++ m_reg_info.last_st = lldb_st7_i386;
++ m_reg_info.first_mm = lldb_mm0_i386;
++ m_reg_info.last_mm = lldb_mm7_i386;
++ m_reg_info.first_xmm = lldb_xmm0_i386;
++ m_reg_info.last_xmm = lldb_xmm7_i386;
++ m_reg_info.first_ymm = lldb_ymm0_i386;
++ m_reg_info.last_ymm = lldb_ymm7_i386;
++ m_reg_info.first_mpxr = lldb_bnd0_i386;
++ m_reg_info.last_mpxr = lldb_bnd3_i386;
++ m_reg_info.first_mpxc = lldb_bndcfgu_i386;
++ m_reg_info.last_mpxc = lldb_bndstatus_i386;
++ m_reg_info.first_dr = lldb_dr0_i386;
++ m_reg_info.gpr_flags = lldb_eflags_i386;
++ break;
++ case llvm::Triple::x86_64:
++ m_reg_info.num_registers = k_num_registers_x86_64;
++ m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
++ m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
++ m_reg_info.num_avx_registers = k_num_avx_registers_x86_64;
++ m_reg_info.num_mpx_registers = k_num_mpx_registers_x86_64;
++ m_reg_info.last_gpr = k_last_gpr_x86_64;
++ m_reg_info.first_fpr = k_first_fpr_x86_64;
++ m_reg_info.last_fpr = k_last_fpr_x86_64;
++ m_reg_info.first_st = lldb_st0_x86_64;
++ m_reg_info.last_st = lldb_st7_x86_64;
++ m_reg_info.first_mm = lldb_mm0_x86_64;
++ m_reg_info.last_mm = lldb_mm7_x86_64;
++ m_reg_info.first_xmm = lldb_xmm0_x86_64;
++ m_reg_info.last_xmm = lldb_xmm15_x86_64;
++ m_reg_info.first_ymm = lldb_ymm0_x86_64;
++ m_reg_info.last_ymm = lldb_ymm15_x86_64;
++ m_reg_info.first_mpxr = lldb_bnd0_x86_64;
++ m_reg_info.last_mpxr = lldb_bnd3_x86_64;
++ m_reg_info.first_mpxc = lldb_bndcfgu_x86_64;
++ m_reg_info.last_mpxc = lldb_bndstatus_x86_64;
++ m_reg_info.first_dr = lldb_dr0_x86_64;
++ m_reg_info.gpr_flags = lldb_rflags_x86_64;
++ break;
++ default:
++ assert(false && "Unhandled target architecture.");
++ break;
++ }
++
++ // Initialize m_iovec to point to the buffer and buffer size
++ // using the conventions of Berkeley style UIO structures, as required
++ // by PTRACE extensions.
++ m_iovec.iov_base = &m_fpr.xstate.xsave;
++ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
++
++ // Clear out the FPR state.
++ ::memset(&m_fpr, 0, sizeof(FPR));
++
++ // Store byte offset of fctrl (i.e. first register of FPR)
++ const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
++ m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
++}
++
++// 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 (IsRegisterSetAvailable(set_index))
++ ++sets;
++ }
++
++ return sets;
++}
++
++uint32_t NativeRegisterContextNetBSD_x86_64::GetUserRegisterCount() const {
++ uint32_t count = 0;
++ for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
++ const RegisterSet *set = GetRegisterSet(set_index);
++ if (set)
++ count += set->num_registers;
++ }
++ return count;
++}
++
++const RegisterSet *
++NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
++ if (!IsRegisterSetAvailable(set_index))
++ return nullptr;
++
++ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
++ case llvm::Triple::x86:
++ return &g_reg_sets_i386[set_index];
++ case llvm::Triple::x86_64:
++ return &g_reg_sets_x86_64[set_index];
++ default:
++ assert(false && "Unhandled target architecture.");
++ return nullptr;
++ }
++
++ return nullptr;
++}
++
++Error NativeRegisterContextNetBSD_x86_64::ReadRegister(
++ const RegisterInfo *reg_info, RegisterValue ®_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;
++ }
++
++ if (IsFPR(reg) || IsAVX(reg) || IsMPX(reg)) {
++ error = ReadFPR();
++ if (error.Fail())
++ return error;
++ } else {
++ uint32_t full_reg = reg;
++ bool is_subreg = reg_info->invalidate_regs &&
++ (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
++
++ if (is_subreg) {
++ // Read the full aligned 64-bit register.
++ full_reg = reg_info->invalidate_regs[0];
++ }
++
++ error = ReadRegisterRaw(full_reg, reg_value);
++
++ if (error.Success()) {
++ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value
++ // one byte to the right.
++ if (is_subreg && (reg_info->byte_offset & 0x1))
++ reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
++
++ // If our return byte size was greater than the return value reg size,
++ // then
++ // use the type specified by reg_info rather than the uint64_t default
++ if (reg_value.GetByteSize() > reg_info->byte_size)
++ reg_value.SetType(reg_info);
++ }
++ return error;
++ }
++
++ if (reg_info->encoding == lldb::eEncodingVector) {
++ lldb::ByteOrder byte_order = GetByteOrder();
++
++ if (byte_order != lldb::eByteOrderInvalid) {
++ if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
++ reg_value.SetBytes(
++ m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes,
++ reg_info->byte_size, byte_order);
++ if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
++ reg_value.SetBytes(
++ m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes,
++ reg_info->byte_size, byte_order);
++ if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
++ reg_value.SetBytes(
++ m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes,
++ reg_info->byte_size, byte_order);
++ if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) {
++ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
++ if (CopyXSTATEtoYMM(reg, byte_order))
++ reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
++ reg_info->byte_size, byte_order);
++ else {
++ error.SetErrorString("failed to copy ymm register value");
++ return error;
++ }
++ }
++ if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
++ if (CopyXSTATEtoMPX(reg))
++ reg_value.SetBytes(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes,
++ reg_info->byte_size, byte_order);
++ else {
++ error.SetErrorString("failed to copy mpx register value");
++ return error;
++ }
++ }
++ if (reg >= m_reg_info.first_mpxc && reg <= m_reg_info.last_mpxc) {
++ if (CopyXSTATEtoMPX(reg))
++ reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,
++ reg_info->byte_size, byte_order);
++ else {
++ error.SetErrorString("failed to copy mpx register value");
++ return error;
++ }
++ }
++
++ if (reg_value.GetType() != RegisterValue::eTypeBytes)
++ error.SetErrorString(
++ "write failed - type was expected to be RegisterValue::eTypeBytes");
++
++ return error;
++ }
++
++ error.SetErrorString("byte order is invalid");
++ return error;
++ }
++
++ // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
++
++ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
++ // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)}
++ // and stores them in 'm_fpr' (of type FPR structure). To extract values of
++ // fpu
++ // registers, m_fpr should be read at byte offsets calculated wrt to FPR
++ // structure.
++
++ // Since, FPR structure is also one of the member of UserArea structure.
++ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) -
++ // byte_offset(fctrl wrt UserArea)
++ assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
++ uint8_t *src =
++ (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
++ switch (reg_info->byte_size) {
++ case 1:
++ reg_value.SetUInt8(*(uint8_t *)src);
++ break;
++ case 2:
++ reg_value.SetUInt16(*(uint16_t *)src);
++ break;
++ case 4:
++ reg_value.SetUInt32(*(uint32_t *)src);
++ break;
++ case 8:
++ reg_value.SetUInt64(*(uint64_t *)src);
++ break;
++ default:
++ assert(false && "Unhandled data size.");
++ error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32,
++ reg_info->byte_size);
++ break;
++ }
++
++ return error;
++}
++
++Error NativeRegisterContextNetBSD_x86_64::WriteRegister(
++ const RegisterInfo *reg_info, const RegisterValue ®_value) {
++ assert(reg_info && "reg_info is null");
++
++ const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
++ if (reg_index == LLDB_INVALID_REGNUM)
++ return Error("no lldb regnum for %s", reg_info && reg_info->name
++ ? reg_info->name
++ : "<unknown register>");
++
++ if (IsGPR(reg_index))
++ return WriteRegisterRaw(reg_index, reg_value);
++
++ if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) {
++ if (reg_info->encoding == lldb::eEncodingVector) {
++ if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
++ ::memcpy(
++ m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++
++ if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
++ ::memcpy(
++ m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++
++ if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
++ ::memcpy(
++ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++
++ if (reg_index >= m_reg_info.first_ymm &&
++ reg_index <= m_reg_info.last_ymm) {
++ // Store ymm register content, and split into the register halves in
++ // xmm.bytes and ymmh.bytes
++ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
++ return Error("CopyYMMtoXSTATE() failed");
++ }
++
++ if (reg_index >= m_reg_info.first_mpxr &&
++ reg_index <= m_reg_info.last_mpxr) {
++ ::memcpy(m_mpx_set.mpxr[reg_index - m_reg_info.first_mpxr].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++ if (!CopyMPXtoXSTATE(reg_index))
++ return Error("CopyMPXtoXSTATE() failed");
++ }
++
++ if (reg_index >= m_reg_info.first_mpxc &&
++ reg_index <= m_reg_info.last_mpxc) {
++ ::memcpy(m_mpx_set.mpxc[reg_index - m_reg_info.first_mpxc].bytes,
++ reg_value.GetBytes(), reg_value.GetByteSize());
++ if (!CopyMPXtoXSTATE(reg_index))
++ return Error("CopyMPXtoXSTATE() failed");
++ }
++ } else {
++ // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
++
++ // Byte offsets of all registers are calculated wrt 'UserArea' structure.
++ // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only
++ // fpu
++ // registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu registers
++ // should
++ // be written in m_fpr at byte offsets calculated wrt FPR structure.
++
++ // Since, FPR structure is also one of the member of UserArea structure.
++ // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) -
++ // byte_offset(fctrl wrt UserArea)
++ assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) <
++ sizeof(m_fpr));
++ uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset -
++ m_fctrl_offset_in_userarea;
++ switch (reg_info->byte_size) {
++ case 1:
++ *(uint8_t *)dst = reg_value.GetAsUInt8();
++ break;
++ case 2:
++ *(uint16_t *)dst = reg_value.GetAsUInt16();
++ break;
++ case 4:
++ *(uint32_t *)dst = reg_value.GetAsUInt32();
++ break;
++ case 8:
++ *(uint64_t *)dst = reg_value.GetAsUInt64();
++ break;
++ default:
++ assert(false && "Unhandled data size.");
++ return Error("unhandled register data size %" PRIu32,
++ reg_info->byte_size);
++ }
++ }
++
++ Error error = WriteFPR();
++ if (error.Fail())
++ return error;
++
++ if (IsAVX(reg_index)) {
++ if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
++ return Error("CopyYMMtoXSTATE() failed");
++ }
++
++ if (IsMPX(reg_index)) {
++ if (!CopyMPXtoXSTATE(reg_index))
++ return Error("CopyMPXtoXSTATE() failed");
++ }
++ return Error();
++ }
++ return Error("failed - register wasn't recognized to be a GPR or an FPR, "
++ "write strategy unknown");
++}
++
++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;
++
++ error = ReadFPR();
++ 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();
++ if (m_xstate_type == XStateType::FXSAVE)
++ ::memcpy(dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
++ else if (m_xstate_type == XStateType::XSAVE) {
++ lldb::ByteOrder byte_order = GetByteOrder();
++
++ if (IsCPUFeatureAvailable(RegSet::avx)) {
++ // Assemble the YMM register content from the register halves.
++ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
++ ++reg) {
++ if (!CopyXSTATEtoYMM(reg, byte_order)) {
++ error.SetErrorStringWithFormat(
++ "NativeRegisterContextNetBSD_x86_64::%s "
++ "CopyXSTATEtoYMM() failed for reg num "
++ "%" PRIu32,
++ __FUNCTION__, reg);
++ return error;
++ }
++ }
++ }
++
++ if (IsCPUFeatureAvailable(RegSet::mpx)) {
++ for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc;
++ ++reg) {
++ if (!CopyXSTATEtoMPX(reg)) {
++ error.SetErrorStringWithFormat(
++ "NativeRegisterContextNetBSD_x86_64::%s "
++ "CopyXSTATEtoMPX() failed for reg num "
++ "%" PRIu32,
++ __FUNCTION__, reg);
++ return error;
++ }
++ }
++ }
++ // Copy the extended register state including the assembled ymm registers.
++ ::memcpy(dst, &m_fpr, sizeof(m_fpr));
++ } else {
++ assert(false && "how do we save the floating point registers?");
++ error.SetErrorString("unsure how to save the floating point registers");
++ }
++ /** The following code is specific to NetBSD x86 based architectures,
++ * where the register orig_eax (32 bit)/orig_rax (64 bit) is set to
++ * -1 to solve the bug 23659, such a setting prevents the automatic
++ * decrement of the instruction pointer which was causing the SIGILL
++ * exception.
++ * **/
++
++ RegisterValue value((uint64_t)-1);
++ const RegisterInfo *reg_info =
++ GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax");
++ if (reg_info == nullptr)
++ reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax");
++
++ if (reg_info != nullptr)
++ return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, value);
++
++ 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();
++ if (m_xstate_type == XStateType::FXSAVE)
++ ::memcpy(&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
++ else if (m_xstate_type == XStateType::XSAVE)
++ ::memcpy(&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
++
++ error = WriteFPR();
++ if (error.Fail())
++ return error;
++
++ if (m_xstate_type == XStateType::XSAVE) {
++ lldb::ByteOrder byte_order = GetByteOrder();
++
++ if (IsCPUFeatureAvailable(RegSet::avx)) {
++ // Parse the YMM register content from the register halves.
++ for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
++ ++reg) {
++ if (!CopyYMMtoXSTATE(reg, byte_order)) {
++ error.SetErrorStringWithFormat(
++ "NativeRegisterContextNetBSD_x86_64::%s "
++ "CopyYMMtoXSTATE() failed for reg num "
++ "%" PRIu32,
++ __FUNCTION__, reg);
++ return error;
++ }
++ }
++ }
++
++ if (IsCPUFeatureAvailable(RegSet::mpx)) {
++ for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc;
++ ++reg) {
++ if (!CopyMPXtoXSTATE(reg)) {
++ error.SetErrorStringWithFormat(
++ "NativeRegisterContextNetBSD_x86_64::%s "
++ "CopyMPXtoXSTATE() failed for reg num "
++ "%" PRIu32,
++ __FUNCTION__, reg);
++ return error;
++ }
++ }
++ }
++ }
++
++ return error;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsCPUFeatureAvailable(
++ RegSet feature_code) const {
++ if (m_xstate_type == XStateType::Invalid) {
++ if (const_cast<NativeRegisterContextNetBSD_x86_64 *>(this)->ReadFPR().Fail())
++ return false;
++ }
++ switch (feature_code) {
++ case RegSet::gpr:
++ case RegSet::fpu:
++ return true;
++ case RegSet::avx: // Check if CPU has AVX and if there is kernel support, by
++ // reading in the XCR0 area of XSAVE.
++ if ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX)
++ return true;
++ break;
++ case RegSet::mpx: // Check if CPU has MPX and if there is kernel support, by
++ // reading in the XCR0 area of XSAVE.
++ if ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX)
++ return true;
++ break;
++ }
++ return false;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsRegisterSetAvailable(
++ uint32_t set_index) const {
++ uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
++
++ switch (static_cast<RegSet>(set_index)) {
++ case RegSet::gpr:
++ case RegSet::fpu:
++ return (set_index < num_sets);
++ case RegSet::avx:
++ return IsCPUFeatureAvailable(RegSet::avx);
++ case RegSet::mpx:
++ return IsCPUFeatureAvailable(RegSet::mpx);
++ }
++ return false;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsGPR(uint32_t reg_index) const {
++ // GPRs come first.
++ return reg_index <= m_reg_info.last_gpr;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsFPR(uint32_t reg_index) const {
++ return (m_reg_info.first_fpr <= reg_index &&
++ reg_index <= m_reg_info.last_fpr);
++}
++
++Error NativeRegisterContextNetBSD_x86_64::WriteFPR() {
++ switch (m_xstate_type) {
++ case XStateType::FXSAVE:
++ return WriteRegisterSet(
++ &m_iovec, sizeof(m_fpr.xstate.xsave),
++ fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture()));
++ case XStateType::XSAVE:
++ return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave),
++ NT_X86_XSTATE);
++ default:
++ return Error("Unrecognized FPR type.");
++ }
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsAVX(uint32_t reg_index) const {
++ if (!IsCPUFeatureAvailable(RegSet::avx))
++ return false;
++ return (m_reg_info.first_ymm <= reg_index &&
++ reg_index <= m_reg_info.last_ymm);
++}
++
++bool NativeRegisterContextNetBSD_x86_64::CopyXSTATEtoYMM(
++ uint32_t reg_index, lldb::ByteOrder byte_order) {
++ if (!IsAVX(reg_index))
++ return false;
++
++ if (byte_order == lldb::eByteOrderLittle) {
++ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
++ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
++ sizeof(XMMReg));
++ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes +
++ sizeof(XMMReg),
++ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
++ sizeof(YMMHReg));
++ return true;
++ }
++
++ if (byte_order == lldb::eByteOrderBig) {
++ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes +
++ sizeof(XMMReg),
++ m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
++ sizeof(XMMReg));
++ ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
++ m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
++ sizeof(YMMHReg));
++ return true;
++ }
++ return false; // unsupported or invalid byte order
++}
++
++bool NativeRegisterContextNetBSD_x86_64::CopyYMMtoXSTATE(
++ uint32_t reg, lldb::ByteOrder byte_order) {
++ if (!IsAVX(reg))
++ return false;
++
++ if (byte_order == lldb::eByteOrderLittle) {
++ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
++ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(XMMReg));
++ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
++ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
++ sizeof(YMMHReg));
++ return true;
++ }
++
++ if (byte_order == lldb::eByteOrderBig) {
++ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
++ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
++ sizeof(XMMReg));
++ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
++ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, sizeof(YMMHReg));
++ return true;
++ }
++ return false; // unsupported or invalid byte order
++}
++
++void *NativeRegisterContextNetBSD_x86_64::GetFPRBuffer() {
++ switch (m_xstate_type) {
++ case XStateType::FXSAVE:
++ return &m_fpr.xstate.fxsave;
++ case XStateType::XSAVE:
++ return &m_iovec;
++ default:
++ return nullptr;
++ }
++}
++
++size_t NativeRegisterContextNetBSD_x86_64::GetFPRSize() {
++ switch (m_xstate_type) {
++ case XStateType::FXSAVE:
++ return sizeof(m_fpr.xstate.fxsave);
++ case XStateType::XSAVE:
++ return sizeof(m_iovec);
++ default:
++ return 0;
++ }
++}
++
++Error NativeRegisterContextNetBSD_x86_64::ReadFPR() {
++ Error error;
++
++ // Probe XSAVE and if it is not supported fall back to FXSAVE.
++ if (m_xstate_type != XStateType::FXSAVE) {
++ error =
++ ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
++ if (!error.Fail()) {
++ m_xstate_type = XStateType::XSAVE;
++ return error;
++ }
++ }
++ error = ReadRegisterSet(
++ &m_iovec, sizeof(m_fpr.xstate.xsave),
++ fxsr_regset(GetRegisterInfoInterface().GetTargetArchitecture()));
++ if (!error.Fail()) {
++ m_xstate_type = XStateType::FXSAVE;
++ return error;
++ }
++ return Error("Unrecognized FPR type.");
++}
++
++bool NativeRegisterContextNetBSD_x86_64::IsMPX(uint32_t reg_index) const {
++ if (!IsCPUFeatureAvailable(RegSet::mpx))
++ return false;
++ return (m_reg_info.first_mpxr <= reg_index &&
++ reg_index <= m_reg_info.last_mpxc);
++}
++
++bool NativeRegisterContextNetBSD_x86_64::CopyXSTATEtoMPX(uint32_t reg) {
++ if (!IsMPX(reg))
++ return false;
++
++ if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
++ ::memcpy(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes,
++ m_fpr.xstate.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes,
++ sizeof(MPXReg));
++ } else {
++ ::memcpy(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,
++ m_fpr.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes,
++ sizeof(MPXCsr));
++ }
++ return true;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::CopyMPXtoXSTATE(uint32_t reg) {
++ if (!IsMPX(reg))
++ return false;
++
++ if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
++ ::memcpy(m_fpr.xstate.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes,
++ m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, sizeof(MPXReg));
++ } else {
++ ::memcpy(m_fpr.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes,
++ m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr));
++ }
++ return true;
++}
++
++Error NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
++ bool &is_hit) {
++ if (wp_index >= NumSupportedHardwareWatchpoints())
++ return Error("Watchpoint index out of range");
++
++ RegisterValue reg_value;
++ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
++ if (error.Fail()) {
++ is_hit = false;
++ return error;
++ }
++
++ uint64_t status_bits = reg_value.GetAsUInt64();
++
++ is_hit = status_bits & (1 << wp_index);
++
++ return error;
++}
++
++Error NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
++ uint32_t &wp_index, lldb::addr_t trap_addr) {
++ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
++ for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
++ bool is_hit;
++ Error error = IsWatchpointHit(wp_index, is_hit);
++ if (error.Fail()) {
++ wp_index = LLDB_INVALID_INDEX32;
++ return error;
++ } else if (is_hit) {
++ return error;
++ }
++ }
++ wp_index = LLDB_INVALID_INDEX32;
++ return Error();
++}
++
++Error NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
++ bool &is_vacant) {
++ if (wp_index >= NumSupportedHardwareWatchpoints())
++ return Error("Watchpoint index out of range");
++
++ RegisterValue reg_value;
++ Error error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
++ if (error.Fail()) {
++ is_vacant = false;
++ return error;
++ }
++
++ uint64_t control_bits = reg_value.GetAsUInt64();
++
++ is_vacant = !(control_bits & (1 << (2 * wp_index)));
++
++ return error;
++}
++
++Error NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
++ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
++
++ if (wp_index >= NumSupportedHardwareWatchpoints())
++ return Error("Watchpoint index out of range");
++
++ // Read only watchpoints aren't supported on x86_64. Fall back to read/write
++ // waitchpoints instead.
++ // TODO: Add logic to detect when a write happens and ignore that watchpoint
++ // hit.
++ if (watch_flags == 0x2)
++ watch_flags = 0x3;
++
++ if (watch_flags != 0x1 && watch_flags != 0x3)
++ return Error("Invalid read/write bits for watchpoint");
++
++ if (size != 1 && size != 2 && size != 4 && size != 8)
++ return Error("Invalid size for watchpoint");
++
++ bool is_vacant;
++ Error error = IsWatchpointVacant(wp_index, is_vacant);
++ if (error.Fail())
++ return error;
++ if (!is_vacant)
++ return Error("Watchpoint index not vacant");
++
++ RegisterValue reg_value;
++ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
++ if (error.Fail())
++ return error;
++
++ // for watchpoints 0, 1, 2, or 3, respectively,
++ // set bits 1, 3, 5, or 7
++ uint64_t enable_bit = 1 << (2 * wp_index);
++
++ // set bits 16-17, 20-21, 24-25, or 28-29
++ // with 0b01 for write, and 0b11 for read/write
++ uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
++
++ // set bits 18-19, 22-23, 26-27, or 30-31
++ // with 0b00, 0b01, 0b10, or 0b11
++ // for 1, 2, 8 (if supported), or 4 bytes, respectively
++ uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
++
++ uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
++
++ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
++
++ control_bits |= enable_bit | rw_bits | size_bits;
++
++ error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr));
++ if (error.Fail())
++ return error;
++
++ error =
++ WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
++ if (error.Fail())
++ return error;
++
++ error.Clear();
++ return error;
++}
++
++bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
++ uint32_t wp_index) {
++ if (wp_index >= NumSupportedHardwareWatchpoints())
++ return false;
++
++ RegisterValue reg_value;
++
++ // for watchpoints 0, 1, 2, or 3, respectively,
++ // clear bits 0, 1, 2, or 3 of the debug status register (DR6)
++ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
++ if (error.Fail())
++ return false;
++ uint64_t bit_mask = 1 << wp_index;
++ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
++ error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
++ if (error.Fail())
++ return false;
++
++ // for watchpoints 0, 1, 2, or 3, respectively,
++ // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31}
++ // of the debug control register (DR7)
++ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
++ if (error.Fail())
++ return false;
++ bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
++ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
++ return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits))
++ .Success();
++}
++
++Error NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
++ RegisterValue reg_value;
++
++ // clear bits {0-4} of the debug status register (DR6)
++ Error error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value);
++ if (error.Fail())
++ return error;
++ uint64_t bit_mask = 0xF;
++ uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
++ error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits));
++ if (error.Fail())
++ return error;
++
++ // clear bits {0-7,16-31} of the debug control register (DR7)
++ error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value);
++ if (error.Fail())
++ return error;
++ bit_mask = 0xFF | (0xFFFF << 16);
++ uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
++ return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits));
++}
++
++uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
++ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
++ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
++ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
++ bool is_vacant;
++ Error error = IsWatchpointVacant(wp_index, is_vacant);
++ if (is_vacant) {
++ error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
++ if (error.Success())
++ return wp_index;
++ }
++ if (error.Fail() && log) {
++ log->Printf("NativeRegisterContextNetBSD_x86_64::%s Error: %s",
++ __FUNCTION__, error.AsCString());
++ }
++ }
++ return LLDB_INVALID_INDEX32;
++}
++
++lldb::addr_t
++NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
++ if (wp_index >= NumSupportedHardwareWatchpoints())
++ return LLDB_INVALID_ADDRESS;
++ RegisterValue reg_value;
++ if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail())
++ return LLDB_INVALID_ADDRESS;
++ return reg_value.GetAsUInt64();
++}
++
++uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
++ // Available debug address registers: dr0, dr1, dr2, dr3
++ return 4;
++}
++
++#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.h
new file mode 100644
index 0000000..5ad98c2
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeRegisterContextNetBSD__x86__64.h
@@ -0,0 +1,151 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h.orig 2016-12-17 13:00:53.153013274 +0000
++++ source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
+@@ -0,0 +1,146 @@
++//===-- 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(__i386__) || defined(__x86_64__)
++
++#ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
++#define lldb_NativeRegisterContextNetBSD_x86_64_h
++
++#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_linux {
++
++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;
++
++ uint32_t GetUserRegisterCount() const override;
++
++ Error ReadRegister(const RegisterInfo *reg_info,
++ RegisterValue ®_value) override;
++
++ Error WriteRegister(const RegisterInfo *reg_info,
++ const RegisterValue ®_value) override;
++
++ Error ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
++
++ Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
++
++ Error IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
++
++ Error GetWatchpointHitIndex(uint32_t &wp_index,
++ lldb::addr_t trap_addr) override;
++
++ Error IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
++
++ bool ClearHardwareWatchpoint(uint32_t wp_index) override;
++
++ Error ClearAllHardwareWatchpoints() override;
++
++ Error SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
++ uint32_t watch_flags, uint32_t wp_index);
++
++ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
++ uint32_t watch_flags) override;
++
++ lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
++
++ uint32_t NumSupportedHardwareWatchpoints() override;
++
++protected:
++ void *GetGPRBuffer() override { return &m_gpr_x86_64; }
++
++ void *GetFPRBuffer() override;
++
++ size_t GetFPRSize() override;
++
++ Error ReadFPR() override;
++
++ Error WriteFPR() override;
++
++private:
++ // Private member types.
++ enum class XStateType { Invalid, FXSAVE, XSAVE };
++ enum class RegSet { gpr, fpu, avx, mpx };
++
++ // Info about register ranges.
++ struct RegInfo {
++ uint32_t num_registers;
++ uint32_t num_gpr_registers;
++ uint32_t num_fpr_registers;
++ uint32_t num_avx_registers;
++ uint32_t num_mpx_registers;
++ uint32_t last_gpr;
++ uint32_t first_fpr;
++ uint32_t last_fpr;
++ uint32_t first_st;
++ uint32_t last_st;
++ uint32_t first_mm;
++ uint32_t last_mm;
++ uint32_t first_xmm;
++ uint32_t last_xmm;
++ uint32_t first_ymm;
++ uint32_t last_ymm;
++ uint32_t first_mpxr;
++ uint32_t last_mpxr;
++ uint32_t first_mpxc;
++ uint32_t last_mpxc;
++ uint32_t first_dr;
++ uint32_t gpr_flags;
++ };
++
++ // Private member variables.
++ mutable XStateType m_xstate_type;
++ FPR m_fpr; // Extended States Area, named FPR for historical reasons.
++ IOVEC m_iovec;
++ YMM m_ymm_set;
++ MPX m_mpx_set;
++ RegInfo m_reg_info;
++ uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
++ uint32_t m_fctrl_offset_in_userarea;
++
++ // Private member methods.
++ bool IsCPUFeatureAvailable(RegSet feature_code) const;
++
++ bool IsRegisterSetAvailable(uint32_t set_index) const;
++
++ bool IsGPR(uint32_t reg_index) const;
++
++ bool IsFPR(uint32_t reg_index) const;
++
++ bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order);
++
++ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
++
++ bool IsAVX(uint32_t reg_index) const;
++
++ bool CopyXSTATEtoMPX(uint32_t reg);
++
++ bool CopyMPXtoXSTATE(uint32_t reg);
++
++ bool IsMPX(uint32_t reg_index) const;
++};
++
++} // namespace process_linux
++} // namespace lldb_private
++
++#endif // #ifndef lldb_NativeRegisterContextNetBSD_x86_64_h
++
++#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp
new file mode 100644
index 0000000..f3292ff
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.cpp
@@ -0,0 +1,486 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp.orig 2016-12-17 13:00:53.154921656 +0000
++++ source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+@@ -0,0 +1,481 @@
++//===-- NativeThreadNetBSD.cpp --------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#include "NativeThreadNetBSD.h"
++
++#include <signal.h>
++#include <sstream>
++
++#include "NativeProcessNetBSD.h"
++#include "NativeRegisterContextNetBSD.h"
++#include "SingleStepCheck.h"
++
++#include "lldb/Core/Log.h"
++#include "lldb/Core/State.h"
++#include "lldb/Host/HostNativeThread.h"
++#include "lldb/Host/linux/Ptrace.h"
++#include "lldb/Utility/LLDBAssert.h"
++#include "lldb/lldb-enumerations.h"
++
++#include "llvm/ADT/SmallString.h"
++
++#include "Plugins/Process/POSIX/CrashReason.h"
++
++#include <sys/syscall.h>
++// Try to define a macro to encapsulate the tgkill syscall
++#define tgkill(pid, tid, sig) \
++ syscall(__NR_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), \
++ sig)
++
++using namespace lldb;
++using namespace lldb_private;
++using namespace lldb_private::process_linux;
++
++namespace {
++void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info,
++ const char *const header) {
++ switch (stop_info.reason) {
++ case eStopReasonNone:
++ log.Printf("%s: %s no stop reason", __FUNCTION__, header);
++ return;
++ case eStopReasonTrace:
++ log.Printf("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header,
++ stop_info.details.signal.signo);
++ return;
++ case eStopReasonBreakpoint:
++ log.Printf("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
++ header, stop_info.details.signal.signo);
++ return;
++ case eStopReasonWatchpoint:
++ log.Printf("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__,
++ header, stop_info.details.signal.signo);
++ return;
++ case eStopReasonSignal:
++ log.Printf("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header,
++ stop_info.details.signal.signo);
++ return;
++ case eStopReasonException:
++ log.Printf("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header,
++ stop_info.details.exception.type);
++ return;
++ case eStopReasonExec:
++ log.Printf("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header,
++ stop_info.details.signal.signo);
++ return;
++ case eStopReasonPlanComplete:
++ log.Printf("%s: %s plan complete", __FUNCTION__, header);
++ return;
++ case eStopReasonThreadExiting:
++ log.Printf("%s: %s thread exiting", __FUNCTION__, header);
++ return;
++ case eStopReasonInstrumentation:
++ log.Printf("%s: %s instrumentation", __FUNCTION__, header);
++ return;
++ default:
++ log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header,
++ static_cast<uint32_t>(stop_info.reason));
++ }
++}
++}
++
++NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD *process,
++ lldb::tid_t tid)
++ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
++ m_stop_info(), m_reg_context_sp(), m_stop_description() {}
++
++std::string NativeThreadNetBSD::GetName() {
++ NativeProcessProtocolSP process_sp = m_process_wp.lock();
++ if (!process_sp)
++ return "<unknown: no process>";
++
++ // const NativeProcessNetBSD *const process =
++ // reinterpret_cast<NativeProcessNetBSD*> (process_sp->get ());
++ llvm::SmallString<32> thread_name;
++ HostNativeThread::GetName(GetID(), thread_name);
++ return thread_name.c_str();
++}
++
++lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
++
++bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
++ std::string &description) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++
++ description.clear();
++
++ switch (m_state) {
++ case eStateStopped:
++ case eStateCrashed:
++ case eStateExited:
++ case eStateSuspended:
++ case eStateUnloaded:
++ if (log)
++ LogThreadStopInfo(*log, m_stop_info, "m_stop_info in thread:");
++ stop_info = m_stop_info;
++ description = m_stop_description;
++ if (log)
++ LogThreadStopInfo(*log, stop_info, "returned stop_info:");
++
++ return true;
++
++ case eStateInvalid:
++ case eStateConnected:
++ case eStateAttaching:
++ case eStateLaunching:
++ case eStateRunning:
++ case eStateStepping:
++ case eStateDetached:
++ if (log) {
++ log->Printf("NativeThreadNetBSD::%s tid %" PRIu64
++ " in state %s cannot answer stop reason",
++ __FUNCTION__, 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) {
++ if (!hardware)
++ return Error("not implemented");
++ if (m_state == eStateLaunching)
++ return Error();
++ Error error = RemoveWatchpoint(addr);
++ if (error.Fail())
++ return error;
++ NativeRegisterContextSP reg_ctx = GetRegisterContext();
++ uint32_t wp_index = reg_ctx->SetHardwareWatchpoint(addr, size, watch_flags);
++ if (wp_index == LLDB_INVALID_INDEX32)
++ return Error("Setting hardware watchpoint failed.");
++ m_watchpoint_index_map.insert({addr, wp_index});
++ return Error();
++}
++
++Error NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
++ auto wp = m_watchpoint_index_map.find(addr);
++ if (wp == m_watchpoint_index_map.end())
++ return Error();
++ uint32_t wp_index = wp->second;
++ m_watchpoint_index_map.erase(wp);
++ if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index))
++ return Error();
++ return Error("Clearing hardware watchpoint failed.");
++}
++
++Error NativeThreadNetBSD::Resume(uint32_t signo) {
++ const StateType new_state = StateType::eStateRunning;
++ MaybeLogStateChange(new_state);
++ m_state = new_state;
++
++ m_stop_info.reason = StopReason::eStopReasonNone;
++ m_stop_description.clear();
++
++ // If watchpoints have been set, but none on this thread,
++ // then this is a new thread. So set all existing watchpoints.
++ if (m_watchpoint_index_map.empty()) {
++ NativeProcessNetBSD &process = GetProcess();
++
++ const auto &watchpoint_map = process.GetWatchpointMap();
++ GetRegisterContext()->ClearAllHardwareWatchpoints();
++ for (const auto &pair : watchpoint_map) {
++ const auto &wp = pair.second;
++ SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware);
++ }
++ }
++
++ intptr_t data = 0;
++
++ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
++ data = signo;
++
++ return NativeProcessNetBSD::PtraceWrapper(PTRACE_CONT, GetID(), nullptr,
++ reinterpret_cast<void *>(data));
++}
++
++void NativeThreadNetBSD::MaybePrepareSingleStepWorkaround() {
++ if (!SingleStepWorkaroundNeeded())
++ return;
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++
++ if (sched_getaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set,
++ &m_original_cpu_set) != 0) {
++ // This should really not fail. But, just in case...
++ if (log) {
++ Error error(errno, eErrorTypePOSIX);
++ log->Printf(
++ "NativeThreadNetBSD::%s Unable to get cpu affinity for thread %" PRIx64
++ ": %s",
++ __FUNCTION__, m_tid, error.AsCString());
++ }
++ return;
++ }
++
++ cpu_set_t set;
++ CPU_ZERO(&set);
++ CPU_SET(0, &set);
++ if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof set, &set) != 0 &&
++ log) {
++ // This may fail in very locked down systems, if the thread is not allowed
++ // to run on
++ // cpu 0. If that happens, only thing we can do is it log it and continue...
++ Error error(errno, eErrorTypePOSIX);
++ log->Printf(
++ "NativeThreadNetBSD::%s Unable to set cpu affinity for thread %" PRIx64
++ ": %s",
++ __FUNCTION__, m_tid, error.AsCString());
++ }
++}
++
++void NativeThreadNetBSD::MaybeCleanupSingleStepWorkaround() {
++ if (!SingleStepWorkaroundNeeded())
++ return;
++
++ if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set,
++ &m_original_cpu_set) != 0) {
++ Error error(errno, eErrorTypePOSIX);
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++ log->Printf(
++ "NativeThreadNetBSD::%s Unable to reset cpu affinity for thread %" PRIx64
++ ": %s",
++ __FUNCTION__, m_tid, error.AsCString());
++ }
++}
++
++Error NativeThreadNetBSD::SingleStep(uint32_t signo) {
++ const StateType new_state = StateType::eStateStepping;
++ MaybeLogStateChange(new_state);
++ m_state = new_state;
++ m_stop_info.reason = StopReason::eStopReasonNone;
++
++ MaybePrepareSingleStepWorkaround();
++
++ intptr_t data = 0;
++ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
++ data = signo;
++
++ // If hardware single-stepping is not supported, we just do a continue. The
++ // breakpoint on the
++ // next instruction has been setup in NativeProcessNetBSD::Resume.
++ return NativeProcessNetBSD::PtraceWrapper(
++ GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP
++ : PTRACE_CONT,
++ m_tid, nullptr, reinterpret_cast<void *>(data));
++}
++
++void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo,
++ const siginfo_t *info) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++ if (log)
++ log->Printf("NativeThreadNetBSD::%s called with signal 0x%02" PRIx32,
++ __FUNCTION__, 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:
++ // In case of MIPS64 target, SI_KERNEL is generated for invalid 64bit
++ // address.
++ const auto reason =
++ (info->si_signo == SIGBUS && info->si_code == SI_KERNEL)
++ ? CrashReason::eInvalidAddress
++ : GetCrashReason(*info);
++ m_stop_description = GetCrashReasonString(reason, *info);
++ break;
++ }
++ }
++}
++
++bool NativeThreadNetBSD::IsStopped(int *signo) {
++ if (!StateIsStoppedState(m_state, false))
++ return false;
++
++ // If we are stopped by a signal, return the signo.
++ if (signo && m_state == StateType::eStateStopped &&
++ m_stop_info.reason == StopReason::eStopReasonSignal) {
++ *signo = m_stop_info.details.signal.signo;
++ }
++
++ // Regardless, we are stopped.
++ return true;
++}
++
++void NativeThreadNetBSD::SetStopped() {
++ if (m_state == StateType::eStateStepping)
++ MaybeCleanupSingleStepWorkaround();
++
++ const StateType new_state = StateType::eStateStopped;
++ MaybeLogStateChange(new_state);
++ m_state = new_state;
++ m_stop_description.clear();
++}
++
++void NativeThreadNetBSD::SetStoppedByExec() {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++ if (log)
++ log->Printf("NativeThreadNetBSD::%s()", __FUNCTION__);
++
++ SetStopped();
++
++ m_stop_info.reason = StopReason::eStopReasonExec;
++ m_stop_info.details.signal.signo = SIGSTOP;
++}
++
++void NativeThreadNetBSD::SetStoppedByBreakpoint() {
++ SetStopped();
++
++ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
++ m_stop_info.details.signal.signo = SIGTRAP;
++ m_stop_description.clear();
++}
++
++void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
++ SetStopped();
++
++ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
++
++ std::ostringstream ostr;
++ ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
++ ostr << wp_index;
++
++ /*
++ * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For
++ * example:
++ * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at
++ * 'm', then
++ * watch exception is generated even when 'n' is read/written. To handle this
++ * case,
++ * find the base address of the load/store instruction and append it in the
++ * stop-info
++ * packet.
++ */
++ ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
++
++ m_stop_description = ostr.str();
++
++ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
++ m_stop_info.details.signal.signo = SIGTRAP;
++}
++
++bool NativeThreadNetBSD::IsStoppedAtBreakpoint() {
++ return GetState() == StateType::eStateStopped &&
++ m_stop_info.reason == StopReason::eStopReasonBreakpoint;
++}
++
++bool NativeThreadNetBSD::IsStoppedAtWatchpoint() {
++ return GetState() == StateType::eStateStopped &&
++ m_stop_info.reason == StopReason::eStopReasonWatchpoint;
++}
++
++void NativeThreadNetBSD::SetStoppedByTrace() {
++ SetStopped();
++
++ m_stop_info.reason = StopReason::eStopReasonTrace;
++ m_stop_info.details.signal.signo = SIGTRAP;
++}
++
++void NativeThreadNetBSD::SetStoppedWithNoReason() {
++ SetStopped();
++
++ m_stop_info.reason = StopReason::eStopReasonNone;
++ m_stop_info.details.signal.signo = 0;
++}
++
++void NativeThreadNetBSD::SetExited() {
++ const StateType new_state = StateType::eStateExited;
++ MaybeLogStateChange(new_state);
++ m_state = new_state;
++
++ m_stop_info.reason = StopReason::eStopReasonThreadExiting;
++}
++
++Error NativeThreadNetBSD::RequestStop() {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++
++ NativeProcessNetBSD &process = GetProcess();
++
++ lldb::pid_t pid = process.GetID();
++ lldb::tid_t tid = GetID();
++
++ if (log)
++ log->Printf("NativeThreadNetBSD::%s requesting thread stop(pid: %" PRIu64
++ ", tid: %" PRIu64 ")",
++ __FUNCTION__, pid, tid);
++
++ Error err;
++ errno = 0;
++ if (::tgkill(pid, tid, SIGSTOP) != 0) {
++ err.SetErrorToErrno();
++ if (log)
++ log->Printf("NativeThreadNetBSD::%s tgkill(%" PRIu64 ", %" PRIu64
++ ", SIGSTOP) failed: %s",
++ __FUNCTION__, pid, tid, err.AsCString());
++ }
++
++ return err;
++}
++
++void NativeThreadNetBSD::MaybeLogStateChange(lldb::StateType new_state) {
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++ // If we're not logging, we're done.
++ if (!log)
++ return;
++
++ // If this is a state change to the same state, we're done.
++ lldb::StateType old_state = m_state;
++ if (new_state == old_state)
++ return;
++
++ NativeProcessProtocolSP m_process_sp = m_process_wp.lock();
++ lldb::pid_t pid =
++ m_process_sp ? m_process_sp->GetID() : LLDB_INVALID_PROCESS_ID;
++
++ // Log it.
++ log->Printf("NativeThreadNetBSD: thread (pid=%" PRIu64 ", tid=%" PRIu64
++ ") changing from state %s to %s",
++ pid, GetID(), StateAsCString(old_state),
++ StateAsCString(new_state));
++}
++
++NativeProcessNetBSD &NativeThreadNetBSD::GetProcess() {
++ auto process_sp = std::static_pointer_cast<NativeProcessNetBSD>(
++ NativeThreadProtocol::GetProcess());
++ assert(process_sp);
++ return *process_sp;
++}
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.h
new file mode 100644
index 0000000..70795c5
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_NativeThreadNetBSD.h
@@ -0,0 +1,122 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/NativeThreadNetBSD.h.orig 2016-12-17 13:00:53.156704200 +0000
++++ source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+@@ -0,0 +1,117 @@
++//===-- NativeThreadNetBSD.h ----------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef liblldb_NativeThreadNetBSD_H_
++#define liblldb_NativeThreadNetBSD_H_
++
++#include "lldb/Host/common/NativeThreadProtocol.h"
++#include "lldb/lldb-private-forward.h"
++
++#include <sched.h>
++
++#include <map>
++#include <memory>
++#include <string>
++
++namespace lldb_private {
++namespace process_linux {
++
++class NativeProcessNetBSD;
++
++class NativeThreadNetBSD : public NativeThreadProtocol {
++ friend class NativeProcessNetBSD;
++
++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;
++
++private:
++ // ---------------------------------------------------------------------
++ // Interface for friend classes
++ // ---------------------------------------------------------------------
++
++ /// Resumes the thread. If @p signo is anything but
++ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
++ Error Resume(uint32_t signo);
++
++ /// Single steps the thread. If @p signo is anything but
++ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
++ Error SingleStep(uint32_t signo);
++
++ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
++
++ /// Return true if the thread is stopped.
++ /// If stopped by a signal, indicate the signo in the signo argument.
++ /// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
++ bool IsStopped(int *signo);
++
++ void SetStoppedByExec();
++
++ void SetStoppedByBreakpoint();
++
++ void SetStoppedByWatchpoint(uint32_t wp_index);
++
++ bool IsStoppedAtBreakpoint();
++
++ bool IsStoppedAtWatchpoint();
++
++ void SetStoppedByTrace();
++
++ void SetStoppedWithNoReason();
++
++ void SetExited();
++
++ Error RequestStop();
++
++ // ---------------------------------------------------------------------
++ // Private interface
++ // ---------------------------------------------------------------------
++ void MaybeLogStateChange(lldb::StateType new_state);
++
++ NativeProcessNetBSD &GetProcess();
++
++ void SetStopped();
++
++ inline void MaybePrepareSingleStepWorkaround();
++
++ inline void MaybeCleanupSingleStepWorkaround();
++
++ // ---------------------------------------------------------------------
++ // Member Variables
++ // ---------------------------------------------------------------------
++ lldb::StateType m_state;
++ ThreadStopInfo m_stop_info;
++ NativeRegisterContextSP m_reg_context_sp;
++ std::string m_stop_description;
++ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
++ WatchpointIndexMap m_watchpoint_index_map;
++ cpu_set_t m_original_cpu_set; // For single-step workaround.
++};
++
++typedef std::shared_ptr<NativeThreadNetBSD> NativeThreadNetBSDSP;
++} // namespace process_linux
++} // namespace lldb_private
++
++#endif // #ifndef liblldb_NativeThreadNetBSD_H_
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.cpp
new file mode 100644
index 0000000..b42bf03
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.cpp
@@ -0,0 +1,108 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcFileReader.cpp.orig 2016-12-17 13:00:53.158464035 +0000
++++ source/Plugins/Process/NetBSD/ProcFileReader.cpp
+@@ -0,0 +1,103 @@
++//===-- ProcFileReader.cpp --------------------------------------*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#include "Plugins/Process/NetBSD/ProcFileReader.h"
++
++// C Headers
++#include <fcntl.h>
++#include <inttypes.h>
++#include <limits.h>
++#include <stdio.h>
++#include <sys/stat.h>
++
++// C++ Headers
++#include <fstream>
++
++// LLDB Headers
++#include "lldb/Core/DataBufferHeap.h"
++#include "lldb/Core/Error.h"
++
++using namespace lldb_private;
++using namespace lldb_private::process_linux;
++
++lldb::DataBufferSP ProcFileReader::ReadIntoDataBuffer(lldb::pid_t pid,
++ const char *name) {
++ int fd;
++ char path[PATH_MAX];
++
++ // Make sure we've got a nil terminated buffer for all the folks calling
++ // GetBytes() directly off our returned DataBufferSP if we hit an error.
++ lldb::DataBufferSP buf_sp(new DataBufferHeap(1, 0));
++
++ // Ideally, we would simply create a FileSpec and call ReadFileContents.
++ // However, files in procfs have zero size (since they are, in general,
++ // dynamically generated by the kernel) which is incompatible with the
++ // current ReadFileContents implementation. Therefore we simply stream the
++ // data into a DataBuffer ourselves.
++ if (snprintf(path, PATH_MAX, "/proc/%" PRIu64 "/%s", pid, name) > 0) {
++ if ((fd = open(path, O_RDONLY, 0)) >= 0) {
++ size_t bytes_read = 0;
++ std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
++
++ for (;;) {
++ size_t avail = buf_ap->GetByteSize() - bytes_read;
++ ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail);
++
++ if (status < 0)
++ break;
++
++ if (status == 0) {
++ buf_ap->SetByteSize(bytes_read);
++ buf_sp.reset(buf_ap.release());
++ break;
++ }
++
++ bytes_read += status;
++
++ if (avail - status == 0)
++ buf_ap->SetByteSize(2 * buf_ap->GetByteSize());
++ }
++
++ close(fd);
++ }
++ }
++
++ return buf_sp;
++}
++
++Error ProcFileReader::ProcessLineByLine(
++ lldb::pid_t pid, const char *name,
++ std::function<bool(const std::string &line)> line_parser) {
++ Error error;
++
++ // Try to open the /proc/{pid}/maps entry.
++ char filename[PATH_MAX];
++ snprintf(filename, sizeof(filename), "/proc/%" PRIu64 "/%s", pid, name);
++ filename[sizeof(filename) - 1] = '\0';
++
++ std::ifstream proc_file(filename);
++ if (proc_file.fail()) {
++ error.SetErrorStringWithFormat("failed to open file '%s'", filename);
++ return error;
++ }
++
++ // Read the file line by line, processing until either end of file or when the
++ // line_parser returns false.
++ std::string line;
++ bool should_continue = true;
++
++ while (should_continue && std::getline(proc_file, line)) {
++ // Pass the line over to the line_parser for processing. If the line_parser
++ // returns false, we
++ // stop processing.
++ should_continue = line_parser(line);
++ }
++
++ return error;
++}
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.h
new file mode 100644
index 0000000..4392b97
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_ProcFileReader.h
@@ -0,0 +1,42 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/ProcFileReader.h.orig 2016-12-17 13:00:53.160209898 +0000
++++ source/Plugins/Process/NetBSD/ProcFileReader.h
+@@ -0,0 +1,37 @@
++//===-- ProcFileReader.h ----------------------------------------*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef liblldb_ProcFileReader_h_
++#define liblldb_ProcFileReader_h_
++
++#include <functional>
++
++#include "lldb/lldb-forward.h"
++#include "lldb/lldb-types.h"
++
++namespace lldb_private {
++namespace process_linux {
++
++class ProcFileReader {
++public:
++ static lldb::DataBufferSP ReadIntoDataBuffer(lldb::pid_t pid,
++ const char *name);
++
++ /// Parse the /proc/{@a pid}/{@a name} file line by line, passing each line to
++ /// line_parser, until
++ /// either end of file or until line_parser returns false.
++ static Error
++ ProcessLineByLine(lldb::pid_t pid, const char *name,
++ std::function<bool(const std::string &line)> line_parser);
++};
++
++} // namespace process_linux
++} // namespace lldb_private
++
++#endif // #ifndef liblldb_ProcFileReader_h_
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_Procfs.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_Procfs.h
new file mode 100644
index 0000000..bbaf61a
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_Procfs.h
@@ -0,0 +1,36 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/Procfs.h.orig 2016-12-17 13:00:53.161956039 +0000
++++ source/Plugins/Process/NetBSD/Procfs.h
+@@ -0,0 +1,31 @@
++//===-- Procfs.h ---------------------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++// source/Plugins/Process/NetBSD/Procfs.h defines the symbols we need from
++// sys/procfs.h on Android/NetBSD for all supported architectures.
++
++#include <sys/ptrace.h>
++
++#ifdef __ANDROID__
++#if defined(__arm64__) || defined(__aarch64__)
++typedef unsigned long elf_greg_t;
++typedef elf_greg_t
++ elf_gregset_t[(sizeof(struct user_pt_regs) / sizeof(elf_greg_t))];
++typedef struct user_fpsimd_state elf_fpregset_t;
++#ifndef NT_FPREGSET
++#define NT_FPREGSET NT_PRFPREG
++#endif // NT_FPREGSET
++#elif defined(__mips__)
++#ifndef NT_FPREGSET
++#define NT_FPREGSET NT_PRFPREG
++#endif // NT_FPREGSET
++#endif
++#else // __ANDROID__
++#include <sys/procfs.h>
++#endif // __ANDROID__
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.cpp b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.cpp
new file mode 100644
index 0000000..ad34c79
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.cpp
@@ -0,0 +1,171 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/SingleStepCheck.cpp.orig 2016-12-17 13:00:53.163732700 +0000
++++ source/Plugins/Process/NetBSD/SingleStepCheck.cpp
+@@ -0,0 +1,166 @@
++//===-- SingleStepCheck.cpp ----------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#include "SingleStepCheck.h"
++
++#include <sched.h>
++#include <signal.h>
++#include <sys/wait.h>
++#include <unistd.h>
++
++#include "NativeProcessNetBSD.h"
++
++#include "llvm/Support/Compiler.h"
++
++#include "lldb/Core/Error.h"
++#include "lldb/Core/Log.h"
++#include "lldb/Host/linux/Ptrace.h"
++
++using namespace lldb_private::process_linux;
++
++#if defined(__arm64__) || defined(__aarch64__)
++namespace {
++
++void LLVM_ATTRIBUTE_NORETURN Child() {
++ if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
++ _exit(1);
++
++ // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer
++ // will fiddle with our cpu
++ // affinities and monitor the behaviour.
++ for (;;) {
++ raise(SIGSTOP);
++
++ // Generate a bunch of instructions here, so that a single-step does not
++ // land in the
++ // raise() accidentally. If single-stepping works, we will be spinning in
++ // this loop. If
++ // it doesn't, we'll land in the raise() call above.
++ for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i)
++ ;
++ }
++}
++
++struct ChildDeleter {
++ ::pid_t pid;
++
++ ~ChildDeleter() {
++ int status;
++ kill(pid, SIGKILL); // Kill the child.
++ waitpid(pid, &status, __WALL); // Pick up the remains.
++ }
++};
++
++} // end anonymous namespace
++
++bool impl::SingleStepWorkaroundNeeded() {
++ // We shall spawn a child, and use it to verify the debug capabilities of the
++ // cpu. We shall
++ // iterate through the cpus, bind the child to each one in turn, and verify
++ // that
++ // single-stepping works on that cpu. A workaround is needed if we find at
++ // least one broken
++ // cpu.
++
++ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
++ Error error;
++ ::pid_t child_pid = fork();
++ if (child_pid == -1) {
++ if (log) {
++ error.SetErrorToErrno();
++ log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString());
++ }
++ return false;
++ }
++ if (child_pid == 0)
++ Child();
++
++ ChildDeleter child_deleter{child_pid};
++ cpu_set_t available_cpus;
++ if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) ==
++ -1) {
++ if (log) {
++ error.SetErrorToErrno();
++ log->Printf("%s failed to get available cpus: %s", __FUNCTION__,
++ error.AsCString());
++ }
++ return false;
++ }
++
++ int status;
++ ::pid_t wpid = waitpid(child_pid, &status, __WALL);
++ if (wpid != child_pid || !WIFSTOPPED(status)) {
++ if (log) {
++ error.SetErrorToErrno();
++ log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status,
++ error.AsCString());
++ }
++ return false;
++ }
++
++ unsigned cpu;
++ for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) {
++ if (!CPU_ISSET(cpu, &available_cpus))
++ continue;
++
++ cpu_set_t cpus;
++ CPU_ZERO(&cpus);
++ CPU_SET(cpu, &cpus);
++ if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) {
++ if (log) {
++ error.SetErrorToErrno();
++ log->Printf("%s failed to switch to cpu %u: %s", __FUNCTION__, cpu,
++ error.AsCString());
++ }
++ continue;
++ }
++
++ int status;
++ error = NativeProcessNetBSD::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
++ if (error.Fail()) {
++ if (log)
++ log->Printf("%s single step failed: %s", __FUNCTION__,
++ error.AsCString());
++ break;
++ }
++
++ wpid = waitpid(child_pid, &status, __WALL);
++ if (wpid != child_pid || !WIFSTOPPED(status)) {
++ if (log) {
++ error.SetErrorToErrno();
++ log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__,
++ status, error.AsCString());
++ }
++ break;
++ }
++ if (WSTOPSIG(status) != SIGTRAP) {
++ if (log)
++ log->Printf("%s single stepping on cpu %d failed with status %x",
++ __FUNCTION__, cpu, status);
++ break;
++ }
++ }
++
++ // cpu is either the index of the first broken cpu, or CPU_SETSIZE.
++ if (cpu == 0) {
++ if (log)
++ log->Printf("%s SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING "
++ "LIKELY TO BE UNRELIABLE.",
++ __FUNCTION__);
++ // No point in trying to fiddle with the affinities, just give it our best
++ // shot and see how it goes.
++ return false;
++ }
++
++ return cpu != CPU_SETSIZE;
++}
++
++#else // !arm64
++bool impl::SingleStepWorkaroundNeeded() { return false; }
++#endif
diff --git a/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.h b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.h
new file mode 100644
index 0000000..0d55507
--- /dev/null
+++ b/lldb-netbsd/patches/patch-source_Plugins_Process_NetBSD_SingleStepCheck.h
@@ -0,0 +1,45 @@
+$NetBSD$
+
+--- source/Plugins/Process/NetBSD/SingleStepCheck.h.orig 2016-12-17 13:00:53.165484448 +0000
++++ source/Plugins/Process/NetBSD/SingleStepCheck.h
+@@ -0,0 +1,40 @@
++//===-- SingleStepCheck.h ------------------------------------- -*- C++ -*-===//
++//
++// The LLVM Compiler Infrastructure
++//
++// This file is distributed under the University of Illinois Open Source
++// License. See LICENSE.TXT for details.
++//
++//===----------------------------------------------------------------------===//
++
++#ifndef liblldb_SingleStepCheck_H_
++#define liblldb_SingleStepCheck_H_
++
++namespace lldb_private {
++namespace process_linux {
++
++namespace impl {
++extern bool SingleStepWorkaroundNeeded();
++}
++
++// arm64 linux had a bug which prevented single-stepping and watchpoints from
++// working on non-boot
++// cpus, due to them being incorrectly initialized after coming out of suspend.
++// This issue is
++// particularly affecting android M, which uses suspend ("doze mode") quite
++// aggressively. This
++// code detects that situation and makes single-stepping work by doing all the
++// step operations on
++// the boot cpu.
++//
++// The underlying issue has been fixed in android N and linux 4.4. This code can
++// be removed once
++// these systems become obsolete.
++inline bool SingleStepWorkaroundNeeded() {
++ static bool value = impl::SingleStepWorkaroundNeeded();
++ return value;
++}
++} // end namespace process_linux
++} // end namespace lldb_private
++
++#endif // #ifndef liblldb_SingleStepCheck_H_
diff --git a/lldb-netbsd/patches/patch-tools_lldb-server_CMakeLists.txt b/lldb-netbsd/patches/patch-tools_lldb-server_CMakeLists.txt
new file mode 100644
index 0000000..2aa63f5
--- /dev/null
+++ b/lldb-netbsd/patches/patch-tools_lldb-server_CMakeLists.txt
@@ -0,0 +1,27 @@
+$NetBSD$
+
+--- tools/lldb-server/CMakeLists.txt.orig 2016-12-17 10:30:54.000000000 +0000
++++ tools/lldb-server/CMakeLists.txt
+@@ -17,6 +17,7 @@ endif ()
+ if ( CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
+ include_directories(
+ ../../../../llvm/include
++ ../../source/Plugins/Process/NetBSD
+ ../../source/Plugins/Process/POSIX
+ )
+ endif ()
+@@ -84,6 +85,14 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Linux" )
+ )
+ endif ()
+
++# Linux-only libraries
++if ( CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
++ list(APPEND LLDB_USED_LIBS
++ lldbPluginProcessNetBSD
++ lldbPluginProcessPOSIX
++ )
++endif ()
++
+ # Darwin-only libraries
+ if ( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
+ list(APPEND LLDB_USED_LIBS
Home |
Main Index |
Thread Index |
Old Index