DNBArchImplI386.h revision 153191e36fcc528c393f0290a646d3f777a33695
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
54protected:
55    kern_return_t           EnableHardwareSingleStep (bool enable);
56
57    typedef __i386_thread_state_t GPR;
58    typedef __i386_float_state_t FPU;
59    typedef __i386_exception_state_t EXC;
60    typedef __i386_avx_state_t AVX;
61
62    static const DNBRegisterInfo g_gpr_registers[];
63    static const DNBRegisterInfo g_fpu_registers_no_avx[];
64    static const DNBRegisterInfo g_fpu_registers_avx[];
65    static const DNBRegisterInfo g_exc_registers[];
66    static const DNBRegisterSetInfo g_reg_sets_no_avx[];
67    static const DNBRegisterSetInfo g_reg_sets_avx[];
68    static const size_t k_num_gpr_registers;
69    static const size_t k_num_fpu_registers_no_avx;
70    static const size_t k_num_fpu_registers_avx;
71    static const size_t k_num_exc_registers;
72    static const size_t k_num_all_registers_no_avx;
73    static const size_t k_num_all_registers_avx;
74    static const size_t k_num_register_sets;
75
76    typedef enum RegisterSetTag
77    {
78        e_regSetALL = REGISTER_SET_ALL,
79        e_regSetGPR,
80        e_regSetFPU,
81        e_regSetEXC,
82        kNumRegisterSets
83    } RegisterSet;
84
85    typedef enum RegisterSetWordSizeTag
86    {
87        e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int),
88        e_regSetWordSizeFPR = sizeof(FPU) / sizeof(int),
89        e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int),
90        e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int)
91    } RegisterSetWordSize;
92
93    enum
94    {
95        Read = 0,
96        Write = 1,
97        kNumErrors = 2
98    };
99
100    struct Context
101    {
102        __i386_thread_state_t       gpr;
103        union {
104            __i386_float_state_t    no_avx;
105            __i386_avx_state_t      avx;
106        } fpu;
107        __i386_exception_state_t    exc;
108    };
109
110    struct State
111    {
112        Context context;
113        kern_return_t gpr_errs[2];    // Read/Write errors
114        kern_return_t fpu_errs[2];    // Read/Write errors
115        kern_return_t exc_errs[2];    // Read/Write errors
116
117        State()
118        {
119            uint32_t i;
120            for (i=0; i<kNumErrors; i++)
121            {
122                gpr_errs[i] = -1;
123                fpu_errs[i] = -1;
124                exc_errs[i] = -1;
125            }
126        }
127        void InvalidateAllRegisterStates()
128        {
129            SetError (e_regSetALL, Read, -1);
130        }
131        kern_return_t GetError (int flavor, uint32_t err_idx) const
132        {
133            if (err_idx < kNumErrors)
134            {
135                switch (flavor)
136                {
137                // When getting all errors, just OR all values together to see if
138                // we got any kind of error.
139                case e_regSetALL:    return gpr_errs[err_idx] |
140                                            fpu_errs[err_idx] |
141                                            exc_errs[err_idx];
142                case e_regSetGPR:    return gpr_errs[err_idx];
143                case e_regSetFPU:    return fpu_errs[err_idx];
144                case e_regSetEXC:    return exc_errs[err_idx];
145                default: break;
146                }
147            }
148            return -1;
149        }
150        bool SetError (int flavor, uint32_t err_idx, kern_return_t err)
151        {
152            if (err_idx < kNumErrors)
153            {
154                switch (flavor)
155                {
156                case e_regSetALL:
157                    gpr_errs[err_idx] =
158                    fpu_errs[err_idx] =
159                    exc_errs[err_idx] = err;
160                    return true;
161
162                case e_regSetGPR:
163                    gpr_errs[err_idx] = err;
164                    return true;
165
166                case e_regSetFPU:
167                    fpu_errs[err_idx] = err;
168                    return true;
169
170                case e_regSetEXC:
171                    exc_errs[err_idx] = err;
172                    return true;
173
174                default: break;
175                }
176            }
177            return false;
178        }
179        bool RegsAreValid (int flavor) const
180        {
181            return GetError(flavor, Read) == KERN_SUCCESS;
182        }
183    };
184
185    kern_return_t GetGPRState (bool force);
186    kern_return_t GetFPUState (bool force);
187    kern_return_t GetEXCState (bool force);
188
189    kern_return_t SetGPRState ();
190    kern_return_t SetFPUState ();
191    kern_return_t SetEXCState ();
192
193    static DNBArchProtocol *
194    Create (MachThread *thread);
195
196    static const uint8_t * const
197    SoftwareBreakpointOpcode (nub_size_t byte_size);
198
199    static const DNBRegisterSetInfo *
200    GetRegisterSetInfo(nub_size_t *num_reg_sets);
201
202    static bool
203    CPUHasAVX()
204    {
205#if 0
206        if (s_has_avx == kAVXUnknown)
207            s_has_avx = (::HasAVX() ? kAVXPresent : kAVXNotPresent);
208
209        return (s_has_avx == kAVXPresent);
210#else
211        // ::HasAVX() will cause this code to crash because the
212        // assembly function doesn't backup and restore the registers
213        // it uses. Until this is fixed, AVX will be disabled.
214        return 0;
215#endif
216    }
217
218    MachThread *m_thread;
219    State       m_state;
220
221    static enum AVXPresence {
222        kAVXPresent,
223        kAVXNotPresent,
224        kAVXUnknown
225    } s_has_avx;
226};
227
228#endif    // #if defined (__i386__) || defined (__x86_64__)
229#endif    // #ifndef __DNBArchImplI386_h__
230