188a1d9fcSBenjamin Kramer //===-- DataExtractor.cpp -------------------------------------------------===//
288a1d9fcSBenjamin Kramer //
388a1d9fcSBenjamin Kramer //                     The LLVM Compiler Infrastructure
488a1d9fcSBenjamin Kramer //
588a1d9fcSBenjamin Kramer // This file is distributed under the University of Illinois Open Source
688a1d9fcSBenjamin Kramer // License. See LICENSE.TXT for details.
788a1d9fcSBenjamin Kramer //
888a1d9fcSBenjamin Kramer //===----------------------------------------------------------------------===//
988a1d9fcSBenjamin Kramer 
1088a1d9fcSBenjamin Kramer #include "llvm/Support/DataExtractor.h"
1188a1d9fcSBenjamin Kramer #include "llvm/Support/ErrorHandling.h"
1288a1d9fcSBenjamin Kramer #include "llvm/Support/Host.h"
1388a1d9fcSBenjamin Kramer #include "llvm/Support/SwapByteOrder.h"
1488a1d9fcSBenjamin Kramer using namespace llvm;
1588a1d9fcSBenjamin Kramer 
1688a1d9fcSBenjamin Kramer template <typename T>
1788a1d9fcSBenjamin Kramer static T getU(uint32_t *offset_ptr, const DataExtractor *de,
1888a1d9fcSBenjamin Kramer               bool isLittleEndian, const char *Data) {
1988a1d9fcSBenjamin Kramer   T val = 0;
2088a1d9fcSBenjamin Kramer   uint32_t offset = *offset_ptr;
2188a1d9fcSBenjamin Kramer   if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) {
2288a1d9fcSBenjamin Kramer     std::memcpy(&val, &Data[offset], sizeof(val));
23*41cb64f4SRafael Espindola     if (sys::IsLittleEndianHost != isLittleEndian)
2488a1d9fcSBenjamin Kramer       val = sys::SwapByteOrder(val);
2588a1d9fcSBenjamin Kramer 
2688a1d9fcSBenjamin Kramer     // Advance the offset
2788a1d9fcSBenjamin Kramer     *offset_ptr += sizeof(val);
2888a1d9fcSBenjamin Kramer   }
2988a1d9fcSBenjamin Kramer   return val;
3088a1d9fcSBenjamin Kramer }
3188a1d9fcSBenjamin Kramer 
3288a1d9fcSBenjamin Kramer template <typename T>
3388a1d9fcSBenjamin Kramer static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count,
3488a1d9fcSBenjamin Kramer                 const DataExtractor *de, bool isLittleEndian, const char *Data){
3588a1d9fcSBenjamin Kramer   uint32_t offset = *offset_ptr;
3688a1d9fcSBenjamin Kramer 
3788a1d9fcSBenjamin Kramer   if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) {
3888a1d9fcSBenjamin Kramer     for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
3988a1d9fcSBenjamin Kramer         ++value_ptr, offset += sizeof(*dst))
4088a1d9fcSBenjamin Kramer       *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data);
4188a1d9fcSBenjamin Kramer     // Advance the offset
4288a1d9fcSBenjamin Kramer     *offset_ptr = offset;
4388a1d9fcSBenjamin Kramer     // Return a non-NULL pointer to the converted data as an indicator of
4488a1d9fcSBenjamin Kramer     // success
4588a1d9fcSBenjamin Kramer     return dst;
4688a1d9fcSBenjamin Kramer   }
4788a1d9fcSBenjamin Kramer   return NULL;
4888a1d9fcSBenjamin Kramer }
4988a1d9fcSBenjamin Kramer 
5088a1d9fcSBenjamin Kramer uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const {
5188a1d9fcSBenjamin Kramer   return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data());
5288a1d9fcSBenjamin Kramer }
5388a1d9fcSBenjamin Kramer 
5488a1d9fcSBenjamin Kramer uint8_t *
5588a1d9fcSBenjamin Kramer DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const {
5688a1d9fcSBenjamin Kramer   return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
5788a1d9fcSBenjamin Kramer                        Data.data());
5888a1d9fcSBenjamin Kramer }
5988a1d9fcSBenjamin Kramer 
6088a1d9fcSBenjamin Kramer 
6188a1d9fcSBenjamin Kramer uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const {
6288a1d9fcSBenjamin Kramer   return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data());
6388a1d9fcSBenjamin Kramer }
6488a1d9fcSBenjamin Kramer 
6588a1d9fcSBenjamin Kramer uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst,
6688a1d9fcSBenjamin Kramer                                 uint32_t count) const {
6788a1d9fcSBenjamin Kramer   return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
6888a1d9fcSBenjamin Kramer                         Data.data());
6988a1d9fcSBenjamin Kramer }
7088a1d9fcSBenjamin Kramer 
7188a1d9fcSBenjamin Kramer uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const {
7288a1d9fcSBenjamin Kramer   return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data());
7388a1d9fcSBenjamin Kramer }
7488a1d9fcSBenjamin Kramer 
7588a1d9fcSBenjamin Kramer uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst,
7688a1d9fcSBenjamin Kramer                                 uint32_t count) const {
7788a1d9fcSBenjamin Kramer   return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
785dfe6dabSChad Rosier                         Data.data());
7988a1d9fcSBenjamin Kramer }
8088a1d9fcSBenjamin Kramer 
8188a1d9fcSBenjamin Kramer uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const {
8288a1d9fcSBenjamin Kramer   return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data());
8388a1d9fcSBenjamin Kramer }
8488a1d9fcSBenjamin Kramer 
8588a1d9fcSBenjamin Kramer uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst,
8688a1d9fcSBenjamin Kramer                                 uint32_t count) const {
8788a1d9fcSBenjamin Kramer   return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
8888a1d9fcSBenjamin Kramer                         Data.data());
8988a1d9fcSBenjamin Kramer }
9088a1d9fcSBenjamin Kramer 
9188a1d9fcSBenjamin Kramer uint64_t
9288a1d9fcSBenjamin Kramer DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const {
9388a1d9fcSBenjamin Kramer   switch (byte_size) {
9488a1d9fcSBenjamin Kramer   case 1:
9588a1d9fcSBenjamin Kramer     return getU8(offset_ptr);
9688a1d9fcSBenjamin Kramer   case 2:
9788a1d9fcSBenjamin Kramer     return getU16(offset_ptr);
9888a1d9fcSBenjamin Kramer   case 4:
9988a1d9fcSBenjamin Kramer     return getU32(offset_ptr);
10088a1d9fcSBenjamin Kramer   case 8:
10188a1d9fcSBenjamin Kramer     return getU64(offset_ptr);
10288a1d9fcSBenjamin Kramer   }
10388a1d9fcSBenjamin Kramer   llvm_unreachable("getUnsigned unhandled case!");
10488a1d9fcSBenjamin Kramer }
10588a1d9fcSBenjamin Kramer 
10688a1d9fcSBenjamin Kramer int64_t
10788a1d9fcSBenjamin Kramer DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
10888a1d9fcSBenjamin Kramer   switch (byte_size) {
10988a1d9fcSBenjamin Kramer   case 1:
11088a1d9fcSBenjamin Kramer     return (int8_t)getU8(offset_ptr);
11188a1d9fcSBenjamin Kramer   case 2:
11288a1d9fcSBenjamin Kramer     return (int16_t)getU16(offset_ptr);
11388a1d9fcSBenjamin Kramer   case 4:
11488a1d9fcSBenjamin Kramer     return (int32_t)getU32(offset_ptr);
11588a1d9fcSBenjamin Kramer   case 8:
11688a1d9fcSBenjamin Kramer     return (int64_t)getU64(offset_ptr);
11788a1d9fcSBenjamin Kramer   }
11888a1d9fcSBenjamin Kramer   llvm_unreachable("getSigned unhandled case!");
11988a1d9fcSBenjamin Kramer }
12088a1d9fcSBenjamin Kramer 
12188a1d9fcSBenjamin Kramer const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
12288a1d9fcSBenjamin Kramer   uint32_t offset = *offset_ptr;
12388a1d9fcSBenjamin Kramer   StringRef::size_type pos = Data.find('\0', offset);
12488a1d9fcSBenjamin Kramer   if (pos != StringRef::npos) {
12588a1d9fcSBenjamin Kramer     *offset_ptr = pos + 1;
12688a1d9fcSBenjamin Kramer     return Data.data() + offset;
12788a1d9fcSBenjamin Kramer   }
12888a1d9fcSBenjamin Kramer   return NULL;
12988a1d9fcSBenjamin Kramer }
13088a1d9fcSBenjamin Kramer 
13188a1d9fcSBenjamin Kramer uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
13288a1d9fcSBenjamin Kramer   uint64_t result = 0;
13388a1d9fcSBenjamin Kramer   if (Data.empty())
13488a1d9fcSBenjamin Kramer     return 0;
13588a1d9fcSBenjamin Kramer 
13688a1d9fcSBenjamin Kramer   unsigned shift = 0;
13788a1d9fcSBenjamin Kramer   uint32_t offset = *offset_ptr;
13888a1d9fcSBenjamin Kramer   uint8_t byte = 0;
13988a1d9fcSBenjamin Kramer 
14088a1d9fcSBenjamin Kramer   while (isValidOffset(offset)) {
14188a1d9fcSBenjamin Kramer     byte = Data[offset++];
1421b07ab51SBenjamin Kramer     result |= uint64_t(byte & 0x7f) << shift;
14388a1d9fcSBenjamin Kramer     shift += 7;
14488a1d9fcSBenjamin Kramer     if ((byte & 0x80) == 0)
14588a1d9fcSBenjamin Kramer       break;
14688a1d9fcSBenjamin Kramer   }
14788a1d9fcSBenjamin Kramer 
14888a1d9fcSBenjamin Kramer   *offset_ptr = offset;
14988a1d9fcSBenjamin Kramer   return result;
15088a1d9fcSBenjamin Kramer }
15188a1d9fcSBenjamin Kramer 
15288a1d9fcSBenjamin Kramer int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
15388a1d9fcSBenjamin Kramer   int64_t result = 0;
15488a1d9fcSBenjamin Kramer   if (Data.empty())
15588a1d9fcSBenjamin Kramer     return 0;
15688a1d9fcSBenjamin Kramer 
15788a1d9fcSBenjamin Kramer   unsigned shift = 0;
15888a1d9fcSBenjamin Kramer   uint32_t offset = *offset_ptr;
15988a1d9fcSBenjamin Kramer   uint8_t byte = 0;
16088a1d9fcSBenjamin Kramer 
16188a1d9fcSBenjamin Kramer   while (isValidOffset(offset)) {
16288a1d9fcSBenjamin Kramer     byte = Data[offset++];
1631b07ab51SBenjamin Kramer     result |= uint64_t(byte & 0x7f) << shift;
16488a1d9fcSBenjamin Kramer     shift += 7;
16588a1d9fcSBenjamin Kramer     if ((byte & 0x80) == 0)
16688a1d9fcSBenjamin Kramer       break;
16788a1d9fcSBenjamin Kramer   }
16888a1d9fcSBenjamin Kramer 
16988a1d9fcSBenjamin Kramer   // Sign bit of byte is 2nd high order bit (0x40)
17088a1d9fcSBenjamin Kramer   if (shift < 64 && (byte & 0x40))
1711b07ab51SBenjamin Kramer     result |= -(1ULL << shift);
17288a1d9fcSBenjamin Kramer 
17388a1d9fcSBenjamin Kramer   *offset_ptr = offset;
17488a1d9fcSBenjamin Kramer   return result;
17588a1d9fcSBenjamin Kramer }
176