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