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

source code of lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h