Opcode.h revision 269024
1//===-- Opcode.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#ifndef lldb_Opcode_h
11#define lldb_Opcode_h
12
13// C Includes
14#include <string.h>
15
16// C++ Includes
17// Other libraries and framework includes
18#include "llvm/Support/MathExtras.h"
19// Project includes
20#include "lldb/Host/Endian.h"
21#include "lldb/lldb-public.h"
22
23namespace lldb
24{
25    class SBInstruction;
26}
27
28namespace lldb_private {
29
30    class Opcode
31    {
32    public:
33        enum Type
34        {
35            eTypeInvalid,
36            eType8,
37            eType16,
38            eType16_2, // a 32-bit Thumb instruction, made up of two words
39            eType32,
40            eType64,
41            eTypeBytes
42        };
43
44        Opcode () : m_byte_order (lldb::eByteOrderInvalid), m_type (eTypeInvalid)
45        {
46        }
47
48        Opcode (uint8_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType8)
49        {
50            m_data.inst8 = inst;
51        }
52
53        Opcode (uint16_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType16)
54        {
55            m_data.inst16 = inst;
56        }
57
58        Opcode (uint32_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType32)
59        {
60            m_data.inst32 = inst;
61        }
62
63        Opcode (uint64_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType64)
64        {
65            m_data.inst64 = inst;
66        }
67
68        Opcode (uint8_t *bytes, size_t length) : m_byte_order (lldb::eByteOrderInvalid)
69        {
70            SetOpcodeBytes (bytes, length);
71        }
72
73        void
74        Clear()
75        {
76            m_byte_order = lldb::eByteOrderInvalid;
77            m_type = Opcode::eTypeInvalid;
78        }
79        Opcode::Type
80        GetType () const
81        {
82            return m_type;
83        }
84
85        uint8_t
86        GetOpcode8 (uint8_t invalid_opcode = UINT8_MAX) const
87        {
88            switch (m_type)
89            {
90            case Opcode::eTypeInvalid:  break;
91            case Opcode::eType8:        return m_data.inst8;
92            case Opcode::eType16:       break;
93            case Opcode::eType16_2:     break;
94            case Opcode::eType32:       break;
95            case Opcode::eType64:       break;
96            case Opcode::eTypeBytes:    break;
97            }
98            return invalid_opcode;
99        }
100
101        uint16_t
102        GetOpcode16 (uint16_t invalid_opcode = UINT16_MAX) const
103        {
104            switch (m_type)
105            {
106            case Opcode::eTypeInvalid:  break;
107            case Opcode::eType8:        return m_data.inst8;
108            case Opcode::eType16:       return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16;
109            case Opcode::eType16_2:     break;
110            case Opcode::eType32:       break;
111            case Opcode::eType64:       break;
112            case Opcode::eTypeBytes:    break;
113            }
114            return invalid_opcode;
115        }
116
117        uint32_t
118        GetOpcode32 (uint32_t invalid_opcode = UINT32_MAX) const
119        {
120            switch (m_type)
121            {
122            case Opcode::eTypeInvalid:  break;
123            case Opcode::eType8:        return m_data.inst8;
124            case Opcode::eType16:       return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16;
125            case Opcode::eType16_2:     // passthrough
126            case Opcode::eType32:       return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32;
127            case Opcode::eType64:       break;
128            case Opcode::eTypeBytes:    break;
129            }
130            return invalid_opcode;
131        }
132
133        uint64_t
134        GetOpcode64 (uint64_t invalid_opcode = UINT64_MAX) const
135        {
136            switch (m_type)
137            {
138            case Opcode::eTypeInvalid:  break;
139            case Opcode::eType8:        return m_data.inst8;
140            case Opcode::eType16:       return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16;
141            case Opcode::eType16_2:     // passthrough
142            case Opcode::eType32:       return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32;
143            case Opcode::eType64:       return GetEndianSwap() ? llvm::ByteSwap_64(m_data.inst64) : m_data.inst64;
144            case Opcode::eTypeBytes:    break;
145            }
146            return invalid_opcode;
147        }
148
149        void
150        SetOpcode8 (uint8_t inst, lldb::ByteOrder order)
151        {
152            m_type = eType8;
153            m_data.inst8 = inst;
154            m_byte_order = order;
155        }
156
157        void
158        SetOpcode16 (uint16_t inst, lldb::ByteOrder order)
159        {
160            m_type = eType16;
161            m_data.inst16 = inst;
162            m_byte_order = order;
163        }
164
165        void
166        SetOpcode16_2 (uint32_t inst, lldb::ByteOrder order)
167        {
168            m_type = eType16_2;
169            m_data.inst32 = inst;
170            m_byte_order = order;
171        }
172
173        void
174        SetOpcode32 (uint32_t inst, lldb::ByteOrder order)
175        {
176            m_type = eType32;
177            m_data.inst32 = inst;
178            m_byte_order = order;
179        }
180
181        void
182        SetOpcode64 (uint64_t inst, lldb::ByteOrder order)
183        {
184            m_type = eType64;
185            m_data.inst64 = inst;
186            m_byte_order = order;
187        }
188
189        void
190        SetOpcodeBytes (const void *bytes, size_t length)
191        {
192            if (bytes && length > 0)
193            {
194                m_type = eTypeBytes;
195                m_data.inst.length = length;
196                assert (length < sizeof (m_data.inst.bytes));
197                memcpy (m_data.inst.bytes, bytes, length);
198                m_byte_order = lldb::eByteOrderInvalid;
199            }
200            else
201            {
202                m_type = eTypeInvalid;
203                m_data.inst.length = 0;
204            }
205        }
206
207        int
208        Dump (Stream *s, uint32_t min_byte_width);
209
210        const void *
211        GetOpcodeBytes () const
212        {
213            if (m_type == Opcode::eTypeBytes)
214                return m_data.inst.bytes;
215            return NULL;
216        }
217
218        uint32_t
219        GetByteSize () const
220        {
221            switch (m_type)
222            {
223            case Opcode::eTypeInvalid: break;
224            case Opcode::eType8:     return sizeof(m_data.inst8);
225            case Opcode::eType16:    return sizeof(m_data.inst16);
226            case Opcode::eType16_2:  // passthrough
227            case Opcode::eType32:    return sizeof(m_data.inst32);
228            case Opcode::eType64:    return sizeof(m_data.inst64);
229            case Opcode::eTypeBytes: return m_data.inst.length;
230            }
231            return 0;
232        }
233
234        // Get the opcode exactly as it would be laid out in memory.
235        uint32_t
236        GetData (DataExtractor &data) const;
237
238    protected:
239
240        friend class lldb::SBInstruction;
241
242        const void *
243        GetOpcodeDataBytes () const
244        {
245            switch (m_type)
246            {
247                case Opcode::eTypeInvalid: break;
248                case Opcode::eType8:     return &m_data.inst8;
249                case Opcode::eType16:    return &m_data.inst16;
250                case Opcode::eType16_2:  // passthrough
251                case Opcode::eType32:    return &m_data.inst32;
252                case Opcode::eType64:    return &m_data.inst64;
253                case Opcode::eTypeBytes: return m_data.inst.bytes;
254            }
255            return NULL;
256        }
257
258        lldb::ByteOrder
259        GetDataByteOrder () const;
260
261        bool
262        GetEndianSwap() const
263        {
264            return (m_byte_order == lldb::eByteOrderBig && lldb::endian::InlHostByteOrder() == lldb::eByteOrderLittle) ||
265                   (m_byte_order == lldb::eByteOrderLittle && lldb::endian::InlHostByteOrder() == lldb::eByteOrderBig);
266        }
267
268        lldb::ByteOrder m_byte_order;
269
270        Opcode::Type m_type;
271        union
272        {
273            uint8_t inst8;
274            uint16_t inst16;
275            uint32_t inst32;
276            uint64_t inst64;
277            struct
278            {
279                uint8_t bytes[16]; // This must be big enough to handle any opcode for any supported target.
280                uint8_t length;
281            } inst;
282        } m_data;
283    };
284
285} // namespace lldb_private
286
287#endif	// lldb_Opcode_h
288