1 //===-- DataEncoder.cpp -----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Utility/DataEncoder.h" 11 12 #include "lldb/Utility/DataBuffer.h" 13 #include "lldb/Utility/Endian.h" 14 15 #include "llvm/Support/MathExtras.h" 16 17 // C Includes 18 // C++ Includes 19 #include <cassert> 20 #include <cstddef> 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 static inline void WriteInt16(unsigned char *ptr, unsigned offset, 26 uint16_t value) { 27 *(uint16_t *)(ptr + offset) = value; 28 } 29 30 static inline void WriteInt32(unsigned char *ptr, unsigned offset, 31 uint32_t value) { 32 *(uint32_t *)(ptr + offset) = value; 33 } 34 35 static inline void WriteInt64(unsigned char *ptr, unsigned offset, 36 uint64_t value) { 37 *(uint64_t *)(ptr + offset) = value; 38 } 39 40 static inline void WriteSwappedInt16(unsigned char *ptr, unsigned offset, 41 uint16_t value) { 42 *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value); 43 } 44 45 static inline void WriteSwappedInt32(unsigned char *ptr, unsigned offset, 46 uint32_t value) { 47 *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value); 48 } 49 50 static inline void WriteSwappedInt64(unsigned char *ptr, unsigned offset, 51 uint64_t value) { 52 *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value); 53 } 54 55 //---------------------------------------------------------------------- 56 // Default constructor. 57 //---------------------------------------------------------------------- 58 DataEncoder::DataEncoder() 59 : m_start(nullptr), m_end(nullptr), 60 m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), 61 m_data_sp() {} 62 63 //---------------------------------------------------------------------- 64 // This constructor allows us to use data that is owned by someone else. 65 // The data must stay around as long as this object is valid. 66 //---------------------------------------------------------------------- 67 DataEncoder::DataEncoder(void *data, uint32_t length, ByteOrder endian, 68 uint8_t addr_size) 69 : m_start((uint8_t *)data), m_end((uint8_t *)data + length), 70 m_byte_order(endian), m_addr_size(addr_size), m_data_sp() {} 71 72 //---------------------------------------------------------------------- 73 // Make a shared pointer reference to the shared data in "data_sp" and 74 // set the endian swapping setting to "swap", and the address size to 75 // "addr_size". The shared data reference will ensure the data lives 76 // as long as any DataEncoder objects exist that have a reference to 77 // this data. 78 //---------------------------------------------------------------------- 79 DataEncoder::DataEncoder(const DataBufferSP &data_sp, ByteOrder endian, 80 uint8_t addr_size) 81 : m_start(nullptr), m_end(nullptr), m_byte_order(endian), 82 m_addr_size(addr_size), m_data_sp() { 83 SetData(data_sp); 84 } 85 86 DataEncoder::~DataEncoder() = default; 87 88 //------------------------------------------------------------------ 89 // Clears the object contents back to a default invalid state, and 90 // release any references to shared data that this object may 91 // contain. 92 //------------------------------------------------------------------ 93 void DataEncoder::Clear() { 94 m_start = nullptr; 95 m_end = nullptr; 96 m_byte_order = endian::InlHostByteOrder(); 97 m_addr_size = sizeof(void *); 98 m_data_sp.reset(); 99 } 100 101 //------------------------------------------------------------------ 102 // If this object contains shared data, this function returns the 103 // offset into that shared data. Else zero is returned. 104 //------------------------------------------------------------------ 105 size_t DataEncoder::GetSharedDataOffset() const { 106 if (m_start != nullptr) { 107 const DataBuffer *data = m_data_sp.get(); 108 if (data != nullptr) { 109 const uint8_t *data_bytes = data->GetBytes(); 110 if (data_bytes != nullptr) { 111 assert(m_start >= data_bytes); 112 return m_start - data_bytes; 113 } 114 } 115 } 116 return 0; 117 } 118 119 //---------------------------------------------------------------------- 120 // Set the data with which this object will extract from to data 121 // starting at BYTES and set the length of the data to LENGTH bytes 122 // long. The data is externally owned must be around at least as 123 // long as this object points to the data. No copy of the data is 124 // made, this object just refers to this data and can extract from 125 // it. If this object refers to any shared data upon entry, the 126 // reference to that data will be released. Is SWAP is set to true, 127 // any data extracted will be endian swapped. 128 //---------------------------------------------------------------------- 129 uint32_t DataEncoder::SetData(void *bytes, uint32_t length, ByteOrder endian) { 130 m_byte_order = endian; 131 m_data_sp.reset(); 132 if (bytes == nullptr || length == 0) { 133 m_start = nullptr; 134 m_end = nullptr; 135 } else { 136 m_start = (uint8_t *)bytes; 137 m_end = m_start + length; 138 } 139 return GetByteSize(); 140 } 141 142 //---------------------------------------------------------------------- 143 // Assign the data for this object to be a subrange of the shared 144 // data in "data_sp" starting "data_offset" bytes into "data_sp" 145 // and ending "data_length" bytes later. If "data_offset" is not 146 // a valid offset into "data_sp", then this object will contain no 147 // bytes. If "data_offset" is within "data_sp" yet "data_length" is 148 // too large, the length will be capped at the number of bytes 149 // remaining in "data_sp". A ref counted pointer to the data in 150 // "data_sp" will be made in this object IF the number of bytes this 151 // object refers to in greater than zero (if at least one byte was 152 // available starting at "data_offset") to ensure the data stays 153 // around as long as it is needed. The address size and endian swap 154 // settings will remain unchanged from their current settings. 155 //---------------------------------------------------------------------- 156 uint32_t DataEncoder::SetData(const DataBufferSP &data_sp, uint32_t data_offset, 157 uint32_t data_length) { 158 m_start = m_end = nullptr; 159 160 if (data_length > 0) { 161 m_data_sp = data_sp; 162 if (data_sp) { 163 const size_t data_size = data_sp->GetByteSize(); 164 if (data_offset < data_size) { 165 m_start = data_sp->GetBytes() + data_offset; 166 const size_t bytes_left = data_size - data_offset; 167 // Cap the length of we asked for too many 168 if (data_length <= bytes_left) 169 m_end = m_start + data_length; // We got all the bytes we wanted 170 else 171 m_end = m_start + bytes_left; // Not all the bytes requested were 172 // available in the shared data 173 } 174 } 175 } 176 177 uint32_t new_size = GetByteSize(); 178 179 // Don't hold a shared pointer to the data buffer if we don't share 180 // any valid bytes in the shared buffer. 181 if (new_size == 0) 182 m_data_sp.reset(); 183 184 return new_size; 185 } 186 187 //---------------------------------------------------------------------- 188 // Extract a single unsigned char from the binary data and update 189 // the offset pointed to by "offset_ptr". 190 // 191 // RETURNS the byte that was extracted, or zero on failure. 192 //---------------------------------------------------------------------- 193 uint32_t DataEncoder::PutU8(uint32_t offset, uint8_t value) { 194 if (ValidOffset(offset)) { 195 m_start[offset] = value; 196 return offset + 1; 197 } 198 return UINT32_MAX; 199 } 200 201 uint32_t DataEncoder::PutU16(uint32_t offset, uint16_t value) { 202 if (ValidOffsetForDataOfSize(offset, sizeof(value))) { 203 if (m_byte_order != endian::InlHostByteOrder()) 204 WriteSwappedInt16(m_start, offset, value); 205 else 206 WriteInt16(m_start, offset, value); 207 208 return offset + sizeof(value); 209 } 210 return UINT32_MAX; 211 } 212 213 uint32_t DataEncoder::PutU32(uint32_t offset, uint32_t value) { 214 if (ValidOffsetForDataOfSize(offset, sizeof(value))) { 215 if (m_byte_order != endian::InlHostByteOrder()) 216 WriteSwappedInt32(m_start, offset, value); 217 else 218 WriteInt32(m_start, offset, value); 219 220 return offset + sizeof(value); 221 } 222 return UINT32_MAX; 223 } 224 225 uint32_t DataEncoder::PutU64(uint32_t offset, uint64_t value) { 226 if (ValidOffsetForDataOfSize(offset, sizeof(value))) { 227 if (m_byte_order != endian::InlHostByteOrder()) 228 WriteSwappedInt64(m_start, offset, value); 229 else 230 WriteInt64(m_start, offset, value); 231 232 return offset + sizeof(value); 233 } 234 return UINT32_MAX; 235 } 236 237 //---------------------------------------------------------------------- 238 // Extract a single integer value from the data and update the offset 239 // pointed to by "offset_ptr". The size of the extracted integer 240 // is specified by the "byte_size" argument. "byte_size" should have 241 // a value >= 1 and <= 8 since the return value is only 64 bits 242 // wide. Any "byte_size" values less than 1 or greater than 8 will 243 // result in nothing being extracted, and zero being returned. 244 // 245 // RETURNS the integer value that was extracted, or zero on failure. 246 //---------------------------------------------------------------------- 247 uint32_t DataEncoder::PutMaxU64(uint32_t offset, uint32_t byte_size, 248 uint64_t value) { 249 switch (byte_size) { 250 case 1: 251 return PutU8(offset, value); 252 case 2: 253 return PutU16(offset, value); 254 case 4: 255 return PutU32(offset, value); 256 case 8: 257 return PutU64(offset, value); 258 default: 259 llvm_unreachable("GetMax64 unhandled case!"); 260 } 261 return UINT32_MAX; 262 } 263 264 uint32_t DataEncoder::PutData(uint32_t offset, const void *src, 265 uint32_t src_len) { 266 if (src == nullptr || src_len == 0) 267 return offset; 268 269 if (ValidOffsetForDataOfSize(offset, src_len)) { 270 memcpy(m_start + offset, src, src_len); 271 return offset + src_len; 272 } 273 return UINT32_MAX; 274 } 275 276 uint32_t DataEncoder::PutAddress(uint32_t offset, lldb::addr_t addr) { 277 return PutMaxU64(offset, GetAddressByteSize(), addr); 278 } 279 280 uint32_t DataEncoder::PutCString(uint32_t offset, const char *cstr) { 281 if (cstr != nullptr) 282 return PutData(offset, cstr, strlen(cstr) + 1); 283 return UINT32_MAX; 284 } 285