1 //===-- DNBArchImplARM64.h --------------------------------------*- C++ -*-===//
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 #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
10 #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
11 
12 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
13 
14 #include <mach/thread_status.h>
15 #include <map>
16 
17 #if defined(ARM_THREAD_STATE64_COUNT)
18 
19 #include "DNBArch.h"
20 
21 class MachThread;
22 
23 class DNBArchMachARM64 : public DNBArchProtocol {
24 public:
25   enum { kMaxNumThumbITBreakpoints = 4 };
26 
DNBArchMachARM64(MachThread * thread)27   DNBArchMachARM64(MachThread *thread)
28       : m_thread(thread), m_state(), m_disabled_watchpoints(),
29         m_disabled_breakpoints(), m_watchpoint_hw_index(-1),
30         m_watchpoint_did_occur(false),
31         m_watchpoint_resume_single_step_enabled(false),
32         m_saved_register_states() {
33     m_disabled_watchpoints.resize(16);
34     m_disabled_breakpoints.resize(16);
35     memset(&m_dbg_save, 0, sizeof(m_dbg_save));
36   }
37 
~DNBArchMachARM64()38   virtual ~DNBArchMachARM64() {}
39 
40   static void Initialize();
41   static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets);
42 
43   bool GetRegisterValue(uint32_t set, uint32_t reg,
44                         DNBRegisterValue *value) override;
45   bool SetRegisterValue(uint32_t set, uint32_t reg,
46                         const DNBRegisterValue *value) override;
47   nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override;
48   nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override;
49   uint32_t SaveRegisterState() override;
50   bool RestoreRegisterState(uint32_t save_id) override;
51 
52   kern_return_t GetRegisterState(int set, bool force) override;
53   kern_return_t SetRegisterState(int set) override;
54   bool RegisterSetStateIsValid(int set) const override;
55 
56   uint64_t GetPC(uint64_t failValue) override; // Get program counter
57   kern_return_t SetPC(uint64_t value) override;
58   uint64_t GetSP(uint64_t failValue) override; // Get stack pointer
59   void ThreadWillResume() override;
60   bool ThreadDidStop() override;
61   bool NotifyException(MachException::Data &exc) override;
62 
63   static DNBArchProtocol *Create(MachThread *thread);
64   static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size);
65   static uint32_t GetCPUType();
66 
67   uint32_t NumSupportedHardwareBreakpoints() override;
68   uint32_t NumSupportedHardwareWatchpoints() override;
69 
70   uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size,
71                                     bool also_set_on_task) override;
72   bool DisableHardwareBreakpoint(uint32_t hw_break_index,
73                                  bool also_set_on_task) override;
74   uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read,
75                                     bool write, bool also_set_on_task) override;
76   bool DisableHardwareWatchpoint(uint32_t hw_break_index,
77                                  bool also_set_on_task) override;
78   bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index,
79                                         bool also_set_on_task);
80 
81 protected:
82   kern_return_t EnableHardwareSingleStep(bool enable);
83   static bool FixGenericRegisterNumber(uint32_t &set, uint32_t &reg);
84 
85   enum RegisterSet {
86     e_regSetALL = REGISTER_SET_ALL,
87     e_regSetGPR, // ARM_THREAD_STATE64,
88     e_regSetVFP, // ARM_NEON_STATE64,
89     e_regSetEXC, // ARM_EXCEPTION_STATE64,
90     e_regSetDBG, // ARM_DEBUG_STATE64,
91     kNumRegisterSets
92   };
93 
94   enum {
95     e_regSetGPRCount = ARM_THREAD_STATE64_COUNT,
96     e_regSetVFPCount = ARM_NEON_STATE64_COUNT,
97     e_regSetEXCCount = ARM_EXCEPTION_STATE64_COUNT,
98     e_regSetDBGCount = ARM_DEBUG_STATE64_COUNT,
99   };
100 
101   enum { Read = 0, Write = 1, kNumErrors = 2 };
102 
103   typedef arm_thread_state64_t GPR;
104   typedef arm_neon_state64_t FPU;
105   typedef arm_exception_state64_t EXC;
106 
107   static const DNBRegisterInfo g_gpr_registers[];
108   static const DNBRegisterInfo g_vfp_registers[];
109   static const DNBRegisterInfo g_exc_registers[];
110   static const DNBRegisterSetInfo g_reg_sets[];
111 
112   static const size_t k_num_gpr_registers;
113   static const size_t k_num_vfp_registers;
114   static const size_t k_num_exc_registers;
115   static const size_t k_num_all_registers;
116   static const size_t k_num_register_sets;
117 
118   struct Context {
119     GPR gpr;
120     FPU vfp;
121     EXC exc;
122   };
123 
124   struct State {
125     Context context;
126     arm_debug_state64_t dbg;
127     kern_return_t gpr_errs[2]; // Read/Write errors
128     kern_return_t vfp_errs[2]; // Read/Write errors
129     kern_return_t exc_errs[2]; // Read/Write errors
130     kern_return_t dbg_errs[2]; // Read/Write errors
StateState131     State() {
132       uint32_t i;
133       for (i = 0; i < kNumErrors; i++) {
134         gpr_errs[i] = -1;
135         vfp_errs[i] = -1;
136         exc_errs[i] = -1;
137         dbg_errs[i] = -1;
138       }
139     }
InvalidateRegisterSetStateState140     void InvalidateRegisterSetState(int set) { SetError(set, Read, -1); }
141 
InvalidateAllRegisterStatesState142     void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); }
143 
GetErrorState144     kern_return_t GetError(int set, uint32_t err_idx) const {
145       if (err_idx < kNumErrors) {
146         switch (set) {
147         // When getting all errors, just OR all values together to see if
148         // we got any kind of error.
149         case e_regSetALL:
150           return gpr_errs[err_idx] | vfp_errs[err_idx] | exc_errs[err_idx] |
151                  dbg_errs[err_idx];
152         case e_regSetGPR:
153           return gpr_errs[err_idx];
154         case e_regSetVFP:
155           return vfp_errs[err_idx];
156         case e_regSetEXC:
157           return exc_errs[err_idx];
158         // case e_regSetDBG:   return dbg_errs[err_idx];
159         default:
160           break;
161         }
162       }
163       return -1;
164     }
SetErrorState165     bool SetError(int set, uint32_t err_idx, kern_return_t err) {
166       if (err_idx < kNumErrors) {
167         switch (set) {
168         case e_regSetALL:
169           gpr_errs[err_idx] = err;
170           vfp_errs[err_idx] = err;
171           dbg_errs[err_idx] = err;
172           exc_errs[err_idx] = err;
173           return true;
174 
175         case e_regSetGPR:
176           gpr_errs[err_idx] = err;
177           return true;
178 
179         case e_regSetVFP:
180           vfp_errs[err_idx] = err;
181           return true;
182 
183         case e_regSetEXC:
184           exc_errs[err_idx] = err;
185           return true;
186 
187         //                case e_regSetDBG:
188         //                    dbg_errs[err_idx] = err;
189         //                    return true;
190         default:
191           break;
192         }
193       }
194       return false;
195     }
RegsAreValidState196     bool RegsAreValid(int set) const {
197       return GetError(set, Read) == KERN_SUCCESS;
198     }
199   };
200 
201   kern_return_t GetGPRState(bool force);
202   kern_return_t GetVFPState(bool force);
203   kern_return_t GetEXCState(bool force);
204   kern_return_t GetDBGState(bool force);
205 
206   kern_return_t SetGPRState();
207   kern_return_t SetVFPState();
208   kern_return_t SetEXCState();
209   kern_return_t SetDBGState(bool also_set_on_task);
210 
211   // Helper functions for watchpoint implementaions.
212 
213   typedef arm_debug_state64_t DBG;
214 
215   void ClearWatchpointOccurred();
216   bool HasWatchpointOccurred();
217   bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index);
218   nub_addr_t GetWatchpointAddressByIndex(uint32_t hw_index);
219   nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index);
220   virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index);
221   virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index);
222   uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override;
223 
224   class disabled_watchpoint {
225   public:
disabled_watchpoint()226     disabled_watchpoint() {
227       addr = 0;
228       control = 0;
229     }
230     nub_addr_t addr;
231     uint32_t control;
232   };
233 
234 protected:
235   MachThread *m_thread;
236   State m_state;
237   arm_debug_state64_t m_dbg_save;
238 
239   // arm64 doesn't keep the disabled watchpoint and breakpoint values in the
240   // debug register context like armv7;
241   // we need to save them aside when we disable them temporarily.
242   std::vector<disabled_watchpoint> m_disabled_watchpoints;
243   std::vector<disabled_watchpoint> m_disabled_breakpoints;
244 
245   // The following member variables should be updated atomically.
246   int32_t m_watchpoint_hw_index;
247   bool m_watchpoint_did_occur;
248   bool m_watchpoint_resume_single_step_enabled;
249 
250   typedef std::map<uint32_t, Context> SaveRegisterStates;
251   SaveRegisterStates m_saved_register_states;
252 };
253 
254 #endif // #if defined (ARM_THREAD_STATE64_COUNT)
255 #endif // #if defined (__arm__)
256 #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
257