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 *)∈
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 ®_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 ®_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