Greg Clayton | d84cc04 | 2011-09-01 18:10:09 +0000 | [diff] [blame] | 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/Core/DataEncoder.h" |
| 11 | |
| 12 | #include <assert.h> |
| 13 | #include <stddef.h> |
| 14 | |
| 15 | #include "llvm/Support/MathExtras.h" |
| 16 | |
| 17 | #include "lldb/Core/DataBuffer.h" |
| 18 | #include "lldb/Host/Endian.h" |
| 19 | |
| 20 | using namespace lldb; |
| 21 | using namespace lldb_private; |
| 22 | |
| 23 | static inline void |
| 24 | WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value) |
| 25 | { |
| 26 | *(uint16_t *)(ptr + offset) = value; |
| 27 | } |
| 28 | static inline void |
| 29 | WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value) |
| 30 | { |
| 31 | *(uint32_t *)(ptr + offset) = value; |
| 32 | } |
| 33 | |
| 34 | static inline void |
| 35 | WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value) |
| 36 | { |
| 37 | *(uint64_t *)(ptr + offset) = value; |
| 38 | } |
| 39 | |
| 40 | static inline void |
| 41 | WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value) |
| 42 | { |
| 43 | *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value); |
| 44 | } |
| 45 | |
| 46 | static inline void |
| 47 | WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value) |
| 48 | { |
| 49 | *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value); |
| 50 | } |
| 51 | |
| 52 | static inline void |
| 53 | WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value) |
| 54 | { |
| 55 | *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value); |
| 56 | } |
| 57 | |
| 58 | //---------------------------------------------------------------------- |
| 59 | // Default constructor. |
| 60 | //---------------------------------------------------------------------- |
| 61 | DataEncoder::DataEncoder () : |
| 62 | m_start (NULL), |
| 63 | m_end (NULL), |
| 64 | m_byte_order(lldb::endian::InlHostByteOrder()), |
| 65 | m_addr_size (sizeof(void*)), |
| 66 | m_data_sp () |
| 67 | { |
| 68 | } |
| 69 | |
| 70 | //---------------------------------------------------------------------- |
| 71 | // This constructor allows us to use data that is owned by someone else. |
| 72 | // The data must stay around as long as this object is valid. |
| 73 | //---------------------------------------------------------------------- |
| 74 | DataEncoder::DataEncoder (void* data, uint32_t length, ByteOrder endian, uint8_t addr_size) : |
| 75 | m_start ((uint8_t*)data), |
| 76 | m_end ((uint8_t*)data + length), |
| 77 | m_byte_order(endian), |
| 78 | m_addr_size (addr_size), |
| 79 | m_data_sp () |
| 80 | { |
| 81 | } |
| 82 | |
| 83 | //---------------------------------------------------------------------- |
| 84 | // Make a shared pointer reference to the shared data in "data_sp" and |
| 85 | // set the endian swapping setting to "swap", and the address size to |
| 86 | // "addr_size". The shared data reference will ensure the data lives |
| 87 | // as long as any DataEncoder objects exist that have a reference to |
| 88 | // this data. |
| 89 | //---------------------------------------------------------------------- |
| 90 | DataEncoder::DataEncoder (const DataBufferSP& data_sp, ByteOrder endian, uint8_t addr_size) : |
| 91 | m_start (NULL), |
| 92 | m_end (NULL), |
| 93 | m_byte_order(endian), |
| 94 | m_addr_size (addr_size), |
| 95 | m_data_sp () |
| 96 | { |
| 97 | SetData (data_sp); |
| 98 | } |
| 99 | |
| 100 | //---------------------------------------------------------------------- |
| 101 | // Destructor |
| 102 | //---------------------------------------------------------------------- |
| 103 | DataEncoder::~DataEncoder () |
| 104 | { |
| 105 | } |
| 106 | |
| 107 | //------------------------------------------------------------------ |
| 108 | // Clears the object contents back to a default invalid state, and |
| 109 | // release any references to shared data that this object may |
| 110 | // contain. |
| 111 | //------------------------------------------------------------------ |
| 112 | void |
| 113 | DataEncoder::Clear () |
| 114 | { |
| 115 | m_start = NULL; |
| 116 | m_end = NULL; |
| 117 | m_byte_order = lldb::endian::InlHostByteOrder(); |
| 118 | m_addr_size = sizeof(void*); |
| 119 | m_data_sp.reset(); |
| 120 | } |
| 121 | |
| 122 | //------------------------------------------------------------------ |
| 123 | // If this object contains shared data, this function returns the |
| 124 | // offset into that shared data. Else zero is returned. |
| 125 | //------------------------------------------------------------------ |
| 126 | size_t |
| 127 | DataEncoder::GetSharedDataOffset () const |
| 128 | { |
| 129 | if (m_start != NULL) |
| 130 | { |
| 131 | const DataBuffer * data = m_data_sp.get(); |
| 132 | if (data != NULL) |
| 133 | { |
| 134 | const uint8_t * data_bytes = data->GetBytes(); |
| 135 | if (data_bytes != NULL) |
| 136 | { |
| 137 | assert(m_start >= data_bytes); |
| 138 | return m_start - data_bytes; |
| 139 | } |
| 140 | } |
| 141 | } |
| 142 | return 0; |
| 143 | } |
| 144 | |
| 145 | //------------------------------------------------------------------ |
| 146 | // Returns true if there are LENGTH bytes availabe starting OFFSET |
| 147 | // into the data that is in this object. |
| 148 | //------------------------------------------------------------------ |
| 149 | bool |
| 150 | DataEncoder::ValidOffsetForDataOfSize (uint32_t offset, uint32_t length) const |
| 151 | { |
| 152 | size_t size = GetByteSize(); |
| 153 | if (offset >= size) |
| 154 | return false; // offset isn't valid |
| 155 | |
| 156 | if (length == 0) |
| 157 | return true; // No bytes requested at this offset, return true |
| 158 | |
| 159 | // If we flip the bits in offset we can figure out how |
| 160 | // many bytes we have left before "offset + length" |
| 161 | // could overflow when doing unsigned arithmetic. |
| 162 | if (length > ~offset) |
| 163 | return false; // unsigned overflow |
| 164 | |
| 165 | // Make sure "offset + length" is a valid offset as well. |
| 166 | // length must be greater than zero for this to be a |
| 167 | // valid expression, and we have already checked for this. |
| 168 | return ((offset + length) <= size); |
| 169 | } |
| 170 | |
| 171 | //---------------------------------------------------------------------- |
| 172 | // Set the data with which this object will extract from to data |
| 173 | // starting at BYTES and set the length of the data to LENGTH bytes |
| 174 | // long. The data is externally owned must be around at least as |
| 175 | // long as this object points to the data. No copy of the data is |
| 176 | // made, this object just refers to this data and can extract from |
| 177 | // it. If this object refers to any shared data upon entry, the |
| 178 | // reference to that data will be released. Is SWAP is set to true, |
| 179 | // any data extracted will be endian swapped. |
| 180 | //---------------------------------------------------------------------- |
| 181 | uint32_t |
| 182 | DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian) |
| 183 | { |
| 184 | m_byte_order = endian; |
| 185 | m_data_sp.reset(); |
| 186 | if (bytes == NULL || length == 0) |
| 187 | { |
| 188 | m_start = NULL; |
| 189 | m_end = NULL; |
| 190 | } |
| 191 | else |
| 192 | { |
| 193 | m_start = (uint8_t *)bytes; |
| 194 | m_end = m_start + length; |
| 195 | } |
| 196 | return GetByteSize(); |
| 197 | } |
| 198 | |
| 199 | //---------------------------------------------------------------------- |
| 200 | // Assign the data for this object to be a subrange of the shared |
| 201 | // data in "data_sp" starting "data_offset" bytes into "data_sp" |
| 202 | // and ending "data_length" bytes later. If "data_offset" is not |
| 203 | // a valid offset into "data_sp", then this object will contain no |
| 204 | // bytes. If "data_offset" is within "data_sp" yet "data_length" is |
| 205 | // too large, the length will be capped at the number of bytes |
| 206 | // remaining in "data_sp". A ref counted pointer to the data in |
| 207 | // "data_sp" will be made in this object IF the number of bytes this |
| 208 | // object refers to in greater than zero (if at least one byte was |
| 209 | // available starting at "data_offset") to ensure the data stays |
| 210 | // around as long as it is needed. The address size and endian swap |
| 211 | // settings will remain unchanged from their current settings. |
| 212 | //---------------------------------------------------------------------- |
| 213 | uint32_t |
| 214 | DataEncoder::SetData (const DataBufferSP& data_sp, uint32_t data_offset, uint32_t data_length) |
| 215 | { |
| 216 | m_start = m_end = NULL; |
| 217 | |
| 218 | if (data_length > 0) |
| 219 | { |
| 220 | m_data_sp = data_sp; |
| 221 | if (data_sp.get()) |
| 222 | { |
| 223 | const size_t data_size = data_sp->GetByteSize(); |
| 224 | if (data_offset < data_size) |
| 225 | { |
| 226 | m_start = data_sp->GetBytes() + data_offset; |
| 227 | const size_t bytes_left = data_size - data_offset; |
| 228 | // Cap the length of we asked for too many |
| 229 | if (data_length <= bytes_left) |
| 230 | m_end = m_start + data_length; // We got all the bytes we wanted |
| 231 | else |
| 232 | m_end = m_start + bytes_left; // Not all the bytes requested were available in the shared data |
| 233 | } |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | uint32_t new_size = GetByteSize(); |
| 238 | |
| 239 | // Don't hold a shared pointer to the data buffer if we don't share |
| 240 | // any valid bytes in the shared buffer. |
| 241 | if (new_size == 0) |
| 242 | m_data_sp.reset(); |
| 243 | |
| 244 | return new_size; |
| 245 | } |
| 246 | |
| 247 | //---------------------------------------------------------------------- |
| 248 | // Extract a single unsigned char from the binary data and update |
| 249 | // the offset pointed to by "offset_ptr". |
| 250 | // |
| 251 | // RETURNS the byte that was extracted, or zero on failure. |
| 252 | //---------------------------------------------------------------------- |
| 253 | uint32_t |
| 254 | DataEncoder::PutU8 (uint32_t offset, uint8_t value) |
| 255 | { |
| 256 | if (ValidOffset(offset)) |
| 257 | { |
| 258 | m_start[offset] = value; |
| 259 | return offset + 1; |
| 260 | } |
| 261 | return UINT32_MAX; |
| 262 | } |
| 263 | |
| 264 | uint32_t |
| 265 | DataEncoder::PutU16 (uint32_t offset, uint16_t value) |
| 266 | { |
| 267 | if (ValidOffsetForDataOfSize(offset, sizeof(value))) |
| 268 | { |
| 269 | if (m_byte_order != lldb::endian::InlHostByteOrder()) |
| 270 | WriteSwappedInt16 (m_start, offset, value); |
| 271 | else |
| 272 | WriteInt16 (m_start, offset, value); |
| 273 | |
| 274 | return offset + sizeof (value); |
| 275 | } |
| 276 | return UINT32_MAX; |
| 277 | } |
| 278 | |
| 279 | uint32_t |
| 280 | DataEncoder::PutU32 (uint32_t offset, uint32_t value) |
| 281 | { |
| 282 | if (ValidOffsetForDataOfSize(offset, sizeof(value))) |
| 283 | { |
| 284 | if (m_byte_order != lldb::endian::InlHostByteOrder()) |
| 285 | WriteSwappedInt32 (m_start, offset, value); |
| 286 | else |
| 287 | WriteInt32 (m_start, offset, value); |
| 288 | |
| 289 | return offset + sizeof (value); |
| 290 | } |
| 291 | return UINT32_MAX; |
| 292 | } |
| 293 | |
| 294 | uint32_t |
| 295 | DataEncoder::PutU64 (uint32_t offset, uint64_t value) |
| 296 | { |
| 297 | if (ValidOffsetForDataOfSize(offset, sizeof(value))) |
| 298 | { |
| 299 | if (m_byte_order != lldb::endian::InlHostByteOrder()) |
| 300 | WriteSwappedInt64 (m_start, offset, value); |
| 301 | else |
| 302 | WriteInt64 (m_start, offset, value); |
| 303 | |
| 304 | return offset + sizeof (value); |
| 305 | } |
| 306 | return UINT32_MAX; |
| 307 | } |
| 308 | |
| 309 | //---------------------------------------------------------------------- |
| 310 | // Extract a single integer value from the data and update the offset |
| 311 | // pointed to by "offset_ptr". The size of the extracted integer |
| 312 | // is specified by the "byte_size" argument. "byte_size" should have |
| 313 | // a value >= 1 and <= 8 since the return value is only 64 bits |
| 314 | // wide. Any "byte_size" values less than 1 or greater than 8 will |
| 315 | // result in nothing being extracted, and zero being returned. |
| 316 | // |
| 317 | // RETURNS the integer value that was extracted, or zero on failure. |
| 318 | //---------------------------------------------------------------------- |
| 319 | uint32_t |
| 320 | DataEncoder::PutMaxU64 (uint32_t offset, uint32_t byte_size, uint64_t value) |
| 321 | { |
| 322 | switch (byte_size) |
| 323 | { |
| 324 | case 1: return PutU8 (offset, value); |
| 325 | case 2: return PutU16(offset, value); |
| 326 | case 4: return PutU32(offset, value); |
| 327 | case 8: return PutU64(offset, value); |
| 328 | default: |
| 329 | assert(!"GetMax64 unhandled case!"); |
| 330 | break; |
| 331 | } |
| 332 | return UINT32_MAX; |
| 333 | } |
| 334 | |
| 335 | uint32_t |
| 336 | DataEncoder::PutData (uint32_t offset, const void *src, uint32_t src_len) |
| 337 | { |
| 338 | if (src == NULL || src_len == 0) |
| 339 | return offset; |
| 340 | |
| 341 | if (ValidOffsetForDataOfSize(offset, src_len)) |
| 342 | { |
| 343 | memcpy (m_start + offset, src, src_len); |
| 344 | return offset + src_len; |
| 345 | } |
| 346 | return UINT32_MAX; |
| 347 | } |
| 348 | |
| 349 | uint32_t |
| 350 | DataEncoder::PutAddress (uint32_t offset, lldb::addr_t addr) |
| 351 | { |
| 352 | return PutMaxU64 (offset, GetAddressByteSize(), addr); |
| 353 | } |
| 354 | |
| 355 | uint32_t |
| 356 | DataEncoder::PutCString (uint32_t offset, const char *cstr) |
| 357 | { |
| 358 | if (cstr) |
Greg Clayton | 97b8f66 | 2011-09-01 18:13:54 +0000 | [diff] [blame] | 359 | return PutData (offset, cstr, strlen(cstr) + 1); |
Greg Clayton | d84cc04 | 2011-09-01 18:10:09 +0000 | [diff] [blame] | 360 | return UINT32_MAX; |
| 361 | } |