mgorny updated this revision to Diff 296439.
mgorny added a comment.

Removed now-redundant DebugProcess.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88796/new/

https://reviews.llvm.org/D88796

Files:
  lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
  lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
  lldb/source/Plugins/Process/CMakeLists.txt
  lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
  lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
  lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
  
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
  
lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
  lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
  lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
  lldb/test/Shell/lit.cfg.py
  lldb/tools/lldb-server/CMakeLists.txt
  lldb/tools/lldb-server/lldb-gdbserver.cpp

Index: lldb/tools/lldb-server/lldb-gdbserver.cpp
===================================================================
--- lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -38,6 +38,8 @@
 
 #if defined(__linux__)
 #include "Plugins/Process/Linux/NativeProcessLinux.h"
+#elif defined(__FreeBSD__)
+#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
 #elif defined(__NetBSD__)
 #include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
 #elif defined(_WIN32)
@@ -61,6 +63,8 @@
 namespace {
 #if defined(__linux__)
 typedef process_linux::NativeProcessLinux::Factory NativeProcessFactory;
+#elif defined(__FreeBSD__)
+typedef process_freebsd::NativeProcessFreeBSD::Factory NativeProcessFactory;
 #elif defined(__NetBSD__)
 typedef process_netbsd::NativeProcessNetBSD::Factory NativeProcessFactory;
 #elif defined(_WIN32)
Index: lldb/tools/lldb-server/CMakeLists.txt
===================================================================
--- lldb/tools/lldb-server/CMakeLists.txt
+++ lldb/tools/lldb-server/CMakeLists.txt
@@ -4,6 +4,12 @@
   list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)
 endif()
 
+if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+  list(APPEND LLDB_PLUGINS
+    lldbPluginProcessFreeBSDRemote
+    lldbPluginProcessFreeBSD)
+endif()
+
 if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
   list(APPEND LLDB_PLUGINS lldbPluginProcessNetBSD)
 endif()
Index: lldb/test/Shell/lit.cfg.py
===================================================================
--- lldb/test/Shell/lit.cfg.py
+++ lldb/test/Shell/lit.cfg.py
@@ -133,3 +133,6 @@
         can_set_dbregs = False
 if can_set_dbregs:
     config.available_features.add('dbregs-set')
+
+# pass control variable through
+llvm_config.with_system_environment('FREEBSD_REMOTE_PLUGIN')
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -843,7 +843,7 @@
   response.PutCString(";QListThreadsInStopReply+");
   response.PutCString(";qEcho+");
   response.PutCString(";qXfer:features:read+");
-#if defined(__linux__) || defined(__NetBSD__)
+#if defined(__linux__) || defined(__NetBSD__) || defined(__FreeBSD__)
   response.PutCString(";QPassSignals+");
   response.PutCString(";qXfer:auxv:read+");
   response.PutCString(";qXfer:libraries-svr4:read+");
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h
@@ -0,0 +1,83 @@
+//===-- NativeThreadFreeBSD.h --------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadFreeBSD_H_
+#define liblldb_NativeThreadFreeBSD_H_
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+
+#include <csignal>
+#include <map>
+#include <string>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeThreadFreeBSD : public NativeThreadProtocol {
+  friend class NativeProcessFreeBSD;
+
+public:
+  NativeThreadFreeBSD(NativeProcessFreeBSD &process, lldb::tid_t tid);
+
+  // NativeThreadProtocol Interface
+  std::string GetName() override;
+
+  lldb::StateType GetState() override;
+
+  bool GetStopReason(ThreadStopInfo &stop_info,
+                     std::string &description) override;
+
+  NativeRegisterContextFreeBSD &GetRegisterContext() override;
+
+  Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+                       bool hardware) override;
+
+  Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+  Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+  Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+  // Interface for friend classes
+
+  Status Resume();
+  Status SingleStep();
+  Status Suspend();
+
+  void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+  void SetStoppedByBreakpoint();
+  void SetStoppedByTrace();
+  void SetStoppedByExec();
+  void SetStoppedByWatchpoint(uint32_t wp_index);
+  void SetStoppedWithNoReason();
+  void SetStopped();
+  void SetRunning();
+  void SetStepping();
+
+  Status CopyWatchpointsFrom(NativeThreadFreeBSD &source);
+
+  // Member Variables
+  lldb::StateType m_state;
+  ThreadStopInfo m_stop_info;
+  std::unique_ptr<NativeRegisterContextFreeBSD> m_reg_context_up;
+  std::string m_stop_description;
+  using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+  WatchpointIndexMap m_watchpoint_index_map;
+  WatchpointIndexMap m_hw_break_index_map;
+};
+
+typedef std::shared_ptr<NativeThreadFreeBSD> NativeThreadFreeBSDSP;
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadFreeBSD_H_
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
@@ -0,0 +1,216 @@
+//===-- NativeThreadFreeBSD.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadFreeBSD.h"
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "NativeProcessFreeBSD.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+// clang-format on
+
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
+                                         lldb::tid_t tid)
+    : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+      m_stop_info(),
+      m_reg_context_up(
+          NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+              process.GetArchitecture(), *this)),
+      m_stop_description() {}
+
+Status NativeThreadFreeBSD::Resume() {
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+                                                   nullptr, GetID());
+  if (!ret.Success())
+    return ret;
+  ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(),
+                                            nullptr, GetID());
+  if (ret.Success())
+    SetRunning();
+  return ret;
+}
+
+Status NativeThreadFreeBSD::SingleStep() {
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, m_process.GetID(),
+                                                   nullptr, GetID());
+  if (!ret.Success())
+    return ret;
+  ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(),
+                                            nullptr, GetID());
+  if (ret.Success())
+    SetStepping();
+  return ret;
+}
+
+Status NativeThreadFreeBSD::Suspend() {
+  Status ret = NativeProcessFreeBSD::PtraceWrapper(
+      PT_SUSPEND, m_process.GetID(), nullptr, GetID());
+  if (ret.Success())
+    SetStopped();
+  return ret;
+}
+
+void NativeThreadFreeBSD::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 NativeThreadFreeBSD::SetStoppedByBreakpoint() {
+  SetStopped();
+  m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+  m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByTrace() {
+  SetStopped();
+  m_stop_info.reason = StopReason::eStopReasonTrace;
+  m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByExec() {
+  SetStopped();
+  m_stop_info.reason = StopReason::eStopReasonExec;
+  m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+  SetStopped();
+}
+
+void NativeThreadFreeBSD::SetStoppedWithNoReason() {
+  SetStopped();
+
+  m_stop_info.reason = StopReason::eStopReasonNone;
+  m_stop_info.details.signal.signo = 0;
+}
+
+void NativeThreadFreeBSD::SetStopped() {
+  const StateType new_state = StateType::eStateStopped;
+  m_state = new_state;
+  m_stop_description.clear();
+}
+
+void NativeThreadFreeBSD::SetRunning() {
+  m_state = StateType::eStateRunning;
+  m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void NativeThreadFreeBSD::SetStepping() {
+  m_state = StateType::eStateStepping;
+  m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadFreeBSD::GetName() { return ""; }
+
+lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }
+
+bool NativeThreadFreeBSD::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!");
+}
+
+NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {
+  assert(m_reg_context_up);
+  return *m_reg_context_up;
+}
+
+Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+                                          uint32_t watch_flags, bool hardware) {
+  return Status("not implemented");
+}
+
+Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {
+  auto wp = m_watchpoint_index_map.find(addr);
+  if (wp == m_watchpoint_index_map.end())
+    return Status();
+  return Status("not implemented");
+}
+
+Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+                                                  size_t size) {
+  if (m_state == eStateLaunching)
+    return Status();
+
+  Status error = RemoveHardwareBreakpoint(addr);
+  if (error.Fail())
+    return error;
+
+  return Status("not implemented");
+}
+
+Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+  auto bp = m_hw_break_index_map.find(addr);
+  if (bp == m_hw_break_index_map.end())
+    return Status();
+
+  return Status("not implemented");
+}
+
+Status NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
+  return Status("not implemented");
+}
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,101 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+#define lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_x86_64
+    : public NativeRegisterContextFreeBSD {
+public:
+  NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch,
+                                      NativeThreadProtocol &native_thread);
+  uint32_t GetRegisterSetCount() const override;
+
+  const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+  Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+  Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+  Status GetWatchpointHitIndex(uint32_t &wp_index,
+                               lldb::addr_t trap_addr) override;
+
+  Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+  bool ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+  Status ClearWatchpointHit(uint32_t wp_index) override;
+
+  Status ClearAllHardwareWatchpoints() override;
+
+  Status 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;
+
+  Status
+  CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+  // Private member types.
+  enum { GPRegSet, FPRegSet, DBRegSet };
+
+  // Private member variables.
+  struct reg m_gpr;
+#if defined(__x86_64__)
+  struct fpreg m_fpr;
+#else
+  struct xmmreg m_fpr;
+#endif
+  struct dbreg m_dbr;
+
+  int GetSetForNativeRegNum(int reg_num) const;
+  int GetDR(int num) const;
+
+  Status ReadRegisterSet(uint32_t set);
+  Status WriteRegisterSet(uint32_t set);
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+#endif // defined(__x86_64__)
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,1315 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "NativeRegisterContextFreeBSD_x86_64.h"
+
+#include <machine/fpu.h>
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// 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");
+
+// 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 registers available via XState.
+static const uint32_t g_xstate_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,
+    // Note: we currently do not provide them but this is needed to avoid
+    // unnamed groups in SBFrame::GetRegisterContext().
+    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_xstate_regnums_x86_64) /
+               sizeof(g_xstate_regnums_x86_64[0])) -
+                      1 ==
+                  k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
+              "g_xstate_regnums_x86_64 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_x86_64[] = {
+    lldb_dr0_x86_64,    lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
+    lldb_dr4_x86_64,    lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
+    LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
+                      1 ==
+                  k_num_dbr_registers_x86_64,
+              "g_dbr_regnums_x86_64 has wrong number of register infos");
+
+// 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 64-bit registers available via XState.
+static const uint32_t g_xstate_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,
+    // Note: we currently do not provide them but this is needed to avoid
+    // unnamed groups in SBFrame::GetRegisterContext().
+    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_xstate_regnums_i386) / sizeof(g_xstate_regnums_i386[0])) - 1 ==
+        k_num_avx_registers_i386 + k_num_mpx_registers_i386,
+    "g_xstate_regnums_i386 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_i386[] = {
+    lldb_dr0_i386,      lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
+    lldb_dr4_i386,      lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
+    LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
+                      1 ==
+                  k_num_dbr_registers_i386,
+              "g_dbr_regnums_i386 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { 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},
+    {"Extended State Registers", "xstate",
+     k_num_avx_registers_i386 + k_num_mpx_registers_i386,
+     g_xstate_regnums_i386},
+    {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_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},
+    {"Extended State Registers", "xstate",
+     k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
+     g_xstate_regnums_x86_64},
+    {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
+     g_dbr_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+} // namespace
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+  return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread);
+}
+
+// NativeRegisterContextFreeBSD_x86_64 members.
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+  if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
+    // 32-bit hosts run with a RegisterContextFreeBSD_i386 context.
+    return new RegisterContextFreeBSD_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 RegisterContextFreeBSD_x86_64(target_arch);
+  }
+}
+
+NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
+    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+    : NativeRegisterContextFreeBSD(native_thread,
+                                   CreateRegisterInfoInterface(target_arch)),
+      m_gpr(), m_fpr(), m_dbr() {}
+
+// 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 NativeRegisterContextFreeBSD_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 *
+NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+  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:
+    llvm_unreachable("Unhandled target architecture.");
+  }
+}
+
+static constexpr int RegNumX86ToX86_64(int regnum) {
+  switch (regnum) {
+  case lldb_eax_i386:
+    return lldb_rax_x86_64;
+  case lldb_ebx_i386:
+    return lldb_rbx_x86_64;
+  case lldb_ecx_i386:
+    return lldb_rcx_x86_64;
+  case lldb_edx_i386:
+    return lldb_rdx_x86_64;
+  case lldb_edi_i386:
+    return lldb_rdi_x86_64;
+  case lldb_esi_i386:
+    return lldb_rsi_x86_64;
+  case lldb_ebp_i386:
+    return lldb_rbp_x86_64;
+  case lldb_esp_i386:
+    return lldb_rsp_x86_64;
+  case lldb_eip_i386:
+    return lldb_rip_x86_64;
+  case lldb_eflags_i386:
+    return lldb_rflags_x86_64;
+  case lldb_cs_i386:
+    return lldb_cs_x86_64;
+  case lldb_fs_i386:
+    return lldb_fs_x86_64;
+  case lldb_gs_i386:
+    return lldb_gs_x86_64;
+  case lldb_ss_i386:
+    return lldb_ss_x86_64;
+  case lldb_ds_i386:
+    return lldb_ds_x86_64;
+  case lldb_es_i386:
+    return lldb_es_x86_64;
+  case lldb_fctrl_i386:
+    return lldb_fctrl_x86_64;
+  case lldb_fstat_i386:
+    return lldb_fstat_x86_64;
+  case lldb_ftag_i386:
+    return lldb_ftag_x86_64;
+  case lldb_fop_i386:
+    return lldb_fop_x86_64;
+  case lldb_fiseg_i386:
+    return lldb_fiseg_x86_64;
+  case lldb_fioff_i386:
+    return lldb_fioff_x86_64;
+  case lldb_foseg_i386:
+    return lldb_foseg_x86_64;
+  case lldb_fooff_i386:
+    return lldb_fooff_x86_64;
+  case lldb_mxcsr_i386:
+    return lldb_mxcsr_x86_64;
+  case lldb_mxcsrmask_i386:
+    return lldb_mxcsrmask_x86_64;
+  case lldb_st0_i386:
+  case lldb_st1_i386:
+  case lldb_st2_i386:
+  case lldb_st3_i386:
+  case lldb_st4_i386:
+  case lldb_st5_i386:
+  case lldb_st6_i386:
+  case lldb_st7_i386:
+    return lldb_st0_x86_64 + regnum - lldb_st0_i386;
+  case lldb_mm0_i386:
+  case lldb_mm1_i386:
+  case lldb_mm2_i386:
+  case lldb_mm3_i386:
+  case lldb_mm4_i386:
+  case lldb_mm5_i386:
+  case lldb_mm6_i386:
+  case lldb_mm7_i386:
+    return lldb_mm0_x86_64 + regnum - lldb_mm0_i386;
+  case lldb_xmm0_i386:
+  case lldb_xmm1_i386:
+  case lldb_xmm2_i386:
+  case lldb_xmm3_i386:
+  case lldb_xmm4_i386:
+  case lldb_xmm5_i386:
+  case lldb_xmm6_i386:
+  case lldb_xmm7_i386:
+    return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386;
+  case lldb_ymm0_i386:
+  case lldb_ymm1_i386:
+  case lldb_ymm2_i386:
+  case lldb_ymm3_i386:
+  case lldb_ymm4_i386:
+  case lldb_ymm5_i386:
+  case lldb_ymm6_i386:
+  case lldb_ymm7_i386:
+    return lldb_ymm0_x86_64 + regnum - lldb_ymm0_i386;
+  case lldb_bnd0_i386:
+  case lldb_bnd1_i386:
+  case lldb_bnd2_i386:
+  case lldb_bnd3_i386:
+    return lldb_bnd0_x86_64 + regnum - lldb_bnd0_i386;
+  case lldb_bndcfgu_i386:
+    return lldb_bndcfgu_x86_64;
+  case lldb_bndstatus_i386:
+    return lldb_bndstatus_x86_64;
+  case lldb_dr0_i386:
+  case lldb_dr1_i386:
+  case lldb_dr2_i386:
+  case lldb_dr3_i386:
+  case lldb_dr4_i386:
+  case lldb_dr5_i386:
+  case lldb_dr6_i386:
+  case lldb_dr7_i386:
+    return lldb_dr0_x86_64 + regnum - lldb_dr0_i386;
+  default:
+    llvm_unreachable("Unhandled i386 register.");
+  }
+}
+
+int NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(
+    int reg_num) const {
+
+  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+  case llvm::Triple::x86:
+    if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
+      return GPRegSet;
+    if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
+      return FPRegSet;
+    if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
+      return -1; // AVX
+    if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
+      return -1; // MPXR
+    if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
+      return -1; // MPXC
+    if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
+      return DBRegSet; // DBR
+    break;
+  case llvm::Triple::x86_64:
+    if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
+      return GPRegSet;
+    if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
+      return FPRegSet;
+    if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
+      return -1; // AVX
+    if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
+      return -1; // MPXR
+    if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
+      return -1; // MPXC
+    if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
+      return DBRegSet; // DBR
+    break;
+  default:
+    llvm_unreachable("Unhandled target architecture.");
+  }
+
+  llvm_unreachable("Register does not belong to any register set");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(uint32_t set) {
+  switch (set) {
+  case GPRegSet:
+    return DoRegisterSet(PT_GETREGS, &m_gpr);
+  case FPRegSet:
+#if defined(__x86_64__)
+    return DoRegisterSet(PT_GETFPREGS, &m_fpr);
+#else
+    return DoRegisterSet(PT_GETXMMREGS, &m_fpr);
+#endif
+  case DBRegSet:
+    return DoRegisterSet(PT_GETDBREGS, &m_dbr);
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(uint32_t set) {
+  switch (set) {
+  case GPRegSet:
+    return DoRegisterSet(PT_SETREGS, &m_gpr);
+  case FPRegSet:
+#if defined(__x86_64__)
+    return DoRegisterSet(PT_SETFPREGS, &m_fpr);
+#else
+    return DoRegisterSet(PT_SETXMMREGS, &m_fpr);
+#endif
+  case DBRegSet:
+    return DoRegisterSet(PT_SETDBREGS, &m_dbr);
+  }
+  llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
+                                                  RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  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;
+  }
+
+  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+  case llvm::Triple::x86_64:
+    break;
+  case llvm::Triple::x86:
+    reg = RegNumX86ToX86_64(reg);
+    break;
+  default:
+    llvm_unreachable("Unhandled target architecture.");
+  }
+
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  switch (reg) {
+#if defined(__x86_64__)
+  case lldb_rax_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rax;
+    break;
+  case lldb_rbx_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rbx;
+    break;
+  case lldb_rcx_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rcx;
+    break;
+  case lldb_rdx_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rdx;
+    break;
+  case lldb_rdi_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rdi;
+    break;
+  case lldb_rsi_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rsi;
+    break;
+  case lldb_rbp_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rbp;
+    break;
+  case lldb_rsp_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rsp;
+    break;
+  case lldb_r8_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r8;
+    break;
+  case lldb_r9_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r9;
+    break;
+  case lldb_r10_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r10;
+    break;
+  case lldb_r11_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r11;
+    break;
+  case lldb_r12_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r12;
+    break;
+  case lldb_r13_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r13;
+    break;
+  case lldb_r14_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r14;
+    break;
+  case lldb_r15_x86_64:
+    reg_value = (uint64_t)m_gpr.r_r15;
+    break;
+  case lldb_rip_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rip;
+    break;
+  case lldb_rflags_x86_64:
+    reg_value = (uint64_t)m_gpr.r_rflags;
+    break;
+  case lldb_cs_x86_64:
+    reg_value = (uint64_t)m_gpr.r_cs;
+    break;
+  case lldb_fs_x86_64:
+    reg_value = (uint64_t)m_gpr.r_fs;
+    break;
+  case lldb_gs_x86_64:
+    reg_value = (uint64_t)m_gpr.r_gs;
+    break;
+  case lldb_ss_x86_64:
+    reg_value = (uint64_t)m_gpr.r_ss;
+    break;
+  case lldb_ds_x86_64:
+    reg_value = (uint64_t)m_gpr.r_ds;
+    break;
+  case lldb_es_x86_64:
+    reg_value = (uint64_t)m_gpr.r_es;
+    break;
+#else
+  case lldb_rax_x86_64:
+    reg_value = (uint32_t)m_gpr.r_eax;
+    break;
+  case lldb_rbx_x86_64:
+    reg_value = (uint32_t)m_gpr.r_ebx;
+    break;
+  case lldb_rcx_x86_64:
+    reg_value = (uint32_t)m_gpr.r_ecx;
+    break;
+  case lldb_rdx_x86_64:
+    reg_value = (uint32_t)m_gpr.r_edx;
+    break;
+  case lldb_rdi_x86_64:
+    reg_value = (uint32_t)m_gpr.r_edi;
+    break;
+  case lldb_rsi_x86_64:
+    reg_value = (uint32_t)m_gpr.r_esi;
+    break;
+  case lldb_rsp_x86_64:
+    reg_value = (uint32_t)m_gpr.r_esp;
+    break;
+  case lldb_rbp_x86_64:
+    reg_value = (uint32_t)m_gpr.r_ebp;
+    break;
+  case lldb_rip_x86_64:
+    reg_value = (uint32_t)m_gpr.r_eip;
+    break;
+  case lldb_rflags_x86_64:
+    reg_value = (uint32_t)m_gpr.r_eflags;
+    break;
+  case lldb_cs_x86_64:
+    reg_value = (uint32_t)m_gpr.r_cs;
+    break;
+  case lldb_fs_x86_64:
+    reg_value = (uint32_t)m_gpr.r_fs;
+    break;
+  case lldb_gs_x86_64:
+    reg_value = (uint32_t)m_gpr.r_gs;
+    break;
+  case lldb_ss_x86_64:
+    reg_value = (uint32_t)m_gpr.r_ss;
+    break;
+  case lldb_ds_x86_64:
+    reg_value = (uint32_t)m_gpr.r_ds;
+    break;
+  case lldb_es_x86_64:
+    reg_value = (uint32_t)m_gpr.r_es;
+    break;
+#endif
+#if defined(__x86_64__)
+// the 32-bit field carries more detail, so we don't have to reinvent
+// the wheel
+#define FPR_ENV(x) ((struct envxmm32 *)m_fpr.fpr_env)->x
+#else
+#define FPR_ENV(x) ((struct envxmm *)m_fpr.xmm_env)->x
+#endif
+  case lldb_fctrl_x86_64:
+    reg_value = (uint16_t)FPR_ENV(en_cw);
+    break;
+  case lldb_fstat_x86_64:
+    reg_value = (uint16_t)FPR_ENV(en_sw);
+    break;
+  case lldb_ftag_x86_64:
+    reg_value = (uint16_t)FPR_ENV(en_tw);
+    break;
+  case lldb_fop_x86_64:
+    reg_value = (uint16_t)FPR_ENV(en_opcode);
+    break;
+  case lldb_fiseg_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_fcs);
+    break;
+  case lldb_fioff_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_fip);
+    break;
+  case lldb_foseg_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_fos);
+    break;
+  case lldb_fooff_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_foo);
+    break;
+  case lldb_mxcsr_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_mxcsr);
+    break;
+  case lldb_mxcsrmask_x86_64:
+    reg_value = (uint32_t)FPR_ENV(en_mxcsr_mask);
+    break;
+  case lldb_st0_x86_64:
+  case lldb_st1_x86_64:
+  case lldb_st2_x86_64:
+  case lldb_st3_x86_64:
+  case lldb_st4_x86_64:
+  case lldb_st5_x86_64:
+  case lldb_st6_x86_64:
+  case lldb_st7_x86_64:
+#if defined(__x86_64__)
+    reg_value.SetBytes(&m_fpr.fpr_acc[reg - lldb_st0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#else
+    reg_value.SetBytes(&m_fpr.xmm_acc[reg - lldb_st0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#endif
+    break;
+  case lldb_mm0_x86_64:
+  case lldb_mm1_x86_64:
+  case lldb_mm2_x86_64:
+  case lldb_mm3_x86_64:
+  case lldb_mm4_x86_64:
+  case lldb_mm5_x86_64:
+  case lldb_mm6_x86_64:
+  case lldb_mm7_x86_64:
+#if defined(__x86_64__)
+    reg_value.SetBytes(&m_fpr.fpr_acc[reg - lldb_mm0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#else
+    reg_value.SetBytes(&m_fpr.xmm_acc[reg - lldb_mm0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#endif
+    break;
+  case lldb_xmm0_x86_64:
+  case lldb_xmm1_x86_64:
+  case lldb_xmm2_x86_64:
+  case lldb_xmm3_x86_64:
+  case lldb_xmm4_x86_64:
+  case lldb_xmm5_x86_64:
+  case lldb_xmm6_x86_64:
+  case lldb_xmm7_x86_64:
+  case lldb_xmm8_x86_64:
+  case lldb_xmm9_x86_64:
+  case lldb_xmm10_x86_64:
+  case lldb_xmm11_x86_64:
+  case lldb_xmm12_x86_64:
+  case lldb_xmm13_x86_64:
+  case lldb_xmm14_x86_64:
+  case lldb_xmm15_x86_64:
+#if defined(__x86_64__)
+    reg_value.SetBytes(&m_fpr.fpr_xacc[reg - lldb_xmm0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#else
+    reg_value.SetBytes(&m_fpr.xmm_reg[reg - lldb_xmm0_x86_64],
+                       reg_info->byte_size, endian::InlHostByteOrder());
+#endif
+    break;
+  case lldb_dr0_x86_64:
+  case lldb_dr1_x86_64:
+  case lldb_dr2_x86_64:
+  case lldb_dr3_x86_64:
+  case lldb_dr4_x86_64:
+  case lldb_dr5_x86_64:
+  case lldb_dr6_x86_64:
+  case lldb_dr7_x86_64:
+    reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64];
+    break;
+  default:
+    llvm_unreachable("Reading unknown/unsupported register");
+  }
+
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  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;
+  }
+
+  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+  case llvm::Triple::x86_64:
+    break;
+  case llvm::Triple::x86:
+    reg = RegNumX86ToX86_64(reg);
+    break;
+  default:
+    llvm_unreachable("Unhandled target architecture.");
+  }
+
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  switch (reg) {
+#if defined(__x86_64__)
+  case lldb_rax_x86_64:
+    m_gpr.r_rax = reg_value.GetAsUInt64();
+    break;
+  case lldb_rbx_x86_64:
+    m_gpr.r_rbx = reg_value.GetAsUInt64();
+    break;
+  case lldb_rcx_x86_64:
+    m_gpr.r_rcx = reg_value.GetAsUInt64();
+    break;
+  case lldb_rdx_x86_64:
+    m_gpr.r_rdx = reg_value.GetAsUInt64();
+    break;
+  case lldb_rdi_x86_64:
+    m_gpr.r_rdi = reg_value.GetAsUInt64();
+    break;
+  case lldb_rsi_x86_64:
+    m_gpr.r_rsi = reg_value.GetAsUInt64();
+    break;
+  case lldb_rbp_x86_64:
+    m_gpr.r_rbp = reg_value.GetAsUInt64();
+    break;
+  case lldb_rsp_x86_64:
+    m_gpr.r_rsp = reg_value.GetAsUInt64();
+    break;
+  case lldb_r8_x86_64:
+    m_gpr.r_r8 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r9_x86_64:
+    m_gpr.r_r9 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r10_x86_64:
+    m_gpr.r_r10 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r11_x86_64:
+    m_gpr.r_r11 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r12_x86_64:
+    m_gpr.r_r12 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r13_x86_64:
+    m_gpr.r_r13 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r14_x86_64:
+    m_gpr.r_r14 = reg_value.GetAsUInt64();
+    break;
+  case lldb_r15_x86_64:
+    m_gpr.r_r15 = reg_value.GetAsUInt64();
+    break;
+  case lldb_rip_x86_64:
+    m_gpr.r_rip = reg_value.GetAsUInt64();
+    break;
+  case lldb_rflags_x86_64:
+    m_gpr.r_rflags = reg_value.GetAsUInt64();
+    break;
+  case lldb_cs_x86_64:
+    m_gpr.r_cs = reg_value.GetAsUInt64();
+    break;
+  case lldb_fs_x86_64:
+    m_gpr.r_fs = reg_value.GetAsUInt64();
+    break;
+  case lldb_gs_x86_64:
+    m_gpr.r_gs = reg_value.GetAsUInt64();
+    break;
+  case lldb_ss_x86_64:
+    m_gpr.r_ss = reg_value.GetAsUInt64();
+    break;
+  case lldb_ds_x86_64:
+    m_gpr.r_ds = reg_value.GetAsUInt64();
+    break;
+  case lldb_es_x86_64:
+    m_gpr.r_es = reg_value.GetAsUInt64();
+    break;
+#else
+  case lldb_rax_x86_64:
+    m_gpr.r_eax = reg_value.GetAsUInt32();
+    break;
+  case lldb_rbx_x86_64:
+    m_gpr.r_ebx = reg_value.GetAsUInt32();
+    break;
+  case lldb_rcx_x86_64:
+    m_gpr.r_ecx = reg_value.GetAsUInt32();
+    break;
+  case lldb_rdx_x86_64:
+    m_gpr.r_edx = reg_value.GetAsUInt32();
+    break;
+  case lldb_rdi_x86_64:
+    m_gpr.r_edi = reg_value.GetAsUInt32();
+    break;
+  case lldb_rsi_x86_64:
+    m_gpr.r_esi = reg_value.GetAsUInt32();
+    break;
+  case lldb_rsp_x86_64:
+    m_gpr.r_esp = reg_value.GetAsUInt32();
+    break;
+  case lldb_rbp_x86_64:
+    m_gpr.r_ebp = reg_value.GetAsUInt32();
+    break;
+  case lldb_rip_x86_64:
+    m_gpr.r_eip = reg_value.GetAsUInt32();
+    break;
+  case lldb_rflags_x86_64:
+    m_gpr.r_eflags = reg_value.GetAsUInt32();
+    break;
+  case lldb_cs_x86_64:
+    m_gpr.r_cs = reg_value.GetAsUInt32();
+    break;
+  case lldb_fs_x86_64:
+    m_gpr.r_fs = reg_value.GetAsUInt32();
+    break;
+  case lldb_gs_x86_64:
+    m_gpr.r_gs = reg_value.GetAsUInt32();
+    break;
+  case lldb_ss_x86_64:
+    m_gpr.r_ss = reg_value.GetAsUInt32();
+    break;
+  case lldb_ds_x86_64:
+    m_gpr.r_ds = reg_value.GetAsUInt32();
+    break;
+  case lldb_es_x86_64:
+    m_gpr.r_es = reg_value.GetAsUInt32();
+    break;
+#endif
+  case lldb_fctrl_x86_64:
+    FPR_ENV(en_cw) = reg_value.GetAsUInt16();
+    break;
+  case lldb_fstat_x86_64:
+    FPR_ENV(en_sw) = reg_value.GetAsUInt16();
+    break;
+  case lldb_ftag_x86_64:
+    FPR_ENV(en_tw) = reg_value.GetAsUInt16();
+    break;
+  case lldb_fop_x86_64:
+    FPR_ENV(en_opcode) = reg_value.GetAsUInt16();
+    break;
+  case lldb_fiseg_x86_64:
+    FPR_ENV(en_fcs) = reg_value.GetAsUInt32();
+    break;
+  case lldb_fioff_x86_64:
+    FPR_ENV(en_fip) = reg_value.GetAsUInt32();
+    break;
+  case lldb_foseg_x86_64:
+    FPR_ENV(en_fos) = reg_value.GetAsUInt32();
+    break;
+  case lldb_fooff_x86_64:
+    FPR_ENV(en_foo) = reg_value.GetAsUInt32();
+    break;
+  case lldb_mxcsr_x86_64:
+    FPR_ENV(en_mxcsr) = reg_value.GetAsUInt32();
+    break;
+  case lldb_mxcsrmask_x86_64:
+    FPR_ENV(en_mxcsr_mask) = reg_value.GetAsUInt32();
+    break;
+  case lldb_st0_x86_64:
+  case lldb_st1_x86_64:
+  case lldb_st2_x86_64:
+  case lldb_st3_x86_64:
+  case lldb_st4_x86_64:
+  case lldb_st5_x86_64:
+  case lldb_st6_x86_64:
+  case lldb_st7_x86_64:
+#if defined(__x86_64__)
+    ::memcpy(&m_fpr.fpr_acc[reg - lldb_st0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#else
+    ::memcpy(&m_fpr.xmm_acc[reg - lldb_st0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#endif
+    break;
+  case lldb_mm0_x86_64:
+  case lldb_mm1_x86_64:
+  case lldb_mm2_x86_64:
+  case lldb_mm3_x86_64:
+  case lldb_mm4_x86_64:
+  case lldb_mm5_x86_64:
+  case lldb_mm6_x86_64:
+  case lldb_mm7_x86_64:
+#if defined(__x86_64__)
+    ::memcpy(&m_fpr.fpr_acc[reg - lldb_mm0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#else
+    ::memcpy(&m_fpr.xmm_acc[reg - lldb_mm0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#endif
+    break;
+  case lldb_xmm0_x86_64:
+  case lldb_xmm1_x86_64:
+  case lldb_xmm2_x86_64:
+  case lldb_xmm3_x86_64:
+  case lldb_xmm4_x86_64:
+  case lldb_xmm5_x86_64:
+  case lldb_xmm6_x86_64:
+  case lldb_xmm7_x86_64:
+  case lldb_xmm8_x86_64:
+  case lldb_xmm9_x86_64:
+  case lldb_xmm10_x86_64:
+  case lldb_xmm11_x86_64:
+  case lldb_xmm12_x86_64:
+  case lldb_xmm13_x86_64:
+  case lldb_xmm14_x86_64:
+  case lldb_xmm15_x86_64:
+#if defined(__x86_64__)
+    ::memcpy(&m_fpr.fpr_xacc[reg - lldb_xmm0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#else
+    ::memcpy(&m_fpr.xmm_reg[reg - lldb_xmm0_x86_64], reg_value.GetBytes(),
+             reg_value.GetByteSize());
+#endif
+    break;
+  case lldb_dr0_x86_64:
+  case lldb_dr1_x86_64:
+  case lldb_dr2_x86_64:
+  case lldb_dr3_x86_64:
+  case lldb_dr4_x86_64:
+  case lldb_dr5_x86_64:
+  case lldb_dr6_x86_64:
+  case lldb_dr7_x86_64:
+    m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
+    break;
+  default:
+    llvm_unreachable("Reading unknown/unsupported register");
+  }
+
+  return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues(
+    lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+  error = ReadRegisterSet(GPRegSet);
+  if (error.Fail())
+    return error;
+
+  uint8_t *dst = data_sp->GetBytes();
+  ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize());
+  dst += GetRegisterInfoInterface().GetGPRSize();
+
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  Status error;
+
+  if (!data_sp) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided",
+        __FUNCTION__);
+    return error;
+  }
+
+  if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+    error.SetErrorStringWithFormat(
+        "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched "
+        "data size, expected %zu, actual %" PRIu64,
+        __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+    return error;
+  }
+
+  uint8_t *src = data_sp->GetBytes();
+  if (src == nullptr) {
+    error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s "
+                                   "DataBuffer::GetBytes() returned a null "
+                                   "pointer",
+                                   __FUNCTION__);
+    return error;
+  }
+  ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize());
+
+  error = WriteRegisterSet(GPRegSet);
+  if (error.Fail())
+    return error;
+  src += GetRegisterInfoInterface().GetGPRSize();
+
+  return error;
+}
+
+int NativeRegisterContextFreeBSD_x86_64::GetDR(int num) const {
+  assert(num >= 0 && num <= 7);
+  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+  case llvm::Triple::x86:
+    return lldb_dr0_i386 + num;
+  case llvm::Triple::x86_64:
+    return lldb_dr0_x86_64 + num;
+  default:
+    llvm_unreachable("Unhandled target architecture.");
+  }
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
+                                                            bool &is_hit) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Status("Watchpoint index out of range");
+
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(6));
+  Status error = ReadRegister(reg_info, 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;
+}
+
+Status NativeRegisterContextFreeBSD_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;
+    Status 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 Status();
+}
+
+Status
+NativeRegisterContextFreeBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
+                                                        bool &is_vacant) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Status("Watchpoint index out of range");
+
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(7));
+  Status error = ReadRegister(reg_info, 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 + 1)));
+
+  return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::SetHardwareWatchpointWithIndex(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Status("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 Status("Invalid read/write bits for watchpoint");
+
+  if (size != 1 && size != 2 && size != 4 && size != 8)
+    return Status("Invalid size for watchpoint");
+
+  bool is_vacant;
+  Status error = IsWatchpointVacant(wp_index, is_vacant);
+  if (error.Fail())
+    return error;
+  if (!is_vacant)
+    return Status("Watchpoint index not vacant");
+
+  const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
+  RegisterValue dr7_value;
+  error = ReadRegister(reg_info_dr7, dr7_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 + 1);
+
+  // 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 = dr7_value.GetAsUInt64() & ~bit_mask;
+
+  control_bits |= enable_bit | rw_bits | size_bits;
+
+  const RegisterInfo *const reg_info_drN =
+      GetRegisterInfoAtIndex(GetDR(wp_index));
+  RegisterValue drN_value;
+  error = ReadRegister(reg_info_drN, drN_value);
+  if (error.Fail())
+    return error;
+
+  // clear dr6 if address or bits changed (i.e. we're not reenabling the same
+  // watchpoint)
+  if (drN_value.GetAsUInt64() != addr ||
+      (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) {
+    ClearWatchpointHit(wp_index);
+
+    error = WriteRegister(reg_info_drN, RegisterValue(addr));
+    if (error.Fail())
+      return error;
+  }
+
+  error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+  if (error.Fail())
+    return error;
+
+  error.Clear();
+  return error;
+}
+
+bool NativeRegisterContextFreeBSD_x86_64::ClearHardwareWatchpoint(
+    uint32_t wp_index) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return false;
+
+  // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5
+  // or 6-7 of the debug control register (DR7)
+  const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
+  RegisterValue reg_value;
+  Status error = ReadRegister(reg_info_dr7, reg_value);
+  if (error.Fail())
+    return false;
+  uint64_t bit_mask = 0x3 << (2 * wp_index);
+  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+
+  return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
+}
+
+Status
+NativeRegisterContextFreeBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return Status("Watchpoint index out of range");
+
+  // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of
+  // the debug status register (DR6)
+  const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6));
+  RegisterValue reg_value;
+  Status error = ReadRegister(reg_info_dr6, reg_value);
+  if (error.Fail())
+    return error;
+
+  uint64_t bit_mask = 1 << wp_index;
+  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  return WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ClearAllHardwareWatchpoints() {
+  RegisterValue reg_value;
+
+  // clear bits {0-4} of the debug status register (DR6)
+  const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6));
+  Status error = ReadRegister(reg_info_dr6, reg_value);
+  if (error.Fail())
+    return error;
+  uint64_t bit_mask = 0xF;
+  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
+  if (error.Fail())
+    return error;
+
+  // clear bits {0-7,16-31} of the debug control register (DR7)
+  const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
+  error = ReadRegister(reg_info_dr7, reg_value);
+  if (error.Fail())
+    return error;
+  bit_mask = 0xFF | (0xFFFF << 16);
+  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
+  return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
+}
+
+uint32_t NativeRegisterContextFreeBSD_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;
+    Status 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) {
+      LLDB_LOGF(log, "NativeRegisterContextFreeBSD_x86_64::%s Error: %s",
+                __FUNCTION__, error.AsCString());
+    }
+  }
+  return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextFreeBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
+  if (wp_index >= NumSupportedHardwareWatchpoints())
+    return LLDB_INVALID_ADDRESS;
+  RegisterValue reg_value;
+  const RegisterInfo *const reg_info_drN =
+      GetRegisterInfoAtIndex(GetDR(wp_index));
+  if (ReadRegister(reg_info_drN, reg_value).Fail())
+    return LLDB_INVALID_ADDRESS;
+  return reg_value.GetAsUInt64();
+}
+
+uint32_t
+NativeRegisterContextFreeBSD_x86_64::NumSupportedHardwareWatchpoints() {
+  // Available debug address registers: dr0, dr1, dr2, dr3
+  return 4;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom(
+    NativeRegisterContextFreeBSD &source) {
+  auto &r_source = static_cast<NativeRegisterContextFreeBSD_x86_64 &>(source);
+  Status res = r_source.ReadRegisterSet(DBRegSet);
+  if (!res.Fail()) {
+    // copy dbregs only if any watchpoints were set
+    if ((r_source.m_dbr.dr[7] & 0xFF) == 0)
+      return res;
+
+    m_dbr = r_source.m_dbr;
+    res = WriteRegisterSet(DBRegSet);
+  }
+  return res;
+}
+
+#endif // defined(__x86_64__)
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
@@ -0,0 +1,48 @@
+//===-- NativeRegisterContextFreeBSD.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextFreeBSD_h
+#define lldb_NativeRegisterContextFreeBSD_h
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD : public NativeRegisterContextRegisterInfo {
+public:
+  NativeRegisterContextFreeBSD(NativeThreadProtocol &native_thread,
+                               RegisterInfoInterface *reg_info_interface_p);
+
+  // This function is implemented in the NativeRegisterContextFreeBSD_*
+  // subclasses to create a new instance of the host specific
+  // NativeRegisterContextFreeBSD. The implementations can't collide as only one
+  // NativeRegisterContextFreeBSD_* variant should be compiled into the final
+  // executable.
+  static NativeRegisterContextFreeBSD *
+  CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch,
+                                         NativeThreadProtocol &native_thread);
+  virtual Status
+  CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0;
+
+  virtual Status ClearWatchpointHit(uint32_t wp_index) = 0;
+
+protected:
+  Status DoRegisterSet(int req, void *buf);
+  virtual NativeProcessFreeBSD &GetProcess();
+  virtual ::pid_t GetProcessPid();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_h
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
@@ -0,0 +1,39 @@
+//===-- NativeRegisterContextFreeBSD.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+NativeRegisterContextFreeBSD::NativeRegisterContextFreeBSD(
+    NativeThreadProtocol &native_thread,
+    RegisterInfoInterface *reg_info_interface_p)
+    : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {}
+
+Status NativeRegisterContextFreeBSD::DoRegisterSet(int ptrace_req, void *buf) {
+  return NativeProcessFreeBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf,
+                                             m_thread.GetID());
+}
+
+NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() {
+  return static_cast<NativeProcessFreeBSD &>(m_thread.GetProcess());
+}
+
+::pid_t NativeRegisterContextFreeBSD::GetProcessPid() {
+  return GetProcess().GetID();
+}
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
@@ -0,0 +1,121 @@
+//===-- NativeProcessFreeBSD.h -------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessFreeBSD_H_
+#define liblldb_NativeProcessFreeBSD_H_
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadFreeBSD.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+/// \class NativeProcessFreeBSD
+/// 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 NativeProcessFreeBSD : public NativeProcessELF {
+public:
+  class Factory : public NativeProcessProtocol::Factory {
+  public:
+    llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+    Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
+           MainLoop &mainloop) const override;
+
+    llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+    Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
+           MainLoop &mainloop) const override;
+  };
+
+  // NativeProcessProtocol Interface
+  Status Resume(const ResumeActionList &resume_actions) override;
+
+  Status Halt() override;
+
+  Status Detach() override;
+
+  Status Signal(int signo) override;
+
+  Status Interrupt() override;
+
+  Status Kill() override;
+
+  Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+                             MemoryRegionInfo &range_info) override;
+
+  Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                    size_t &bytes_read) override;
+
+  Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+                     size_t &bytes_written) override;
+
+  Status AllocateMemory(size_t size, uint32_t permissions,
+                        lldb::addr_t &addr) override;
+
+  Status DeallocateMemory(lldb::addr_t addr) override;
+
+  lldb::addr_t GetSharedLibraryInfoAddress() override;
+
+  size_t UpdateThreads() override;
+
+  const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+  Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+                       bool hardware) override;
+
+  Status GetLoadedModuleFileSpec(const char *module_path,
+                                 FileSpec &file_spec) override;
+
+  Status 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 Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+                              int data = 0, int *result = nullptr);
+
+private:
+  MainLoop::SignalHandleUP m_sigchld_handle;
+  ArchSpec m_arch;
+  LazyBool m_supports_mem_region = eLazyBoolCalculate;
+  std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+  // Private Instance Methods
+  NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+                       const ArchSpec &arch, MainLoop &mainloop);
+
+  bool HasThreadNoLock(lldb::tid_t thread_id);
+
+  NativeThreadFreeBSD &AddThread(lldb::tid_t thread_id);
+  void RemoveThread(lldb::tid_t thread_id);
+
+  void MonitorCallback(lldb::pid_t pid, int signal);
+  void MonitorExited(lldb::pid_t pid, WaitStatus status);
+  void MonitorSIGSTOP(lldb::pid_t pid);
+  void MonitorSIGTRAP(lldb::pid_t pid);
+  void MonitorSignal(lldb::pid_t pid, int signal);
+
+  Status PopulateMemoryRegionCache();
+  void SigchldHandler();
+
+  Status Attach();
+  Status ReinitializeThreads();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessFreeBSD_H_
Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
@@ -0,0 +1,781 @@
+//===-- NativeProcessFreeBSD.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessFreeBSD.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <machine/elf.h>
+// clang-format on
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+  Status 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
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
+                                      NativeDelegate &native_delegate,
+                                      MainLoop &mainloop) const {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+  Status status;
+  ::pid_t pid = ProcessLauncherPosixFork()
+                    .LaunchProcess(launch_info, status)
+                    .GetProcessId();
+  LLDB_LOG(log, "pid = {0:x}", pid);
+  if (status.Fail()) {
+    LLDB_LOG(log, "failed to launch process: {0}", status);
+    return status.ToError();
+  }
+
+  // Wait for the child process to trap on its call to execve.
+  int wstatus;
+  ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+  assert(wpid == pid);
+  (void)wpid;
+  if (!WIFSTOPPED(wstatus)) {
+    LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+             WaitStatus::Decode(wstatus));
+    return llvm::make_error<StringError>("Could not sync with inferior process",
+                                         llvm::inconvertibleErrorCode());
+  }
+  LLDB_LOG(log, "inferior started, now in stopped state");
+
+  ProcessInstanceInfo Info;
+  if (!Host::GetProcessInfo(pid, Info)) {
+    return llvm::make_error<StringError>("Cannot get process architecture",
+                                         llvm::inconvertibleErrorCode());
+  }
+
+  // Set the architecture to the exe architecture.
+  LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+           Info.GetArchitecture().GetArchitectureName());
+
+  std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+      pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+      Info.GetArchitecture(), mainloop));
+
+  status = process_up->ReinitializeThreads();
+  if (status.Fail())
+    return status.ToError();
+
+  for (const auto &thread : process_up->m_threads)
+    static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+  process_up->SetState(StateType::eStateStopped, false);
+
+  return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Factory::Attach(
+    lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
+    MainLoop &mainloop) const {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  LLDB_LOG(log, "pid = {0:x}", pid);
+
+  // Retrieve the architecture for the running process.
+  ProcessInstanceInfo Info;
+  if (!Host::GetProcessInfo(pid, Info)) {
+    return llvm::make_error<StringError>("Cannot get process architecture",
+                                         llvm::inconvertibleErrorCode());
+  }
+
+  std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+      pid, -1, native_delegate, Info.GetArchitecture(), mainloop));
+
+  Status status = process_up->Attach();
+  if (!status.Success())
+    return status.ToError();
+
+  return std::move(process_up);
+}
+
+// Public Instance Methods
+
+NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd,
+                                           NativeDelegate &delegate,
+                                           const ArchSpec &arch,
+                                           MainLoop &mainloop)
+    : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
+  if (m_terminal_fd != -1) {
+    Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+    assert(status.Success());
+  }
+
+  Status status;
+  m_sigchld_handle = mainloop.RegisterSignal(
+      SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+  assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+  switch (signal) {
+  case SIGTRAP:
+    return MonitorSIGTRAP(pid);
+  case SIGSTOP:
+    return MonitorSIGSTOP(pid);
+  default:
+    return MonitorSignal(pid, signal);
+  }
+}
+
+void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+  LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+  /* Stop Tracking All Threads attached to Process */
+  m_threads.clear();
+
+  SetExitStatus(status, true);
+
+  // Notify delegate that our process has exited.
+  SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+  /* Stop all Threads attached to Process */
+  for (const auto &thread : m_threads) {
+    static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP,
+                                                                   nullptr);
+  }
+  SetState(StateType::eStateStopped, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  struct ptrace_lwpinfo info;
+
+  const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+  if (siginfo_err.Fail()) {
+    LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+    return;
+  }
+  assert(info.pl_event == PL_EVENT_SIGNAL);
+  // TODO: do we need to handle !PL_FLAG_SI?
+  assert(info.pl_flags & PL_FLAG_SI);
+  assert(info.pl_siginfo.si_signo == SIGTRAP);
+
+  LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
+           info.pl_lwpid, info.pl_siginfo.si_code);
+
+  NativeThreadFreeBSD *thread = nullptr;
+  if (info.pl_lwpid > 0) {
+    for (const auto &t : m_threads) {
+      if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid)) {
+        thread = static_cast<NativeThreadFreeBSD *>(t.get());
+        break;
+      }
+      static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason();
+    }
+    if (!thread)
+      LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+               info.pl_lwpid);
+  }
+
+  switch (info.pl_siginfo.si_code) {
+  case TRAP_BRKPT:
+    if (thread) {
+      thread->SetStoppedByBreakpoint();
+      FixupBreakpointPCAsNeeded(*thread);
+    }
+    SetState(StateType::eStateStopped, true);
+    break;
+  case TRAP_TRACE:
+    if (thread)
+      thread->SetStoppedByTrace();
+    SetState(StateType::eStateStopped, true);
+    break;
+  }
+}
+
+void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  struct ptrace_lwpinfo info;
+
+  const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+  if (siginfo_err.Fail()) {
+    LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+    return;
+  }
+  assert(info.pl_event == PL_EVENT_SIGNAL);
+  // TODO: do we need to handle !PL_FLAG_SI?
+  assert(info.pl_flags & PL_FLAG_SI);
+  assert(info.pl_siginfo.si_signo == signal);
+
+  for (const auto &abs_thread : m_threads) {
+    NativeThreadFreeBSD &thread =
+        static_cast<NativeThreadFreeBSD &>(*abs_thread);
+    assert(info.pl_lwpid >= 0);
+    if (info.pl_lwpid == 0 ||
+        static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID())
+      thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo);
+    else
+      thread.SetStoppedWithNoReason();
+  }
+  SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+                                           int data, int *result) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+  Status error;
+  int ret;
+
+  errno = 0;
+  ret =
+      ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(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;
+}
+
+Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  LLDB_LOG(log, "pid {0}", GetID());
+
+  Status ret;
+
+  int signal = 0;
+  for (const auto &abs_thread : m_threads) {
+    assert(abs_thread && "thread list should not contain NULL threads");
+    NativeThreadFreeBSD &thread =
+        static_cast<NativeThreadFreeBSD &>(*abs_thread);
+
+    const ResumeAction *action =
+        resume_actions.GetActionForThread(thread.GetID(), true);
+    // we need to explicit issue suspend requests, so it is simpler to map it
+    // into proper action
+    ResumeAction suspend_action{thread.GetID(), eStateSuspended,
+                                LLDB_INVALID_SIGNAL_NUMBER};
+
+    if (action == nullptr) {
+      LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+               thread.GetID());
+      action = &suspend_action;
+    }
+
+    LLDB_LOG(
+        log,
+        "processing resume action state {0} signal {1} for pid {2} tid {3}",
+        action->state, action->signal, GetID(), thread.GetID());
+
+    switch (action->state) {
+    case eStateRunning:
+      ret = thread.Resume();
+      break;
+    case eStateStepping:
+      ret = thread.SingleStep();
+      break;
+    case eStateSuspended:
+    case eStateStopped:
+      if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+        return Status("Passing signal to suspended thread unsupported");
+
+      ret = thread.Suspend();
+      break;
+
+    default:
+      return Status(
+          "NativeProcessFreeBSD::%s (): unexpected state %s specified "
+          "for pid %" PRIu64 ", tid %" PRIu64,
+          __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());
+    }
+
+    if (!ret.Success())
+      return ret;
+    if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+      signal = action->signal;
+  }
+
+  ret =
+      PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
+  if (ret.Success())
+    SetState(eStateRunning, true);
+  return ret;
+}
+
+Status NativeProcessFreeBSD::Halt() {
+  Status error;
+
+  if (kill(GetID(), SIGSTOP) != 0)
+    error.SetErrorToErrno();
+  return error;
+}
+
+Status NativeProcessFreeBSD::Detach() {
+  Status 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());
+}
+
+Status NativeProcessFreeBSD::Signal(int signo) {
+  Status error;
+
+  if (kill(GetID(), signo))
+    error.SetErrorToErrno();
+
+  return error;
+}
+
+Status NativeProcessFreeBSD::Interrupt() { return Halt(); }
+
+Status NativeProcessFreeBSD::Kill() {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  LLDB_LOG(log, "pid {0}", GetID());
+
+  Status 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;
+}
+
+Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+                                                 MemoryRegionInfo &range_info) {
+
+  if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+    // We're done.
+    return Status("unsupported");
+  }
+
+  Status 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;
+}
+
+Status NativeProcessFreeBSD::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 Status();
+  }
+
+  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)};
+  int ret;
+  size_t len;
+
+  ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0);
+  if (ret != 0) {
+    m_supports_mem_region = LazyBool::eLazyBoolNo;
+    return Status("sysctl() for KERN_PROC_VMMAP failed");
+  }
+
+  std::unique_ptr<WritableMemoryBuffer> buf =
+      llvm::WritableMemoryBuffer::getNewMemBuffer(len);
+  ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0);
+  if (ret != 0) {
+    m_supports_mem_region = LazyBool::eLazyBoolNo;
+    return Status("sysctl() for KERN_PROC_VMMAP failed");
+  }
+
+  char *bp = buf->getBufferStart();;
+  char *end = bp + len;
+  while (bp < end) {
+    auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp);
+    if (kv->kve_structsize == 0)
+      break;
+    bp += kv->kve_structsize;
+
+    MemoryRegionInfo info;
+    info.Clear();
+    info.GetRange().SetRangeBase(kv->kve_start);
+    info.GetRange().SetRangeEnd(kv->kve_end);
+    info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+    if (kv->kve_protection & VM_PROT_READ)
+      info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+    else
+      info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+    if (kv->kve_protection & VM_PROT_WRITE)
+      info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+    else
+      info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+    if (kv->kve_protection & VM_PROT_EXECUTE)
+      info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+    else
+      info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+    if (kv->kve_path[0])
+      info.SetName(kv->kve_path);
+
+    m_mem_region_cache.emplace_back(info,
+                                    FileSpec(info.GetName().GetCString()));
+  }
+
+  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;
+    return Status("not supported");
+  }
+  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 Status();
+}
+
+Status NativeProcessFreeBSD::AllocateMemory(size_t size, uint32_t permissions,
+                                            lldb::addr_t &addr) {
+  return Status("Unimplemented");
+}
+
+Status NativeProcessFreeBSD::DeallocateMemory(lldb::addr_t addr) {
+  return Status("Unimplemented");
+}
+
+lldb::addr_t NativeProcessFreeBSD::GetSharedLibraryInfoAddress() {
+  // punt on this for now
+  return LLDB_INVALID_ADDRESS;
+}
+
+size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); }
+
+Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+                                           bool hardware) {
+  if (hardware)
+    return Status("NativeProcessFreeBSD does not support hardware breakpoints");
+  else
+    return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path,
+                                                     FileSpec &file_spec) {
+  return Status("Unimplemented");
+}
+
+Status
+NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+                                         lldb::addr_t &load_addr) {
+  load_addr = LLDB_INVALID_ADDRESS;
+  return Status();
+}
+
+void NativeProcessFreeBSD::SigchldHandler() {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+  // Process all pending waitpid notifications.
+  int status;
+  ::pid_t wait_pid =
+      llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);
+
+  if (wait_pid == 0)
+    return; // We are done.
+
+  if (wait_pid == -1) {
+    Status error(errno, eErrorTypePOSIX);
+    LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+  }
+
+  WaitStatus wait_status = WaitStatus::Decode(status);
+  bool exited = wait_status.type == WaitStatus::Exit ||
+                (wait_status.type == WaitStatus::Signal &&
+                 wait_pid == static_cast<::pid_t>(GetID()));
+
+  LLDB_LOG(log,
+           "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+           GetID(), wait_pid, status, exited);
+
+  if (exited)
+    MonitorExited(wait_pid, wait_status);
+  else {
+    assert(wait_status.type == WaitStatus::Stop);
+    MonitorCallback(wait_pid, wait_status.status);
+  }
+}
+
+bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+  for (const auto &thread : m_threads) {
+    assert(thread && "thread list should not contain NULL threads");
+    if (thread->GetID() == thread_id) {
+      // We have this thread.
+      return true;
+    }
+  }
+
+  // We don't have this thread.
+  return false;
+}
+
+NativeThreadFreeBSD &NativeProcessFreeBSD::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(thread_id > 0);
+  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);
+
+  m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id));
+  return static_cast<NativeThreadFreeBSD &>(*m_threads.back());
+}
+
+void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) {
+  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+  LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
+
+  assert(thread_id > 0);
+  assert(HasThreadNoLock(thread_id) &&
+         "attempted to remove a thread that does not exist");
+
+  for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
+    if ((*it)->GetID() == thread_id) {
+      m_threads.erase(it);
+      break;
+    }
+  }
+}
+
+Status NativeProcessFreeBSD::Attach() {
+  // Attach to the requested process.
+  // An attach will cause the thread to stop with a SIGSTOP.
+  Status status = PtraceWrapper(PT_ATTACH, m_pid);
+  if (status.Fail())
+    return status;
+
+  int wstatus;
+  // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
+  // point we should have a thread stopped if waitpid succeeds.
+  if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) <
+      0)
+    return Status(errno, eErrorTypePOSIX);
+
+  /* Initialize threads */
+  status = ReinitializeThreads();
+  if (status.Fail())
+    return status;
+
+  for (const auto &thread : m_threads)
+    static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+
+  // Let our process instance know the thread has stopped.
+  SetState(StateType::eStateStopped);
+  return Status();
+}
+
+Status NativeProcessFreeBSD::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;
+
+    Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+    if (error.Fail() || io.piod_len == 0)
+      return error;
+
+    bytes_read += io.piod_len;
+    io.piod_len = size - bytes_read;
+  } while (bytes_read < size);
+
+  return Status();
+}
+
+Status NativeProcessFreeBSD::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);
+  Status 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 =
+        const_cast<void *>(static_cast<const void *>(src + bytes_written));
+    io.piod_offs = (void *)(addr + bytes_written);
+
+    Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+    if (error.Fail() || io.piod_len == 0)
+      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>>
+NativeProcessFreeBSD::GetAuxvData() const {
+  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())};
+  size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
+  std::unique_ptr<WritableMemoryBuffer> buf =
+      llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
+
+  if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0)
+    return std::error_code(errno, std::generic_category());
+
+  return buf;
+}
+
+Status NativeProcessFreeBSD::ReinitializeThreads() {
+  // Clear old threads
+  m_threads.clear();
+
+  int num_lwps;
+  Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps);
+  if (error.Fail())
+    return error;
+
+  std::vector<lwpid_t> lwp_ids;
+  lwp_ids.resize(num_lwps);
+  error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(),
+                        lwp_ids.size() * sizeof(lwpid_t), &num_lwps);
+  if (error.Fail())
+    return error;
+
+  // Reinitialize from scratch threads and register them in process
+  for (lwpid_t lwp : lwp_ids)
+    AddThread(lwp);
+
+  return error;
+}
Index: lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_lldb_library(lldbPluginProcessFreeBSDRemote
+  NativeProcessFreeBSD.cpp
+  NativeRegisterContextFreeBSD.cpp
+  NativeRegisterContextFreeBSD_x86_64.cpp
+  NativeThreadFreeBSD.cpp
+
+  LINK_LIBS
+    lldbHost
+    lldbSymbol
+    lldbTarget
+    lldbUtility
+    lldbPluginProcessPOSIX
+    lldbPluginProcessUtility
+  LINK_COMPONENTS
+    Support
+  )
Index: lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -79,12 +79,14 @@
 }
 
 void ProcessFreeBSD::Initialize() {
-  static llvm::once_flag g_once_flag;
+  if (!getenv("FREEBSD_REMOTE_PLUGIN")) {
+    static llvm::once_flag g_once_flag;
 
-  llvm::call_once(g_once_flag, []() {
-    PluginManager::RegisterPlugin(GetPluginNameStatic(),
-                                  GetPluginDescriptionStatic(), CreateInstance);
-  });
+    llvm::call_once(g_once_flag, []() {
+      PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                    GetPluginDescriptionStatic(), CreateInstance);
+    });
+  }
 }
 
 lldb_private::ConstString ProcessFreeBSD::GetPluginNameStatic() {
Index: lldb/source/Plugins/Process/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/CMakeLists.txt
+++ lldb/source/Plugins/Process/CMakeLists.txt
@@ -2,6 +2,7 @@
   add_subdirectory(Linux)
   add_subdirectory(POSIX)
 elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+  add_subdirectory(FreeBSDRemote)
   add_subdirectory(FreeBSD)
   add_subdirectory(POSIX)
 elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
Index: lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
===================================================================
--- lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
+++ lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -49,11 +49,6 @@
   size_t GetSoftwareBreakpointTrapOpcode(Target &target,
                                          BreakpointSite *bp_site) override;
 
-  Status LaunchProcess(ProcessLaunchInfo &launch_info) override;
-
-  lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
-                         Target *target, Status &error) override;
-
   void CalculateTrapHandlerSymbolNames() override;
 
   MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
Index: lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
===================================================================
--- lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -246,58 +246,15 @@
   }
 }
 
-Status PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
-  Status error;
-  if (IsHost()) {
-    error = Platform::LaunchProcess(launch_info);
-  } else {
-    if (m_remote_platform_sp)
-      error = m_remote_platform_sp->LaunchProcess(launch_info);
-    else
-      error.SetErrorString("the platform is not currently connected");
-  }
-  return error;
-}
-
-lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
-                                        Debugger &debugger, Target *target,
-                                        Status &error) {
-  lldb::ProcessSP process_sp;
-  if (IsHost()) {
-    if (target == nullptr) {
-      TargetSP new_target_sp;
-      ArchSpec emptyArchSpec;
-
-      error = debugger.GetTargetList().CreateTarget(
-          debugger, "", emptyArchSpec, eLoadDependentsNo, m_remote_platform_sp,
-          new_target_sp);
-      target = new_target_sp.get();
-    } else
-      error.Clear();
-
-    if (target && error.Success()) {
-      debugger.GetTargetList().SetSelectedTarget(target);
-      // The freebsd always currently uses the GDB remote debugger plug-in so
-      // even when debugging locally we are debugging remotely! Just like the
-      // darwin plugin.
-      process_sp = target->CreateProcess(
-          attach_info.GetListenerForProcess(debugger), "gdb-remote", nullptr);
-
-      if (process_sp)
-        error = process_sp->Attach(attach_info);
+bool PlatformFreeBSD::CanDebugProcess() {
+  if (getenv("FREEBSD_REMOTE_PLUGIN")) {
+    if (IsHost()) {
+      return true;
+    } else {
+      // If we're connected, we can debug.
+      return IsConnected();
     }
-  } else {
-    if (m_remote_platform_sp)
-      process_sp =
-          m_remote_platform_sp->Attach(attach_info, debugger, target, error);
-    else
-      error.SetErrorString("the platform is not currently connected");
   }
-  return process_sp;
-}
-
-// FreeBSD processes cannot yet be launched by spawning and attaching.
-bool PlatformFreeBSD::CanDebugProcess() {
   return false;
 }
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to