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 <cassert>
18#include <cstdint>
19#include <cstring>
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() = default;
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<uint16_t>(V: m_data.inst16)
103 : m_data.inst16;
104 case Opcode::eType16_2:
105 break;
106 case Opcode::eType32:
107 break;
108 case Opcode::eType64:
109 break;
110 case Opcode::eTypeBytes:
111 break;
112 }
113 return invalid_opcode;
114 }
115
116 uint32_t GetOpcode32(uint32_t invalid_opcode = UINT32_MAX) const {
117 switch (m_type) {
118 case Opcode::eTypeInvalid:
119 break;
120 case Opcode::eType8:
121 return m_data.inst8;
122 case Opcode::eType16:
123 return GetEndianSwap() ? llvm::byteswap<uint16_t>(V: m_data.inst16)
124 : m_data.inst16;
125 case Opcode::eType16_2: // passthrough
126 case Opcode::eType32:
127 return GetEndianSwap() ? llvm::byteswap<uint32_t>(V: m_data.inst32)
128 : m_data.inst32;
129 case Opcode::eType64:
130 break;
131 case Opcode::eTypeBytes:
132 break;
133 }
134 return invalid_opcode;
135 }
136
137 uint64_t GetOpcode64(uint64_t invalid_opcode = UINT64_MAX) const {
138 switch (m_type) {
139 case Opcode::eTypeInvalid:
140 break;
141 case Opcode::eType8:
142 return m_data.inst8;
143 case Opcode::eType16:
144 return GetEndianSwap() ? llvm::byteswap<uint16_t>(V: m_data.inst16)
145 : m_data.inst16;
146 case Opcode::eType16_2: // passthrough
147 case Opcode::eType32:
148 return GetEndianSwap() ? llvm::byteswap<uint32_t>(V: m_data.inst32)
149 : m_data.inst32;
150 case Opcode::eType64:
151 return GetEndianSwap() ? llvm::byteswap<uint64_t>(V: m_data.inst64)
152 : m_data.inst64;
153 case Opcode::eTypeBytes:
154 break;
155 }
156 return invalid_opcode;
157 }
158
159 void SetOpcode8(uint8_t inst, lldb::ByteOrder order) {
160 m_type = eType8;
161 m_data.inst8 = inst;
162 m_byte_order = order;
163 }
164
165 void SetOpcode16(uint16_t inst, lldb::ByteOrder order) {
166 m_type = eType16;
167 m_data.inst16 = inst;
168 m_byte_order = order;
169 }
170
171 void SetOpcode16_2(uint32_t inst, lldb::ByteOrder order) {
172 m_type = eType16_2;
173 m_data.inst32 = inst;
174 m_byte_order = order;
175 }
176
177 void SetOpcode32(uint32_t inst, lldb::ByteOrder order) {
178 m_type = eType32;
179 m_data.inst32 = inst;
180 m_byte_order = order;
181 }
182
183 void SetOpcode64(uint64_t inst, lldb::ByteOrder order) {
184 m_type = eType64;
185 m_data.inst64 = inst;
186 m_byte_order = order;
187 }
188
189 void SetOpcodeBytes(const void *bytes, size_t length) {
190 if (bytes != nullptr && length > 0) {
191 m_type = eTypeBytes;
192 m_data.inst.length = length;
193 assert(length < sizeof(m_data.inst.bytes));
194 memcpy(dest: m_data.inst.bytes, src: bytes, n: length);
195 m_byte_order = lldb::eByteOrderInvalid;
196 } else {
197 m_type = eTypeInvalid;
198 m_data.inst.length = 0;
199 }
200 }
201
202 int Dump(Stream *s, uint32_t min_byte_width);
203
204 const void *GetOpcodeBytes() const {
205 return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr);
206 }
207
208 uint32_t GetByteSize() const {
209 switch (m_type) {
210 case Opcode::eTypeInvalid:
211 break;
212 case Opcode::eType8:
213 return sizeof(m_data.inst8);
214 case Opcode::eType16:
215 return sizeof(m_data.inst16);
216 case Opcode::eType16_2: // passthrough
217 case Opcode::eType32:
218 return sizeof(m_data.inst32);
219 case Opcode::eType64:
220 return sizeof(m_data.inst64);
221 case Opcode::eTypeBytes:
222 return m_data.inst.length;
223 }
224 return 0;
225 }
226
227 // Get the opcode exactly as it would be laid out in memory.
228 uint32_t GetData(DataExtractor &data) const;
229
230protected:
231 friend class lldb::SBInstruction;
232
233 const void *GetOpcodeDataBytes() const {
234 switch (m_type) {
235 case Opcode::eTypeInvalid:
236 break;
237 case Opcode::eType8:
238 return &m_data.inst8;
239 case Opcode::eType16:
240 return &m_data.inst16;
241 case Opcode::eType16_2: // passthrough
242 case Opcode::eType32:
243 return &m_data.inst32;
244 case Opcode::eType64:
245 return &m_data.inst64;
246 case Opcode::eTypeBytes:
247 return m_data.inst.bytes;
248 }
249 return nullptr;
250 }
251
252 lldb::ByteOrder GetDataByteOrder() const;
253
254 bool GetEndianSwap() const {
255 return (m_byte_order == lldb::eByteOrderBig &&
256 endian::InlHostByteOrder() == lldb::eByteOrderLittle) ||
257 (m_byte_order == lldb::eByteOrderLittle &&
258 endian::InlHostByteOrder() == lldb::eByteOrderBig);
259 }
260
261 lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid;
262
263 Opcode::Type m_type = eTypeInvalid;
264 union {
265 uint8_t inst8;
266 uint16_t inst16;
267 uint32_t inst32;
268 uint64_t inst64;
269 struct {
270 uint8_t bytes[16]; // This must be big enough to handle any opcode for any
271 // supported target.
272 uint8_t length;
273 } inst;
274 } m_data;
275};
276
277} // namespace lldb_private
278
279#endif // LLDB_CORE_OPCODE_H
280

source code of lldb/include/lldb/Core/Opcode.h