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 Opcode() = default; 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<uint16_t>(m_data.inst16) 103 : m_data.inst16; 104 case Opcode::eType16_2: 105 break; 106 case Opcode::eType32: 107 break; 108 case Opcode::eType64: 109 break; 110 case Opcode::eTypeBytes: 111 break; 112 } 113 return invalid_opcode; 114 } 115 116 uint32_t GetOpcode32(uint32_t invalid_opcode = UINT32_MAX) const { 117 switch (m_type) { 118 case Opcode::eTypeInvalid: 119 break; 120 case Opcode::eType8: 121 return m_data.inst8; 122 case Opcode::eType16: 123 return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16) 124 : m_data.inst16; 125 case Opcode::eType16_2: // passthrough 126 case Opcode::eType32: 127 return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32) 128 : m_data.inst32; 129 case Opcode::eType64: 130 break; 131 case Opcode::eTypeBytes: 132 break; 133 } 134 return invalid_opcode; 135 } 136 137 uint64_t GetOpcode64(uint64_t invalid_opcode = UINT64_MAX) const { 138 switch (m_type) { 139 case Opcode::eTypeInvalid: 140 break; 141 case Opcode::eType8: 142 return m_data.inst8; 143 case Opcode::eType16: 144 return GetEndianSwap() ? llvm::byteswap<uint16_t>(m_data.inst16) 145 : m_data.inst16; 146 case Opcode::eType16_2: // passthrough 147 case Opcode::eType32: 148 return GetEndianSwap() ? llvm::byteswap<uint32_t>(m_data.inst32) 149 : m_data.inst32; 150 case Opcode::eType64: 151 return GetEndianSwap() ? llvm::byteswap<uint64_t>(m_data.inst64) 152 : m_data.inst64; 153 case Opcode::eTypeBytes: 154 break; 155 } 156 return invalid_opcode; 157 } 158 SetOpcode8(uint8_t inst,lldb::ByteOrder order)159 void SetOpcode8(uint8_t inst, lldb::ByteOrder order) { 160 m_type = eType8; 161 m_data.inst8 = inst; 162 m_byte_order = order; 163 } 164 SetOpcode16(uint16_t inst,lldb::ByteOrder order)165 void SetOpcode16(uint16_t inst, lldb::ByteOrder order) { 166 m_type = eType16; 167 m_data.inst16 = inst; 168 m_byte_order = order; 169 } 170 SetOpcode16_2(uint32_t inst,lldb::ByteOrder order)171 void SetOpcode16_2(uint32_t inst, lldb::ByteOrder order) { 172 m_type = eType16_2; 173 m_data.inst32 = inst; 174 m_byte_order = order; 175 } 176 SetOpcode32(uint32_t inst,lldb::ByteOrder order)177 void SetOpcode32(uint32_t inst, lldb::ByteOrder order) { 178 m_type = eType32; 179 m_data.inst32 = inst; 180 m_byte_order = order; 181 } 182 SetOpcode64(uint64_t inst,lldb::ByteOrder order)183 void SetOpcode64(uint64_t inst, lldb::ByteOrder order) { 184 m_type = eType64; 185 m_data.inst64 = inst; 186 m_byte_order = order; 187 } 188 SetOpcodeBytes(const void * bytes,size_t length)189 void SetOpcodeBytes(const void *bytes, size_t length) { 190 if (bytes != nullptr && length > 0) { 191 m_type = eTypeBytes; 192 m_data.inst.length = length; 193 assert(length < sizeof(m_data.inst.bytes)); 194 memcpy(m_data.inst.bytes, bytes, length); 195 m_byte_order = lldb::eByteOrderInvalid; 196 } else { 197 m_type = eTypeInvalid; 198 m_data.inst.length = 0; 199 } 200 } 201 202 int Dump(Stream *s, uint32_t min_byte_width); 203 GetOpcodeBytes()204 const void *GetOpcodeBytes() const { 205 return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr); 206 } 207 GetByteSize()208 uint32_t GetByteSize() const { 209 switch (m_type) { 210 case Opcode::eTypeInvalid: 211 break; 212 case Opcode::eType8: 213 return sizeof(m_data.inst8); 214 case Opcode::eType16: 215 return sizeof(m_data.inst16); 216 case Opcode::eType16_2: // passthrough 217 case Opcode::eType32: 218 return sizeof(m_data.inst32); 219 case Opcode::eType64: 220 return sizeof(m_data.inst64); 221 case Opcode::eTypeBytes: 222 return m_data.inst.length; 223 } 224 return 0; 225 } 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 GetOpcodeDataBytes()233 const void *GetOpcodeDataBytes() const { 234 switch (m_type) { 235 case Opcode::eTypeInvalid: 236 break; 237 case Opcode::eType8: 238 return &m_data.inst8; 239 case Opcode::eType16: 240 return &m_data.inst16; 241 case Opcode::eType16_2: // passthrough 242 case Opcode::eType32: 243 return &m_data.inst32; 244 case Opcode::eType64: 245 return &m_data.inst64; 246 case Opcode::eTypeBytes: 247 return m_data.inst.bytes; 248 } 249 return nullptr; 250 } 251 252 lldb::ByteOrder GetDataByteOrder() const; 253 GetEndianSwap()254 bool GetEndianSwap() const { 255 return (m_byte_order == lldb::eByteOrderBig && 256 endian::InlHostByteOrder() == lldb::eByteOrderLittle) || 257 (m_byte_order == lldb::eByteOrderLittle && 258 endian::InlHostByteOrder() == lldb::eByteOrderBig); 259 } 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 280