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