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) const {
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::eType16_32Tuples: {
42 const bool format_as_words = (m_data.inst.length % 4) == 0;
43 uint32_t i = 0;
44 while (i < m_data.inst.length) {
45 if (i > 0)
46 s->PutChar(ch: ' ');
47 if (format_as_words) {
48 // Format as words; print 1 or more UInt32 values.
49 s->Printf(format: "%2.2x%2.2x%2.2x%2.2x", m_data.inst.bytes[i + 3],
50 m_data.inst.bytes[i + 2], m_data.inst.bytes[i + 1],
51 m_data.inst.bytes[i + 0]);
52 i += 4;
53 } else {
54 // Format as halfwords; print 1 or more UInt16 values.
55 s->Printf(format: "%2.2x%2.2x", m_data.inst.bytes[i + 1],
56 m_data.inst.bytes[i + 0]);
57 i += 2;
58 }
59 }
60 } break;
61
62 case Opcode::eType64:
63 s->Printf(format: "0x%16.16" PRIx64, m_data.inst64);
64 break;
65
66 case Opcode::eTypeBytes:
67 for (uint32_t i = 0; i < m_data.inst.length; ++i) {
68 if (i > 0)
69 s->PutChar(ch: ' ');
70 s->Printf(format: "%2.2x", m_data.inst.bytes[i]);
71 }
72 break;
73 }
74
75 uint32_t bytes_written_so_far = s->GetWrittenBytes() - previous_bytes;
76 // Add spaces to make sure bytes display comes out even in case opcodes aren't
77 // all the same size.
78 if (bytes_written_so_far < min_byte_width)
79 s->Printf(format: "%*s", min_byte_width - bytes_written_so_far, "");
80 return s->GetWrittenBytes() - previous_bytes;
81}
82
83lldb::ByteOrder Opcode::GetDataByteOrder() const {
84 if (m_byte_order != eByteOrderInvalid) {
85 return m_byte_order;
86 }
87 switch (m_type) {
88 case Opcode::eTypeInvalid:
89 break;
90 case Opcode::eType8:
91 case Opcode::eType16:
92 case Opcode::eType16_2:
93 case Opcode::eType16_32Tuples:
94 case Opcode::eType32:
95 case Opcode::eType64:
96 return endian::InlHostByteOrder();
97 case Opcode::eTypeBytes:
98 break;
99 }
100 return eByteOrderInvalid;
101}
102
103uint32_t Opcode::GetData(DataExtractor &data) const {
104 uint32_t byte_size = GetByteSize();
105 uint8_t swap_buf[8];
106 const void *buf = nullptr;
107
108 if (byte_size > 0) {
109 if (!GetEndianSwap()) {
110 if (m_type == Opcode::eType16_2) {
111 // 32 bit thumb instruction, we need to sizzle this a bit
112 swap_buf[0] = m_data.inst.bytes[2];
113 swap_buf[1] = m_data.inst.bytes[3];
114 swap_buf[2] = m_data.inst.bytes[0];
115 swap_buf[3] = m_data.inst.bytes[1];
116 buf = swap_buf;
117 } else {
118 buf = GetOpcodeDataBytes();
119 }
120 } else {
121 switch (m_type) {
122 case Opcode::eTypeInvalid:
123 break;
124 case Opcode::eType8:
125 buf = GetOpcodeDataBytes();
126 break;
127 case Opcode::eType16:
128 *(uint16_t *)swap_buf = llvm::byteswap<uint16_t>(V: m_data.inst16);
129 buf = swap_buf;
130 break;
131 case Opcode::eType16_2:
132 swap_buf[0] = m_data.inst.bytes[1];
133 swap_buf[1] = m_data.inst.bytes[0];
134 swap_buf[2] = m_data.inst.bytes[3];
135 swap_buf[3] = m_data.inst.bytes[2];
136 buf = swap_buf;
137 break;
138 case Opcode::eType16_32Tuples:
139 buf = GetOpcodeDataBytes();
140 break;
141 case Opcode::eType32:
142 *(uint32_t *)swap_buf = llvm::byteswap<uint32_t>(V: m_data.inst32);
143 buf = swap_buf;
144 break;
145 case Opcode::eType64:
146 *(uint32_t *)swap_buf = llvm::byteswap<uint64_t>(V: m_data.inst64);
147 buf = swap_buf;
148 break;
149 case Opcode::eTypeBytes:
150 buf = GetOpcodeDataBytes();
151 break;
152 }
153 }
154 }
155 if (buf != nullptr) {
156 DataBufferSP buffer_sp;
157
158 buffer_sp = std::make_shared<DataBufferHeap>(args&: buf, args&: byte_size);
159 data.SetByteOrder(GetDataByteOrder());
160 data.SetData(data_sp: buffer_sp);
161 return byte_size;
162 }
163 data.Clear();
164 return 0;
165}
166

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