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
21namespace lldb {
22class SBInstruction;
23}
24
25namespace lldb_private {
26class DataExtractor;
27class Stream;
28
29class Opcode {
30public:
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 GetData(DataExtractor &data) const;
223
224protected:
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