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 &reg_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 &reg_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 &reg_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 &reg_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 *>(&regset), 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 *>(&regset), 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 &reg_value);
++
++  virtual Error WriteRegisterRaw(uint32_t reg_index,
++                                 const RegisterValue &reg_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 &reg_value) {
++  Error error;
++
++  if (!reg_info) {
++    error.SetErrorString("reg_info NULL");
++    return error;
++  }
++
++  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
++  if (reg == LLDB_INVALID_REGNUM) {
++    // This is likely an internal register for lldb use only and should not be
++    // directly queried.
++    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
++                                   "register, cannot read directly",
++                                   reg_info->name);
++    return error;
++  }
++
++  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 &reg_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 &reg_value) override;
++
++  Error WriteRegister(const RegisterInfo *reg_info,
++                      const RegisterValue &reg_value) override;
++
++  Error ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
++
++  Error WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
++
++  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