1//===-- Opcode.cpp --------------------------------------------------------===//
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#include "lldb/Core/Opcode.h"
10
11#include "lldb/Utility/DataBufferHeap.h"
12#include "lldb/Utility/DataExtractor.h"
13#include "lldb/Utility/Endian.h"
14#include "lldb/Utility/Stream.h"
15#include "lldb/lldb-forward.h"
16
17#include <memory>
18
19#include <cinttypes>
20
21using namespace lldb;
22using namespace lldb_private;
23
24int Opcode::Dump(Stream *s, uint32_t min_byte_width) {
25 const uint32_t previous_bytes = s->GetWrittenBytes();
26 switch (m_type) {
27 case Opcode::eTypeInvalid:
28 s->PutCString(cstr: "<invalid>");
29 break;
30 case Opcode::eType8:
31 s->Printf(format: "0x%2.2x", m_data.inst8);
32 break;
33 case Opcode::eType16:
34 s->Printf(format: "0x%4.4x", m_data.inst16);
35 break;
36 case Opcode::eType16_2:
37 case Opcode::eType32:
38 s->Printf(format: "0x%8.8x", m_data.inst32);
39 break;
40
41 case Opcode::eType64:
42 s->Printf(format: "0x%16.16" PRIx64, m_data.inst64);
43 break;
44
45 case Opcode::eTypeBytes:
46 for (uint32_t i = 0; i < m_data.inst.length; ++i) {
47 if (i > 0)
48 s->PutChar(ch: ' ');
49 s->Printf(format: "%2.2x", m_data.inst.bytes[i]);
50 }
51 break;
52 }
53
54 uint32_t bytes_written_so_far = s->GetWrittenBytes() - previous_bytes;
55 // Add spaces to make sure bytes display comes out even in case opcodes aren't
56 // all the same size.
57 if (bytes_written_so_far < min_byte_width)
58 s->Printf(format: "%*s", min_byte_width - bytes_written_so_far, "");
59 return s->GetWrittenBytes() - previous_bytes;
60}
61
62lldb::ByteOrder Opcode::GetDataByteOrder() const {
63 if (m_byte_order != eByteOrderInvalid) {
64 return m_byte_order;
65 }
66 switch (m_type) {
67 case Opcode::eTypeInvalid:
68 break;
69 case Opcode::eType8:
70 case Opcode::eType16:
71 case Opcode::eType16_2:
72 case Opcode::eType32:
73 case Opcode::eType64:
74 return endian::InlHostByteOrder();
75 case Opcode::eTypeBytes:
76 break;
77 }
78 return eByteOrderInvalid;
79}
80
81uint32_t Opcode::GetData(DataExtractor &data) const {
82 uint32_t byte_size = GetByteSize();
83 uint8_t swap_buf[8];
84 const void *buf = nullptr;
85
86 if (byte_size > 0) {
87 if (!GetEndianSwap()) {
88 if (m_type == Opcode::eType16_2) {
89 // 32 bit thumb instruction, we need to sizzle this a bit
90 swap_buf[0] = m_data.inst.bytes[2];
91 swap_buf[1] = m_data.inst.bytes[3];
92 swap_buf[2] = m_data.inst.bytes[0];
93 swap_buf[3] = m_data.inst.bytes[1];
94 buf = swap_buf;
95 } else {
96 buf = GetOpcodeDataBytes();
97 }
98 } else {
99 switch (m_type) {
100 case Opcode::eTypeInvalid:
101 break;
102 case Opcode::eType8:
103 buf = GetOpcodeDataBytes();
104 break;
105 case Opcode::eType16:
106 *(uint16_t *)swap_buf = llvm::byteswap<uint16_t>(V: m_data.inst16);
107 buf = swap_buf;
108 break;
109 case Opcode::eType16_2:
110 swap_buf[0] = m_data.inst.bytes[1];
111 swap_buf[1] = m_data.inst.bytes[0];
112 swap_buf[2] = m_data.inst.bytes[3];
113 swap_buf[3] = m_data.inst.bytes[2];
114 buf = swap_buf;
115 break;
116 case Opcode::eType32:
117 *(uint32_t *)swap_buf = llvm::byteswap<uint32_t>(V: m_data.inst32);
118 buf = swap_buf;
119 break;
120 case Opcode::eType64:
121 *(uint32_t *)swap_buf = llvm::byteswap<uint64_t>(V: m_data.inst64);
122 buf = swap_buf;
123 break;
124 case Opcode::eTypeBytes:
125 buf = GetOpcodeDataBytes();
126 break;
127 }
128 }
129 }
130 if (buf != nullptr) {
131 DataBufferSP buffer_sp;
132
133 buffer_sp = std::make_shared<DataBufferHeap>(args&: buf, args&: byte_size);
134 data.SetByteOrder(GetDataByteOrder());
135 data.SetData(data_sp: buffer_sp);
136 return byte_size;
137 }
138 data.Clear();
139 return 0;
140}
141

source code of lldb/source/Core/Opcode.cpp