1 | //===-- RegisterContextDarwin_arm64.h -----------------------------*- C++ |
2 | //-*-===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H |
11 | #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H |
12 | |
13 | #include "lldb/Target/RegisterContext.h" |
14 | #include "lldb/lldb-private.h" |
15 | |
16 | // Break only in privileged or user mode |
17 | #define S_RSVD ((uint32_t)(0u << 1)) |
18 | #define S_PRIV ((uint32_t)(1u << 1)) |
19 | #define S_USER ((uint32_t)(2u << 1)) |
20 | #define S_PRIV_USER ((S_PRIV) | (S_USER)) |
21 | |
22 | #define WCR_ENABLE ((uint32_t)(1u)) |
23 | |
24 | // Watchpoint load/store |
25 | #define WCR_LOAD ((uint32_t)(1u << 3)) |
26 | #define WCR_STORE ((uint32_t)(1u << 4)) |
27 | |
28 | class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext { |
29 | public: |
30 | RegisterContextDarwin_arm64(lldb_private::Thread &thread, |
31 | uint32_t concrete_frame_idx); |
32 | |
33 | ~RegisterContextDarwin_arm64() override; |
34 | |
35 | void InvalidateAllRegisters() override; |
36 | |
37 | size_t GetRegisterCount() override; |
38 | |
39 | const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override; |
40 | |
41 | size_t GetRegisterSetCount() override; |
42 | |
43 | const lldb_private::RegisterSet *GetRegisterSet(size_t set) override; |
44 | |
45 | bool ReadRegister(const lldb_private::RegisterInfo *reg_info, |
46 | lldb_private::RegisterValue ®_value) override; |
47 | |
48 | bool WriteRegister(const lldb_private::RegisterInfo *reg_info, |
49 | const lldb_private::RegisterValue ®_value) override; |
50 | |
51 | bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override; |
52 | |
53 | bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; |
54 | |
55 | uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, |
56 | uint32_t num) override; |
57 | |
58 | uint32_t NumSupportedHardwareWatchpoints() override; |
59 | |
60 | uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, |
61 | bool write) override; |
62 | |
63 | bool ClearHardwareWatchpoint(uint32_t hw_index) override; |
64 | |
65 | // mirrors <mach/arm/thread_status.h> arm_thread_state64_t |
66 | struct GPR { |
67 | uint64_t x[29]; // x0-x28 |
68 | uint64_t fp; // x29 |
69 | uint64_t lr; // x30 |
70 | uint64_t sp; // x31 |
71 | uint64_t pc; // pc |
72 | uint32_t cpsr; // cpsr |
73 | }; |
74 | |
75 | struct VReg { |
76 | alignas(16) char bytes[16]; |
77 | }; |
78 | |
79 | // mirrors <mach/arm/thread_status.h> arm_neon_state64_t |
80 | struct FPU { |
81 | VReg v[32]; |
82 | uint32_t fpsr; |
83 | uint32_t fpcr; |
84 | }; |
85 | |
86 | // mirrors <mach/arm/thread_status.h> arm_exception_state64_t |
87 | struct EXC { |
88 | uint64_t far; // Virtual Fault Address |
89 | uint32_t esr; // Exception syndrome |
90 | uint32_t exception; // number of arm exception token |
91 | }; |
92 | |
93 | // mirrors <mach/arm/thread_status.h> arm_debug_state64_t |
94 | struct DBG { |
95 | uint64_t bvr[16]; |
96 | uint64_t bcr[16]; |
97 | uint64_t wvr[16]; |
98 | uint64_t wcr[16]; |
99 | uint64_t mdscr_el1; |
100 | }; |
101 | |
102 | static void LogDBGRegisters(lldb_private::Log *log, const DBG &dbg); |
103 | |
104 | protected: |
105 | enum { |
106 | GPRRegSet = 6, // ARM_THREAD_STATE64 |
107 | FPURegSet = 17, // ARM_NEON_STATE64 |
108 | EXCRegSet = 7, // ARM_EXCEPTION_STATE64 |
109 | DBGRegSet = 15 // ARM_DEBUG_STATE64 |
110 | }; |
111 | |
112 | enum { |
113 | GPRWordCount = sizeof(GPR) / sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT |
114 | FPUWordCount = sizeof(FPU) / sizeof(uint32_t), // ARM_NEON_STATE64_COUNT |
115 | EXCWordCount = |
116 | sizeof(EXC) / sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT |
117 | DBGWordCount = sizeof(DBG) / sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT |
118 | }; |
119 | |
120 | enum { Read = 0, Write = 1, kNumErrors = 2 }; |
121 | |
122 | GPR gpr; |
123 | FPU fpu; |
124 | EXC exc; |
125 | DBG dbg; |
126 | int gpr_errs[2]; // Read/Write errors |
127 | int fpu_errs[2]; // Read/Write errors |
128 | int exc_errs[2]; // Read/Write errors |
129 | int dbg_errs[2]; // Read/Write errors |
130 | |
131 | void InvalidateAllRegisterStates() { |
132 | SetError(flavor: GPRRegSet, err_idx: Read, err: -1); |
133 | SetError(flavor: FPURegSet, err_idx: Read, err: -1); |
134 | SetError(flavor: EXCRegSet, err_idx: Read, err: -1); |
135 | } |
136 | |
137 | int GetError(int flavor, uint32_t err_idx) const { |
138 | if (err_idx < kNumErrors) { |
139 | switch (flavor) { |
140 | // When getting all errors, just OR all values together to see if |
141 | // we got any kind of error. |
142 | case GPRRegSet: |
143 | return gpr_errs[err_idx]; |
144 | case FPURegSet: |
145 | return fpu_errs[err_idx]; |
146 | case EXCRegSet: |
147 | return exc_errs[err_idx]; |
148 | case DBGRegSet: |
149 | return dbg_errs[err_idx]; |
150 | default: |
151 | break; |
152 | } |
153 | } |
154 | return -1; |
155 | } |
156 | |
157 | bool SetError(int flavor, uint32_t err_idx, int err) { |
158 | if (err_idx < kNumErrors) { |
159 | switch (flavor) { |
160 | case GPRRegSet: |
161 | gpr_errs[err_idx] = err; |
162 | return true; |
163 | |
164 | case FPURegSet: |
165 | fpu_errs[err_idx] = err; |
166 | return true; |
167 | |
168 | case EXCRegSet: |
169 | exc_errs[err_idx] = err; |
170 | return true; |
171 | |
172 | case DBGRegSet: |
173 | exc_errs[err_idx] = err; |
174 | return true; |
175 | |
176 | default: |
177 | break; |
178 | } |
179 | } |
180 | return false; |
181 | } |
182 | |
183 | bool RegisterSetIsCached(int set) const { return GetError(flavor: set, err_idx: Read) == 0; } |
184 | |
185 | int ReadGPR(bool force); |
186 | |
187 | int ReadFPU(bool force); |
188 | |
189 | int ReadEXC(bool force); |
190 | |
191 | int ReadDBG(bool force); |
192 | |
193 | int WriteGPR(); |
194 | |
195 | int WriteFPU(); |
196 | |
197 | int WriteEXC(); |
198 | |
199 | int WriteDBG(); |
200 | |
201 | // Subclasses override these to do the actual reading. |
202 | virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { return -1; } |
203 | |
204 | virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) = 0; |
205 | |
206 | virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0; |
207 | |
208 | virtual int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) = 0; |
209 | |
210 | virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0; |
211 | |
212 | virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) = 0; |
213 | |
214 | virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0; |
215 | |
216 | virtual int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) = 0; |
217 | |
218 | int ReadRegisterSet(uint32_t set, bool force); |
219 | |
220 | int WriteRegisterSet(uint32_t set); |
221 | |
222 | static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num); |
223 | |
224 | static int GetSetForNativeRegNum(int reg_num); |
225 | |
226 | static size_t GetRegisterInfosCount(); |
227 | |
228 | static const lldb_private::RegisterInfo *GetRegisterInfos(); |
229 | }; |
230 | |
231 | #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_ARM64_H |
232 | |