1254721Semaste//===-- Opcode.cpp ----------------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "lldb/Core/Opcode.h"
10254721Semaste
11321369Sdim#include "lldb/Utility/DataBufferHeap.h"
12321369Sdim#include "lldb/Utility/DataExtractor.h"
13321369Sdim#include "lldb/Utility/Endian.h"
14321369Sdim#include "lldb/Utility/Stream.h"
15344779Sdim#include "lldb/lldb-forward.h"
16309124Sdim
17344779Sdim#include <memory>
18254721Semaste
19344779Sdim#include <inttypes.h>
20321369Sdim
21254721Semasteusing namespace lldb;
22254721Semasteusing namespace lldb_private;
23254721Semaste
24314564Sdimint Opcode::Dump(Stream *s, uint32_t min_byte_width) {
25344779Sdim  const uint32_t previous_bytes = s->GetWrittenBytes();
26314564Sdim  switch (m_type) {
27314564Sdim  case Opcode::eTypeInvalid:
28344779Sdim    s->PutCString("<invalid>");
29314564Sdim    break;
30314564Sdim  case Opcode::eType8:
31344779Sdim    s->Printf("0x%2.2x", m_data.inst8);
32314564Sdim    break;
33314564Sdim  case Opcode::eType16:
34344779Sdim    s->Printf("0x%4.4x", m_data.inst16);
35314564Sdim    break;
36314564Sdim  case Opcode::eType16_2:
37314564Sdim  case Opcode::eType32:
38344779Sdim    s->Printf("0x%8.8x", m_data.inst32);
39314564Sdim    break;
40254721Semaste
41314564Sdim  case Opcode::eType64:
42344779Sdim    s->Printf("0x%16.16" PRIx64, m_data.inst64);
43314564Sdim    break;
44254721Semaste
45314564Sdim  case Opcode::eTypeBytes:
46314564Sdim    for (uint32_t i = 0; i < m_data.inst.length; ++i) {
47314564Sdim      if (i > 0)
48344779Sdim        s->PutChar(' ');
49344779Sdim      s->Printf("%2.2x", m_data.inst.bytes[i]);
50254721Semaste    }
51314564Sdim    break;
52314564Sdim  }
53258054Semaste
54344779Sdim  uint32_t bytes_written_so_far = s->GetWrittenBytes() - previous_bytes;
55344779Sdim  // Add spaces to make sure bytes display comes out even in case opcodes aren't
56344779Sdim  // all the same size.
57344779Sdim  if (bytes_written_so_far < min_byte_width)
58344779Sdim    s->Printf("%*s", min_byte_width - bytes_written_so_far, "");
59344779Sdim  return s->GetWrittenBytes() - previous_bytes;
60254721Semaste}
61254721Semaste
62314564Sdimlldb::ByteOrder Opcode::GetDataByteOrder() const {
63314564Sdim  if (m_byte_order != eByteOrderInvalid) {
64314564Sdim    return m_byte_order;
65314564Sdim  }
66314564Sdim  switch (m_type) {
67314564Sdim  case Opcode::eTypeInvalid:
68314564Sdim    break;
69314564Sdim  case Opcode::eType8:
70314564Sdim  case Opcode::eType16:
71314564Sdim  case Opcode::eType16_2:
72314564Sdim  case Opcode::eType32:
73314564Sdim  case Opcode::eType64:
74314564Sdim    return endian::InlHostByteOrder();
75314564Sdim  case Opcode::eTypeBytes:
76314564Sdim    break;
77314564Sdim  }
78314564Sdim  return eByteOrderInvalid;
79254721Semaste}
80254721Semaste
81314564Sdimuint32_t Opcode::GetData(DataExtractor &data) const {
82314564Sdim  uint32_t byte_size = GetByteSize();
83314564Sdim  uint8_t swap_buf[8];
84314564Sdim  const void *buf = nullptr;
85258054Semaste
86314564Sdim  if (byte_size > 0) {
87314564Sdim    if (!GetEndianSwap()) {
88314564Sdim      if (m_type == Opcode::eType16_2) {
89314564Sdim        // 32 bit thumb instruction, we need to sizzle this a bit
90314564Sdim        swap_buf[0] = m_data.inst.bytes[2];
91314564Sdim        swap_buf[1] = m_data.inst.bytes[3];
92314564Sdim        swap_buf[2] = m_data.inst.bytes[0];
93314564Sdim        swap_buf[3] = m_data.inst.bytes[1];
94314564Sdim        buf = swap_buf;
95314564Sdim      } else {
96314564Sdim        buf = GetOpcodeDataBytes();
97314564Sdim      }
98314564Sdim    } else {
99314564Sdim      switch (m_type) {
100314564Sdim      case Opcode::eTypeInvalid:
101314564Sdim        break;
102314564Sdim      case Opcode::eType8:
103314564Sdim        buf = GetOpcodeDataBytes();
104314564Sdim        break;
105314564Sdim      case Opcode::eType16:
106314564Sdim        *(uint16_t *)swap_buf = llvm::ByteSwap_16(m_data.inst16);
107314564Sdim        buf = swap_buf;
108314564Sdim        break;
109314564Sdim      case Opcode::eType16_2:
110314564Sdim        swap_buf[0] = m_data.inst.bytes[1];
111314564Sdim        swap_buf[1] = m_data.inst.bytes[0];
112314564Sdim        swap_buf[2] = m_data.inst.bytes[3];
113314564Sdim        swap_buf[3] = m_data.inst.bytes[2];
114314564Sdim        buf = swap_buf;
115314564Sdim        break;
116314564Sdim      case Opcode::eType32:
117314564Sdim        *(uint32_t *)swap_buf = llvm::ByteSwap_32(m_data.inst32);
118314564Sdim        buf = swap_buf;
119314564Sdim        break;
120314564Sdim      case Opcode::eType64:
121314564Sdim        *(uint32_t *)swap_buf = llvm::ByteSwap_64(m_data.inst64);
122314564Sdim        buf = swap_buf;
123314564Sdim        break;
124314564Sdim      case Opcode::eTypeBytes:
125314564Sdim        buf = GetOpcodeDataBytes();
126314564Sdim        break;
127314564Sdim      }
128254721Semaste    }
129314564Sdim  }
130314564Sdim  if (buf != nullptr) {
131314564Sdim    DataBufferSP buffer_sp;
132258054Semaste
133321369Sdim    buffer_sp = std::make_shared<DataBufferHeap>(buf, byte_size);
134314564Sdim    data.SetByteOrder(GetDataByteOrder());
135314564Sdim    data.SetData(buffer_sp);
136314564Sdim    return byte_size;
137314564Sdim  }
138314564Sdim  data.Clear();
139314564Sdim  return 0;
140254721Semaste}
141