/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Core/Opcode.h
Line | Count | Source (jump to first uncovered line) |
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 | | eType32, |
37 | | eType64, |
38 | | eTypeBytes |
39 | | }; |
40 | | |
41 | 980k | Opcode() = default; |
42 | | |
43 | | Opcode(uint8_t inst, lldb::ByteOrder order) |
44 | 0 | : m_byte_order(order), m_type(eType8) { |
45 | 0 | m_data.inst8 = inst; |
46 | 0 | } |
47 | | |
48 | | Opcode(uint16_t inst, lldb::ByteOrder order) |
49 | 0 | : m_byte_order(order), m_type(eType16) { |
50 | 0 | m_data.inst16 = inst; |
51 | 0 | } |
52 | | |
53 | | Opcode(uint32_t inst, lldb::ByteOrder order) |
54 | 0 | : m_byte_order(order), m_type(eType32) { |
55 | 0 | m_data.inst32 = inst; |
56 | 0 | } |
57 | | |
58 | | Opcode(uint64_t inst, lldb::ByteOrder order) |
59 | 0 | : m_byte_order(order), m_type(eType64) { |
60 | 0 | m_data.inst64 = inst; |
61 | 0 | } |
62 | | |
63 | | Opcode(uint8_t *bytes, size_t length) |
64 | 0 | : m_byte_order(lldb::eByteOrderInvalid) { |
65 | 0 | SetOpcodeBytes(bytes, length); |
66 | 0 | } |
67 | | |
68 | 246 | void Clear() { |
69 | 246 | m_byte_order = lldb::eByteOrderInvalid; |
70 | 246 | m_type = Opcode::eTypeInvalid; |
71 | 246 | } |
72 | | |
73 | 6.04k | Opcode::Type GetType() const { return m_type; } |
74 | | |
75 | 0 | uint8_t GetOpcode8(uint8_t invalid_opcode = UINT8_MAX) const { |
76 | 0 | switch (m_type) { |
77 | 0 | case Opcode::eTypeInvalid: |
78 | 0 | break; |
79 | 0 | case Opcode::eType8: |
80 | 0 | return m_data.inst8; |
81 | 0 | case Opcode::eType16: |
82 | 0 | break; |
83 | 0 | case Opcode::eType16_2: |
84 | 0 | break; |
85 | 0 | case Opcode::eType32: |
86 | 0 | break; |
87 | 0 | case Opcode::eType64: |
88 | 0 | break; |
89 | 0 | case Opcode::eTypeBytes: |
90 | 0 | break; |
91 | 0 | } |
92 | 0 | return invalid_opcode; |
93 | 0 | } |
94 | | |
95 | 0 | uint16_t GetOpcode16(uint16_t invalid_opcode = UINT16_MAX) const { |
96 | 0 | switch (m_type) { |
97 | 0 | case Opcode::eTypeInvalid: |
98 | 0 | break; |
99 | 0 | case Opcode::eType8: |
100 | 0 | return m_data.inst8; |
101 | 0 | case Opcode::eType16: |
102 | 0 | return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16) |
103 | 0 | : m_data.inst16; |
104 | 0 | case Opcode::eType16_2: |
105 | 0 | break; |
106 | 0 | case Opcode::eType32: |
107 | 0 | break; |
108 | 0 | case Opcode::eType64: |
109 | 0 | break; |
110 | 0 | case Opcode::eTypeBytes: |
111 | 0 | break; |
112 | 0 | } |
113 | 0 | return invalid_opcode; |
114 | 0 | } |
115 | | |
116 | 490 | uint32_t GetOpcode32(uint32_t invalid_opcode = UINT32_MAX) const { |
117 | 490 | switch (m_type) { |
118 | 0 | case Opcode::eTypeInvalid: |
119 | 0 | break; |
120 | 0 | case Opcode::eType8: |
121 | 0 | return m_data.inst8; |
122 | 138 | case Opcode::eType16: |
123 | 138 | return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16)0 |
124 | 138 | : m_data.inst16; |
125 | 20 | case Opcode::eType16_2: // passthrough |
126 | 352 | case Opcode::eType32: |
127 | 352 | return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32)0 |
128 | 352 | : m_data.inst32; |
129 | 0 | case Opcode::eType64: |
130 | 0 | break; |
131 | 0 | case Opcode::eTypeBytes: |
132 | 0 | break; |
133 | 490 | } |
134 | 0 | return invalid_opcode; |
135 | 490 | } |
136 | | |
137 | 0 | uint64_t GetOpcode64(uint64_t invalid_opcode = UINT64_MAX) const { |
138 | 0 | switch (m_type) { |
139 | 0 | case Opcode::eTypeInvalid: |
140 | 0 | break; |
141 | 0 | case Opcode::eType8: |
142 | 0 | return m_data.inst8; |
143 | 0 | case Opcode::eType16: |
144 | 0 | return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16) |
145 | 0 | : m_data.inst16; |
146 | 0 | case Opcode::eType16_2: // passthrough |
147 | 0 | case Opcode::eType32: |
148 | 0 | return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32) |
149 | 0 | : m_data.inst32; |
150 | 0 | case Opcode::eType64: |
151 | 0 | return GetEndianSwap() ? llvm::byteswap<uint64_t>(m_data.inst64) |
152 | 0 | : m_data.inst64; |
153 | 0 | case Opcode::eTypeBytes: |
154 | 0 | break; |
155 | 0 | } |
156 | 0 | return invalid_opcode; |
157 | 0 | } |
158 | | |
159 | 0 | void SetOpcode8(uint8_t inst, lldb::ByteOrder order) { |
160 | 0 | m_type = eType8; |
161 | 0 | m_data.inst8 = inst; |
162 | 0 | m_byte_order = order; |
163 | 0 | } |
164 | | |
165 | 72 | void SetOpcode16(uint16_t inst, lldb::ByteOrder order) { |
166 | 72 | m_type = eType16; |
167 | 72 | m_data.inst16 = inst; |
168 | 72 | m_byte_order = order; |
169 | 72 | } |
170 | | |
171 | 12 | void SetOpcode16_2(uint32_t inst, lldb::ByteOrder order) { |
172 | 12 | m_type = eType16_2; |
173 | 12 | m_data.inst32 = inst; |
174 | 12 | m_byte_order = order; |
175 | 12 | } |
176 | | |
177 | 342 | void SetOpcode32(uint32_t inst, lldb::ByteOrder order) { |
178 | 342 | m_type = eType32; |
179 | 342 | m_data.inst32 = inst; |
180 | 342 | m_byte_order = order; |
181 | 342 | } |
182 | | |
183 | 0 | void SetOpcode64(uint64_t inst, lldb::ByteOrder order) { |
184 | 0 | m_type = eType64; |
185 | 0 | m_data.inst64 = inst; |
186 | 0 | m_byte_order = order; |
187 | 0 | } |
188 | | |
189 | 979k | void SetOpcodeBytes(const void *bytes, size_t length) { |
190 | 979k | if (bytes != nullptr && length > 0) { |
191 | 979k | m_type = eTypeBytes; |
192 | 979k | m_data.inst.length = length; |
193 | 979k | assert(length < sizeof(m_data.inst.bytes)); |
194 | 979k | memcpy(m_data.inst.bytes, bytes, length); |
195 | 979k | m_byte_order = lldb::eByteOrderInvalid; |
196 | 979k | } else { |
197 | 0 | m_type = eTypeInvalid; |
198 | 0 | m_data.inst.length = 0; |
199 | 0 | } |
200 | 979k | } |
201 | | |
202 | | int Dump(Stream *s, uint32_t min_byte_width); |
203 | | |
204 | 12.1k | const void *GetOpcodeBytes() const { |
205 | 12.1k | return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr0 ); |
206 | 12.1k | } |
207 | | |
208 | 2.94M | uint32_t GetByteSize() const { |
209 | 2.94M | switch (m_type) { |
210 | 246 | case Opcode::eTypeInvalid: |
211 | 246 | break; |
212 | 0 | case Opcode::eType8: |
213 | 0 | return sizeof(m_data.inst8); |
214 | 147 | case Opcode::eType16: |
215 | 147 | return sizeof(m_data.inst16); |
216 | 38 | case Opcode::eType16_2: // passthrough |
217 | 786 | case Opcode::eType32: |
218 | 786 | return sizeof(m_data.inst32); |
219 | 0 | case Opcode::eType64: |
220 | 0 | return sizeof(m_data.inst64); |
221 | 2.94M | case Opcode::eTypeBytes: |
222 | 2.94M | return m_data.inst.length; |
223 | 2.94M | } |
224 | 246 | return 0; |
225 | 2.94M | } |
226 | | |
227 | | // Get the opcode exactly as it would be laid out in memory. |
228 | | uint32_t GetData(DataExtractor &data) const; |
229 | | |
230 | | protected: |
231 | | friend class lldb::SBInstruction; |
232 | | |
233 | 977k | const void *GetOpcodeDataBytes() const { |
234 | 977k | switch (m_type) { |
235 | 0 | case Opcode::eTypeInvalid: |
236 | 0 | break; |
237 | 0 | case Opcode::eType8: |
238 | 0 | return &m_data.inst8; |
239 | 5 | case Opcode::eType16: |
240 | 5 | return &m_data.inst16; |
241 | 0 | case Opcode::eType16_2: // passthrough |
242 | 99 | case Opcode::eType32: |
243 | 99 | return &m_data.inst32; |
244 | 0 | case Opcode::eType64: |
245 | 0 | return &m_data.inst64; |
246 | 977k | case Opcode::eTypeBytes: |
247 | 977k | return m_data.inst.bytes; |
248 | 977k | } |
249 | 0 | return nullptr; |
250 | 977k | } |
251 | | |
252 | | lldb::ByteOrder GetDataByteOrder() const; |
253 | | |
254 | 978k | bool GetEndianSwap() const { |
255 | 978k | return (m_byte_order == lldb::eByteOrderBig && |
256 | 978k | endian::InlHostByteOrder() == lldb::eByteOrderLittle0 ) || |
257 | 978k | (m_byte_order == lldb::eByteOrderLittle && |
258 | 978k | endian::InlHostByteOrder() == lldb::eByteOrderBig601 ); |
259 | 978k | } |
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 |