mgorny updated this revision to Diff 296238.
mgorny marked 2 inline comments as done.
mgorny added a comment.
For a start, removed leftover printf and len increment.
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 ®_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue ®_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 ®_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 ®_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
@@ -46,14 +46,13 @@
bool CanDebugProcess() override;
+ lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
+ Debugger &debugger, Target *target,
+ Status &error) override;
+
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,59 +246,131 @@
}
}
-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");
+bool PlatformFreeBSD::CanDebugProcess() {
+ if (getenv("FREEBSD_REMOTE_PLUGIN")) {
+ if (IsHost()) {
+ return true;
+ } else {
+ // If we're connected, we can debug.
+ return IsConnected();
+ }
}
- return error;
+ return false;
}
-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);
+// For local debugging, FreeBSD will override the debug logic to use llgs-launch
+// rather than lldb-launch, llgs-attach. This differs from current lldb-
+// launch, debugserver-attach approach on MacOSX.
+lldb::ProcessSP
+PlatformFreeBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new
+ // target, else use existing one
+ Status &error) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ LLDB_LOG(log, "target {0}", target);
+
+ // If we're a remote host, use standard behavior from parent class.
+ if (!IsHost())
+ return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error);
+
+ //
+ // For local debugging, we'll insist on having ProcessGDBRemote create the
+ // process.
+ //
+
+ ProcessSP process_sp;
+
+ // Make sure we stop at the entry point
+ launch_info.GetFlags().Set(eLaunchFlagDebug);
+
+ // We always launch the process we are going to debug in a separate process
+ // group, since then we can handle ^C interrupts ourselves w/o having to
+ // worry about the target getting them as well.
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ // Ensure we have a target.
+ if (target == nullptr) {
+ LLDB_LOG(log, "creating new target");
+ TargetSP new_target_sp;
+ error = debugger.GetTargetList().CreateTarget(
+ debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to create new target: {0}", error);
+ return process_sp;
+ }
+
+ target = new_target_sp.get();
+ if (!target) {
+ error.SetErrorString("CreateTarget() returned nullptr");
+ LLDB_LOG(log, "error: {0}", error);
+ return process_sp;
+ }
+ }
+
+ // Mark target as currently selected target.
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ // Now create the gdb-remote process.
+ LLDB_LOG(log, "having target create process with gdb-remote plugin");
+ process_sp =
+ target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr);
+
+ if (!process_sp) {
+ error.SetErrorString("CreateProcess() failed for gdb-remote process");
+ LLDB_LOG(log, "error: {0}", error);
+ return process_sp;
+ }
+
+ LLDB_LOG(log, "successfully created process");
+ // Adjust launch for a hijacker.
+ ListenerSP listener_sp;
+ if (!launch_info.GetHijackListener()) {
+ LLDB_LOG(log, "setting up hijacker");
+ listener_sp =
+ Listener::MakeListener("lldb.PlatformFreeBSD.DebugProcess.hijack");
+ launch_info.SetHijackListener(listener_sp);
+ process_sp->HijackProcessEvents(listener_sp);
+ }
+
+ // Log file actions.
+ if (log) {
+ LLDB_LOG(log, "launching process with the following file actions:");
+ StreamString stream;
+ size_t i = 0;
+ const FileAction *file_action;
+ while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
+ file_action->Dump(stream);
+ LLDB_LOG(log, "{0}", stream.GetData());
+ stream.Clear();
+ }
+ }
+
+ // Do the launch.
+ error = process_sp->Launch(launch_info);
+ if (error.Success()) {
+ // Handle the hijacking of process events.
+ if (listener_sp) {
+ const StateType state = process_sp->WaitForProcessToStop(
+ llvm::None, nullptr, false, listener_sp);
+
+ LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state);
}
+
+ // Hook up process PTY if we have one (which we should for local debugging
+ // with llgs).
+ int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor();
+ if (pty_fd != PseudoTerminal::invalid_fd) {
+ process_sp->SetSTDIOFileDescriptor(pty_fd);
+ LLDB_LOG(log, "hooked up STDIO pty to process");
+ } else
+ LLDB_LOG(log, "not using process STDIO pty");
} 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");
+ LLDB_LOG(log, "{0}", error);
+ // FIXME figure out appropriate cleanup here. Do we delete the target? Do
+ // we delete the process? Does our caller do that?
}
- return process_sp;
-}
-// FreeBSD processes cannot yet be launched by spawning and attaching.
-bool PlatformFreeBSD::CanDebugProcess() {
- return false;
+ return process_sp;
}
void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() {
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits