xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Process/OpenBSD/NativeRegisterContextOpenBSD_arm64.cpp (revision 101d251d5caf88a9341f3045ab62e122abae1b90)
1 //===-- NativeRegisterContextOpenBSD_arm64.cpp ---------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #if defined(__arm64__) || defined(__aarch64__)
11 
12 #include <elf.h>
13 #include <err.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 
17 #include "NativeRegisterContextOpenBSD_arm64.h"
18 
19 #include "lldb/Host/HostInfo.h"
20 #include "lldb/Utility/DataBufferHeap.h"
21 #include "lldb/Utility/RegisterValue.h"
22 #include "lldb/Utility/Status.h"
23 #include "llvm/ADT/APInt.h"
24 
25 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
26 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
27 
28 // clang-format off
29 #include <sys/types.h>
30 #include <sys/ptrace.h>
31 #include <sys/sysctl.h>
32 #include <sys/time.h>
33 #include <machine/cpu.h>
34 // clang-format on
35 
36 using namespace lldb_private;
37 using namespace lldb_private::process_openbsd;
38 
39 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
40 
41 std::unique_ptr<NativeRegisterContextOpenBSD>
CreateHostNativeRegisterContextOpenBSD(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)42 NativeRegisterContextOpenBSD::CreateHostNativeRegisterContextOpenBSD(
43     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
44   return std::make_unique<NativeRegisterContextOpenBSD_arm64>(target_arch, native_thread);
45 }
46 
47 // ----------------------------------------------------------------------------
48 // NativeRegisterContextOpenBSD_arm64 members.
49 // ----------------------------------------------------------------------------
50 
51 static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec & target_arch)52 CreateRegisterInfoInterface(const ArchSpec &target_arch) {
53   assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
54          "Register setting path assumes this is a 64-bit host");
55 
56   Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskPAuth;
57   return new RegisterInfoPOSIX_arm64(target_arch, opt_regsets);
58 }
59 
uint128ToAPInt(__uint128_t in)60 static llvm::APInt uint128ToAPInt(__uint128_t in) {
61   uint64_t *pair = (uint64_t *)&in;
62   llvm::APInt out(128, 2, pair);
63   return out;
64 }
65 
APIntTouint128(llvm::APInt in)66 static __uint128_t APIntTouint128(llvm::APInt in) {
67   assert(in.getBitWidth() == 128);
68   __uint128_t out = 0;
69   const uint64_t *data = in.getRawData();
70   ::memcpy((uint64_t *)&out, data, sizeof(__uint128_t));
71   return out;
72 }
73 
NativeRegisterContextOpenBSD_arm64(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)74 NativeRegisterContextOpenBSD_arm64::NativeRegisterContextOpenBSD_arm64(
75     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
76     : NativeRegisterContextOpenBSD(native_thread,
77                                   CreateRegisterInfoInterface(target_arch)),
78       m_gpr(), m_fpr() {}
79 
80 RegisterInfoPOSIX_arm64 &
GetRegisterInfo() const81 NativeRegisterContextOpenBSD_arm64::GetRegisterInfo() const {
82   return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
83 }
84 
GetRegisterSetCount() const85 uint32_t NativeRegisterContextOpenBSD_arm64::GetRegisterSetCount() const {
86   return GetRegisterInfo().GetRegisterSetCount();
87 }
88 
89 const RegisterSet *
GetRegisterSet(uint32_t set_index) const90 NativeRegisterContextOpenBSD_arm64::GetRegisterSet(uint32_t set_index) const {
91   return GetRegisterInfo().GetRegisterSet(set_index);
92 }
93 
GetUserRegisterCount() const94 uint32_t NativeRegisterContextOpenBSD_arm64::GetUserRegisterCount() const {
95   uint32_t count = 0;
96   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
97     count += GetRegisterSet(set_index)->num_registers;
98   return count;
99 }
100 
101 Status
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)102 NativeRegisterContextOpenBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
103                                                  RegisterValue &reg_value) {
104   Status error;
105   Log *log = GetLog(POSIXLog::Registers);
106 
107   if (!reg_info) {
108     error.SetErrorString("reg_info NULL");
109     return error;
110   }
111 
112   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
113   if (reg == LLDB_INVALID_REGNUM) {
114     // This is likely an internal register for lldb use only and should not be
115     // directly queried.
116     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
117                                    "register, cannot read directly",
118                                    reg_info->name);
119     return error;
120   }
121 
122   int set = GetSetForNativeRegNum(reg);
123   if (set == -1) {
124     // This is likely an internal register for lldb use only and should not be
125     // directly queried.
126     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
127                                    reg_info->name);
128     return error;
129   }
130 
131   if (ReadRegisterSet(set) != 0) {
132     // This is likely an internal register for lldb use only and should not be
133     // directly queried.
134     error.SetErrorStringWithFormat(
135         "reading register set for register \"%s\" failed", reg_info->name);
136     return error;
137   }
138 
139   if (GetRegisterInfo().IsPAuthReg(reg)) {
140     uint32_t offset;
141 
142     offset = reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset();
143     reg_value = (uint64_t)m_pacmask[offset > 0];
144     if (reg_value.GetByteSize() > reg_info->byte_size) {
145       reg_value.SetType(*reg_info);
146     }
147 
148     return error;
149   }
150 
151   switch (reg) {
152   case gpr_x0_arm64:
153   case gpr_x1_arm64:
154   case gpr_x2_arm64:
155   case gpr_x3_arm64:
156   case gpr_x4_arm64:
157   case gpr_x5_arm64:
158   case gpr_x6_arm64:
159   case gpr_x7_arm64:
160   case gpr_x8_arm64:
161   case gpr_x9_arm64:
162   case gpr_x10_arm64:
163   case gpr_x11_arm64:
164   case gpr_x12_arm64:
165   case gpr_x13_arm64:
166   case gpr_x14_arm64:
167   case gpr_x15_arm64:
168   case gpr_x16_arm64:
169   case gpr_x17_arm64:
170   case gpr_x18_arm64:
171   case gpr_x19_arm64:
172   case gpr_x20_arm64:
173   case gpr_x21_arm64:
174   case gpr_x22_arm64:
175   case gpr_x23_arm64:
176   case gpr_x24_arm64:
177   case gpr_x25_arm64:
178   case gpr_x26_arm64:
179   case gpr_x27_arm64:
180   case gpr_x28_arm64:
181     reg_value = (uint64_t)m_gpr.r_reg[reg - gpr_x0_arm64];
182     break;
183   case gpr_fp_arm64:
184     reg_value = (uint64_t)m_gpr.r_reg[29];
185     break;
186   case gpr_lr_arm64:
187     reg_value = (uint64_t)m_gpr.r_lr;
188     break;
189   case gpr_sp_arm64:
190     reg_value = (uint64_t)m_gpr.r_sp;
191     break;
192   case gpr_pc_arm64:
193     reg_value = (uint64_t)m_gpr.r_pc;
194     break;
195   case gpr_cpsr_arm64:
196     reg_value = (uint64_t)m_gpr.r_spsr;
197     break;
198   case fpu_v0_arm64:
199   case fpu_v1_arm64:
200   case fpu_v2_arm64:
201   case fpu_v3_arm64:
202   case fpu_v4_arm64:
203   case fpu_v5_arm64:
204   case fpu_v6_arm64:
205   case fpu_v7_arm64:
206   case fpu_v8_arm64:
207   case fpu_v9_arm64:
208   case fpu_v10_arm64:
209   case fpu_v11_arm64:
210   case fpu_v12_arm64:
211   case fpu_v13_arm64:
212   case fpu_v14_arm64:
213   case fpu_v15_arm64:
214   case fpu_v16_arm64:
215   case fpu_v17_arm64:
216   case fpu_v18_arm64:
217   case fpu_v19_arm64:
218   case fpu_v20_arm64:
219   case fpu_v21_arm64:
220   case fpu_v22_arm64:
221   case fpu_v23_arm64:
222   case fpu_v24_arm64:
223   case fpu_v25_arm64:
224   case fpu_v26_arm64:
225   case fpu_v27_arm64:
226   case fpu_v28_arm64:
227   case fpu_v29_arm64:
228   case fpu_v30_arm64:
229   case fpu_v31_arm64:
230     reg_value = uint128ToAPInt(m_fpr.fp_reg[reg - fpu_v0_arm64]);
231     break;
232   case fpu_fpsr_arm64:
233     reg_value = (uint32_t)m_fpr.fp_sr;
234     break;
235   case fpu_fpcr_arm64:
236     reg_value = (uint32_t)m_fpr.fp_cr;
237     break;
238   default:
239     log->Printf("Requested read to unhandled reg: %u", reg);
240     break;
241   }
242 
243   if (reg_value.GetByteSize() > reg_info->byte_size) {
244     reg_value.SetType(*reg_info);
245   }
246 
247   return error;
248 }
249 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)250 Status NativeRegisterContextOpenBSD_arm64::WriteRegister(
251     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
252 
253   Status error;
254   Log *log = GetLog(POSIXLog::Registers);
255 
256   if (!reg_info) {
257     error.SetErrorString("reg_info NULL");
258     return error;
259   }
260 
261   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
262   if (reg == LLDB_INVALID_REGNUM) {
263     // This is likely an internal register for lldb use only and should not be
264     // directly queried.
265     error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
266                                    "register, cannot read directly",
267                                    reg_info->name);
268     return error;
269   }
270 
271   int set = GetSetForNativeRegNum(reg);
272   if (set == -1) {
273     // This is likely an internal register for lldb use only and should not be
274     // directly queried.
275     error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
276                                    reg_info->name);
277     return error;
278   }
279 
280   if (ReadRegisterSet(set) != 0) {
281     // This is likely an internal register for lldb use only and should not be
282     // directly queried.
283     error.SetErrorStringWithFormat(
284         "reading register set for register \"%s\" failed", reg_info->name);
285     return error;
286   }
287 
288   switch (reg) {
289   case gpr_x0_arm64:
290   case gpr_x1_arm64:
291   case gpr_x2_arm64:
292   case gpr_x3_arm64:
293   case gpr_x4_arm64:
294   case gpr_x5_arm64:
295   case gpr_x6_arm64:
296   case gpr_x7_arm64:
297   case gpr_x8_arm64:
298   case gpr_x9_arm64:
299   case gpr_x10_arm64:
300   case gpr_x11_arm64:
301   case gpr_x12_arm64:
302   case gpr_x13_arm64:
303   case gpr_x14_arm64:
304   case gpr_x15_arm64:
305   case gpr_x16_arm64:
306   case gpr_x17_arm64:
307   case gpr_x18_arm64:
308   case gpr_x19_arm64:
309   case gpr_x20_arm64:
310   case gpr_x21_arm64:
311   case gpr_x22_arm64:
312   case gpr_x23_arm64:
313   case gpr_x24_arm64:
314   case gpr_x25_arm64:
315   case gpr_x26_arm64:
316   case gpr_x27_arm64:
317   case gpr_x28_arm64:
318     m_gpr.r_reg[reg - gpr_x0_arm64] = reg_value.GetAsUInt64();
319     break;
320   case gpr_fp_arm64:
321     m_gpr.r_reg[29] = reg_value.GetAsUInt64();
322     break;
323   case gpr_lr_arm64:
324     m_gpr.r_lr = reg_value.GetAsUInt64();
325     break;
326   case gpr_sp_arm64:
327     m_gpr.r_sp = reg_value.GetAsUInt64();
328     break;
329   case gpr_pc_arm64:
330     m_gpr.r_pc = reg_value.GetAsUInt64();
331     break;
332   case gpr_cpsr_arm64:
333     m_gpr.r_spsr = reg_value.GetAsUInt64();
334     break;
335   case fpu_v0_arm64:
336   case fpu_v1_arm64:
337   case fpu_v2_arm64:
338   case fpu_v3_arm64:
339   case fpu_v4_arm64:
340   case fpu_v5_arm64:
341   case fpu_v6_arm64:
342   case fpu_v7_arm64:
343   case fpu_v8_arm64:
344   case fpu_v9_arm64:
345   case fpu_v10_arm64:
346   case fpu_v11_arm64:
347   case fpu_v12_arm64:
348   case fpu_v13_arm64:
349   case fpu_v14_arm64:
350   case fpu_v15_arm64:
351   case fpu_v16_arm64:
352   case fpu_v17_arm64:
353   case fpu_v18_arm64:
354   case fpu_v19_arm64:
355   case fpu_v20_arm64:
356   case fpu_v21_arm64:
357   case fpu_v22_arm64:
358   case fpu_v23_arm64:
359   case fpu_v24_arm64:
360   case fpu_v25_arm64:
361   case fpu_v26_arm64:
362   case fpu_v27_arm64:
363   case fpu_v28_arm64:
364   case fpu_v29_arm64:
365   case fpu_v30_arm64:
366   case fpu_v31_arm64:
367     m_fpr.fp_reg[reg - fpu_v0_arm64] =
368       APIntTouint128(reg_value.GetAsUInt128(llvm::APInt(128, 0, false)));
369     break;
370   case fpu_fpsr_arm64:
371     m_fpr.fp_sr = reg_value.GetAsUInt32();
372     break;
373   case fpu_fpcr_arm64:
374     m_fpr.fp_cr = reg_value.GetAsUInt32();
375     break;
376   default:
377     log->Printf("Requested write of unhandled reg: %u", reg);
378     break;
379   }
380 
381   if (WriteRegisterSet(set) != 0)
382     error.SetErrorStringWithFormat("failed to write register set");
383 
384   return error;
385 }
386 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)387 Status NativeRegisterContextOpenBSD_arm64::ReadAllRegisterValues(
388     lldb::WritableDataBufferSP &data_sp) {
389   Status error;
390 
391   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
392   if (!data_sp) {
393     error.SetErrorStringWithFormat(
394         "failed to allocate DataBufferHeap instance of size %zu",
395         REG_CONTEXT_SIZE);
396     return error;
397   }
398 
399   error = ReadGPR();
400   if (error.Fail())
401     return error;
402 
403   error = ReadFPR();
404   if (error.Fail())
405     return error;
406 
407   uint8_t *dst = data_sp->GetBytes();
408   if (dst == nullptr) {
409     error.SetErrorStringWithFormat("DataBufferHeap instance of size %zu"
410                                    " returned a null pointer",
411                                    REG_CONTEXT_SIZE);
412     return error;
413   }
414 
415   ::memcpy(dst, &m_gpr, GetGPRSize());
416   dst += GetGPRSize();
417 
418   ::memcpy(dst, &m_fpr, GetFPRSize());
419   dst += GetFPRSize();
420 
421   return error;
422 }
423 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)424 Status NativeRegisterContextOpenBSD_arm64::WriteAllRegisterValues(
425     const lldb::DataBufferSP &data_sp) {
426   Status error;
427 
428   if (!data_sp) {
429     error.SetErrorStringWithFormat(
430         "NativeRegisterContextOpenBSD_arm64::%s invalid data_sp provided",
431         __FUNCTION__);
432     return error;
433   }
434 
435   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
436     error.SetErrorStringWithFormat(
437         "NativeRegisterContextOpenBSD_arm64::%s data_sp contained mismatched "
438         "data size, expected %zu, actual %llu",
439         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
440     return error;
441   }
442 
443   const uint8_t *src = data_sp->GetBytes();
444   if (src == nullptr) {
445     error.SetErrorStringWithFormat("NativeRegisterContextOpenBSD_arm64::%s "
446                                    "DataBuffer::GetBytes() returned a null "
447                                    "pointer",
448                                    __FUNCTION__);
449     return error;
450   }
451   // TODO ?
452   // Do we need to make a custom RegisterInfoOpenBSD_arm64
453   // because the RegisterInfoPOSIX_arm64 doesn't quite match
454   // our machine/reg.h?
455   ::memcpy(&m_gpr, src, GetGPRSize());
456   error = WriteGPR();
457   if (error.Fail())
458     return error;
459   src += GetGPRSize();
460 
461   ::memcpy(&m_fpr, src, GetFPRSize());
462   error = WriteFPR();
463   if (error.Fail())
464     return error;
465   src += GetFPRSize();
466 
467   return error;
468 }
469 
GetSetForNativeRegNum(int reg_num) const470 int NativeRegisterContextOpenBSD_arm64::GetSetForNativeRegNum(
471     int reg_num) const {
472   if (reg_num >= k_first_gpr_arm64 && reg_num <= k_last_gpr_arm64)
473     return GPRegSet;
474   else if (reg_num >= k_first_fpr_arm64 && reg_num <= k_last_fpr_arm64)
475     return FPRegSet;
476   else if (GetRegisterInfo().IsPAuthReg(reg_num))
477     return PACMaskRegSet;
478   else
479     return -1;
480 }
481 
ReadRegisterSet(uint32_t set)482 int NativeRegisterContextOpenBSD_arm64::ReadRegisterSet(uint32_t set) {
483   switch (set) {
484   case GPRegSet:
485     ReadGPR();
486     return 0;
487   case FPRegSet:
488     ReadFPR();
489     return 0;
490   case PACMaskRegSet:
491     ReadPACMask();
492     return 0;
493   default:
494     break;
495   }
496   return -1;
497 }
498 
WriteRegisterSet(uint32_t set)499 int NativeRegisterContextOpenBSD_arm64::WriteRegisterSet(uint32_t set) {
500   switch (set) {
501   case GPRegSet:
502     WriteGPR();
503     return 0;
504   case FPRegSet:
505     WriteFPR();
506     return 0;
507   default:
508     break;
509   }
510   return -1;
511 }
512 
ReadPACMask()513 Status NativeRegisterContextOpenBSD_arm64::ReadPACMask() {
514 #ifdef PT_PACMASK
515   return NativeProcessOpenBSD::PtraceWrapper(PT_PACMASK, GetProcessPid(),
516 					     &m_pacmask, sizeof(m_pacmask));
517 #else
518   Status error;
519   ::memset(&m_pacmask, 0, sizeof(m_pacmask));
520   return error;
521 #endif
522 }
523 
524 #endif
525