15ffd83dbSDimitry Andric //===-- Opcode.cpp --------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Core/Opcode.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
120b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
130b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
140b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
150b57cec5SDimitry Andric #include "lldb/lldb-forward.h"
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #include <memory>
180b57cec5SDimitry Andric
19fe6060f1SDimitry Andric #include <cinttypes>
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace lldb;
220b57cec5SDimitry Andric using namespace lldb_private;
230b57cec5SDimitry Andric
Dump(Stream * s,uint32_t min_byte_width)240b57cec5SDimitry Andric int Opcode::Dump(Stream *s, uint32_t min_byte_width) {
250b57cec5SDimitry Andric const uint32_t previous_bytes = s->GetWrittenBytes();
260b57cec5SDimitry Andric switch (m_type) {
270b57cec5SDimitry Andric case Opcode::eTypeInvalid:
280b57cec5SDimitry Andric s->PutCString("<invalid>");
290b57cec5SDimitry Andric break;
300b57cec5SDimitry Andric case Opcode::eType8:
310b57cec5SDimitry Andric s->Printf("0x%2.2x", m_data.inst8);
320b57cec5SDimitry Andric break;
330b57cec5SDimitry Andric case Opcode::eType16:
340b57cec5SDimitry Andric s->Printf("0x%4.4x", m_data.inst16);
350b57cec5SDimitry Andric break;
360b57cec5SDimitry Andric case Opcode::eType16_2:
370b57cec5SDimitry Andric case Opcode::eType32:
380b57cec5SDimitry Andric s->Printf("0x%8.8x", m_data.inst32);
390b57cec5SDimitry Andric break;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric case Opcode::eType64:
420b57cec5SDimitry Andric s->Printf("0x%16.16" PRIx64, m_data.inst64);
430b57cec5SDimitry Andric break;
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric case Opcode::eTypeBytes:
460b57cec5SDimitry Andric for (uint32_t i = 0; i < m_data.inst.length; ++i) {
470b57cec5SDimitry Andric if (i > 0)
480b57cec5SDimitry Andric s->PutChar(' ');
490b57cec5SDimitry Andric s->Printf("%2.2x", m_data.inst.bytes[i]);
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric break;
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric uint32_t bytes_written_so_far = s->GetWrittenBytes() - previous_bytes;
550b57cec5SDimitry Andric // Add spaces to make sure bytes display comes out even in case opcodes aren't
560b57cec5SDimitry Andric // all the same size.
570b57cec5SDimitry Andric if (bytes_written_so_far < min_byte_width)
580b57cec5SDimitry Andric s->Printf("%*s", min_byte_width - bytes_written_so_far, "");
590b57cec5SDimitry Andric return s->GetWrittenBytes() - previous_bytes;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric
GetDataByteOrder() const620b57cec5SDimitry Andric lldb::ByteOrder Opcode::GetDataByteOrder() const {
630b57cec5SDimitry Andric if (m_byte_order != eByteOrderInvalid) {
640b57cec5SDimitry Andric return m_byte_order;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric switch (m_type) {
670b57cec5SDimitry Andric case Opcode::eTypeInvalid:
680b57cec5SDimitry Andric break;
690b57cec5SDimitry Andric case Opcode::eType8:
700b57cec5SDimitry Andric case Opcode::eType16:
710b57cec5SDimitry Andric case Opcode::eType16_2:
720b57cec5SDimitry Andric case Opcode::eType32:
730b57cec5SDimitry Andric case Opcode::eType64:
740b57cec5SDimitry Andric return endian::InlHostByteOrder();
750b57cec5SDimitry Andric case Opcode::eTypeBytes:
760b57cec5SDimitry Andric break;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric return eByteOrderInvalid;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric
GetData(DataExtractor & data) const810b57cec5SDimitry Andric uint32_t Opcode::GetData(DataExtractor &data) const {
820b57cec5SDimitry Andric uint32_t byte_size = GetByteSize();
830b57cec5SDimitry Andric uint8_t swap_buf[8];
840b57cec5SDimitry Andric const void *buf = nullptr;
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric if (byte_size > 0) {
870b57cec5SDimitry Andric if (!GetEndianSwap()) {
880b57cec5SDimitry Andric if (m_type == Opcode::eType16_2) {
890b57cec5SDimitry Andric // 32 bit thumb instruction, we need to sizzle this a bit
900b57cec5SDimitry Andric swap_buf[0] = m_data.inst.bytes[2];
910b57cec5SDimitry Andric swap_buf[1] = m_data.inst.bytes[3];
920b57cec5SDimitry Andric swap_buf[2] = m_data.inst.bytes[0];
930b57cec5SDimitry Andric swap_buf[3] = m_data.inst.bytes[1];
940b57cec5SDimitry Andric buf = swap_buf;
950b57cec5SDimitry Andric } else {
960b57cec5SDimitry Andric buf = GetOpcodeDataBytes();
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric } else {
990b57cec5SDimitry Andric switch (m_type) {
1000b57cec5SDimitry Andric case Opcode::eTypeInvalid:
1010b57cec5SDimitry Andric break;
1020b57cec5SDimitry Andric case Opcode::eType8:
1030b57cec5SDimitry Andric buf = GetOpcodeDataBytes();
1040b57cec5SDimitry Andric break;
1050b57cec5SDimitry Andric case Opcode::eType16:
106*06c3fb27SDimitry Andric *(uint16_t *)swap_buf = llvm::byteswap<uint16_t>(m_data.inst16);
1070b57cec5SDimitry Andric buf = swap_buf;
1080b57cec5SDimitry Andric break;
1090b57cec5SDimitry Andric case Opcode::eType16_2:
1100b57cec5SDimitry Andric swap_buf[0] = m_data.inst.bytes[1];
1110b57cec5SDimitry Andric swap_buf[1] = m_data.inst.bytes[0];
1120b57cec5SDimitry Andric swap_buf[2] = m_data.inst.bytes[3];
1130b57cec5SDimitry Andric swap_buf[3] = m_data.inst.bytes[2];
1140b57cec5SDimitry Andric buf = swap_buf;
1150b57cec5SDimitry Andric break;
1160b57cec5SDimitry Andric case Opcode::eType32:
117*06c3fb27SDimitry Andric *(uint32_t *)swap_buf = llvm::byteswap<uint32_t>(m_data.inst32);
1180b57cec5SDimitry Andric buf = swap_buf;
1190b57cec5SDimitry Andric break;
1200b57cec5SDimitry Andric case Opcode::eType64:
121*06c3fb27SDimitry Andric *(uint32_t *)swap_buf = llvm::byteswap<uint64_t>(m_data.inst64);
1220b57cec5SDimitry Andric buf = swap_buf;
1230b57cec5SDimitry Andric break;
1240b57cec5SDimitry Andric case Opcode::eTypeBytes:
1250b57cec5SDimitry Andric buf = GetOpcodeDataBytes();
1260b57cec5SDimitry Andric break;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric if (buf != nullptr) {
1310b57cec5SDimitry Andric DataBufferSP buffer_sp;
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric buffer_sp = std::make_shared<DataBufferHeap>(buf, byte_size);
1340b57cec5SDimitry Andric data.SetByteOrder(GetDataByteOrder());
1350b57cec5SDimitry Andric data.SetData(buffer_sp);
1360b57cec5SDimitry Andric return byte_size;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric data.Clear();
1390b57cec5SDimitry Andric return 0;
1400b57cec5SDimitry Andric }
141