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 liblldb_RegisterContextDarwin_arm64_h_
11 #define liblldb_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 &reg_value) override;
47 
48   bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
49                      const lldb_private::RegisterValue &reg_value) override;
50 
51   bool ReadAllRegisterValues(lldb::DataBufferSP &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(GPRRegSet, Read, -1);
133     SetError(FPURegSet, Read, -1);
134     SetError(EXCRegSet, Read, -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(set, 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 // liblldb_RegisterContextDarwin_arm64_h_
232