1 //===-- DNBArchImplX86_64.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 __DNBArchImplX86_64_h__
15 #define __DNBArchImplX86_64_h__
16 
17 #if defined (__i386__) || defined (__x86_64__)
18 #include "DNBArch.h"
19 #include "../HasAVX.h"
20 #include "MachRegisterStatesX86_64.h"
21 
22 class MachThread;
23 
24 class DNBArchImplX86_64 : public DNBArchProtocol
25 {
26 public:
DNBArchImplX86_64(MachThread * thread)27     DNBArchImplX86_64(MachThread *thread) :
28         m_thread(thread),
29         m_state(),
30         m_2pc_dbg_checkpoint(),
31         m_2pc_trans_state(Trans_Done)
32     {
33     }
~DNBArchImplX86_64()34     virtual ~DNBArchImplX86_64()
35     {
36     }
37 
38     static  void            Initialize();
39     virtual bool            GetRegisterValue(int set, int reg, DNBRegisterValue *value);
40     virtual bool            SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
41     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
42     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
43 
44     virtual kern_return_t   GetRegisterState  (int set, bool force);
45     virtual kern_return_t   SetRegisterState  (int set);
46     virtual bool            RegisterSetStateIsValid (int set) const;
47 
48     virtual uint64_t        GetPC(uint64_t failValue);    // Get program counter
49     virtual kern_return_t   SetPC(uint64_t value);
50     virtual uint64_t        GetSP(uint64_t failValue);    // Get stack pointer
51     virtual void            ThreadWillResume();
52     virtual bool            ThreadDidStop();
53     virtual bool            NotifyException(MachException::Data& exc);
54 
55     virtual uint32_t        NumSupportedHardwareWatchpoints();
56     virtual uint32_t        EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task);
57     virtual bool            DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task);
58     virtual uint32_t        GetHardwareWatchpointHit(nub_addr_t &addr);
59 
60 protected:
61     kern_return_t           EnableHardwareSingleStep (bool enable);
62 
63     typedef __x86_64_thread_state_t GPR;
64     typedef __x86_64_float_state_t FPU;
65     typedef __x86_64_exception_state_t EXC;
66     typedef __x86_64_avx_state_t AVX;
67     typedef __x86_64_debug_state_t DBG;
68 
69     static const DNBRegisterInfo g_gpr_registers[];
70     static const DNBRegisterInfo g_fpu_registers_no_avx[];
71     static const DNBRegisterInfo g_fpu_registers_avx[];
72     static const DNBRegisterInfo g_exc_registers[];
73     static const DNBRegisterSetInfo g_reg_sets_no_avx[];
74     static const DNBRegisterSetInfo g_reg_sets_avx[];
75     static const size_t k_num_gpr_registers;
76     static const size_t k_num_fpu_registers_no_avx;
77     static const size_t k_num_fpu_registers_avx;
78     static const size_t k_num_exc_registers;
79     static const size_t k_num_all_registers_no_avx;
80     static const size_t k_num_all_registers_avx;
81     static const size_t k_num_register_sets;
82 
83     typedef enum RegisterSetTag
84     {
85         e_regSetALL = REGISTER_SET_ALL,
86         e_regSetGPR,
87         e_regSetFPU,
88         e_regSetEXC,
89         e_regSetDBG,
90         kNumRegisterSets
91     } RegisterSet;
92 
93     typedef enum RegisterSetWordSizeTag
94     {
95         e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int),
96         e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int),
97         e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int),
98         e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int),
99         e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int)
100     } RegisterSetWordSize;
101 
102     enum
103     {
104         Read = 0,
105         Write = 1,
106         kNumErrors = 2
107     };
108 
109     struct Context
110     {
111         GPR gpr;
112         union {
113             FPU no_avx;
114             AVX avx;
115         } fpu;
116         EXC exc;
117         DBG dbg;
118     };
119 
120     struct State
121     {
122         Context context;
123         kern_return_t gpr_errs[2];    // Read/Write errors
124         kern_return_t fpu_errs[2];    // Read/Write errors
125         kern_return_t exc_errs[2];    // Read/Write errors
126         kern_return_t dbg_errs[2];    // Read/Write errors
127 
StateState128         State()
129         {
130             uint32_t i;
131             for (i=0; i<kNumErrors; i++)
132             {
133                 gpr_errs[i] = -1;
134                 fpu_errs[i] = -1;
135                 exc_errs[i] = -1;
136                 dbg_errs[i] = -1;
137             }
138         }
139 
140         void
InvalidateAllRegisterStatesState141         InvalidateAllRegisterStates()
142         {
143             SetError (e_regSetALL, Read, -1);
144         }
145 
146         kern_return_t
GetErrorState147         GetError (int flavor, uint32_t err_idx) const
148         {
149             if (err_idx < kNumErrors)
150             {
151                 switch (flavor)
152                 {
153                 // When getting all errors, just OR all values together to see if
154                 // we got any kind of error.
155                 case e_regSetALL:    return gpr_errs[err_idx] |
156                                             fpu_errs[err_idx] |
157                                             exc_errs[err_idx];
158                 case e_regSetGPR:    return gpr_errs[err_idx];
159                 case e_regSetFPU:    return fpu_errs[err_idx];
160                 case e_regSetEXC:    return exc_errs[err_idx];
161                 case e_regSetDBG:    return dbg_errs[err_idx];
162                 default: break;
163                 }
164             }
165             return -1;
166         }
167 
168         bool
SetErrorState169         SetError (int flavor, uint32_t err_idx, kern_return_t err)
170         {
171             if (err_idx < kNumErrors)
172             {
173                 switch (flavor)
174                 {
175                 case e_regSetALL:
176                     gpr_errs[err_idx] =
177                     fpu_errs[err_idx] =
178                     exc_errs[err_idx] =
179                     dbg_errs[err_idx] = err;
180                     return true;
181 
182                 case e_regSetGPR:
183                     gpr_errs[err_idx] = err;
184                     return true;
185 
186                 case e_regSetFPU:
187                     fpu_errs[err_idx] = err;
188                     return true;
189 
190                 case e_regSetEXC:
191                     exc_errs[err_idx] = err;
192                     return true;
193 
194                 case e_regSetDBG:
195                     dbg_errs[err_idx] = err;
196                     return true;
197 
198                 default: break;
199                 }
200             }
201             return false;
202         }
203 
204         bool
RegsAreValidState205         RegsAreValid (int flavor) const
206         {
207             return GetError(flavor, Read) == KERN_SUCCESS;
208         }
209     };
210 
211     kern_return_t GetGPRState (bool force);
212     kern_return_t GetFPUState (bool force);
213     kern_return_t GetEXCState (bool force);
214     kern_return_t GetDBGState (bool force);
215 
216     kern_return_t SetGPRState ();
217     kern_return_t SetFPUState ();
218     kern_return_t SetEXCState ();
219     kern_return_t SetDBGState (bool also_set_on_task);
220 
221     static DNBArchProtocol *
222     Create (MachThread *thread);
223 
224     static const uint8_t * const
225     SoftwareBreakpointOpcode (nub_size_t byte_size);
226 
227     static const DNBRegisterSetInfo *
228     GetRegisterSetInfo(nub_size_t *num_reg_sets);
229 
230     // Helper functions for watchpoint manipulations.
231     static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write);
232     static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index);
233     static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index);
234     static void ClearWatchpointHits(DBG &debug_state);
235     static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index);
236     static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index);
237 
238     virtual bool StartTransForHWP();
239     virtual bool RollbackTransForHWP();
240     virtual bool FinishTransForHWP();
241     DBG GetDBGCheckpoint();
242 
243     MachThread *m_thread;
244     State       m_state;
245     DBG         m_2pc_dbg_checkpoint;
246     uint32_t    m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)?
247 };
248 
249 #endif    // #if defined (__i386__) || defined (__x86_64__)
250 #endif    // #ifndef __DNBArchImplX86_64_h__
251