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 
DNBArchMachARM(MachThread * thread)28     DNBArchMachARM(MachThread *thread) :
29         m_thread(thread),
30         m_state(),
31         m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS),
32         m_last_decode_pc(INVALID_NUB_ADDRESS),
33         m_watchpoint_hw_index(-1),
34         m_watchpoint_did_occur(false),
35         m_watchpoint_resume_single_step_enabled(false)
36     {
37         memset(&m_dbg_save, 0, sizeof(m_dbg_save));
38 #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
39         ThumbStaticsInit(&m_last_decode_thumb);
40 #endif
41     }
42 
~DNBArchMachARM()43     virtual ~DNBArchMachARM()
44     {
45     }
46 
47     static void Initialize();
48     static const DNBRegisterSetInfo *
49     GetRegisterSetInfo(nub_size_t *num_reg_sets);
50 
51     virtual bool            GetRegisterValue(int set, int reg, DNBRegisterValue *value);
52     virtual bool            SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
53     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
54     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
55 
56     virtual kern_return_t   GetRegisterState  (int set, bool force);
57     virtual kern_return_t   SetRegisterState  (int set);
58     virtual bool            RegisterSetStateIsValid (int set) const;
59 
60     virtual uint64_t        GetPC(uint64_t failValue);    // Get program counter
61     virtual kern_return_t   SetPC(uint64_t value);
62     virtual uint64_t        GetSP(uint64_t failValue);    // Get stack pointer
63     virtual void            ThreadWillResume();
64     virtual bool            ThreadDidStop();
65     virtual bool            NotifyException(MachException::Data& exc);
66 
67     static DNBArchProtocol *Create (MachThread *thread);
68     static const uint8_t * const SoftwareBreakpointOpcode (nub_size_t byte_size);
69     static uint32_t         GetCPUType();
70 
71     virtual uint32_t        NumSupportedHardwareBreakpoints();
72     virtual uint32_t        NumSupportedHardwareWatchpoints();
73     virtual uint32_t        EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size);
74     virtual uint32_t        EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task);
75     virtual bool            DisableHardwareBreakpoint (uint32_t hw_break_index);
76     virtual bool            DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task);
77     virtual bool            EnableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate, bool also_set_on_task);
78     virtual bool            DisableHardwareWatchpoint0 (uint32_t hw_break_index, bool Delegate, bool also_set_on_task);
79     virtual bool            StepNotComplete ();
80     virtual uint32_t        GetHardwareWatchpointHit(nub_addr_t &addr);
81 
82     typedef arm_debug_state_t DBG;
83 
84 protected:
85 
86 
87     kern_return_t           EnableHardwareSingleStep (bool enable);
88     kern_return_t           SetSingleStepSoftwareBreakpoints ();
89 
90     bool                    ConditionPassed(uint8_t condition, uint32_t cpsr);
91 #if defined (USE_ARM_DISASSEMBLER_FRAMEWORK)
92     bool                    ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC);
93     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);
94     void                    DecodeITBlockInstructions(nub_addr_t curr_pc);
95 #endif
96     void                    EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb);
97 
98     typedef enum RegisterSetTag
99     {
100         e_regSetALL = REGISTER_SET_ALL,
101         e_regSetGPR = ARM_THREAD_STATE,
102         e_regSetVFP = ARM_VFP_STATE,
103         e_regSetEXC = ARM_EXCEPTION_STATE,
104         e_regSetDBG = ARM_DEBUG_STATE,
105         kNumRegisterSets
106     } RegisterSet;
107 
108     enum
109     {
110         Read = 0,
111         Write = 1,
112         kNumErrors = 2
113     };
114 
115     typedef arm_thread_state_t GPR;
116     typedef arm_vfp_state_t FPU;
117     typedef arm_exception_state_t EXC;
118 
119     static const DNBRegisterInfo g_gpr_registers[];
120     static const DNBRegisterInfo g_vfp_registers[];
121     static const DNBRegisterInfo g_exc_registers[];
122     static const DNBRegisterSetInfo g_reg_sets[];
123 
124     static const size_t k_num_gpr_registers;
125     static const size_t k_num_vfp_registers;
126     static const size_t k_num_exc_registers;
127     static const size_t k_num_all_registers;
128     static const size_t k_num_register_sets;
129 
130     struct Context
131     {
132         GPR gpr;
133         FPU vfp;
134         EXC exc;
135     };
136 
137     struct State
138     {
139         Context                 context;
140         DBG                     dbg;
141         kern_return_t           gpr_errs[2];    // Read/Write errors
142         kern_return_t           vfp_errs[2];    // Read/Write errors
143         kern_return_t           exc_errs[2];    // Read/Write errors
144         kern_return_t           dbg_errs[2];    // Read/Write errors
StateState145         State()
146         {
147             uint32_t i;
148             for (i=0; i<kNumErrors; i++)
149             {
150                 gpr_errs[i] = -1;
151                 vfp_errs[i] = -1;
152                 exc_errs[i] = -1;
153                 dbg_errs[i] = -1;
154             }
155         }
InvalidateRegisterSetStateState156         void InvalidateRegisterSetState(int set)
157         {
158             SetError (set, Read, -1);
159         }
GetErrorState160         kern_return_t GetError (int set, uint32_t err_idx) const
161         {
162             if (err_idx < kNumErrors)
163             {
164                 switch (set)
165                 {
166                 // When getting all errors, just OR all values together to see if
167                 // we got any kind of error.
168                 case e_regSetALL:   return gpr_errs[err_idx] |
169                                            vfp_errs[err_idx] |
170                                            exc_errs[err_idx] |
171                                            dbg_errs[err_idx] ;
172                 case e_regSetGPR:   return gpr_errs[err_idx];
173                 case e_regSetVFP:   return vfp_errs[err_idx];
174                 case e_regSetEXC:   return exc_errs[err_idx];
175                 case e_regSetDBG:   return dbg_errs[err_idx];
176                 default: break;
177                 }
178             }
179             return -1;
180         }
SetErrorState181         bool SetError (int set, uint32_t err_idx, kern_return_t err)
182         {
183             if (err_idx < kNumErrors)
184             {
185                 switch (set)
186                 {
187                 case e_regSetALL:
188                     gpr_errs[err_idx] = err;
189                     vfp_errs[err_idx] = err;
190                     dbg_errs[err_idx] = err;
191                     exc_errs[err_idx] = err;
192                     return true;
193 
194                 case e_regSetGPR:
195                     gpr_errs[err_idx] = err;
196                     return true;
197 
198                 case e_regSetVFP:
199                     vfp_errs[err_idx] = err;
200                     return true;
201 
202                 case e_regSetEXC:
203                     exc_errs[err_idx] = err;
204                     return true;
205 
206                 case e_regSetDBG:
207                     dbg_errs[err_idx] = err;
208                     return true;
209                 default: break;
210                 }
211             }
212             return false;
213         }
RegsAreValidState214         bool RegsAreValid (int set) const
215         {
216             return GetError(set, Read) == KERN_SUCCESS;
217         }
218     };
219 
220     kern_return_t GetGPRState (bool force);
221     kern_return_t GetVFPState (bool force);
222     kern_return_t GetEXCState (bool force);
223     kern_return_t GetDBGState (bool force);
224 
225     kern_return_t SetGPRState ();
226     kern_return_t SetVFPState ();
227     kern_return_t SetEXCState ();
228     kern_return_t SetDBGState (bool also_set_on_task);
229 
230     // Helper functions for watchpoint implementaions.
231     static void ClearWatchpointOccurred();
232     static bool HasWatchpointOccurred();
233     static bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index);
234     static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index);
235 
236 protected:
237     MachThread *    m_thread;
238     State           m_state;
239     DBG             m_dbg_save;
240     nub_addr_t      m_hw_single_chained_step_addr;
241     nub_addr_t      m_last_decode_pc;
242 
243     // The following member variables should be updated atomically.
244     int32_t         m_watchpoint_hw_index;
245     bool            m_watchpoint_did_occur;
246     bool            m_watchpoint_resume_single_step_enabled;
247 };
248 
249 #endif    // #if defined (__arm__)
250 #endif    // #ifndef __DebugNubArchMachARM_h__
251