xref: /openbsd-src/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1061da546Spatrick //===-- DNBArchImplARM64.h --------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9dda28197Spatrick #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
10dda28197Spatrick #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
11061da546Spatrick 
12061da546Spatrick #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
13061da546Spatrick 
14061da546Spatrick #include <mach/thread_status.h>
15061da546Spatrick #include <map>
16061da546Spatrick 
17061da546Spatrick #if defined(ARM_THREAD_STATE64_COUNT)
18061da546Spatrick 
19061da546Spatrick #include "DNBArch.h"
20061da546Spatrick 
21061da546Spatrick class MachThread;
22061da546Spatrick 
23061da546Spatrick class DNBArchMachARM64 : public DNBArchProtocol {
24061da546Spatrick public:
25061da546Spatrick   enum { kMaxNumThumbITBreakpoints = 4 };
26061da546Spatrick 
DNBArchMachARM64(MachThread * thread)27061da546Spatrick   DNBArchMachARM64(MachThread *thread)
28061da546Spatrick       : m_thread(thread), m_state(), m_disabled_watchpoints(),
29dda28197Spatrick         m_disabled_breakpoints(), m_watchpoint_hw_index(-1),
30dda28197Spatrick         m_watchpoint_did_occur(false),
31061da546Spatrick         m_watchpoint_resume_single_step_enabled(false),
32061da546Spatrick         m_saved_register_states() {
33061da546Spatrick     m_disabled_watchpoints.resize(16);
34dda28197Spatrick     m_disabled_breakpoints.resize(16);
35061da546Spatrick     memset(&m_dbg_save, 0, sizeof(m_dbg_save));
36061da546Spatrick   }
37061da546Spatrick 
~DNBArchMachARM64()38061da546Spatrick   virtual ~DNBArchMachARM64() {}
39061da546Spatrick 
40061da546Spatrick   static void Initialize();
41061da546Spatrick   static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets);
42061da546Spatrick 
43*be691f3bSpatrick   bool GetRegisterValue(uint32_t set, uint32_t reg,
44*be691f3bSpatrick                         DNBRegisterValue *value) override;
45*be691f3bSpatrick   bool SetRegisterValue(uint32_t set, uint32_t reg,
46*be691f3bSpatrick                         const DNBRegisterValue *value) override;
47*be691f3bSpatrick   nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override;
48*be691f3bSpatrick   nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override;
49*be691f3bSpatrick   uint32_t SaveRegisterState() override;
50*be691f3bSpatrick   bool RestoreRegisterState(uint32_t save_id) override;
51061da546Spatrick 
52*be691f3bSpatrick   kern_return_t GetRegisterState(int set, bool force) override;
53*be691f3bSpatrick   kern_return_t SetRegisterState(int set) override;
54*be691f3bSpatrick   bool RegisterSetStateIsValid(int set) const override;
55061da546Spatrick 
56*be691f3bSpatrick   uint64_t GetPC(uint64_t failValue) override; // Get program counter
57*be691f3bSpatrick   kern_return_t SetPC(uint64_t value) override;
58*be691f3bSpatrick   uint64_t GetSP(uint64_t failValue) override; // Get stack pointer
59*be691f3bSpatrick   void ThreadWillResume() override;
60*be691f3bSpatrick   bool ThreadDidStop() override;
61*be691f3bSpatrick   bool NotifyException(MachException::Data &exc) override;
62061da546Spatrick 
63061da546Spatrick   static DNBArchProtocol *Create(MachThread *thread);
64061da546Spatrick   static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size);
65061da546Spatrick   static uint32_t GetCPUType();
66061da546Spatrick 
67*be691f3bSpatrick   uint32_t NumSupportedHardwareBreakpoints() override;
68*be691f3bSpatrick   uint32_t NumSupportedHardwareWatchpoints() override;
69dda28197Spatrick 
70*be691f3bSpatrick   uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size,
71*be691f3bSpatrick                                     bool also_set_on_task) override;
72*be691f3bSpatrick   bool DisableHardwareBreakpoint(uint32_t hw_break_index,
73*be691f3bSpatrick                                  bool also_set_on_task) override;
74*be691f3bSpatrick   uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read,
75*be691f3bSpatrick                                     bool write, bool also_set_on_task) override;
76*be691f3bSpatrick   bool DisableHardwareWatchpoint(uint32_t hw_break_index,
77*be691f3bSpatrick                                  bool also_set_on_task) override;
78*be691f3bSpatrick   bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index,
79061da546Spatrick                                         bool also_set_on_task);
80061da546Spatrick 
81061da546Spatrick protected:
82061da546Spatrick   kern_return_t EnableHardwareSingleStep(bool enable);
83061da546Spatrick   static bool FixGenericRegisterNumber(uint32_t &set, uint32_t &reg);
84061da546Spatrick 
85061da546Spatrick   enum RegisterSet {
86061da546Spatrick     e_regSetALL = REGISTER_SET_ALL,
87061da546Spatrick     e_regSetGPR, // ARM_THREAD_STATE64,
88061da546Spatrick     e_regSetVFP, // ARM_NEON_STATE64,
89061da546Spatrick     e_regSetEXC, // ARM_EXCEPTION_STATE64,
90061da546Spatrick     e_regSetDBG, // ARM_DEBUG_STATE64,
91061da546Spatrick     kNumRegisterSets
92061da546Spatrick   };
93061da546Spatrick 
94061da546Spatrick   enum {
95061da546Spatrick     e_regSetGPRCount = ARM_THREAD_STATE64_COUNT,
96061da546Spatrick     e_regSetVFPCount = ARM_NEON_STATE64_COUNT,
97061da546Spatrick     e_regSetEXCCount = ARM_EXCEPTION_STATE64_COUNT,
98061da546Spatrick     e_regSetDBGCount = ARM_DEBUG_STATE64_COUNT,
99061da546Spatrick   };
100061da546Spatrick 
101061da546Spatrick   enum { Read = 0, Write = 1, kNumErrors = 2 };
102061da546Spatrick 
103061da546Spatrick   typedef arm_thread_state64_t GPR;
104061da546Spatrick   typedef arm_neon_state64_t FPU;
105061da546Spatrick   typedef arm_exception_state64_t EXC;
106061da546Spatrick 
107061da546Spatrick   static const DNBRegisterInfo g_gpr_registers[];
108061da546Spatrick   static const DNBRegisterInfo g_vfp_registers[];
109061da546Spatrick   static const DNBRegisterInfo g_exc_registers[];
110061da546Spatrick   static const DNBRegisterSetInfo g_reg_sets[];
111061da546Spatrick 
112061da546Spatrick   static const size_t k_num_gpr_registers;
113061da546Spatrick   static const size_t k_num_vfp_registers;
114061da546Spatrick   static const size_t k_num_exc_registers;
115061da546Spatrick   static const size_t k_num_all_registers;
116061da546Spatrick   static const size_t k_num_register_sets;
117061da546Spatrick 
118061da546Spatrick   struct Context {
119061da546Spatrick     GPR gpr;
120061da546Spatrick     FPU vfp;
121061da546Spatrick     EXC exc;
122061da546Spatrick   };
123061da546Spatrick 
124061da546Spatrick   struct State {
125061da546Spatrick     Context context;
126061da546Spatrick     arm_debug_state64_t dbg;
127061da546Spatrick     kern_return_t gpr_errs[2]; // Read/Write errors
128061da546Spatrick     kern_return_t vfp_errs[2]; // Read/Write errors
129061da546Spatrick     kern_return_t exc_errs[2]; // Read/Write errors
130061da546Spatrick     kern_return_t dbg_errs[2]; // Read/Write errors
StateState131061da546Spatrick     State() {
132061da546Spatrick       uint32_t i;
133061da546Spatrick       for (i = 0; i < kNumErrors; i++) {
134061da546Spatrick         gpr_errs[i] = -1;
135061da546Spatrick         vfp_errs[i] = -1;
136061da546Spatrick         exc_errs[i] = -1;
137061da546Spatrick         dbg_errs[i] = -1;
138061da546Spatrick       }
139061da546Spatrick     }
InvalidateRegisterSetStateState140061da546Spatrick     void InvalidateRegisterSetState(int set) { SetError(set, Read, -1); }
141061da546Spatrick 
InvalidateAllRegisterStatesState142061da546Spatrick     void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); }
143061da546Spatrick 
GetErrorState144061da546Spatrick     kern_return_t GetError(int set, uint32_t err_idx) const {
145061da546Spatrick       if (err_idx < kNumErrors) {
146061da546Spatrick         switch (set) {
147061da546Spatrick         // When getting all errors, just OR all values together to see if
148061da546Spatrick         // we got any kind of error.
149061da546Spatrick         case e_regSetALL:
150061da546Spatrick           return gpr_errs[err_idx] | vfp_errs[err_idx] | exc_errs[err_idx] |
151061da546Spatrick                  dbg_errs[err_idx];
152061da546Spatrick         case e_regSetGPR:
153061da546Spatrick           return gpr_errs[err_idx];
154061da546Spatrick         case e_regSetVFP:
155061da546Spatrick           return vfp_errs[err_idx];
156061da546Spatrick         case e_regSetEXC:
157061da546Spatrick           return exc_errs[err_idx];
158061da546Spatrick         // case e_regSetDBG:   return dbg_errs[err_idx];
159061da546Spatrick         default:
160061da546Spatrick           break;
161061da546Spatrick         }
162061da546Spatrick       }
163061da546Spatrick       return -1;
164061da546Spatrick     }
SetErrorState165061da546Spatrick     bool SetError(int set, uint32_t err_idx, kern_return_t err) {
166061da546Spatrick       if (err_idx < kNumErrors) {
167061da546Spatrick         switch (set) {
168061da546Spatrick         case e_regSetALL:
169061da546Spatrick           gpr_errs[err_idx] = err;
170061da546Spatrick           vfp_errs[err_idx] = err;
171061da546Spatrick           dbg_errs[err_idx] = err;
172061da546Spatrick           exc_errs[err_idx] = err;
173061da546Spatrick           return true;
174061da546Spatrick 
175061da546Spatrick         case e_regSetGPR:
176061da546Spatrick           gpr_errs[err_idx] = err;
177061da546Spatrick           return true;
178061da546Spatrick 
179061da546Spatrick         case e_regSetVFP:
180061da546Spatrick           vfp_errs[err_idx] = err;
181061da546Spatrick           return true;
182061da546Spatrick 
183061da546Spatrick         case e_regSetEXC:
184061da546Spatrick           exc_errs[err_idx] = err;
185061da546Spatrick           return true;
186061da546Spatrick 
187061da546Spatrick         //                case e_regSetDBG:
188061da546Spatrick         //                    dbg_errs[err_idx] = err;
189061da546Spatrick         //                    return true;
190061da546Spatrick         default:
191061da546Spatrick           break;
192061da546Spatrick         }
193061da546Spatrick       }
194061da546Spatrick       return false;
195061da546Spatrick     }
RegsAreValidState196061da546Spatrick     bool RegsAreValid(int set) const {
197061da546Spatrick       return GetError(set, Read) == KERN_SUCCESS;
198061da546Spatrick     }
199061da546Spatrick   };
200061da546Spatrick 
201061da546Spatrick   kern_return_t GetGPRState(bool force);
202061da546Spatrick   kern_return_t GetVFPState(bool force);
203061da546Spatrick   kern_return_t GetEXCState(bool force);
204061da546Spatrick   kern_return_t GetDBGState(bool force);
205061da546Spatrick 
206061da546Spatrick   kern_return_t SetGPRState();
207061da546Spatrick   kern_return_t SetVFPState();
208061da546Spatrick   kern_return_t SetEXCState();
209061da546Spatrick   kern_return_t SetDBGState(bool also_set_on_task);
210061da546Spatrick 
211061da546Spatrick   // Helper functions for watchpoint implementaions.
212061da546Spatrick 
213061da546Spatrick   typedef arm_debug_state64_t DBG;
214061da546Spatrick 
215061da546Spatrick   void ClearWatchpointOccurred();
216061da546Spatrick   bool HasWatchpointOccurred();
217061da546Spatrick   bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index);
218061da546Spatrick   nub_addr_t GetWatchpointAddressByIndex(uint32_t hw_index);
219061da546Spatrick   nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index);
220061da546Spatrick   virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index);
221061da546Spatrick   virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index);
222*be691f3bSpatrick   uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override;
223061da546Spatrick 
224061da546Spatrick   class disabled_watchpoint {
225061da546Spatrick   public:
disabled_watchpoint()226061da546Spatrick     disabled_watchpoint() {
227061da546Spatrick       addr = 0;
228061da546Spatrick       control = 0;
229061da546Spatrick     }
230061da546Spatrick     nub_addr_t addr;
231061da546Spatrick     uint32_t control;
232061da546Spatrick   };
233061da546Spatrick 
234061da546Spatrick protected:
235061da546Spatrick   MachThread *m_thread;
236061da546Spatrick   State m_state;
237061da546Spatrick   arm_debug_state64_t m_dbg_save;
238061da546Spatrick 
239dda28197Spatrick   // arm64 doesn't keep the disabled watchpoint and breakpoint values in the
240dda28197Spatrick   // debug register context like armv7;
241061da546Spatrick   // we need to save them aside when we disable them temporarily.
242061da546Spatrick   std::vector<disabled_watchpoint> m_disabled_watchpoints;
243dda28197Spatrick   std::vector<disabled_watchpoint> m_disabled_breakpoints;
244061da546Spatrick 
245061da546Spatrick   // The following member variables should be updated atomically.
246061da546Spatrick   int32_t m_watchpoint_hw_index;
247061da546Spatrick   bool m_watchpoint_did_occur;
248061da546Spatrick   bool m_watchpoint_resume_single_step_enabled;
249061da546Spatrick 
250061da546Spatrick   typedef std::map<uint32_t, Context> SaveRegisterStates;
251061da546Spatrick   SaveRegisterStates m_saved_register_states;
252061da546Spatrick };
253061da546Spatrick 
254061da546Spatrick #endif // #if defined (ARM_THREAD_STATE64_COUNT)
255061da546Spatrick #endif // #if defined (__arm__)
256dda28197Spatrick #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_ARM64_DNBARCHIMPLARM64_H
257