NativeRegisterContextNetBSD_x86_64.cpp revision 360784
1//===-- NativeRegisterContextNetBSD_x86_64.cpp ---------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#if defined(__x86_64__)
10
11#include "NativeRegisterContextNetBSD_x86_64.h"
12
13#include "lldb/Host/HostInfo.h"
14#include "lldb/Utility/DataBufferHeap.h"
15#include "lldb/Utility/Log.h"
16#include "lldb/Utility/RegisterValue.h"
17#include "lldb/Utility/Status.h"
18
19#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h"
20
21// clang-format off
22#include <sys/types.h>
23#include <sys/ptrace.h>
24#include <sys/sysctl.h>
25#include <sys/uio.h>
26#include <x86/cpu.h>
27#include <x86/cpu_extended_state.h>
28#include <x86/specialreg.h>
29#include <elf.h>
30#include <err.h>
31#include <stdint.h>
32#include <stdlib.h>
33// clang-format on
34
35using namespace lldb_private;
36using namespace lldb_private::process_netbsd;
37
38// Private namespace.
39
40namespace {
41// x86 64-bit general purpose registers.
42static const uint32_t g_gpr_regnums_x86_64[] = {
43    lldb_rax_x86_64,    lldb_rbx_x86_64,    lldb_rcx_x86_64, lldb_rdx_x86_64,
44    lldb_rdi_x86_64,    lldb_rsi_x86_64,    lldb_rbp_x86_64, lldb_rsp_x86_64,
45    lldb_r8_x86_64,     lldb_r9_x86_64,     lldb_r10_x86_64, lldb_r11_x86_64,
46    lldb_r12_x86_64,    lldb_r13_x86_64,    lldb_r14_x86_64, lldb_r15_x86_64,
47    lldb_rip_x86_64,    lldb_rflags_x86_64, lldb_cs_x86_64,  lldb_fs_x86_64,
48    lldb_gs_x86_64,     lldb_ss_x86_64,     lldb_ds_x86_64,  lldb_es_x86_64,
49    lldb_eax_x86_64,    lldb_ebx_x86_64,    lldb_ecx_x86_64, lldb_edx_x86_64,
50    lldb_edi_x86_64,    lldb_esi_x86_64,    lldb_ebp_x86_64, lldb_esp_x86_64,
51    lldb_r8d_x86_64,  // Low 32 bits or r8
52    lldb_r9d_x86_64,  // Low 32 bits or r9
53    lldb_r10d_x86_64, // Low 32 bits or r10
54    lldb_r11d_x86_64, // Low 32 bits or r11
55    lldb_r12d_x86_64, // Low 32 bits or r12
56    lldb_r13d_x86_64, // Low 32 bits or r13
57    lldb_r14d_x86_64, // Low 32 bits or r14
58    lldb_r15d_x86_64, // Low 32 bits or r15
59    lldb_ax_x86_64,     lldb_bx_x86_64,     lldb_cx_x86_64,  lldb_dx_x86_64,
60    lldb_di_x86_64,     lldb_si_x86_64,     lldb_bp_x86_64,  lldb_sp_x86_64,
61    lldb_r8w_x86_64,  // Low 16 bits or r8
62    lldb_r9w_x86_64,  // Low 16 bits or r9
63    lldb_r10w_x86_64, // Low 16 bits or r10
64    lldb_r11w_x86_64, // Low 16 bits or r11
65    lldb_r12w_x86_64, // Low 16 bits or r12
66    lldb_r13w_x86_64, // Low 16 bits or r13
67    lldb_r14w_x86_64, // Low 16 bits or r14
68    lldb_r15w_x86_64, // Low 16 bits or r15
69    lldb_ah_x86_64,     lldb_bh_x86_64,     lldb_ch_x86_64,  lldb_dh_x86_64,
70    lldb_al_x86_64,     lldb_bl_x86_64,     lldb_cl_x86_64,  lldb_dl_x86_64,
71    lldb_dil_x86_64,    lldb_sil_x86_64,    lldb_bpl_x86_64, lldb_spl_x86_64,
72    lldb_r8l_x86_64,    // Low 8 bits or r8
73    lldb_r9l_x86_64,    // Low 8 bits or r9
74    lldb_r10l_x86_64,   // Low 8 bits or r10
75    lldb_r11l_x86_64,   // Low 8 bits or r11
76    lldb_r12l_x86_64,   // Low 8 bits or r12
77    lldb_r13l_x86_64,   // Low 8 bits or r13
78    lldb_r14l_x86_64,   // Low 8 bits or r14
79    lldb_r15l_x86_64,   // Low 8 bits or r15
80    LLDB_INVALID_REGNUM // register sets need to end with this flag
81};
82static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
83                      1 ==
84                  k_num_gpr_registers_x86_64,
85              "g_gpr_regnums_x86_64 has wrong number of register infos");
86
87// x86 64-bit floating point registers.
88static const uint32_t g_fpu_regnums_x86_64[] = {
89    lldb_fctrl_x86_64,     lldb_fstat_x86_64, lldb_ftag_x86_64,
90    lldb_fop_x86_64,       lldb_fiseg_x86_64, lldb_fioff_x86_64,
91    lldb_foseg_x86_64,     lldb_fooff_x86_64, lldb_mxcsr_x86_64,
92    lldb_mxcsrmask_x86_64, lldb_st0_x86_64,   lldb_st1_x86_64,
93    lldb_st2_x86_64,       lldb_st3_x86_64,   lldb_st4_x86_64,
94    lldb_st5_x86_64,       lldb_st6_x86_64,   lldb_st7_x86_64,
95    lldb_mm0_x86_64,       lldb_mm1_x86_64,   lldb_mm2_x86_64,
96    lldb_mm3_x86_64,       lldb_mm4_x86_64,   lldb_mm5_x86_64,
97    lldb_mm6_x86_64,       lldb_mm7_x86_64,   lldb_xmm0_x86_64,
98    lldb_xmm1_x86_64,      lldb_xmm2_x86_64,  lldb_xmm3_x86_64,
99    lldb_xmm4_x86_64,      lldb_xmm5_x86_64,  lldb_xmm6_x86_64,
100    lldb_xmm7_x86_64,      lldb_xmm8_x86_64,  lldb_xmm9_x86_64,
101    lldb_xmm10_x86_64,     lldb_xmm11_x86_64, lldb_xmm12_x86_64,
102    lldb_xmm13_x86_64,     lldb_xmm14_x86_64, lldb_xmm15_x86_64,
103    LLDB_INVALID_REGNUM // register sets need to end with this flag
104};
105static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
106                      1 ==
107                  k_num_fpr_registers_x86_64,
108              "g_fpu_regnums_x86_64 has wrong number of register infos");
109
110// x86 64-bit registers available via XState.
111static const uint32_t g_xstate_regnums_x86_64[] = {
112    lldb_ymm0_x86_64,   lldb_ymm1_x86_64,  lldb_ymm2_x86_64,  lldb_ymm3_x86_64,
113    lldb_ymm4_x86_64,   lldb_ymm5_x86_64,  lldb_ymm6_x86_64,  lldb_ymm7_x86_64,
114    lldb_ymm8_x86_64,   lldb_ymm9_x86_64,  lldb_ymm10_x86_64, lldb_ymm11_x86_64,
115    lldb_ymm12_x86_64,  lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
116    // Note: we currently do not provide them but this is needed to avoid
117    // unnamed groups in SBFrame::GetRegisterContext().
118    lldb_bnd0_x86_64,    lldb_bnd1_x86_64,    lldb_bnd2_x86_64,
119    lldb_bnd3_x86_64,    lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
120    LLDB_INVALID_REGNUM // register sets need to end with this flag
121};
122static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) -
123                      1 ==
124                  k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
125              "g_xstate_regnums_x86_64 has wrong number of register infos");
126
127// x86 debug registers.
128static const uint32_t g_dbr_regnums_x86_64[] = {
129    lldb_dr0_x86_64,   lldb_dr1_x86_64,  lldb_dr2_x86_64,  lldb_dr3_x86_64,
130    lldb_dr4_x86_64,   lldb_dr5_x86_64,  lldb_dr6_x86_64,  lldb_dr7_x86_64,
131    LLDB_INVALID_REGNUM // register sets need to end with this flag
132};
133static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
134                      1 ==
135                  k_num_dbr_registers_x86_64,
136              "g_dbr_regnums_x86_64 has wrong number of register infos");
137
138// Number of register sets provided by this context.
139enum { k_num_register_sets = 4 };
140
141// Register sets for x86 64-bit.
142static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
143    {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
144     g_gpr_regnums_x86_64},
145    {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
146     g_fpu_regnums_x86_64},
147    {"Extended State Registers", "xstate",
148     k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
149     g_xstate_regnums_x86_64},
150    {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
151     g_dbr_regnums_x86_64},
152};
153
154#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
155} // namespace
156
157NativeRegisterContextNetBSD *
158NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
159    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
160  return new NativeRegisterContextNetBSD_x86_64(target_arch, native_thread);
161}
162
163// NativeRegisterContextNetBSD_x86_64 members.
164
165static RegisterInfoInterface *
166CreateRegisterInfoInterface(const ArchSpec &target_arch) {
167  assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
168         "Register setting path assumes this is a 64-bit host");
169  // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64
170  // register context.
171  return new RegisterContextNetBSD_x86_64(target_arch);
172}
173
174NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
175    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
176    : NativeRegisterContextNetBSD(native_thread,
177                                  CreateRegisterInfoInterface(target_arch)),
178      m_gpr_x86_64(), m_fpr_x86_64(), m_dbr_x86_64() {}
179
180// CONSIDER after local and llgs debugging are merged, register set support can
181// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
182uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
183  uint32_t sets = 0;
184  for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
185    if (GetSetForNativeRegNum(set_index) != -1)
186      ++sets;
187  }
188
189  return sets;
190}
191
192const RegisterSet *
193NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
194  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
195  case llvm::Triple::x86_64:
196    return &g_reg_sets_x86_64[set_index];
197  default:
198    assert(false && "Unhandled target architecture.");
199    return nullptr;
200  }
201
202  return nullptr;
203}
204
205int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
206    int reg_num) const {
207  if (reg_num <= k_last_gpr_x86_64)
208    return GPRegSet;
209  else if (reg_num <= k_last_fpr_x86_64)
210    return FPRegSet;
211  else if (reg_num <= k_last_avx_x86_64)
212    return XStateRegSet; // AVX
213  else if (reg_num <= k_last_mpxr_x86_64)
214    return -1; // MPXR
215  else if (reg_num <= k_last_mpxc_x86_64)
216    return -1; // MPXC
217  else if (reg_num <= lldb_dr7_x86_64)
218    return DBRegSet; // DBR
219  else
220    return -1;
221}
222
223Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
224  switch (set) {
225  case GPRegSet:
226    return DoRegisterSet(PT_GETREGS, &m_gpr_x86_64);
227  case FPRegSet:
228    return DoRegisterSet(PT_GETFPREGS, &m_fpr_x86_64);
229  case DBRegSet:
230    return DoRegisterSet(PT_GETDBREGS, &m_dbr_x86_64);
231  case XStateRegSet:
232#ifdef HAVE_XSTATE
233    {
234      struct iovec iov = {&m_xstate_x86_64, sizeof(m_xstate_x86_64)};
235      return DoRegisterSet(PT_GETXSTATE, &iov);
236    }
237#else
238    return Status("XState is not supported by the kernel");
239#endif
240  }
241  llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet");
242}
243
244Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
245  switch (set) {
246  case GPRegSet:
247    return DoRegisterSet(PT_SETREGS, &m_gpr_x86_64);
248  case FPRegSet:
249    return DoRegisterSet(PT_SETFPREGS, &m_fpr_x86_64);
250  case DBRegSet:
251    return DoRegisterSet(PT_SETDBREGS, &m_dbr_x86_64);
252  case XStateRegSet:
253#ifdef HAVE_XSTATE
254    {
255      struct iovec iov = {&m_xstate_x86_64, sizeof(m_xstate_x86_64)};
256      return DoRegisterSet(PT_SETXSTATE, &iov);
257    }
258#else
259    return Status("XState is not supported by the kernel");
260#endif
261  }
262  llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet");
263}
264
265Status
266NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
267                                                 RegisterValue &reg_value) {
268  Status error;
269
270  if (!reg_info) {
271    error.SetErrorString("reg_info NULL");
272    return error;
273  }
274
275  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
276  if (reg == LLDB_INVALID_REGNUM) {
277    // This is likely an internal register for lldb use only and should not be
278    // directly queried.
279    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
280                                   "register, cannot read directly",
281                                   reg_info->name);
282    return error;
283  }
284
285  int set = GetSetForNativeRegNum(reg);
286  if (set == -1) {
287    // This is likely an internal register for lldb use only and should not be
288    // directly queried.
289    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
290                                   reg_info->name);
291    return error;
292  }
293
294  error = ReadRegisterSet(set);
295  if (error.Fail())
296    return error;
297
298  switch (reg) {
299  case lldb_rax_x86_64:
300    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RAX];
301    break;
302  case lldb_rbx_x86_64:
303    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBX];
304    break;
305  case lldb_rcx_x86_64:
306    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RCX];
307    break;
308  case lldb_rdx_x86_64:
309    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDX];
310    break;
311  case lldb_rdi_x86_64:
312    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RDI];
313    break;
314  case lldb_rsi_x86_64:
315    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSI];
316    break;
317  case lldb_rbp_x86_64:
318    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RBP];
319    break;
320  case lldb_rsp_x86_64:
321    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RSP];
322    break;
323  case lldb_r8_x86_64:
324    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R8];
325    break;
326  case lldb_r9_x86_64:
327    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R9];
328    break;
329  case lldb_r10_x86_64:
330    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R10];
331    break;
332  case lldb_r11_x86_64:
333    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R11];
334    break;
335  case lldb_r12_x86_64:
336    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R12];
337    break;
338  case lldb_r13_x86_64:
339    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R13];
340    break;
341  case lldb_r14_x86_64:
342    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R14];
343    break;
344  case lldb_r15_x86_64:
345    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_R15];
346    break;
347  case lldb_rip_x86_64:
348    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RIP];
349    break;
350  case lldb_rflags_x86_64:
351    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_RFLAGS];
352    break;
353  case lldb_cs_x86_64:
354    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_CS];
355    break;
356  case lldb_fs_x86_64:
357    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_FS];
358    break;
359  case lldb_gs_x86_64:
360    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_GS];
361    break;
362  case lldb_ss_x86_64:
363    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_SS];
364    break;
365  case lldb_ds_x86_64:
366    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_DS];
367    break;
368  case lldb_es_x86_64:
369    reg_value = (uint64_t)m_gpr_x86_64.regs[_REG_ES];
370    break;
371  case lldb_fctrl_x86_64:
372    reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_cw;
373    break;
374  case lldb_fstat_x86_64:
375    reg_value = (uint16_t)m_fpr_x86_64.fxstate.fx_sw;
376    break;
377  case lldb_ftag_x86_64:
378    reg_value = (uint8_t)m_fpr_x86_64.fxstate.fx_tw;
379    break;
380  case lldb_fop_x86_64:
381    reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_opcode;
382    break;
383  case lldb_fiseg_x86_64:
384    reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_ip.fa_64;
385    break;
386  case lldb_fioff_x86_64:
387    reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off;
388    break;
389  case lldb_foseg_x86_64:
390    reg_value = (uint64_t)m_fpr_x86_64.fxstate.fx_dp.fa_64;
391    break;
392  case lldb_fooff_x86_64:
393    reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off;
394    break;
395  case lldb_mxcsr_x86_64:
396    reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr;
397    break;
398  case lldb_mxcsrmask_x86_64:
399    reg_value = (uint32_t)m_fpr_x86_64.fxstate.fx_mxcsr_mask;
400    break;
401  case lldb_st0_x86_64:
402  case lldb_st1_x86_64:
403  case lldb_st2_x86_64:
404  case lldb_st3_x86_64:
405  case lldb_st4_x86_64:
406  case lldb_st5_x86_64:
407  case lldb_st6_x86_64:
408  case lldb_st7_x86_64:
409    reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
410                       reg_info->byte_size, endian::InlHostByteOrder());
411    break;
412  case lldb_mm0_x86_64:
413  case lldb_mm1_x86_64:
414  case lldb_mm2_x86_64:
415  case lldb_mm3_x86_64:
416  case lldb_mm4_x86_64:
417  case lldb_mm5_x86_64:
418  case lldb_mm6_x86_64:
419  case lldb_mm7_x86_64:
420    reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
421                       reg_info->byte_size, endian::InlHostByteOrder());
422    break;
423  case lldb_xmm0_x86_64:
424  case lldb_xmm1_x86_64:
425  case lldb_xmm2_x86_64:
426  case lldb_xmm3_x86_64:
427  case lldb_xmm4_x86_64:
428  case lldb_xmm5_x86_64:
429  case lldb_xmm6_x86_64:
430  case lldb_xmm7_x86_64:
431  case lldb_xmm8_x86_64:
432  case lldb_xmm9_x86_64:
433  case lldb_xmm10_x86_64:
434  case lldb_xmm11_x86_64:
435  case lldb_xmm12_x86_64:
436  case lldb_xmm13_x86_64:
437  case lldb_xmm14_x86_64:
438  case lldb_xmm15_x86_64:
439    reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
440                       reg_info->byte_size, endian::InlHostByteOrder());
441    break;
442  case lldb_ymm0_x86_64:
443  case lldb_ymm1_x86_64:
444  case lldb_ymm2_x86_64:
445  case lldb_ymm3_x86_64:
446  case lldb_ymm4_x86_64:
447  case lldb_ymm5_x86_64:
448  case lldb_ymm6_x86_64:
449  case lldb_ymm7_x86_64:
450  case lldb_ymm8_x86_64:
451  case lldb_ymm9_x86_64:
452  case lldb_ymm10_x86_64:
453  case lldb_ymm11_x86_64:
454  case lldb_ymm12_x86_64:
455  case lldb_ymm13_x86_64:
456  case lldb_ymm14_x86_64:
457  case lldb_ymm15_x86_64:
458#ifdef HAVE_XSTATE
459    if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) ||
460        !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) {
461      error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
462                                     reg_info->name);
463    } else {
464      uint32_t reg_index = reg - lldb_ymm0_x86_64;
465      YMMReg ymm = XStateToYMM(
466          m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
467          m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes);
468      reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
469                         endian::InlHostByteOrder());
470    }
471#else
472    error.SetErrorString("XState queries not supported by the kernel");
473#endif
474    break;
475  case lldb_dr0_x86_64:
476  case lldb_dr1_x86_64:
477  case lldb_dr2_x86_64:
478  case lldb_dr3_x86_64:
479  case lldb_dr4_x86_64:
480  case lldb_dr5_x86_64:
481  case lldb_dr6_x86_64:
482  case lldb_dr7_x86_64:
483    reg_value = (uint64_t)m_dbr_x86_64.dr[reg - lldb_dr0_x86_64];
484    break;
485  }
486
487  return error;
488}
489
490Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
491    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
492
493  Status error;
494
495  if (!reg_info) {
496    error.SetErrorString("reg_info NULL");
497    return error;
498  }
499
500  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
501  if (reg == LLDB_INVALID_REGNUM) {
502    // This is likely an internal register for lldb use only and should not be
503    // directly queried.
504    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
505                                   "register, cannot read directly",
506                                   reg_info->name);
507    return error;
508  }
509
510  int set = GetSetForNativeRegNum(reg);
511  if (set == -1) {
512    // This is likely an internal register for lldb use only and should not be
513    // directly queried.
514    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
515                                   reg_info->name);
516    return error;
517  }
518
519  error = ReadRegisterSet(set);
520  if (error.Fail())
521    return error;
522
523  switch (reg) {
524  case lldb_rax_x86_64:
525    m_gpr_x86_64.regs[_REG_RAX] = reg_value.GetAsUInt64();
526    break;
527  case lldb_rbx_x86_64:
528    m_gpr_x86_64.regs[_REG_RBX] = reg_value.GetAsUInt64();
529    break;
530  case lldb_rcx_x86_64:
531    m_gpr_x86_64.regs[_REG_RCX] = reg_value.GetAsUInt64();
532    break;
533  case lldb_rdx_x86_64:
534    m_gpr_x86_64.regs[_REG_RDX] = reg_value.GetAsUInt64();
535    break;
536  case lldb_rdi_x86_64:
537    m_gpr_x86_64.regs[_REG_RDI] = reg_value.GetAsUInt64();
538    break;
539  case lldb_rsi_x86_64:
540    m_gpr_x86_64.regs[_REG_RSI] = reg_value.GetAsUInt64();
541    break;
542  case lldb_rbp_x86_64:
543    m_gpr_x86_64.regs[_REG_RBP] = reg_value.GetAsUInt64();
544    break;
545  case lldb_rsp_x86_64:
546    m_gpr_x86_64.regs[_REG_RSP] = reg_value.GetAsUInt64();
547    break;
548  case lldb_r8_x86_64:
549    m_gpr_x86_64.regs[_REG_R8] = reg_value.GetAsUInt64();
550    break;
551  case lldb_r9_x86_64:
552    m_gpr_x86_64.regs[_REG_R9] = reg_value.GetAsUInt64();
553    break;
554  case lldb_r10_x86_64:
555    m_gpr_x86_64.regs[_REG_R10] = reg_value.GetAsUInt64();
556    break;
557  case lldb_r11_x86_64:
558    m_gpr_x86_64.regs[_REG_R11] = reg_value.GetAsUInt64();
559    break;
560  case lldb_r12_x86_64:
561    m_gpr_x86_64.regs[_REG_R12] = reg_value.GetAsUInt64();
562    break;
563  case lldb_r13_x86_64:
564    m_gpr_x86_64.regs[_REG_R13] = reg_value.GetAsUInt64();
565    break;
566  case lldb_r14_x86_64:
567    m_gpr_x86_64.regs[_REG_R14] = reg_value.GetAsUInt64();
568    break;
569  case lldb_r15_x86_64:
570    m_gpr_x86_64.regs[_REG_R15] = reg_value.GetAsUInt64();
571    break;
572  case lldb_rip_x86_64:
573    m_gpr_x86_64.regs[_REG_RIP] = reg_value.GetAsUInt64();
574    break;
575  case lldb_rflags_x86_64:
576    m_gpr_x86_64.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
577    break;
578  case lldb_cs_x86_64:
579    m_gpr_x86_64.regs[_REG_CS] = reg_value.GetAsUInt64();
580    break;
581  case lldb_fs_x86_64:
582    m_gpr_x86_64.regs[_REG_FS] = reg_value.GetAsUInt64();
583    break;
584  case lldb_gs_x86_64:
585    m_gpr_x86_64.regs[_REG_GS] = reg_value.GetAsUInt64();
586    break;
587  case lldb_ss_x86_64:
588    m_gpr_x86_64.regs[_REG_SS] = reg_value.GetAsUInt64();
589    break;
590  case lldb_ds_x86_64:
591    m_gpr_x86_64.regs[_REG_DS] = reg_value.GetAsUInt64();
592    break;
593  case lldb_es_x86_64:
594    m_gpr_x86_64.regs[_REG_ES] = reg_value.GetAsUInt64();
595    break;
596  case lldb_fctrl_x86_64:
597    m_fpr_x86_64.fxstate.fx_cw = reg_value.GetAsUInt16();
598    break;
599  case lldb_fstat_x86_64:
600    m_fpr_x86_64.fxstate.fx_sw = reg_value.GetAsUInt16();
601    break;
602  case lldb_ftag_x86_64:
603    m_fpr_x86_64.fxstate.fx_tw = reg_value.GetAsUInt8();
604    break;
605  case lldb_fop_x86_64:
606    m_fpr_x86_64.fxstate.fx_opcode = reg_value.GetAsUInt16();
607    break;
608  case lldb_fiseg_x86_64:
609    m_fpr_x86_64.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
610    break;
611  case lldb_fioff_x86_64:
612    m_fpr_x86_64.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
613    break;
614  case lldb_foseg_x86_64:
615    m_fpr_x86_64.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
616    break;
617  case lldb_fooff_x86_64:
618    m_fpr_x86_64.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
619    break;
620  case lldb_mxcsr_x86_64:
621    m_fpr_x86_64.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
622    break;
623  case lldb_mxcsrmask_x86_64:
624    m_fpr_x86_64.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
625    break;
626  case lldb_st0_x86_64:
627  case lldb_st1_x86_64:
628  case lldb_st2_x86_64:
629  case lldb_st3_x86_64:
630  case lldb_st4_x86_64:
631  case lldb_st5_x86_64:
632  case lldb_st6_x86_64:
633  case lldb_st7_x86_64:
634    ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
635             reg_value.GetBytes(), reg_value.GetByteSize());
636    break;
637  case lldb_mm0_x86_64:
638  case lldb_mm1_x86_64:
639  case lldb_mm2_x86_64:
640  case lldb_mm3_x86_64:
641  case lldb_mm4_x86_64:
642  case lldb_mm5_x86_64:
643  case lldb_mm6_x86_64:
644  case lldb_mm7_x86_64:
645    ::memcpy(&m_fpr_x86_64.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
646             reg_value.GetBytes(), reg_value.GetByteSize());
647    break;
648  case lldb_xmm0_x86_64:
649  case lldb_xmm1_x86_64:
650  case lldb_xmm2_x86_64:
651  case lldb_xmm3_x86_64:
652  case lldb_xmm4_x86_64:
653  case lldb_xmm5_x86_64:
654  case lldb_xmm6_x86_64:
655  case lldb_xmm7_x86_64:
656  case lldb_xmm8_x86_64:
657  case lldb_xmm9_x86_64:
658  case lldb_xmm10_x86_64:
659  case lldb_xmm11_x86_64:
660  case lldb_xmm12_x86_64:
661  case lldb_xmm13_x86_64:
662  case lldb_xmm14_x86_64:
663  case lldb_xmm15_x86_64:
664    ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
665             reg_value.GetBytes(), reg_value.GetByteSize());
666    break;
667  case lldb_ymm0_x86_64:
668  case lldb_ymm1_x86_64:
669  case lldb_ymm2_x86_64:
670  case lldb_ymm3_x86_64:
671  case lldb_ymm4_x86_64:
672  case lldb_ymm5_x86_64:
673  case lldb_ymm6_x86_64:
674  case lldb_ymm7_x86_64:
675  case lldb_ymm8_x86_64:
676  case lldb_ymm9_x86_64:
677  case lldb_ymm10_x86_64:
678  case lldb_ymm11_x86_64:
679  case lldb_ymm12_x86_64:
680  case lldb_ymm13_x86_64:
681  case lldb_ymm14_x86_64:
682  case lldb_ymm15_x86_64:
683#ifdef HAVE_XSTATE
684    if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) ||
685        !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) {
686      error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
687                                     reg_info->name);
688    } else {
689      uint32_t reg_index = reg - lldb_ymm0_x86_64;
690      YMMReg ymm;
691      ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
692      YMMToXState(ymm,
693          m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
694          m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes);
695    }
696#else
697    error.SetErrorString("XState not supported by the kernel");
698#endif
699    break;
700  case lldb_dr0_x86_64:
701  case lldb_dr1_x86_64:
702  case lldb_dr2_x86_64:
703  case lldb_dr3_x86_64:
704  case lldb_dr4_x86_64:
705  case lldb_dr5_x86_64:
706  case lldb_dr6_x86_64:
707  case lldb_dr7_x86_64:
708    m_dbr_x86_64.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
709    break;
710  }
711
712  return WriteRegisterSet(set);
713}
714
715Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
716    lldb::DataBufferSP &data_sp) {
717  Status error;
718
719  data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
720  error = ReadRegisterSet(GPRegSet);
721  if (error.Fail())
722    return error;
723
724  uint8_t *dst = data_sp->GetBytes();
725  ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
726  dst += GetRegisterInfoInterface().GetGPRSize();
727
728  return error;
729}
730
731Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
732    const lldb::DataBufferSP &data_sp) {
733  Status error;
734
735  if (!data_sp) {
736    error.SetErrorStringWithFormat(
737        "NativeRegisterContextNetBSD_x86_64::%s invalid data_sp provided",
738        __FUNCTION__);
739    return error;
740  }
741
742  if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
743    error.SetErrorStringWithFormat(
744        "NativeRegisterContextNetBSD_x86_64::%s data_sp contained mismatched "
745        "data size, expected %" PRIu64 ", actual %" PRIu64,
746        __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
747    return error;
748  }
749
750  uint8_t *src = data_sp->GetBytes();
751  if (src == nullptr) {
752    error.SetErrorStringWithFormat("NativeRegisterContextNetBSD_x86_64::%s "
753                                   "DataBuffer::GetBytes() returned a null "
754                                   "pointer",
755                                   __FUNCTION__);
756    return error;
757  }
758  ::memcpy(&m_gpr_x86_64, src, GetRegisterInfoInterface().GetGPRSize());
759
760  error = WriteRegisterSet(GPRegSet);
761  if (error.Fail())
762    return error;
763  src += GetRegisterInfoInterface().GetGPRSize();
764
765  return error;
766}
767
768Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
769                                                           bool &is_hit) {
770  if (wp_index >= NumSupportedHardwareWatchpoints())
771    return Status("Watchpoint index out of range");
772
773  RegisterValue reg_value;
774  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr6_x86_64);
775  Status error = ReadRegister(reg_info, reg_value);
776  if (error.Fail()) {
777    is_hit = false;
778    return error;
779  }
780
781  uint64_t status_bits = reg_value.GetAsUInt64();
782
783  is_hit = status_bits & (1 << wp_index);
784
785  return error;
786}
787
788Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
789    uint32_t &wp_index, lldb::addr_t trap_addr) {
790  uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
791  for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
792    bool is_hit;
793    Status error = IsWatchpointHit(wp_index, is_hit);
794    if (error.Fail()) {
795      wp_index = LLDB_INVALID_INDEX32;
796      return error;
797    } else if (is_hit) {
798      return error;
799    }
800  }
801  wp_index = LLDB_INVALID_INDEX32;
802  return Status();
803}
804
805Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
806                                                              bool &is_vacant) {
807  if (wp_index >= NumSupportedHardwareWatchpoints())
808    return Status("Watchpoint index out of range");
809
810  RegisterValue reg_value;
811  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(lldb_dr7_x86_64);
812  Status error = ReadRegister(reg_info, reg_value);
813  if (error.Fail()) {
814    is_vacant = false;
815    return error;
816  }
817
818  uint64_t control_bits = reg_value.GetAsUInt64();
819
820  is_vacant = !(control_bits & (1 << (2 * wp_index + 1)));
821
822  return error;
823}
824
825Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
826    lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
827
828  if (wp_index >= NumSupportedHardwareWatchpoints())
829    return Status("Watchpoint index out of range");
830
831  // Read only watchpoints aren't supported on x86_64. Fall back to read/write
832  // waitchpoints instead.
833  // TODO: Add logic to detect when a write happens and ignore that watchpoint
834  // hit.
835  if (watch_flags == 0x2)
836    watch_flags = 0x3;
837
838  if (watch_flags != 0x1 && watch_flags != 0x3)
839    return Status("Invalid read/write bits for watchpoint");
840
841  if (size != 1 && size != 2 && size != 4 && size != 8)
842    return Status("Invalid size for watchpoint");
843
844  bool is_vacant;
845  Status error = IsWatchpointVacant(wp_index, is_vacant);
846  if (error.Fail())
847    return error;
848  if (!is_vacant)
849    return Status("Watchpoint index not vacant");
850
851  const RegisterInfo *const reg_info_dr7 =
852      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
853  RegisterValue dr7_value;
854  error = ReadRegister(reg_info_dr7, dr7_value);
855  if (error.Fail())
856    return error;
857
858  // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
859  uint64_t enable_bit = 1 << (2 * wp_index + 1);
860
861  // set bits 16-17, 20-21, 24-25, or 28-29
862  // with 0b01 for write, and 0b11 for read/write
863  uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
864
865  // set bits 18-19, 22-23, 26-27, or 30-31
866  // with 0b00, 0b01, 0b10, or 0b11
867  // for 1, 2, 8 (if supported), or 4 bytes, respectively
868  uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
869
870  uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
871
872  uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask;
873
874  control_bits |= enable_bit | rw_bits | size_bits;
875
876  const RegisterInfo *const reg_info_drN =
877      GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
878  RegisterValue drN_value;
879  error = ReadRegister(reg_info_drN, drN_value);
880  if (error.Fail())
881    return error;
882
883  // clear dr6 if address or bits changed (i.e. we're not reenabling the same
884  // watchpoint)
885  if (drN_value.GetAsUInt64() != addr ||
886      (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) {
887    ClearWatchpointHit(wp_index);
888
889    error = WriteRegister(reg_info_drN, RegisterValue(addr));
890    if (error.Fail())
891      return error;
892  }
893
894  error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
895  if (error.Fail())
896    return error;
897
898  error.Clear();
899  return error;
900}
901
902bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
903    uint32_t wp_index) {
904  if (wp_index >= NumSupportedHardwareWatchpoints())
905    return false;
906
907  // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5
908  // or 6-7 of the debug control register (DR7)
909  const RegisterInfo *const reg_info_dr7 =
910      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
911  RegisterValue reg_value;
912  Status error = ReadRegister(reg_info_dr7, reg_value);
913  if (error.Fail())
914    return false;
915  uint64_t bit_mask = 0x3 << (2 * wp_index);
916  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
917
918  return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
919}
920
921Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) {
922  if (wp_index >= NumSupportedHardwareWatchpoints())
923    return Status("Watchpoint index out of range");
924
925  // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of
926  // the debug status register (DR6)
927  const RegisterInfo *const reg_info_dr6 =
928      GetRegisterInfoAtIndex(lldb_dr6_x86_64);
929  RegisterValue reg_value;
930  Status error = ReadRegister(reg_info_dr6, reg_value);
931  if (error.Fail())
932    return error;
933
934  uint64_t bit_mask = 1 << wp_index;
935  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
936  return WriteRegister(reg_info_dr6, RegisterValue(status_bits));
937}
938
939Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
940  RegisterValue reg_value;
941
942  // clear bits {0-4} of the debug status register (DR6)
943  const RegisterInfo *const reg_info_dr6 =
944      GetRegisterInfoAtIndex(lldb_dr6_x86_64);
945  Status error = ReadRegister(reg_info_dr6, reg_value);
946  if (error.Fail())
947    return error;
948  uint64_t bit_mask = 0xF;
949  uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
950  error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
951  if (error.Fail())
952    return error;
953
954  // clear bits {0-7,16-31} of the debug control register (DR7)
955  const RegisterInfo *const reg_info_dr7 =
956      GetRegisterInfoAtIndex(lldb_dr7_x86_64);
957  error = ReadRegister(reg_info_dr7, reg_value);
958  if (error.Fail())
959    return error;
960  bit_mask = 0xFF | (0xFFFF << 16);
961  uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
962  return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
963}
964
965uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
966    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
967  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
968  const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
969  for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
970    bool is_vacant;
971    Status error = IsWatchpointVacant(wp_index, is_vacant);
972    if (is_vacant) {
973      error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
974      if (error.Success())
975        return wp_index;
976    }
977    if (error.Fail() && log) {
978      LLDB_LOGF(log, "NativeRegisterContextNetBSD_x86_64::%s Error: %s",
979                __FUNCTION__, error.AsCString());
980    }
981  }
982  return LLDB_INVALID_INDEX32;
983}
984
985lldb::addr_t
986NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
987  if (wp_index >= NumSupportedHardwareWatchpoints())
988    return LLDB_INVALID_ADDRESS;
989  RegisterValue reg_value;
990  const RegisterInfo *const reg_info_drN =
991      GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index);
992  if (ReadRegister(reg_info_drN, reg_value).Fail())
993    return LLDB_INVALID_ADDRESS;
994  return reg_value.GetAsUInt64();
995}
996
997uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
998  // Available debug address registers: dr0, dr1, dr2, dr3
999  return 4;
1000}
1001
1002Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom(
1003    NativeRegisterContextNetBSD &source) {
1004  auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64&>(source);
1005  Status res = r_source.ReadRegisterSet(DBRegSet);
1006  if (!res.Fail()) {
1007    // copy dbregs only if any watchpoints were set
1008    if ((r_source.m_dbr_x86_64.dr[7] & 0xFF) == 0)
1009      return res;
1010
1011    m_dbr_x86_64 = r_source.m_dbr_x86_64;
1012    res = WriteRegisterSet(DBRegSet);
1013  }
1014  return res;
1015}
1016
1017#endif // defined(__x86_64__)
1018