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