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