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