1 //===-- DNBArchImpl.h -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Greg Clayton on 6/25/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef __DebugNubArchMachARM_h__
15 #define __DebugNubArchMachARM_h__
16 
17 #if defined (__arm__)
18 
19 #include "DNBArch.h"
20 
21 class MachThread;
22 
23 class DNBArchMachARM : public DNBArchProtocol
24 {
25 public:
26     enum { kMaxNumThumbITBreakpoints = 4 };
27 
28     DNBArchMachARM(MachThread *thread) :
29         m_thread(thread),
30         m_state(),
31         m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS),
32         m_sw_single_step_next_pc(INVALID_NUB_ADDRESS),
33         m_sw_single_step_break_id(INVALID_NUB_BREAK_ID),
34         m_sw_single_step_itblock_break_count(0),
35         m_last_decode_pc(INVALID_NUB_ADDRESS),
36         m_watchpoint_hw_index(-1),
37         m_watchpoint_did_occur(false),
38         m_watchpoint_resume_single_step_enabled(false)
39     {
40         memset(&m_dbg_save, 0, sizeof(m_dbg_save));
41 #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
42         ThumbStaticsInit(&m_last_decode_thumb);
43 #endif
44         for (int i = 0; i < kMaxNumThumbITBreakpoints; i++)
45             m_sw_single_step_itblock_break_id[i] = INVALID_NUB_BREAK_ID;
46     }
47 
48     virtual ~DNBArchMachARM()
49     {
50     }
51 
52     static void Initialize();
53     static const DNBRegisterSetInfo *
54     GetRegisterSetInfo(nub_size_t *num_reg_sets);
55 
56     virtual bool            GetRegisterValue(int set, int reg, DNBRegisterValue *value);
57     virtual bool            SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
58     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
59     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
60 
61     virtual kern_return_t   GetRegisterState  (int set, bool force);
62     virtual kern_return_t   SetRegisterState  (int set);
63     virtual bool            RegisterSetStateIsValid (int set) const;
64 
65     virtual uint64_t        GetPC(uint64_t failValue);    // Get program counter
66     virtual kern_return_t   SetPC(uint64_t value);
67     virtual uint64_t        GetSP(uint64_t failValue);    // Get stack pointer
68     virtual void            ThreadWillResume();
69     virtual bool            ThreadDidStop();
70     virtual bool            NotifyException(MachException::Data& exc);
71 
72     static DNBArchProtocol *Create (MachThread *thread);
73     static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
74     static uint32_t         GetCPUType();
75 
76     virtual uint32_t        NumSupportedHardwareBreakpoints();
77     virtual uint32_t        NumSupportedHardwareWatchpoints();
78     virtual uint32_t        EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size);
79     virtual uint32_t        EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write);
80     virtual bool            DisableHardwareBreakpoint (uint32_t hw_break_index);
81     virtual bool            DisableHardwareWatchpoint (uint32_t hw_break_index);
82     virtual bool            EnableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate);
83     virtual bool            DisableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate);
84     virtual bool            StepNotComplete ();
85     virtual void            HardwareWatchpointStateChanged ();
86     virtual uint32_t        GetHardwareWatchpointHit(nub_addr_t &addr);
87 
88     typedef arm_debug_state_t DBG;
89 
90 protected:
91 
92 
93     kern_return_t           EnableHardwareSingleStep (bool enable);
94     kern_return_t           SetSingleStepSoftwareBreakpoints ();
95 
96     bool                    ConditionPassed(uint8_t condition, uint32_t cpsr);
97 #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
98     bool                    ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC);
99     arm_error_t             DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc);
100     void                    DecodeITBlockInstructions(nub_addr_t curr_pc);
101 #endif
102     void                    EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb);
103     static nub_bool_t       BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton);
104 
105     typedef enum RegisterSetTag
106     {
107         e_regSetALL = REGISTER_SET_ALL,
108         e_regSetGPR = ARM_THREAD_STATE,
109         e_regSetVFP = ARM_VFP_STATE,
110         e_regSetEXC = ARM_EXCEPTION_STATE,
111         e_regSetDBG = ARM_DEBUG_STATE,
112         kNumRegisterSets
113     } RegisterSet;
114 
115     enum
116     {
117         Read = 0,
118         Write = 1,
119         kNumErrors = 2
120     };
121 
122     typedef arm_thread_state_t GPR;
123     typedef arm_vfp_state_t FPU;
124     typedef arm_exception_state_t EXC;
125 
126     static const DNBRegisterInfo g_gpr_registers[];
127     static const DNBRegisterInfo g_vfp_registers[];
128     static const DNBRegisterInfo g_exc_registers[];
129     static const DNBRegisterSetInfo g_reg_sets[];
130 
131     static const size_t k_num_gpr_registers;
132     static const size_t k_num_vfp_registers;
133     static const size_t k_num_exc_registers;
134     static const size_t k_num_all_registers;
135     static const size_t k_num_register_sets;
136 
137     struct Context
138     {
139         GPR gpr;
140         FPU vfp;
141         EXC exc;
142     };
143 
144     // See also HardwareWatchpointStateChanged() which updates this class-wide variable.
145     static DBG Global_Debug_State;
146     static bool Valid_Global_Debug_State;
147 
148     struct State
149     {
150         Context                 context;
151         DBG                     dbg;
152         kern_return_t           gpr_errs[2];    // Read/Write errors
153         kern_return_t           vfp_errs[2];    // Read/Write errors
154         kern_return_t           exc_errs[2];    // Read/Write errors
155         kern_return_t           dbg_errs[2];    // Read/Write errors
156         State()
157         {
158             uint32_t i;
159             for (i=0; i<kNumErrors; i++)
160             {
161                 gpr_errs[i] = -1;
162                 vfp_errs[i] = -1;
163                 exc_errs[i] = -1;
164                 dbg_errs[i] = -1;
165             }
166         }
167         void InvalidateRegisterSetState(int set)
168         {
169             SetError (set, Read, -1);
170         }
171         kern_return_t GetError (int set, uint32_t err_idx) const
172         {
173             if (err_idx < kNumErrors)
174             {
175                 switch (set)
176                 {
177                 // When getting all errors, just OR all values together to see if
178                 // we got any kind of error.
179                 case e_regSetALL:   return gpr_errs[err_idx] |
180                                            vfp_errs[err_idx] |
181                                            exc_errs[err_idx] |
182                                            dbg_errs[err_idx] ;
183                 case e_regSetGPR:   return gpr_errs[err_idx];
184                 case e_regSetVFP:   return vfp_errs[err_idx];
185                 case e_regSetEXC:   return exc_errs[err_idx];
186                 case e_regSetDBG:   return dbg_errs[err_idx];
187                 default: break;
188                 }
189             }
190             return -1;
191         }
192         bool SetError (int set, uint32_t err_idx, kern_return_t err)
193         {
194             if (err_idx < kNumErrors)
195             {
196                 switch (set)
197                 {
198                 case e_regSetALL:
199                     gpr_errs[err_idx] = err;
200                     vfp_errs[err_idx] = err;
201                     dbg_errs[err_idx] = err;
202                     exc_errs[err_idx] = err;
203                     return true;
204 
205                 case e_regSetGPR:
206                     gpr_errs[err_idx] = err;
207                     return true;
208 
209                 case e_regSetVFP:
210                     vfp_errs[err_idx] = err;
211                     return true;
212 
213                 case e_regSetEXC:
214                     exc_errs[err_idx] = err;
215                     return true;
216 
217                 case e_regSetDBG:
218                     dbg_errs[err_idx] = err;
219                     return true;
220                 default: break;
221                 }
222             }
223             return false;
224         }
225         bool RegsAreValid (int set) const
226         {
227             return GetError(set, Read) == KERN_SUCCESS;
228         }
229     };
230 
231     kern_return_t GetGPRState (bool force);
232     kern_return_t GetVFPState (bool force);
233     kern_return_t GetEXCState (bool force);
234     kern_return_t GetDBGState (bool force);
235 
236     kern_return_t SetGPRState ();
237     kern_return_t SetVFPState ();
238     kern_return_t SetEXCState ();
239     kern_return_t SetDBGState ();
240 
241     // Helper functions for watchpoint implementaions.
242     static void ClearWatchpointOccurred();
243     static bool HasWatchpointOccurred();
244     static bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index);
245     static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index);
246 
247 protected:
248     MachThread *    m_thread;
249     State           m_state;
250     DBG             m_dbg_save;
251     nub_addr_t      m_hw_single_chained_step_addr;
252     // Software single stepping support
253     nub_addr_t      m_sw_single_step_next_pc;
254     nub_break_t     m_sw_single_step_break_id;
255     nub_break_t     m_sw_single_step_itblock_break_id[kMaxNumThumbITBreakpoints];
256     nub_addr_t      m_sw_single_step_itblock_break_count;
257     // Disassembler state
258 #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
259     thumb_static_data_t m_last_decode_thumb;
260     arm_decoded_instruction_t m_last_decode_arm;
261 #endif
262     nub_addr_t      m_last_decode_pc;
263 
264     // The following member variables should be updated atomically.
265     int32_t         m_watchpoint_hw_index;
266     bool            m_watchpoint_did_occur;
267     bool            m_watchpoint_resume_single_step_enabled;
268 };
269 
270 #endif    // #if defined (__arm__)
271 #endif    // #ifndef __DebugNubArchMachARM_h__
272