16122f3e6SDimitry Andric //===-- DataExtractor.cpp -------------------------------------------------===//
26122f3e6SDimitry Andric //
36122f3e6SDimitry Andric //                     The LLVM Compiler Infrastructure
46122f3e6SDimitry Andric //
56122f3e6SDimitry Andric // This file is distributed under the University of Illinois Open Source
66122f3e6SDimitry Andric // License. See LICENSE.TXT for details.
76122f3e6SDimitry Andric //
86122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
96122f3e6SDimitry Andric 
106122f3e6SDimitry Andric #include "llvm/Support/DataExtractor.h"
116122f3e6SDimitry Andric #include "llvm/Support/ErrorHandling.h"
126122f3e6SDimitry Andric #include "llvm/Support/Host.h"
136122f3e6SDimitry Andric #include "llvm/Support/SwapByteOrder.h"
146122f3e6SDimitry Andric using namespace llvm;
156122f3e6SDimitry Andric 
166122f3e6SDimitry Andric template <typename T>
getU(uint32_t * offset_ptr,const DataExtractor * de,bool isLittleEndian,const char * Data)176122f3e6SDimitry Andric static T getU(uint32_t *offset_ptr, const DataExtractor *de,
186122f3e6SDimitry Andric               bool isLittleEndian, const char *Data) {
196122f3e6SDimitry Andric   T val = 0;
206122f3e6SDimitry Andric   uint32_t offset = *offset_ptr;
216122f3e6SDimitry Andric   if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) {
226122f3e6SDimitry Andric     std::memcpy(&val, &Data[offset], sizeof(val));
23284c1978SDimitry Andric     if (sys::IsLittleEndianHost != isLittleEndian)
2491bc56edSDimitry Andric       sys::swapByteOrder(val);
256122f3e6SDimitry Andric 
266122f3e6SDimitry Andric     // Advance the offset
276122f3e6SDimitry Andric     *offset_ptr += sizeof(val);
286122f3e6SDimitry Andric   }
296122f3e6SDimitry Andric   return val;
306122f3e6SDimitry Andric }
316122f3e6SDimitry Andric 
326122f3e6SDimitry Andric template <typename T>
getUs(uint32_t * offset_ptr,T * dst,uint32_t count,const DataExtractor * de,bool isLittleEndian,const char * Data)336122f3e6SDimitry Andric static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count,
346122f3e6SDimitry Andric                 const DataExtractor *de, bool isLittleEndian, const char *Data){
356122f3e6SDimitry Andric   uint32_t offset = *offset_ptr;
366122f3e6SDimitry Andric 
376122f3e6SDimitry Andric   if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) {
386122f3e6SDimitry Andric     for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
396122f3e6SDimitry Andric         ++value_ptr, offset += sizeof(*dst))
406122f3e6SDimitry Andric       *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data);
416122f3e6SDimitry Andric     // Advance the offset
426122f3e6SDimitry Andric     *offset_ptr = offset;
436122f3e6SDimitry Andric     // Return a non-NULL pointer to the converted data as an indicator of
446122f3e6SDimitry Andric     // success
456122f3e6SDimitry Andric     return dst;
466122f3e6SDimitry Andric   }
4791bc56edSDimitry Andric   return nullptr;
486122f3e6SDimitry Andric }
496122f3e6SDimitry Andric 
getU8(uint32_t * offset_ptr) const506122f3e6SDimitry Andric uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const {
516122f3e6SDimitry Andric   return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data());
526122f3e6SDimitry Andric }
536122f3e6SDimitry Andric 
546122f3e6SDimitry Andric uint8_t *
getU8(uint32_t * offset_ptr,uint8_t * dst,uint32_t count) const556122f3e6SDimitry Andric DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const {
566122f3e6SDimitry Andric   return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
576122f3e6SDimitry Andric                        Data.data());
586122f3e6SDimitry Andric }
596122f3e6SDimitry Andric 
606122f3e6SDimitry Andric 
getU16(uint32_t * offset_ptr) const616122f3e6SDimitry Andric uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const {
626122f3e6SDimitry Andric   return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data());
636122f3e6SDimitry Andric }
646122f3e6SDimitry Andric 
getU16(uint32_t * offset_ptr,uint16_t * dst,uint32_t count) const656122f3e6SDimitry Andric uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst,
666122f3e6SDimitry Andric                                 uint32_t count) const {
676122f3e6SDimitry Andric   return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
686122f3e6SDimitry Andric                         Data.data());
696122f3e6SDimitry Andric }
706122f3e6SDimitry Andric 
getU24(uint32_t * offset_ptr) const71*edd7eaddSDimitry Andric uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const {
72*edd7eaddSDimitry Andric   uint24_t ExtractedVal =
73*edd7eaddSDimitry Andric       getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data());
74*edd7eaddSDimitry Andric   // The 3 bytes are in the correct byte order for the host.
75*edd7eaddSDimitry Andric   return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
76*edd7eaddSDimitry Andric }
77*edd7eaddSDimitry Andric 
getU32(uint32_t * offset_ptr) const786122f3e6SDimitry Andric uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const {
796122f3e6SDimitry Andric   return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data());
806122f3e6SDimitry Andric }
816122f3e6SDimitry Andric 
getU32(uint32_t * offset_ptr,uint32_t * dst,uint32_t count) const826122f3e6SDimitry Andric uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst,
836122f3e6SDimitry Andric                                 uint32_t count) const {
846122f3e6SDimitry Andric   return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
85dff0c46cSDimitry Andric                         Data.data());
866122f3e6SDimitry Andric }
876122f3e6SDimitry Andric 
getU64(uint32_t * offset_ptr) const886122f3e6SDimitry Andric uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const {
896122f3e6SDimitry Andric   return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data());
906122f3e6SDimitry Andric }
916122f3e6SDimitry Andric 
getU64(uint32_t * offset_ptr,uint64_t * dst,uint32_t count) const926122f3e6SDimitry Andric uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst,
936122f3e6SDimitry Andric                                 uint32_t count) const {
946122f3e6SDimitry Andric   return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
956122f3e6SDimitry Andric                         Data.data());
966122f3e6SDimitry Andric }
976122f3e6SDimitry Andric 
986122f3e6SDimitry Andric uint64_t
getUnsigned(uint32_t * offset_ptr,uint32_t byte_size) const996122f3e6SDimitry Andric DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const {
1006122f3e6SDimitry Andric   switch (byte_size) {
1016122f3e6SDimitry Andric   case 1:
1026122f3e6SDimitry Andric     return getU8(offset_ptr);
1036122f3e6SDimitry Andric   case 2:
1046122f3e6SDimitry Andric     return getU16(offset_ptr);
1056122f3e6SDimitry Andric   case 4:
1066122f3e6SDimitry Andric     return getU32(offset_ptr);
1076122f3e6SDimitry Andric   case 8:
1086122f3e6SDimitry Andric     return getU64(offset_ptr);
1096122f3e6SDimitry Andric   }
1106122f3e6SDimitry Andric   llvm_unreachable("getUnsigned unhandled case!");
1116122f3e6SDimitry Andric }
1126122f3e6SDimitry Andric 
1136122f3e6SDimitry Andric int64_t
getSigned(uint32_t * offset_ptr,uint32_t byte_size) const1146122f3e6SDimitry Andric DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
1156122f3e6SDimitry Andric   switch (byte_size) {
1166122f3e6SDimitry Andric   case 1:
1176122f3e6SDimitry Andric     return (int8_t)getU8(offset_ptr);
1186122f3e6SDimitry Andric   case 2:
1196122f3e6SDimitry Andric     return (int16_t)getU16(offset_ptr);
1206122f3e6SDimitry Andric   case 4:
1216122f3e6SDimitry Andric     return (int32_t)getU32(offset_ptr);
1226122f3e6SDimitry Andric   case 8:
1236122f3e6SDimitry Andric     return (int64_t)getU64(offset_ptr);
1246122f3e6SDimitry Andric   }
1256122f3e6SDimitry Andric   llvm_unreachable("getSigned unhandled case!");
1266122f3e6SDimitry Andric }
1276122f3e6SDimitry Andric 
getCStr(uint32_t * offset_ptr) const1286122f3e6SDimitry Andric const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
1296122f3e6SDimitry Andric   uint32_t offset = *offset_ptr;
1306122f3e6SDimitry Andric   StringRef::size_type pos = Data.find('\0', offset);
1316122f3e6SDimitry Andric   if (pos != StringRef::npos) {
1326122f3e6SDimitry Andric     *offset_ptr = pos + 1;
1336122f3e6SDimitry Andric     return Data.data() + offset;
1346122f3e6SDimitry Andric   }
13591bc56edSDimitry Andric   return nullptr;
1366122f3e6SDimitry Andric }
1376122f3e6SDimitry Andric 
getCStrRef(uint32_t * OffsetPtr) const138f37b6182SDimitry Andric StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const {
139f37b6182SDimitry Andric   uint32_t Start = *OffsetPtr;
140f37b6182SDimitry Andric   StringRef::size_type Pos = Data.find('\0', Start);
141f37b6182SDimitry Andric   if (Pos != StringRef::npos) {
142f37b6182SDimitry Andric     *OffsetPtr = Pos + 1;
143f37b6182SDimitry Andric     return StringRef(Data.data() + Start, Pos - Start);
144f37b6182SDimitry Andric   }
145f37b6182SDimitry Andric   return StringRef();
146f37b6182SDimitry Andric }
147f37b6182SDimitry Andric 
getULEB128(uint32_t * offset_ptr) const1486122f3e6SDimitry Andric uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
1496122f3e6SDimitry Andric   uint64_t result = 0;
1506122f3e6SDimitry Andric   if (Data.empty())
1516122f3e6SDimitry Andric     return 0;
1526122f3e6SDimitry Andric 
1536122f3e6SDimitry Andric   unsigned shift = 0;
1546122f3e6SDimitry Andric   uint32_t offset = *offset_ptr;
1556122f3e6SDimitry Andric   uint8_t byte = 0;
1566122f3e6SDimitry Andric 
1576122f3e6SDimitry Andric   while (isValidOffset(offset)) {
1586122f3e6SDimitry Andric     byte = Data[offset++];
1593861d79fSDimitry Andric     result |= uint64_t(byte & 0x7f) << shift;
1606122f3e6SDimitry Andric     shift += 7;
1616122f3e6SDimitry Andric     if ((byte & 0x80) == 0)
1626122f3e6SDimitry Andric       break;
1636122f3e6SDimitry Andric   }
1646122f3e6SDimitry Andric 
1656122f3e6SDimitry Andric   *offset_ptr = offset;
1666122f3e6SDimitry Andric   return result;
1676122f3e6SDimitry Andric }
1686122f3e6SDimitry Andric 
getSLEB128(uint32_t * offset_ptr) const1696122f3e6SDimitry Andric int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
1706122f3e6SDimitry Andric   int64_t result = 0;
1716122f3e6SDimitry Andric   if (Data.empty())
1726122f3e6SDimitry Andric     return 0;
1736122f3e6SDimitry Andric 
1746122f3e6SDimitry Andric   unsigned shift = 0;
1756122f3e6SDimitry Andric   uint32_t offset = *offset_ptr;
1766122f3e6SDimitry Andric   uint8_t byte = 0;
1776122f3e6SDimitry Andric 
1786122f3e6SDimitry Andric   while (isValidOffset(offset)) {
1796122f3e6SDimitry Andric     byte = Data[offset++];
1803861d79fSDimitry Andric     result |= uint64_t(byte & 0x7f) << shift;
1816122f3e6SDimitry Andric     shift += 7;
1826122f3e6SDimitry Andric     if ((byte & 0x80) == 0)
1836122f3e6SDimitry Andric       break;
1846122f3e6SDimitry Andric   }
1856122f3e6SDimitry Andric 
1866122f3e6SDimitry Andric   // Sign bit of byte is 2nd high order bit (0x40)
1876122f3e6SDimitry Andric   if (shift < 64 && (byte & 0x40))
1883861d79fSDimitry Andric     result |= -(1ULL << shift);
1896122f3e6SDimitry Andric 
1906122f3e6SDimitry Andric   *offset_ptr = offset;
1916122f3e6SDimitry Andric   return result;
1926122f3e6SDimitry Andric }
193