xref: /freebsd/contrib/llvm-project/lldb/source/Core/Opcode.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
21 using namespace lldb;
22 using namespace lldb_private;
23 
Dump(Stream * s,uint32_t min_byte_width) const24 int 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("<invalid>");
29     break;
30   case Opcode::eType8:
31     s->Printf("0x%2.2x", m_data.inst8);
32     break;
33   case Opcode::eType16:
34     s->Printf("0x%4.4x", m_data.inst16);
35     break;
36   case Opcode::eType16_2:
37   case Opcode::eType32:
38     s->Printf("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(' ');
47       if (format_as_words) {
48         // Format as words; print 1 or more UInt32 values.
49         s->Printf("%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("%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("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(' ');
70       s->Printf("%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("%*s", min_byte_width - bytes_written_so_far, "");
80   return s->GetWrittenBytes() - previous_bytes;
81 }
82 
GetDataByteOrder() const83 lldb::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 
GetData(DataExtractor & data) const103 uint32_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>(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>(m_data.inst32);
143         buf = swap_buf;
144         break;
145       case Opcode::eType64:
146         *(uint32_t *)swap_buf = llvm::byteswap<uint64_t>(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>(buf, byte_size);
159     data.SetByteOrder(GetDataByteOrder());
160     data.SetData(buffer_sp);
161     return byte_size;
162   }
163   data.Clear();
164   return 0;
165 }
166