xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Core/Opcode.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
21 namespace lldb {
22 class SBInstruction;
23 }
24 
25 namespace lldb_private {
26 class DataExtractor;
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     eType16_32Tuples, // RISC-V that can have 2, 4, 6, 8 etc byte long
37                       // instructions which will be printed in combinations of
38                       // 16 & 32-bit words.
39     eType32,
40     eType64,
41     eTypeBytes
42   };
43 
44   Opcode() = default;
45 
Opcode(uint8_t inst,lldb::ByteOrder order)46   Opcode(uint8_t inst, lldb::ByteOrder order)
47       : m_byte_order(order), m_type(eType8) {
48     m_data.inst8 = inst;
49   }
50 
Opcode(uint16_t inst,lldb::ByteOrder order)51   Opcode(uint16_t inst, lldb::ByteOrder order)
52       : m_byte_order(order), m_type(eType16) {
53     m_data.inst16 = inst;
54   }
55 
Opcode(uint32_t inst,lldb::ByteOrder order)56   Opcode(uint32_t inst, lldb::ByteOrder order)
57       : m_byte_order(order), m_type(eType32) {
58     m_data.inst32 = inst;
59   }
60 
Opcode(uint64_t inst,lldb::ByteOrder order)61   Opcode(uint64_t inst, lldb::ByteOrder order)
62       : m_byte_order(order), m_type(eType64) {
63     m_data.inst64 = inst;
64   }
65 
Opcode(uint8_t * bytes,size_t length,Opcode::Type type,lldb::ByteOrder order)66   Opcode(uint8_t *bytes, size_t length, Opcode::Type type,
67          lldb::ByteOrder order) {
68     DoSetOpcodeBytes(bytes, length, type, order);
69   }
70 
Clear()71   void Clear() {
72     m_byte_order = lldb::eByteOrderInvalid;
73     m_type = Opcode::eTypeInvalid;
74   }
75 
GetType()76   Opcode::Type GetType() const { return m_type; }
77 
78   uint8_t GetOpcode8(uint8_t invalid_opcode = UINT8_MAX) const {
79     switch (m_type) {
80     case Opcode::eTypeInvalid:
81       break;
82     case Opcode::eType8:
83       return m_data.inst8;
84     case Opcode::eType16:
85       break;
86     case Opcode::eType16_2:
87       break;
88     case Opcode::eType16_32Tuples:
89       break;
90     case Opcode::eType32:
91       break;
92     case Opcode::eType64:
93       break;
94     case Opcode::eTypeBytes:
95       break;
96     }
97     return invalid_opcode;
98   }
99 
100   uint16_t GetOpcode16(uint16_t invalid_opcode = UINT16_MAX) const {
101     switch (m_type) {
102     case Opcode::eTypeInvalid:
103       break;
104     case Opcode::eType8:
105       return m_data.inst8;
106     case Opcode::eType16:
107       return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16)
108                              : m_data.inst16;
109     case Opcode::eType16_2:
110       break;
111     case Opcode::eType16_32Tuples:
112       break;
113     case Opcode::eType32:
114       break;
115     case Opcode::eType64:
116       break;
117     case Opcode::eTypeBytes:
118       break;
119     }
120     return invalid_opcode;
121   }
122 
123   uint32_t GetOpcode32(uint32_t invalid_opcode = UINT32_MAX) const {
124     switch (m_type) {
125     case Opcode::eTypeInvalid:
126       break;
127     case Opcode::eType8:
128       return m_data.inst8;
129     case Opcode::eType16:
130       return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16)
131                              : m_data.inst16;
132     case Opcode::eType16_32Tuples:
133       break;
134     case Opcode::eType16_2: // passthrough
135     case Opcode::eType32:
136       return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32)
137                              : m_data.inst32;
138     case Opcode::eType64:
139       break;
140     case Opcode::eTypeBytes:
141       break;
142     }
143     return invalid_opcode;
144   }
145 
146   uint64_t GetOpcode64(uint64_t invalid_opcode = UINT64_MAX) const {
147     switch (m_type) {
148     case Opcode::eTypeInvalid:
149       break;
150     case Opcode::eType8:
151       return m_data.inst8;
152     case Opcode::eType16:
153       return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16)
154                              : m_data.inst16;
155     case Opcode::eType16_32Tuples:
156       break;
157     case Opcode::eType16_2: // passthrough
158     case Opcode::eType32:
159       return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32)
160                              : m_data.inst32;
161     case Opcode::eType64:
162       return GetEndianSwap() ? llvm::byteswap<uint64_t>(m_data.inst64)
163                              : m_data.inst64;
164     case Opcode::eTypeBytes:
165       break;
166     }
167     return invalid_opcode;
168   }
169 
SetOpcode8(uint8_t inst,lldb::ByteOrder order)170   void SetOpcode8(uint8_t inst, lldb::ByteOrder order) {
171     m_type = eType8;
172     m_data.inst8 = inst;
173     m_byte_order = order;
174   }
175 
SetOpcode16(uint16_t inst,lldb::ByteOrder order)176   void SetOpcode16(uint16_t inst, lldb::ByteOrder order) {
177     m_type = eType16;
178     m_data.inst16 = inst;
179     m_byte_order = order;
180   }
181 
SetOpcode16_2(uint32_t inst,lldb::ByteOrder order)182   void SetOpcode16_2(uint32_t inst, lldb::ByteOrder order) {
183     m_type = eType16_2;
184     m_data.inst32 = inst;
185     m_byte_order = order;
186   }
187 
SetOpcode32(uint32_t inst,lldb::ByteOrder order)188   void SetOpcode32(uint32_t inst, lldb::ByteOrder order) {
189     m_type = eType32;
190     m_data.inst32 = inst;
191     m_byte_order = order;
192   }
193 
SetOpcode64(uint64_t inst,lldb::ByteOrder order)194   void SetOpcode64(uint64_t inst, lldb::ByteOrder order) {
195     m_type = eType64;
196     m_data.inst64 = inst;
197     m_byte_order = order;
198   }
199 
SetOpcode16_32TupleBytes(const void * bytes,size_t length,lldb::ByteOrder order)200   void SetOpcode16_32TupleBytes(const void *bytes, size_t length,
201                                 lldb::ByteOrder order) {
202     DoSetOpcodeBytes(bytes, length, eType16_32Tuples, order);
203   }
204 
SetOpcodeBytes(const void * bytes,size_t length)205   void SetOpcodeBytes(const void *bytes, size_t length) {
206     DoSetOpcodeBytes(bytes, length, eTypeBytes, lldb::eByteOrderInvalid);
207   }
208 
DoSetOpcodeBytes(const void * bytes,size_t length,Opcode::Type type,lldb::ByteOrder order)209   void DoSetOpcodeBytes(const void *bytes, size_t length, Opcode::Type type,
210                         lldb::ByteOrder order) {
211     if (bytes != nullptr && length > 0) {
212       m_type = type;
213       m_data.inst.length = length;
214       assert(length < sizeof(m_data.inst.bytes));
215       memcpy(m_data.inst.bytes, bytes, length);
216       m_byte_order = order;
217     } else {
218       m_type = eTypeInvalid;
219       m_data.inst.length = 0;
220     }
221   }
222 
223   int Dump(Stream *s, uint32_t min_byte_width) const;
224 
GetOpcodeBytes()225   const void *GetOpcodeBytes() const {
226     return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr);
227   }
228 
GetByteSize()229   uint32_t GetByteSize() const {
230     switch (m_type) {
231     case Opcode::eTypeInvalid:
232       break;
233     case Opcode::eType8:
234       return sizeof(m_data.inst8);
235     case Opcode::eType16:
236       return sizeof(m_data.inst16);
237     case Opcode::eType16_32Tuples:
238       return m_data.inst.length;
239     case Opcode::eType16_2: // passthrough
240     case Opcode::eType32:
241       return sizeof(m_data.inst32);
242     case Opcode::eType64:
243       return sizeof(m_data.inst64);
244     case Opcode::eTypeBytes:
245       return m_data.inst.length;
246     }
247     return 0;
248   }
249 
250   // Get the opcode exactly as it would be laid out in memory.
251   uint32_t GetData(DataExtractor &data) const;
252 
253 protected:
254   friend class lldb::SBInstruction;
255 
GetOpcodeDataBytes()256   const void *GetOpcodeDataBytes() const {
257     switch (m_type) {
258     case Opcode::eTypeInvalid:
259       break;
260     case Opcode::eType8:
261       return &m_data.inst8;
262     case Opcode::eType16:
263       return &m_data.inst16;
264     case Opcode::eType16_32Tuples:
265       return m_data.inst.bytes;
266     case Opcode::eType16_2: // passthrough
267     case Opcode::eType32:
268       return &m_data.inst32;
269     case Opcode::eType64:
270       return &m_data.inst64;
271     case Opcode::eTypeBytes:
272       return m_data.inst.bytes;
273     }
274     return nullptr;
275   }
276 
277   lldb::ByteOrder GetDataByteOrder() const;
278 
GetEndianSwap()279   bool GetEndianSwap() const {
280     return (m_byte_order == lldb::eByteOrderBig &&
281             endian::InlHostByteOrder() == lldb::eByteOrderLittle) ||
282            (m_byte_order == lldb::eByteOrderLittle &&
283             endian::InlHostByteOrder() == lldb::eByteOrderBig);
284   }
285 
286   lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid;
287 
288   Opcode::Type m_type = eTypeInvalid;
289   union {
290     uint8_t inst8;
291     uint16_t inst16;
292     uint32_t inst32;
293     uint64_t inst64;
294     struct {
295       uint8_t bytes[16]; // This must be big enough to handle any opcode for any
296                          // supported target.
297       uint8_t length;
298     } inst;
299   } m_data;
300 };
301 
302 } // namespace lldb_private
303 
304 #endif // LLDB_CORE_OPCODE_H
305