1 | //===-- RegisterContextDarwin_arm64.cpp -----------------------------------===// |
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 | #include "RegisterContextDarwin_arm64.h" |
10 | #include "RegisterContextDarwinConstants.h" |
11 | |
12 | #include "lldb/Target/Process.h" |
13 | #include "lldb/Target/Thread.h" |
14 | #include "lldb/Utility/DataBufferHeap.h" |
15 | #include "lldb/Utility/DataExtractor.h" |
16 | #include "lldb/Utility/Endian.h" |
17 | #include "lldb/Utility/Log.h" |
18 | #include "lldb/Utility/RegisterValue.h" |
19 | #include "lldb/Utility/Scalar.h" |
20 | #include "llvm/ADT/STLExtras.h" |
21 | #include "llvm/Support/Compiler.h" |
22 | |
23 | #include "Plugins/Process/Utility/InstructionUtils.h" |
24 | |
25 | #include <memory> |
26 | |
27 | #if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) |
28 | #include <sys/types.h> |
29 | #include <sys/sysctl.h> |
30 | #endif |
31 | |
32 | #include "Utility/ARM64_DWARF_Registers.h" |
33 | |
34 | using namespace lldb; |
35 | using namespace lldb_private; |
36 | |
37 | #define GPR_OFFSET(idx) ((idx)*8) |
38 | #define GPR_OFFSET_NAME(reg) \ |
39 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::GPR, reg)) |
40 | |
41 | #define FPU_OFFSET(idx) ((idx)*16 + sizeof(RegisterContextDarwin_arm64::GPR)) |
42 | #define FPU_OFFSET_NAME(reg) \ |
43 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::FPU, reg)) |
44 | |
45 | #define EXC_OFFSET_NAME(reg) \ |
46 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::EXC, reg) + \ |
47 | sizeof(RegisterContextDarwin_arm64::GPR) + \ |
48 | sizeof(RegisterContextDarwin_arm64::FPU)) |
49 | #define DBG_OFFSET_NAME(reg) \ |
50 | (LLVM_EXTENSION offsetof(RegisterContextDarwin_arm64::DBG, reg) + \ |
51 | sizeof(RegisterContextDarwin_arm64::GPR) + \ |
52 | sizeof(RegisterContextDarwin_arm64::FPU) + \ |
53 | sizeof(RegisterContextDarwin_arm64::EXC)) |
54 | |
55 | #define DEFINE_DBG(reg, i) \ |
56 | #reg, NULL, \ |
57 | sizeof(((RegisterContextDarwin_arm64::DBG *) NULL)->reg[i]), \ |
58 | DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, \ |
59 | {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
60 | LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ |
61 | LLDB_INVALID_REGNUM }, \ |
62 | NULL, NULL, NULL |
63 | #define REG_CONTEXT_SIZE \ |
64 | (sizeof(RegisterContextDarwin_arm64::GPR) + \ |
65 | sizeof(RegisterContextDarwin_arm64::FPU) + \ |
66 | sizeof(RegisterContextDarwin_arm64::EXC)) |
67 | |
68 | // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. |
69 | #define DECLARE_REGISTER_INFOS_ARM64_STRUCT |
70 | #include "RegisterInfos_arm64.h" |
71 | #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT |
72 | |
73 | // General purpose registers |
74 | static uint32_t g_gpr_regnums[] = { |
75 | gpr_x0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6, |
76 | gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13, |
77 | gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20, |
78 | gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27, |
79 | gpr_x28, gpr_fp, gpr_lr, gpr_sp, gpr_pc, gpr_cpsr}; |
80 | |
81 | // Floating point registers |
82 | static uint32_t g_fpu_regnums[] = { |
83 | fpu_v0, fpu_v1, fpu_v2, fpu_v3, fpu_v4, fpu_v5, fpu_v6, |
84 | fpu_v7, fpu_v8, fpu_v9, fpu_v10, fpu_v11, fpu_v12, fpu_v13, |
85 | fpu_v14, fpu_v15, fpu_v16, fpu_v17, fpu_v18, fpu_v19, fpu_v20, |
86 | fpu_v21, fpu_v22, fpu_v23, fpu_v24, fpu_v25, fpu_v26, fpu_v27, |
87 | fpu_v28, fpu_v29, fpu_v30, fpu_v31, fpu_fpsr, fpu_fpcr}; |
88 | |
89 | // Exception registers |
90 | |
91 | static uint32_t g_exc_regnums[] = {exc_far, exc_esr, exc_exception}; |
92 | |
93 | static size_t k_num_register_infos = std::size(g_register_infos_arm64_le); |
94 | |
95 | RegisterContextDarwin_arm64::RegisterContextDarwin_arm64( |
96 | Thread &thread, uint32_t concrete_frame_idx) |
97 | : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() { |
98 | uint32_t i; |
99 | for (i = 0; i < kNumErrors; i++) { |
100 | gpr_errs[i] = -1; |
101 | fpu_errs[i] = -1; |
102 | exc_errs[i] = -1; |
103 | } |
104 | } |
105 | |
106 | RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() = default; |
107 | |
108 | void RegisterContextDarwin_arm64::InvalidateAllRegisters() { |
109 | InvalidateAllRegisterStates(); |
110 | } |
111 | |
112 | size_t RegisterContextDarwin_arm64::GetRegisterCount() { |
113 | assert(k_num_register_infos == k_num_registers); |
114 | return k_num_registers; |
115 | } |
116 | |
117 | const RegisterInfo * |
118 | RegisterContextDarwin_arm64::GetRegisterInfoAtIndex(size_t reg) { |
119 | assert(k_num_register_infos == k_num_registers); |
120 | if (reg < k_num_registers) |
121 | return &g_register_infos_arm64_le[reg]; |
122 | return nullptr; |
123 | } |
124 | |
125 | size_t RegisterContextDarwin_arm64::GetRegisterInfosCount() { |
126 | return k_num_register_infos; |
127 | } |
128 | |
129 | const RegisterInfo *RegisterContextDarwin_arm64::GetRegisterInfos() { |
130 | return g_register_infos_arm64_le; |
131 | } |
132 | |
133 | // Number of registers in each register set |
134 | const size_t k_num_gpr_registers = std::size(g_gpr_regnums); |
135 | const size_t k_num_fpu_registers = std::size(g_fpu_regnums); |
136 | const size_t k_num_exc_registers = std::size(g_exc_regnums); |
137 | |
138 | // Register set definitions. The first definitions at register set index of |
139 | // zero is for all registers, followed by other registers sets. The register |
140 | // information for the all register set need not be filled in. |
141 | static const RegisterSet g_reg_sets[] = { |
142 | { |
143 | .name: "General Purpose Registers" , .short_name: "gpr" , .num_registers: k_num_gpr_registers, .registers: g_gpr_regnums, |
144 | }, |
145 | {.name: "Floating Point Registers" , .short_name: "fpu" , .num_registers: k_num_fpu_registers, .registers: g_fpu_regnums}, |
146 | {.name: "Exception State Registers" , .short_name: "exc" , .num_registers: k_num_exc_registers, .registers: g_exc_regnums}}; |
147 | |
148 | const size_t k_num_regsets = std::size(g_reg_sets); |
149 | |
150 | size_t RegisterContextDarwin_arm64::GetRegisterSetCount() { |
151 | return k_num_regsets; |
152 | } |
153 | |
154 | const RegisterSet *RegisterContextDarwin_arm64::GetRegisterSet(size_t reg_set) { |
155 | if (reg_set < k_num_regsets) |
156 | return &g_reg_sets[reg_set]; |
157 | return nullptr; |
158 | } |
159 | |
160 | // Register information definitions for arm64 |
161 | int RegisterContextDarwin_arm64::GetSetForNativeRegNum(int reg) { |
162 | if (reg < fpu_v0) |
163 | return GPRRegSet; |
164 | else if (reg < exc_far) |
165 | return FPURegSet; |
166 | else if (reg < k_num_registers) |
167 | return EXCRegSet; |
168 | return -1; |
169 | } |
170 | |
171 | int RegisterContextDarwin_arm64::ReadGPR(bool force) { |
172 | int set = GPRRegSet; |
173 | if (force || !RegisterSetIsCached(set)) { |
174 | SetError(flavor: set, err_idx: Read, err: DoReadGPR(tid: GetThreadID(), flavor: set, gpr)); |
175 | } |
176 | return GetError(flavor: GPRRegSet, err_idx: Read); |
177 | } |
178 | |
179 | int RegisterContextDarwin_arm64::ReadFPU(bool force) { |
180 | int set = FPURegSet; |
181 | if (force || !RegisterSetIsCached(set)) { |
182 | SetError(flavor: set, err_idx: Read, err: DoReadFPU(tid: GetThreadID(), flavor: set, fpu)); |
183 | } |
184 | return GetError(flavor: FPURegSet, err_idx: Read); |
185 | } |
186 | |
187 | int RegisterContextDarwin_arm64::ReadEXC(bool force) { |
188 | int set = EXCRegSet; |
189 | if (force || !RegisterSetIsCached(set)) { |
190 | SetError(flavor: set, err_idx: Read, err: DoReadEXC(tid: GetThreadID(), flavor: set, exc)); |
191 | } |
192 | return GetError(flavor: EXCRegSet, err_idx: Read); |
193 | } |
194 | |
195 | int RegisterContextDarwin_arm64::ReadDBG(bool force) { |
196 | int set = DBGRegSet; |
197 | if (force || !RegisterSetIsCached(set)) { |
198 | SetError(flavor: set, err_idx: Read, err: DoReadDBG(tid: GetThreadID(), flavor: set, dbg)); |
199 | } |
200 | return GetError(flavor: DBGRegSet, err_idx: Read); |
201 | } |
202 | |
203 | int RegisterContextDarwin_arm64::WriteGPR() { |
204 | int set = GPRRegSet; |
205 | if (!RegisterSetIsCached(set)) { |
206 | SetError(flavor: set, err_idx: Write, err: -1); |
207 | return KERN_INVALID_ARGUMENT; |
208 | } |
209 | SetError(flavor: set, err_idx: Write, err: DoWriteGPR(tid: GetThreadID(), flavor: set, gpr)); |
210 | SetError(flavor: set, err_idx: Read, err: -1); |
211 | return GetError(flavor: GPRRegSet, err_idx: Write); |
212 | } |
213 | |
214 | int RegisterContextDarwin_arm64::WriteFPU() { |
215 | int set = FPURegSet; |
216 | if (!RegisterSetIsCached(set)) { |
217 | SetError(flavor: set, err_idx: Write, err: -1); |
218 | return KERN_INVALID_ARGUMENT; |
219 | } |
220 | SetError(flavor: set, err_idx: Write, err: DoWriteFPU(tid: GetThreadID(), flavor: set, fpu)); |
221 | SetError(flavor: set, err_idx: Read, err: -1); |
222 | return GetError(flavor: FPURegSet, err_idx: Write); |
223 | } |
224 | |
225 | int RegisterContextDarwin_arm64::WriteEXC() { |
226 | int set = EXCRegSet; |
227 | if (!RegisterSetIsCached(set)) { |
228 | SetError(flavor: set, err_idx: Write, err: -1); |
229 | return KERN_INVALID_ARGUMENT; |
230 | } |
231 | SetError(flavor: set, err_idx: Write, err: DoWriteEXC(tid: GetThreadID(), flavor: set, exc)); |
232 | SetError(flavor: set, err_idx: Read, err: -1); |
233 | return GetError(flavor: EXCRegSet, err_idx: Write); |
234 | } |
235 | |
236 | int RegisterContextDarwin_arm64::WriteDBG() { |
237 | int set = DBGRegSet; |
238 | if (!RegisterSetIsCached(set)) { |
239 | SetError(flavor: set, err_idx: Write, err: -1); |
240 | return KERN_INVALID_ARGUMENT; |
241 | } |
242 | SetError(flavor: set, err_idx: Write, err: DoWriteDBG(tid: GetThreadID(), flavor: set, dbg)); |
243 | SetError(flavor: set, err_idx: Read, err: -1); |
244 | return GetError(flavor: DBGRegSet, err_idx: Write); |
245 | } |
246 | |
247 | int RegisterContextDarwin_arm64::ReadRegisterSet(uint32_t set, bool force) { |
248 | switch (set) { |
249 | case GPRRegSet: |
250 | return ReadGPR(force); |
251 | case FPURegSet: |
252 | return ReadFPU(force); |
253 | case EXCRegSet: |
254 | return ReadEXC(force); |
255 | case DBGRegSet: |
256 | return ReadDBG(force); |
257 | default: |
258 | break; |
259 | } |
260 | return KERN_INVALID_ARGUMENT; |
261 | } |
262 | |
263 | int RegisterContextDarwin_arm64::WriteRegisterSet(uint32_t set) { |
264 | // Make sure we have a valid context to set. |
265 | if (RegisterSetIsCached(set)) { |
266 | switch (set) { |
267 | case GPRRegSet: |
268 | return WriteGPR(); |
269 | case FPURegSet: |
270 | return WriteFPU(); |
271 | case EXCRegSet: |
272 | return WriteEXC(); |
273 | case DBGRegSet: |
274 | return WriteDBG(); |
275 | default: |
276 | break; |
277 | } |
278 | } |
279 | return KERN_INVALID_ARGUMENT; |
280 | } |
281 | |
282 | void RegisterContextDarwin_arm64::LogDBGRegisters(Log *log, const DBG &dbg) { |
283 | if (log) { |
284 | for (uint32_t i = 0; i < 16; i++) |
285 | LLDB_LOGF(log, |
286 | "BVR%-2u/BCR%-2u = { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 |
287 | " } WVR%-2u/WCR%-2u " |
288 | "= { 0x%8.8" PRIu64 ", 0x%8.8" PRIu64 " }" , |
289 | i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]); |
290 | } |
291 | } |
292 | |
293 | bool RegisterContextDarwin_arm64::ReadRegister(const RegisterInfo *reg_info, |
294 | RegisterValue &value) { |
295 | const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
296 | int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum(reg); |
297 | |
298 | if (set == -1) |
299 | return false; |
300 | |
301 | if (ReadRegisterSet(set, force: false) != KERN_SUCCESS) |
302 | return false; |
303 | |
304 | switch (reg) { |
305 | case gpr_x0: |
306 | case gpr_x1: |
307 | case gpr_x2: |
308 | case gpr_x3: |
309 | case gpr_x4: |
310 | case gpr_x5: |
311 | case gpr_x6: |
312 | case gpr_x7: |
313 | case gpr_x8: |
314 | case gpr_x9: |
315 | case gpr_x10: |
316 | case gpr_x11: |
317 | case gpr_x12: |
318 | case gpr_x13: |
319 | case gpr_x14: |
320 | case gpr_x15: |
321 | case gpr_x16: |
322 | case gpr_x17: |
323 | case gpr_x18: |
324 | case gpr_x19: |
325 | case gpr_x20: |
326 | case gpr_x21: |
327 | case gpr_x22: |
328 | case gpr_x23: |
329 | case gpr_x24: |
330 | case gpr_x25: |
331 | case gpr_x26: |
332 | case gpr_x27: |
333 | case gpr_x28: |
334 | value.SetUInt64(uint: gpr.x[reg - gpr_x0]); |
335 | break; |
336 | case gpr_fp: |
337 | value.SetUInt64(uint: gpr.fp); |
338 | break; |
339 | case gpr_sp: |
340 | value.SetUInt64(uint: gpr.sp); |
341 | break; |
342 | case gpr_lr: |
343 | value.SetUInt64(uint: gpr.lr); |
344 | break; |
345 | case gpr_pc: |
346 | value.SetUInt64(uint: gpr.pc); |
347 | break; |
348 | case gpr_cpsr: |
349 | value.SetUInt64(uint: gpr.cpsr); |
350 | break; |
351 | |
352 | case gpr_w0: |
353 | case gpr_w1: |
354 | case gpr_w2: |
355 | case gpr_w3: |
356 | case gpr_w4: |
357 | case gpr_w5: |
358 | case gpr_w6: |
359 | case gpr_w7: |
360 | case gpr_w8: |
361 | case gpr_w9: |
362 | case gpr_w10: |
363 | case gpr_w11: |
364 | case gpr_w12: |
365 | case gpr_w13: |
366 | case gpr_w14: |
367 | case gpr_w15: |
368 | case gpr_w16: |
369 | case gpr_w17: |
370 | case gpr_w18: |
371 | case gpr_w19: |
372 | case gpr_w20: |
373 | case gpr_w21: |
374 | case gpr_w22: |
375 | case gpr_w23: |
376 | case gpr_w24: |
377 | case gpr_w25: |
378 | case gpr_w26: |
379 | case gpr_w27: |
380 | case gpr_w28: { |
381 | ProcessSP process_sp(m_thread.GetProcess()); |
382 | if (process_sp.get()) { |
383 | DataExtractor regdata(&gpr.x[reg - gpr_w0], 8, process_sp->GetByteOrder(), |
384 | process_sp->GetAddressByteSize()); |
385 | offset_t offset = 0; |
386 | uint64_t retval = regdata.GetMaxU64(offset_ptr: &offset, byte_size: 8); |
387 | uint32_t retval_lower32 = static_cast<uint32_t>(retval & 0xffffffff); |
388 | value.SetUInt32(uint: retval_lower32); |
389 | } |
390 | } break; |
391 | |
392 | case fpu_v0: |
393 | case fpu_v1: |
394 | case fpu_v2: |
395 | case fpu_v3: |
396 | case fpu_v4: |
397 | case fpu_v5: |
398 | case fpu_v6: |
399 | case fpu_v7: |
400 | case fpu_v8: |
401 | case fpu_v9: |
402 | case fpu_v10: |
403 | case fpu_v11: |
404 | case fpu_v12: |
405 | case fpu_v13: |
406 | case fpu_v14: |
407 | case fpu_v15: |
408 | case fpu_v16: |
409 | case fpu_v17: |
410 | case fpu_v18: |
411 | case fpu_v19: |
412 | case fpu_v20: |
413 | case fpu_v21: |
414 | case fpu_v22: |
415 | case fpu_v23: |
416 | case fpu_v24: |
417 | case fpu_v25: |
418 | case fpu_v26: |
419 | case fpu_v27: |
420 | case fpu_v28: |
421 | case fpu_v29: |
422 | case fpu_v30: |
423 | case fpu_v31: |
424 | value.SetBytes(bytes: fpu.v[reg - fpu_v0].bytes, length: reg_info->byte_size, |
425 | byte_order: endian::InlHostByteOrder()); |
426 | break; |
427 | |
428 | case fpu_s0: |
429 | case fpu_s1: |
430 | case fpu_s2: |
431 | case fpu_s3: |
432 | case fpu_s4: |
433 | case fpu_s5: |
434 | case fpu_s6: |
435 | case fpu_s7: |
436 | case fpu_s8: |
437 | case fpu_s9: |
438 | case fpu_s10: |
439 | case fpu_s11: |
440 | case fpu_s12: |
441 | case fpu_s13: |
442 | case fpu_s14: |
443 | case fpu_s15: |
444 | case fpu_s16: |
445 | case fpu_s17: |
446 | case fpu_s18: |
447 | case fpu_s19: |
448 | case fpu_s20: |
449 | case fpu_s21: |
450 | case fpu_s22: |
451 | case fpu_s23: |
452 | case fpu_s24: |
453 | case fpu_s25: |
454 | case fpu_s26: |
455 | case fpu_s27: |
456 | case fpu_s28: |
457 | case fpu_s29: |
458 | case fpu_s30: |
459 | case fpu_s31: { |
460 | ProcessSP process_sp(m_thread.GetProcess()); |
461 | if (process_sp.get()) { |
462 | DataExtractor regdata(&fpu.v[reg - fpu_s0], 4, process_sp->GetByteOrder(), |
463 | process_sp->GetAddressByteSize()); |
464 | offset_t offset = 0; |
465 | value.SetFloat(regdata.GetFloat(offset_ptr: &offset)); |
466 | } |
467 | } break; |
468 | |
469 | case fpu_d0: |
470 | case fpu_d1: |
471 | case fpu_d2: |
472 | case fpu_d3: |
473 | case fpu_d4: |
474 | case fpu_d5: |
475 | case fpu_d6: |
476 | case fpu_d7: |
477 | case fpu_d8: |
478 | case fpu_d9: |
479 | case fpu_d10: |
480 | case fpu_d11: |
481 | case fpu_d12: |
482 | case fpu_d13: |
483 | case fpu_d14: |
484 | case fpu_d15: |
485 | case fpu_d16: |
486 | case fpu_d17: |
487 | case fpu_d18: |
488 | case fpu_d19: |
489 | case fpu_d20: |
490 | case fpu_d21: |
491 | case fpu_d22: |
492 | case fpu_d23: |
493 | case fpu_d24: |
494 | case fpu_d25: |
495 | case fpu_d26: |
496 | case fpu_d27: |
497 | case fpu_d28: |
498 | case fpu_d29: |
499 | case fpu_d30: |
500 | case fpu_d31: { |
501 | ProcessSP process_sp(m_thread.GetProcess()); |
502 | if (process_sp.get()) { |
503 | DataExtractor regdata(&fpu.v[reg - fpu_d0], 8, process_sp->GetByteOrder(), |
504 | process_sp->GetAddressByteSize()); |
505 | offset_t offset = 0; |
506 | value.SetDouble(regdata.GetDouble(offset_ptr: &offset)); |
507 | } |
508 | } break; |
509 | |
510 | case fpu_fpsr: |
511 | value.SetUInt32(uint: fpu.fpsr); |
512 | break; |
513 | |
514 | case fpu_fpcr: |
515 | value.SetUInt32(uint: fpu.fpcr); |
516 | break; |
517 | |
518 | case exc_exception: |
519 | value.SetUInt32(uint: exc.exception); |
520 | break; |
521 | case exc_esr: |
522 | value.SetUInt32(uint: exc.esr); |
523 | break; |
524 | case exc_far: |
525 | value.SetUInt64(uint: exc.far); |
526 | break; |
527 | |
528 | default: |
529 | value.SetValueToInvalid(); |
530 | return false; |
531 | } |
532 | return true; |
533 | } |
534 | |
535 | bool RegisterContextDarwin_arm64::WriteRegister(const RegisterInfo *reg_info, |
536 | const RegisterValue &value) { |
537 | const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; |
538 | int set = GetSetForNativeRegNum(reg); |
539 | |
540 | if (set == -1) |
541 | return false; |
542 | |
543 | if (ReadRegisterSet(set, force: false) != KERN_SUCCESS) |
544 | return false; |
545 | |
546 | switch (reg) { |
547 | case gpr_x0: |
548 | case gpr_x1: |
549 | case gpr_x2: |
550 | case gpr_x3: |
551 | case gpr_x4: |
552 | case gpr_x5: |
553 | case gpr_x6: |
554 | case gpr_x7: |
555 | case gpr_x8: |
556 | case gpr_x9: |
557 | case gpr_x10: |
558 | case gpr_x11: |
559 | case gpr_x12: |
560 | case gpr_x13: |
561 | case gpr_x14: |
562 | case gpr_x15: |
563 | case gpr_x16: |
564 | case gpr_x17: |
565 | case gpr_x18: |
566 | case gpr_x19: |
567 | case gpr_x20: |
568 | case gpr_x21: |
569 | case gpr_x22: |
570 | case gpr_x23: |
571 | case gpr_x24: |
572 | case gpr_x25: |
573 | case gpr_x26: |
574 | case gpr_x27: |
575 | case gpr_x28: |
576 | case gpr_fp: |
577 | case gpr_sp: |
578 | case gpr_lr: |
579 | case gpr_pc: |
580 | case gpr_cpsr: |
581 | gpr.x[reg - gpr_x0] = value.GetAsUInt64(); |
582 | break; |
583 | |
584 | case fpu_v0: |
585 | case fpu_v1: |
586 | case fpu_v2: |
587 | case fpu_v3: |
588 | case fpu_v4: |
589 | case fpu_v5: |
590 | case fpu_v6: |
591 | case fpu_v7: |
592 | case fpu_v8: |
593 | case fpu_v9: |
594 | case fpu_v10: |
595 | case fpu_v11: |
596 | case fpu_v12: |
597 | case fpu_v13: |
598 | case fpu_v14: |
599 | case fpu_v15: |
600 | case fpu_v16: |
601 | case fpu_v17: |
602 | case fpu_v18: |
603 | case fpu_v19: |
604 | case fpu_v20: |
605 | case fpu_v21: |
606 | case fpu_v22: |
607 | case fpu_v23: |
608 | case fpu_v24: |
609 | case fpu_v25: |
610 | case fpu_v26: |
611 | case fpu_v27: |
612 | case fpu_v28: |
613 | case fpu_v29: |
614 | case fpu_v30: |
615 | case fpu_v31: |
616 | ::memcpy(dest: fpu.v[reg - fpu_v0].bytes, src: value.GetBytes(), |
617 | n: value.GetByteSize()); |
618 | break; |
619 | |
620 | case fpu_fpsr: |
621 | fpu.fpsr = value.GetAsUInt32(); |
622 | break; |
623 | |
624 | case fpu_fpcr: |
625 | fpu.fpcr = value.GetAsUInt32(); |
626 | break; |
627 | |
628 | case exc_exception: |
629 | exc.exception = value.GetAsUInt32(); |
630 | break; |
631 | case exc_esr: |
632 | exc.esr = value.GetAsUInt32(); |
633 | break; |
634 | case exc_far: |
635 | exc.far = value.GetAsUInt64(); |
636 | break; |
637 | |
638 | default: |
639 | return false; |
640 | } |
641 | return WriteRegisterSet(set) == KERN_SUCCESS; |
642 | } |
643 | |
644 | bool RegisterContextDarwin_arm64::ReadAllRegisterValues( |
645 | lldb::WritableDataBufferSP &data_sp) { |
646 | data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, args: 0); |
647 | if (ReadGPR(force: false) == KERN_SUCCESS && ReadFPU(force: false) == KERN_SUCCESS && |
648 | ReadEXC(force: false) == KERN_SUCCESS) { |
649 | uint8_t *dst = data_sp->GetBytes(); |
650 | ::memcpy(dest: dst, src: &gpr, n: sizeof(gpr)); |
651 | dst += sizeof(gpr); |
652 | |
653 | ::memcpy(dest: dst, src: &fpu, n: sizeof(fpu)); |
654 | dst += sizeof(gpr); |
655 | |
656 | ::memcpy(dest: dst, src: &exc, n: sizeof(exc)); |
657 | return true; |
658 | } |
659 | return false; |
660 | } |
661 | |
662 | bool RegisterContextDarwin_arm64::WriteAllRegisterValues( |
663 | const lldb::DataBufferSP &data_sp) { |
664 | if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { |
665 | const uint8_t *src = data_sp->GetBytes(); |
666 | ::memcpy(dest: &gpr, src: src, n: sizeof(gpr)); |
667 | src += sizeof(gpr); |
668 | |
669 | ::memcpy(dest: &fpu, src: src, n: sizeof(fpu)); |
670 | src += sizeof(gpr); |
671 | |
672 | ::memcpy(dest: &exc, src: src, n: sizeof(exc)); |
673 | uint32_t success_count = 0; |
674 | if (WriteGPR() == KERN_SUCCESS) |
675 | ++success_count; |
676 | if (WriteFPU() == KERN_SUCCESS) |
677 | ++success_count; |
678 | if (WriteEXC() == KERN_SUCCESS) |
679 | ++success_count; |
680 | return success_count == 3; |
681 | } |
682 | return false; |
683 | } |
684 | |
685 | uint32_t RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber( |
686 | RegisterKind kind, uint32_t reg) { |
687 | if (kind == eRegisterKindGeneric) { |
688 | switch (reg) { |
689 | case LLDB_REGNUM_GENERIC_PC: |
690 | return gpr_pc; |
691 | case LLDB_REGNUM_GENERIC_SP: |
692 | return gpr_sp; |
693 | case LLDB_REGNUM_GENERIC_FP: |
694 | return gpr_fp; |
695 | case LLDB_REGNUM_GENERIC_RA: |
696 | return gpr_lr; |
697 | case LLDB_REGNUM_GENERIC_FLAGS: |
698 | return gpr_cpsr; |
699 | default: |
700 | break; |
701 | } |
702 | } else if (kind == eRegisterKindDWARF) { |
703 | switch (reg) { |
704 | case arm64_dwarf::x0: |
705 | return gpr_x0; |
706 | case arm64_dwarf::x1: |
707 | return gpr_x1; |
708 | case arm64_dwarf::x2: |
709 | return gpr_x2; |
710 | case arm64_dwarf::x3: |
711 | return gpr_x3; |
712 | case arm64_dwarf::x4: |
713 | return gpr_x4; |
714 | case arm64_dwarf::x5: |
715 | return gpr_x5; |
716 | case arm64_dwarf::x6: |
717 | return gpr_x6; |
718 | case arm64_dwarf::x7: |
719 | return gpr_x7; |
720 | case arm64_dwarf::x8: |
721 | return gpr_x8; |
722 | case arm64_dwarf::x9: |
723 | return gpr_x9; |
724 | case arm64_dwarf::x10: |
725 | return gpr_x10; |
726 | case arm64_dwarf::x11: |
727 | return gpr_x11; |
728 | case arm64_dwarf::x12: |
729 | return gpr_x12; |
730 | case arm64_dwarf::x13: |
731 | return gpr_x13; |
732 | case arm64_dwarf::x14: |
733 | return gpr_x14; |
734 | case arm64_dwarf::x15: |
735 | return gpr_x15; |
736 | case arm64_dwarf::x16: |
737 | return gpr_x16; |
738 | case arm64_dwarf::x17: |
739 | return gpr_x17; |
740 | case arm64_dwarf::x18: |
741 | return gpr_x18; |
742 | case arm64_dwarf::x19: |
743 | return gpr_x19; |
744 | case arm64_dwarf::x20: |
745 | return gpr_x20; |
746 | case arm64_dwarf::x21: |
747 | return gpr_x21; |
748 | case arm64_dwarf::x22: |
749 | return gpr_x22; |
750 | case arm64_dwarf::x23: |
751 | return gpr_x23; |
752 | case arm64_dwarf::x24: |
753 | return gpr_x24; |
754 | case arm64_dwarf::x25: |
755 | return gpr_x25; |
756 | case arm64_dwarf::x26: |
757 | return gpr_x26; |
758 | case arm64_dwarf::x27: |
759 | return gpr_x27; |
760 | case arm64_dwarf::x28: |
761 | return gpr_x28; |
762 | |
763 | case arm64_dwarf::fp: |
764 | return gpr_fp; |
765 | case arm64_dwarf::sp: |
766 | return gpr_sp; |
767 | case arm64_dwarf::lr: |
768 | return gpr_lr; |
769 | case arm64_dwarf::pc: |
770 | return gpr_pc; |
771 | case arm64_dwarf::cpsr: |
772 | return gpr_cpsr; |
773 | |
774 | case arm64_dwarf::v0: |
775 | return fpu_v0; |
776 | case arm64_dwarf::v1: |
777 | return fpu_v1; |
778 | case arm64_dwarf::v2: |
779 | return fpu_v2; |
780 | case arm64_dwarf::v3: |
781 | return fpu_v3; |
782 | case arm64_dwarf::v4: |
783 | return fpu_v4; |
784 | case arm64_dwarf::v5: |
785 | return fpu_v5; |
786 | case arm64_dwarf::v6: |
787 | return fpu_v6; |
788 | case arm64_dwarf::v7: |
789 | return fpu_v7; |
790 | case arm64_dwarf::v8: |
791 | return fpu_v8; |
792 | case arm64_dwarf::v9: |
793 | return fpu_v9; |
794 | case arm64_dwarf::v10: |
795 | return fpu_v10; |
796 | case arm64_dwarf::v11: |
797 | return fpu_v11; |
798 | case arm64_dwarf::v12: |
799 | return fpu_v12; |
800 | case arm64_dwarf::v13: |
801 | return fpu_v13; |
802 | case arm64_dwarf::v14: |
803 | return fpu_v14; |
804 | case arm64_dwarf::v15: |
805 | return fpu_v15; |
806 | case arm64_dwarf::v16: |
807 | return fpu_v16; |
808 | case arm64_dwarf::v17: |
809 | return fpu_v17; |
810 | case arm64_dwarf::v18: |
811 | return fpu_v18; |
812 | case arm64_dwarf::v19: |
813 | return fpu_v19; |
814 | case arm64_dwarf::v20: |
815 | return fpu_v20; |
816 | case arm64_dwarf::v21: |
817 | return fpu_v21; |
818 | case arm64_dwarf::v22: |
819 | return fpu_v22; |
820 | case arm64_dwarf::v23: |
821 | return fpu_v23; |
822 | case arm64_dwarf::v24: |
823 | return fpu_v24; |
824 | case arm64_dwarf::v25: |
825 | return fpu_v25; |
826 | case arm64_dwarf::v26: |
827 | return fpu_v26; |
828 | case arm64_dwarf::v27: |
829 | return fpu_v27; |
830 | case arm64_dwarf::v28: |
831 | return fpu_v28; |
832 | case arm64_dwarf::v29: |
833 | return fpu_v29; |
834 | case arm64_dwarf::v30: |
835 | return fpu_v30; |
836 | case arm64_dwarf::v31: |
837 | return fpu_v31; |
838 | |
839 | default: |
840 | break; |
841 | } |
842 | } else if (kind == eRegisterKindEHFrame) { |
843 | switch (reg) { |
844 | case arm64_ehframe::x0: |
845 | return gpr_x0; |
846 | case arm64_ehframe::x1: |
847 | return gpr_x1; |
848 | case arm64_ehframe::x2: |
849 | return gpr_x2; |
850 | case arm64_ehframe::x3: |
851 | return gpr_x3; |
852 | case arm64_ehframe::x4: |
853 | return gpr_x4; |
854 | case arm64_ehframe::x5: |
855 | return gpr_x5; |
856 | case arm64_ehframe::x6: |
857 | return gpr_x6; |
858 | case arm64_ehframe::x7: |
859 | return gpr_x7; |
860 | case arm64_ehframe::x8: |
861 | return gpr_x8; |
862 | case arm64_ehframe::x9: |
863 | return gpr_x9; |
864 | case arm64_ehframe::x10: |
865 | return gpr_x10; |
866 | case arm64_ehframe::x11: |
867 | return gpr_x11; |
868 | case arm64_ehframe::x12: |
869 | return gpr_x12; |
870 | case arm64_ehframe::x13: |
871 | return gpr_x13; |
872 | case arm64_ehframe::x14: |
873 | return gpr_x14; |
874 | case arm64_ehframe::x15: |
875 | return gpr_x15; |
876 | case arm64_ehframe::x16: |
877 | return gpr_x16; |
878 | case arm64_ehframe::x17: |
879 | return gpr_x17; |
880 | case arm64_ehframe::x18: |
881 | return gpr_x18; |
882 | case arm64_ehframe::x19: |
883 | return gpr_x19; |
884 | case arm64_ehframe::x20: |
885 | return gpr_x20; |
886 | case arm64_ehframe::x21: |
887 | return gpr_x21; |
888 | case arm64_ehframe::x22: |
889 | return gpr_x22; |
890 | case arm64_ehframe::x23: |
891 | return gpr_x23; |
892 | case arm64_ehframe::x24: |
893 | return gpr_x24; |
894 | case arm64_ehframe::x25: |
895 | return gpr_x25; |
896 | case arm64_ehframe::x26: |
897 | return gpr_x26; |
898 | case arm64_ehframe::x27: |
899 | return gpr_x27; |
900 | case arm64_ehframe::x28: |
901 | return gpr_x28; |
902 | case arm64_ehframe::fp: |
903 | return gpr_fp; |
904 | case arm64_ehframe::sp: |
905 | return gpr_sp; |
906 | case arm64_ehframe::lr: |
907 | return gpr_lr; |
908 | case arm64_ehframe::pc: |
909 | return gpr_pc; |
910 | case arm64_ehframe::cpsr: |
911 | return gpr_cpsr; |
912 | } |
913 | } else if (kind == eRegisterKindLLDB) { |
914 | return reg; |
915 | } |
916 | return LLDB_INVALID_REGNUM; |
917 | } |
918 | |
919 | uint32_t RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints() { |
920 | #if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) |
921 | // autodetect how many watchpoints are supported dynamically... |
922 | static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; |
923 | if (g_num_supported_hw_watchpoints == UINT32_MAX) { |
924 | size_t len; |
925 | uint32_t n = 0; |
926 | len = sizeof(n); |
927 | if (::sysctlbyname("hw.optional.watchpoint" , &n, &len, NULL, 0) == 0) { |
928 | g_num_supported_hw_watchpoints = n; |
929 | } |
930 | } |
931 | return g_num_supported_hw_watchpoints; |
932 | #else |
933 | // TODO: figure out remote case here! |
934 | return 2; |
935 | #endif |
936 | } |
937 | |
938 | uint32_t RegisterContextDarwin_arm64::SetHardwareWatchpoint(lldb::addr_t addr, |
939 | size_t size, |
940 | bool read, |
941 | bool write) { |
942 | // if (log) log->Printf |
943 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, |
944 | // size = %u, read = %u, write = %u)", addr, size, read, write); |
945 | |
946 | const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); |
947 | |
948 | // Can't watch zero bytes |
949 | if (size == 0) |
950 | return LLDB_INVALID_INDEX32; |
951 | |
952 | // We must watch for either read or write |
953 | if (!read && !write) |
954 | return LLDB_INVALID_INDEX32; |
955 | |
956 | // Can't watch more than 4 bytes per WVR/WCR pair |
957 | if (size > 4) |
958 | return LLDB_INVALID_INDEX32; |
959 | |
960 | // We can only watch up to four bytes that follow a 4 byte aligned address |
961 | // per watchpoint register pair. Since we have at most so we can only watch |
962 | // until the next 4 byte boundary and we need to make sure we can properly |
963 | // encode this. |
964 | uint32_t addr_word_offset = addr % 4; |
965 | // if (log) log->Printf |
966 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - |
967 | // addr_word_offset = 0x%8.8x", addr_word_offset); |
968 | |
969 | uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; |
970 | // if (log) log->Printf |
971 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = |
972 | // 0x%8.8x", byte_mask); |
973 | if (byte_mask > 0xfu) |
974 | return LLDB_INVALID_INDEX32; |
975 | |
976 | // Read the debug state |
977 | int kret = ReadDBG(force: false); |
978 | |
979 | if (kret == KERN_SUCCESS) { |
980 | // Check to make sure we have the needed hardware support |
981 | uint32_t i = 0; |
982 | |
983 | for (i = 0; i < num_hw_watchpoints; ++i) { |
984 | if ((dbg.wcr[i] & WCR_ENABLE) == 0) |
985 | break; // We found an available hw breakpoint slot (in i) |
986 | } |
987 | |
988 | // See if we found an available hw breakpoint slot above |
989 | if (i < num_hw_watchpoints) { |
990 | // Make the byte_mask into a valid Byte Address Select mask |
991 | uint32_t byte_address_select = byte_mask << 5; |
992 | // Make sure bits 1:0 are clear in our address |
993 | dbg.wvr[i] = addr & ~((lldb::addr_t)3); |
994 | dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA |
995 | // that we will watch |
996 | S_USER | // Stop only in user mode |
997 | (read ? WCR_LOAD : 0) | // Stop on read access? |
998 | (write ? WCR_STORE : 0) | // Stop on write access? |
999 | WCR_ENABLE; // Enable this watchpoint; |
1000 | |
1001 | kret = WriteDBG(); |
1002 | // if (log) log->Printf |
1003 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() |
1004 | // WriteDBG() => 0x%8.8x.", kret); |
1005 | |
1006 | if (kret == KERN_SUCCESS) |
1007 | return i; |
1008 | } else { |
1009 | // if (log) log->Printf |
1010 | // ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): |
1011 | // All hardware resources (%u) are in use.", |
1012 | // num_hw_watchpoints); |
1013 | } |
1014 | } |
1015 | return LLDB_INVALID_INDEX32; |
1016 | } |
1017 | |
1018 | bool RegisterContextDarwin_arm64::ClearHardwareWatchpoint(uint32_t hw_index) { |
1019 | int kret = ReadDBG(force: false); |
1020 | |
1021 | const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); |
1022 | if (kret == KERN_SUCCESS) { |
1023 | if (hw_index < num_hw_points) { |
1024 | dbg.wcr[hw_index] = 0; |
1025 | // if (log) log->Printf |
1026 | // ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) |
1027 | // - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", |
1028 | // hw_index, |
1029 | // hw_index, |
1030 | // dbg.wvr[hw_index], |
1031 | // hw_index, |
1032 | // dbg.wcr[hw_index]); |
1033 | |
1034 | kret = WriteDBG(); |
1035 | |
1036 | if (kret == KERN_SUCCESS) |
1037 | return true; |
1038 | } |
1039 | } |
1040 | return false; |
1041 | } |
1042 | |