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
22class MachThread;
23
24class DNBArchImplX86_64 : public DNBArchProtocol
25{
26public:
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    }
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
60protected:
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
128        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
141        InvalidateAllRegisterStates()
142        {
143            SetError (e_regSetALL, Read, -1);
144        }
145
146        kern_return_t
147        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
169        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
205        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