1 //===-- DataEncoder.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/Utility/DataEncoder.h"
10 
11 #include "lldb/Utility/DataBufferHeap.h"
12 #include "lldb/Utility/Endian.h"
13 
14 #include "llvm/Support/Endian.h"
15 #include "llvm/Support/ErrorHandling.h"
16 
17 #include <cstddef>
18 
19 #include <cstring>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace llvm::support::endian;
24 
25 DataEncoder::DataEncoder()
26     : m_data_sp(new DataBufferHeap()), m_byte_order(endian::InlHostByteOrder()),
27       m_addr_size(sizeof(void *)) {}
28 
29 DataEncoder::DataEncoder(const void *data, uint32_t length, ByteOrder endian,
30                          uint8_t addr_size)
31     : m_data_sp(new DataBufferHeap(data, length)), m_byte_order(endian),
32       m_addr_size(addr_size) {}
33 
34 DataEncoder::DataEncoder(ByteOrder endian, uint8_t addr_size)
35     : m_data_sp(new DataBufferHeap()), m_byte_order(endian),
36       m_addr_size(addr_size) {}
37 
38 DataEncoder::~DataEncoder() = default;
39 
40 llvm::ArrayRef<uint8_t> DataEncoder::GetData() const {
41   return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), GetByteSize());
42 }
43 
44 size_t DataEncoder::GetByteSize() const { return m_data_sp->GetByteSize(); }
45 
46 // Extract a single unsigned char from the binary data and update the offset
47 // pointed to by "offset_ptr".
48 //
49 // RETURNS the byte that was extracted, or zero on failure.
50 uint32_t DataEncoder::PutU8(uint32_t offset, uint8_t value) {
51   if (ValidOffset(offset)) {
52     m_data_sp->GetBytes()[offset] = value;
53     return offset + 1;
54   }
55   return UINT32_MAX;
56 }
57 
58 uint32_t DataEncoder::PutU16(uint32_t offset, uint16_t value) {
59   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
60     if (m_byte_order != endian::InlHostByteOrder())
61       write16be(m_data_sp->GetBytes() + offset, value);
62     else
63       write16le(m_data_sp->GetBytes() + offset, value);
64 
65     return offset + sizeof(value);
66   }
67   return UINT32_MAX;
68 }
69 
70 uint32_t DataEncoder::PutU32(uint32_t offset, uint32_t value) {
71   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
72     if (m_byte_order != endian::InlHostByteOrder())
73       write32be(m_data_sp->GetBytes() + offset, value);
74     else
75       write32le(m_data_sp->GetBytes() + offset, value);
76 
77     return offset + sizeof(value);
78   }
79   return UINT32_MAX;
80 }
81 
82 uint32_t DataEncoder::PutU64(uint32_t offset, uint64_t value) {
83   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
84     if (m_byte_order != endian::InlHostByteOrder())
85       write64be(m_data_sp->GetBytes() + offset, value);
86     else
87       write64le(m_data_sp->GetBytes() + offset, value);
88 
89     return offset + sizeof(value);
90   }
91   return UINT32_MAX;
92 }
93 
94 uint32_t DataEncoder::PutUnsigned(uint32_t offset, uint32_t byte_size,
95                                   uint64_t value) {
96   switch (byte_size) {
97   case 1:
98     return PutU8(offset, value);
99   case 2:
100     return PutU16(offset, value);
101   case 4:
102     return PutU32(offset, value);
103   case 8:
104     return PutU64(offset, value);
105   default:
106     llvm_unreachable("GetMax64 unhandled case!");
107   }
108   return UINT32_MAX;
109 }
110 
111 uint32_t DataEncoder::PutData(uint32_t offset, const void *src,
112                               uint32_t src_len) {
113   if (src == nullptr || src_len == 0)
114     return offset;
115 
116   if (ValidOffsetForDataOfSize(offset, src_len)) {
117     memcpy(m_data_sp->GetBytes() + offset, src, src_len);
118     return offset + src_len;
119   }
120   return UINT32_MAX;
121 }
122 
123 uint32_t DataEncoder::PutAddress(uint32_t offset, lldb::addr_t addr) {
124   return PutUnsigned(offset, m_addr_size, addr);
125 }
126 
127 uint32_t DataEncoder::PutCString(uint32_t offset, const char *cstr) {
128   if (cstr != nullptr)
129     return PutData(offset, cstr, strlen(cstr) + 1);
130   return UINT32_MAX;
131 }
132 
133 void DataEncoder::AppendU8(uint8_t value) {
134   m_data_sp->AppendData(&value, sizeof(value));
135 }
136 
137 void DataEncoder::AppendU16(uint16_t value) {
138   uint32_t offset = m_data_sp->GetByteSize();
139   m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
140   PutU16(offset, value);
141 }
142 
143 void DataEncoder::AppendU32(uint32_t value) {
144   uint32_t offset = m_data_sp->GetByteSize();
145   m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
146   PutU32(offset, value);
147 }
148 
149 void DataEncoder::AppendU64(uint64_t value) {
150   uint32_t offset = m_data_sp->GetByteSize();
151   m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
152   PutU64(offset, value);
153 }
154 
155 void DataEncoder::AppendAddress(lldb::addr_t addr) {
156   switch (m_addr_size) {
157   case 4:
158     AppendU32(addr);
159     break;
160   case 8:
161     AppendU64(addr);
162     break;
163   default:
164     llvm_unreachable("AppendAddress unhandled case!");
165   }
166 }
167 
168 void DataEncoder::AppendData(llvm::StringRef data) {
169   const char *bytes = data.data();
170   const size_t length = data.size();
171   if (bytes && length > 0)
172     m_data_sp->AppendData(bytes, length);
173 }
174 
175 void DataEncoder::AppendData(llvm::ArrayRef<uint8_t> data) {
176   const uint8_t *bytes = data.data();
177   const size_t length = data.size();
178   if (bytes && length > 0)
179     m_data_sp->AppendData(bytes, length);
180 }
181 
182 void DataEncoder::AppendCString(llvm::StringRef data) {
183   const char *bytes = data.data();
184   const size_t length = data.size();
185   if (bytes) {
186     if (length > 0)
187       m_data_sp->AppendData(bytes, length);
188     if (length == 0 || bytes[length - 1] != '\0')
189       AppendU8(0);
190   }
191 }
192