Coverage Report

Created: 2023-09-21 18:56

/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