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)); 2388a1d9fcSBenjamin Kramer 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, 78*5dfe6dabSChad 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++]; 14288a1d9fcSBenjamin Kramer result |= (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++]; 16388a1d9fcSBenjamin Kramer result |= (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)) 17188a1d9fcSBenjamin Kramer result |= -(1 << shift); 17288a1d9fcSBenjamin Kramer 17388a1d9fcSBenjamin Kramer *offset_ptr = offset; 17488a1d9fcSBenjamin Kramer return result; 17588a1d9fcSBenjamin Kramer } 176