1 //===-- NativeRegisterContextFreeBSD_arm64.cpp ----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #if defined(__aarch64__)
11 #include "NativeRegisterContextFreeBSD_arm64.h"
13 #include "lldb/Utility/DataBufferHeap.h"
14 #include "lldb/Utility/RegisterValue.h"
15 #include "lldb/Utility/Status.h"
17 #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
18 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
19 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
22 #include <sys/param.h>
23 #include <sys/ptrace.h>
24 #include <sys/types.h>
28 using namespace lldb_private
;
29 using namespace lldb_private::process_freebsd
;
31 NativeRegisterContextFreeBSD
*
32 NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
33 const ArchSpec
&target_arch
, NativeThreadProtocol
&native_thread
) {
34 return new NativeRegisterContextFreeBSD_arm64(target_arch
, native_thread
);
37 NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
38 const ArchSpec
&target_arch
, NativeThreadProtocol
&native_thread
)
39 : NativeRegisterContextRegisterInfo(
40 native_thread
, new RegisterInfoPOSIX_arm64(target_arch
, 0))
41 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
46 ::memset(&m_hwp_regs
, 0, sizeof(m_hwp_regs
));
47 ::memset(&m_hbp_regs
, 0, sizeof(m_hbp_regs
));
50 RegisterInfoPOSIX_arm64
&
51 NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const {
52 return static_cast<RegisterInfoPOSIX_arm64
&>(*m_register_info_interface_up
);
55 uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const {
56 return GetRegisterInfo().GetRegisterSetCount();
60 NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index
) const {
61 return GetRegisterInfo().GetRegisterSet(set_index
);
64 uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const {
66 for (uint32_t set_index
= 0; set_index
< GetRegisterSetCount(); ++set_index
)
67 count
+= GetRegisterSet(set_index
)->num_registers
;
71 Status
NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set
) {
73 case RegisterInfoPOSIX_arm64::GPRegSet
:
74 return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS
, m_thread
.GetID(),
76 case RegisterInfoPOSIX_arm64::FPRegSet
:
77 return NativeProcessFreeBSD::PtraceWrapper(
78 PT_GETFPREGS
, m_thread
.GetID(),
79 m_reg_data
.data() + sizeof(RegisterInfoPOSIX_arm64::GPR
));
81 llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet");
84 Status
NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set
) {
86 case RegisterInfoPOSIX_arm64::GPRegSet
:
87 return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS
, m_thread
.GetID(),
89 case RegisterInfoPOSIX_arm64::FPRegSet
:
90 return NativeProcessFreeBSD::PtraceWrapper(
91 PT_SETFPREGS
, m_thread
.GetID(),
92 m_reg_data
.data() + sizeof(RegisterInfoPOSIX_arm64::GPR
));
94 llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet");
98 NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo
*reg_info
,
99 RegisterValue
®_value
) {
103 error
.SetErrorString("reg_info NULL");
107 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
109 if (reg
== LLDB_INVALID_REGNUM
)
110 return Status("no lldb regnum for %s", reg_info
&& reg_info
->name
112 : "<unknown register>");
114 uint32_t set
= GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg
);
115 error
= ReadRegisterSet(set
);
119 assert(reg_info
->byte_offset
+ reg_info
->byte_size
<= m_reg_data
.size());
120 reg_value
.SetBytes(m_reg_data
.data() + reg_info
->byte_offset
,
121 reg_info
->byte_size
, endian::InlHostByteOrder());
125 Status
NativeRegisterContextFreeBSD_arm64::WriteRegister(
126 const RegisterInfo
*reg_info
, const RegisterValue
®_value
) {
130 return Status("reg_info NULL");
132 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
134 if (reg
== LLDB_INVALID_REGNUM
)
135 return Status("no lldb regnum for %s", reg_info
&& reg_info
->name
137 : "<unknown register>");
139 uint32_t set
= GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg
);
140 error
= ReadRegisterSet(set
);
144 assert(reg_info
->byte_offset
+ reg_info
->byte_size
<= m_reg_data
.size());
145 ::memcpy(m_reg_data
.data() + reg_info
->byte_offset
, reg_value
.GetBytes(),
146 reg_info
->byte_size
);
148 return WriteRegisterSet(set
);
151 Status
NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues(
152 lldb::WritableDataBufferSP
&data_sp
) {
155 error
= ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet
);
159 error
= ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet
);
163 data_sp
.reset(new DataBufferHeap(m_reg_data
.size(), 0));
164 uint8_t *dst
= data_sp
->GetBytes();
165 ::memcpy(dst
, m_reg_data
.data(), m_reg_data
.size());
170 Status
NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues(
171 const lldb::DataBufferSP
&data_sp
) {
175 error
.SetErrorStringWithFormat(
176 "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided",
181 if (data_sp
->GetByteSize() != m_reg_data
.size()) {
182 error
.SetErrorStringWithFormat(
183 "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched "
184 "data size, expected %" PRIu64
", actual %" PRIu64
,
185 __FUNCTION__
, m_reg_data
.size(), data_sp
->GetByteSize());
189 const uint8_t *src
= data_sp
->GetBytes();
190 if (src
== nullptr) {
191 error
.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s "
192 "DataBuffer::GetBytes() returned a null "
197 ::memcpy(m_reg_data
.data(), src
, m_reg_data
.size());
199 error
= WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet
);
203 return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet
);
206 llvm::Error
NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom(
207 NativeRegisterContextFreeBSD
&source
) {
208 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
209 auto &r_source
= static_cast<NativeRegisterContextFreeBSD_arm64
&>(source
);
210 llvm::Error error
= r_source
.ReadHardwareDebugInfo();
214 m_dbreg
= r_source
.m_dbreg
;
215 m_hbp_regs
= r_source
.m_hbp_regs
;
216 m_hwp_regs
= r_source
.m_hwp_regs
;
217 m_max_hbp_supported
= r_source
.m_max_hbp_supported
;
218 m_max_hwp_supported
= r_source
.m_max_hwp_supported
;
221 // on FreeBSD this writes both breakpoints and watchpoints
222 return WriteHardwareDebugRegs(eDREGTypeWATCH
);
224 return llvm::Error::success();
228 llvm::Error
NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() {
229 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
230 Log
*log
= GetLog(POSIXLog::Registers
);
232 // we're fully stateful, so no need to reread control registers ever
234 return llvm::Error::success();
236 Status res
= NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS
,
237 m_thread
.GetID(), &m_dbreg
);
239 return res
.ToError();
241 LLDB_LOG(log
, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}",
242 m_dbreg
.db_debug_ver
, m_dbreg
.db_nbkpts
, m_dbreg
.db_nwtpts
);
243 m_max_hbp_supported
= m_dbreg
.db_nbkpts
;
244 m_max_hwp_supported
= m_dbreg
.db_nwtpts
;
245 assert(m_max_hbp_supported
<= m_hbp_regs
.size());
246 assert(m_max_hwp_supported
<= m_hwp_regs
.size());
249 return llvm::Error::success();
251 return llvm::createStringError(
252 llvm::inconvertibleErrorCode(),
253 "Hardware breakpoints/watchpoints require FreeBSD 14.0");
258 NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType
) {
259 #ifdef LLDB_HAS_FREEBSD_WATCHPOINT
260 assert(m_read_dbreg
&& "dbregs must be read before writing them back");
262 // copy data from m_*_regs to m_dbreg before writing it back
263 for (uint32_t i
= 0; i
< m_max_hbp_supported
; i
++) {
264 m_dbreg
.db_breakregs
[i
].dbr_addr
= m_hbp_regs
[i
].address
;
265 m_dbreg
.db_breakregs
[i
].dbr_ctrl
= m_hbp_regs
[i
].control
;
267 for (uint32_t i
= 0; i
< m_max_hwp_supported
; i
++) {
268 m_dbreg
.db_watchregs
[i
].dbw_addr
= m_hwp_regs
[i
].address
;
269 m_dbreg
.db_watchregs
[i
].dbw_ctrl
= m_hwp_regs
[i
].control
;
272 return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS
, m_thread
.GetID(),
276 return llvm::createStringError(
277 llvm::inconvertibleErrorCode(),
278 "Hardware breakpoints/watchpoints require FreeBSD 14.0");
282 #endif // defined (__aarch64__)