krytarowski updated this revision to Diff 93312.
krytarowski added a comment.

Apply changes from review.


Repository:
  rL LLVM

https://reviews.llvm.org/D31374

Files:
  source/Plugins/Process/NetBSD/CMakeLists.txt
  source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
  source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
  source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
  source/Plugins/Process/NetBSD/NativeThreadNetBSD.h

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

Reply via email to