xref: /aosp_15_r20/external/llvm/lib/Support/DataExtractor.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- DataExtractor.cpp -------------------------------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker 
10*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/DataExtractor.h"
11*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ErrorHandling.h"
12*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Host.h"
13*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/SwapByteOrder.h"
14*9880d681SAndroid Build Coastguard Worker using namespace llvm;
15*9880d681SAndroid Build Coastguard Worker 
16*9880d681SAndroid Build Coastguard Worker template <typename T>
getU(uint32_t * offset_ptr,const DataExtractor * de,bool isLittleEndian,const char * Data)17*9880d681SAndroid Build Coastguard Worker static T getU(uint32_t *offset_ptr, const DataExtractor *de,
18*9880d681SAndroid Build Coastguard Worker               bool isLittleEndian, const char *Data) {
19*9880d681SAndroid Build Coastguard Worker   T val = 0;
20*9880d681SAndroid Build Coastguard Worker   uint32_t offset = *offset_ptr;
21*9880d681SAndroid Build Coastguard Worker   if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) {
22*9880d681SAndroid Build Coastguard Worker     std::memcpy(&val, &Data[offset], sizeof(val));
23*9880d681SAndroid Build Coastguard Worker     if (sys::IsLittleEndianHost != isLittleEndian)
24*9880d681SAndroid Build Coastguard Worker       sys::swapByteOrder(val);
25*9880d681SAndroid Build Coastguard Worker 
26*9880d681SAndroid Build Coastguard Worker     // Advance the offset
27*9880d681SAndroid Build Coastguard Worker     *offset_ptr += sizeof(val);
28*9880d681SAndroid Build Coastguard Worker   }
29*9880d681SAndroid Build Coastguard Worker   return val;
30*9880d681SAndroid Build Coastguard Worker }
31*9880d681SAndroid Build Coastguard Worker 
32*9880d681SAndroid Build Coastguard Worker template <typename T>
getUs(uint32_t * offset_ptr,T * dst,uint32_t count,const DataExtractor * de,bool isLittleEndian,const char * Data)33*9880d681SAndroid Build Coastguard Worker static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count,
34*9880d681SAndroid Build Coastguard Worker                 const DataExtractor *de, bool isLittleEndian, const char *Data){
35*9880d681SAndroid Build Coastguard Worker   uint32_t offset = *offset_ptr;
36*9880d681SAndroid Build Coastguard Worker 
37*9880d681SAndroid Build Coastguard Worker   if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) {
38*9880d681SAndroid Build Coastguard Worker     for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
39*9880d681SAndroid Build Coastguard Worker         ++value_ptr, offset += sizeof(*dst))
40*9880d681SAndroid Build Coastguard Worker       *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data);
41*9880d681SAndroid Build Coastguard Worker     // Advance the offset
42*9880d681SAndroid Build Coastguard Worker     *offset_ptr = offset;
43*9880d681SAndroid Build Coastguard Worker     // Return a non-NULL pointer to the converted data as an indicator of
44*9880d681SAndroid Build Coastguard Worker     // success
45*9880d681SAndroid Build Coastguard Worker     return dst;
46*9880d681SAndroid Build Coastguard Worker   }
47*9880d681SAndroid Build Coastguard Worker   return nullptr;
48*9880d681SAndroid Build Coastguard Worker }
49*9880d681SAndroid Build Coastguard Worker 
getU8(uint32_t * offset_ptr) const50*9880d681SAndroid Build Coastguard Worker uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const {
51*9880d681SAndroid Build Coastguard Worker   return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data());
52*9880d681SAndroid Build Coastguard Worker }
53*9880d681SAndroid Build Coastguard Worker 
54*9880d681SAndroid Build Coastguard Worker uint8_t *
getU8(uint32_t * offset_ptr,uint8_t * dst,uint32_t count) const55*9880d681SAndroid Build Coastguard Worker DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const {
56*9880d681SAndroid Build Coastguard Worker   return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
57*9880d681SAndroid Build Coastguard Worker                        Data.data());
58*9880d681SAndroid Build Coastguard Worker }
59*9880d681SAndroid Build Coastguard Worker 
60*9880d681SAndroid Build Coastguard Worker 
getU16(uint32_t * offset_ptr) const61*9880d681SAndroid Build Coastguard Worker uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const {
62*9880d681SAndroid Build Coastguard Worker   return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data());
63*9880d681SAndroid Build Coastguard Worker }
64*9880d681SAndroid Build Coastguard Worker 
getU16(uint32_t * offset_ptr,uint16_t * dst,uint32_t count) const65*9880d681SAndroid Build Coastguard Worker uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst,
66*9880d681SAndroid Build Coastguard Worker                                 uint32_t count) const {
67*9880d681SAndroid Build Coastguard Worker   return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
68*9880d681SAndroid Build Coastguard Worker                         Data.data());
69*9880d681SAndroid Build Coastguard Worker }
70*9880d681SAndroid Build Coastguard Worker 
getU32(uint32_t * offset_ptr) const71*9880d681SAndroid Build Coastguard Worker uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const {
72*9880d681SAndroid Build Coastguard Worker   return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data());
73*9880d681SAndroid Build Coastguard Worker }
74*9880d681SAndroid Build Coastguard Worker 
getU32(uint32_t * offset_ptr,uint32_t * dst,uint32_t count) const75*9880d681SAndroid Build Coastguard Worker uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst,
76*9880d681SAndroid Build Coastguard Worker                                 uint32_t count) const {
77*9880d681SAndroid Build Coastguard Worker   return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
78*9880d681SAndroid Build Coastguard Worker                         Data.data());
79*9880d681SAndroid Build Coastguard Worker }
80*9880d681SAndroid Build Coastguard Worker 
getU64(uint32_t * offset_ptr) const81*9880d681SAndroid Build Coastguard Worker uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const {
82*9880d681SAndroid Build Coastguard Worker   return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data());
83*9880d681SAndroid Build Coastguard Worker }
84*9880d681SAndroid Build Coastguard Worker 
getU64(uint32_t * offset_ptr,uint64_t * dst,uint32_t count) const85*9880d681SAndroid Build Coastguard Worker uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst,
86*9880d681SAndroid Build Coastguard Worker                                 uint32_t count) const {
87*9880d681SAndroid Build Coastguard Worker   return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
88*9880d681SAndroid Build Coastguard Worker                         Data.data());
89*9880d681SAndroid Build Coastguard Worker }
90*9880d681SAndroid Build Coastguard Worker 
91*9880d681SAndroid Build Coastguard Worker uint64_t
getUnsigned(uint32_t * offset_ptr,uint32_t byte_size) const92*9880d681SAndroid Build Coastguard Worker DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const {
93*9880d681SAndroid Build Coastguard Worker   switch (byte_size) {
94*9880d681SAndroid Build Coastguard Worker   case 1:
95*9880d681SAndroid Build Coastguard Worker     return getU8(offset_ptr);
96*9880d681SAndroid Build Coastguard Worker   case 2:
97*9880d681SAndroid Build Coastguard Worker     return getU16(offset_ptr);
98*9880d681SAndroid Build Coastguard Worker   case 4:
99*9880d681SAndroid Build Coastguard Worker     return getU32(offset_ptr);
100*9880d681SAndroid Build Coastguard Worker   case 8:
101*9880d681SAndroid Build Coastguard Worker     return getU64(offset_ptr);
102*9880d681SAndroid Build Coastguard Worker   }
103*9880d681SAndroid Build Coastguard Worker   llvm_unreachable("getUnsigned unhandled case!");
104*9880d681SAndroid Build Coastguard Worker }
105*9880d681SAndroid Build Coastguard Worker 
106*9880d681SAndroid Build Coastguard Worker int64_t
getSigned(uint32_t * offset_ptr,uint32_t byte_size) const107*9880d681SAndroid Build Coastguard Worker DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const {
108*9880d681SAndroid Build Coastguard Worker   switch (byte_size) {
109*9880d681SAndroid Build Coastguard Worker   case 1:
110*9880d681SAndroid Build Coastguard Worker     return (int8_t)getU8(offset_ptr);
111*9880d681SAndroid Build Coastguard Worker   case 2:
112*9880d681SAndroid Build Coastguard Worker     return (int16_t)getU16(offset_ptr);
113*9880d681SAndroid Build Coastguard Worker   case 4:
114*9880d681SAndroid Build Coastguard Worker     return (int32_t)getU32(offset_ptr);
115*9880d681SAndroid Build Coastguard Worker   case 8:
116*9880d681SAndroid Build Coastguard Worker     return (int64_t)getU64(offset_ptr);
117*9880d681SAndroid Build Coastguard Worker   }
118*9880d681SAndroid Build Coastguard Worker   llvm_unreachable("getSigned unhandled case!");
119*9880d681SAndroid Build Coastguard Worker }
120*9880d681SAndroid Build Coastguard Worker 
getCStr(uint32_t * offset_ptr) const121*9880d681SAndroid Build Coastguard Worker const char *DataExtractor::getCStr(uint32_t *offset_ptr) const {
122*9880d681SAndroid Build Coastguard Worker   uint32_t offset = *offset_ptr;
123*9880d681SAndroid Build Coastguard Worker   StringRef::size_type pos = Data.find('\0', offset);
124*9880d681SAndroid Build Coastguard Worker   if (pos != StringRef::npos) {
125*9880d681SAndroid Build Coastguard Worker     *offset_ptr = pos + 1;
126*9880d681SAndroid Build Coastguard Worker     return Data.data() + offset;
127*9880d681SAndroid Build Coastguard Worker   }
128*9880d681SAndroid Build Coastguard Worker   return nullptr;
129*9880d681SAndroid Build Coastguard Worker }
130*9880d681SAndroid Build Coastguard Worker 
getULEB128(uint32_t * offset_ptr) const131*9880d681SAndroid Build Coastguard Worker uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const {
132*9880d681SAndroid Build Coastguard Worker   uint64_t result = 0;
133*9880d681SAndroid Build Coastguard Worker   if (Data.empty())
134*9880d681SAndroid Build Coastguard Worker     return 0;
135*9880d681SAndroid Build Coastguard Worker 
136*9880d681SAndroid Build Coastguard Worker   unsigned shift = 0;
137*9880d681SAndroid Build Coastguard Worker   uint32_t offset = *offset_ptr;
138*9880d681SAndroid Build Coastguard Worker   uint8_t byte = 0;
139*9880d681SAndroid Build Coastguard Worker 
140*9880d681SAndroid Build Coastguard Worker   while (isValidOffset(offset)) {
141*9880d681SAndroid Build Coastguard Worker     byte = Data[offset++];
142*9880d681SAndroid Build Coastguard Worker     result |= uint64_t(byte & 0x7f) << shift;
143*9880d681SAndroid Build Coastguard Worker     shift += 7;
144*9880d681SAndroid Build Coastguard Worker     if ((byte & 0x80) == 0)
145*9880d681SAndroid Build Coastguard Worker       break;
146*9880d681SAndroid Build Coastguard Worker   }
147*9880d681SAndroid Build Coastguard Worker 
148*9880d681SAndroid Build Coastguard Worker   *offset_ptr = offset;
149*9880d681SAndroid Build Coastguard Worker   return result;
150*9880d681SAndroid Build Coastguard Worker }
151*9880d681SAndroid Build Coastguard Worker 
getSLEB128(uint32_t * offset_ptr) const152*9880d681SAndroid Build Coastguard Worker int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const {
153*9880d681SAndroid Build Coastguard Worker   int64_t result = 0;
154*9880d681SAndroid Build Coastguard Worker   if (Data.empty())
155*9880d681SAndroid Build Coastguard Worker     return 0;
156*9880d681SAndroid Build Coastguard Worker 
157*9880d681SAndroid Build Coastguard Worker   unsigned shift = 0;
158*9880d681SAndroid Build Coastguard Worker   uint32_t offset = *offset_ptr;
159*9880d681SAndroid Build Coastguard Worker   uint8_t byte = 0;
160*9880d681SAndroid Build Coastguard Worker 
161*9880d681SAndroid Build Coastguard Worker   while (isValidOffset(offset)) {
162*9880d681SAndroid Build Coastguard Worker     byte = Data[offset++];
163*9880d681SAndroid Build Coastguard Worker     result |= uint64_t(byte & 0x7f) << shift;
164*9880d681SAndroid Build Coastguard Worker     shift += 7;
165*9880d681SAndroid Build Coastguard Worker     if ((byte & 0x80) == 0)
166*9880d681SAndroid Build Coastguard Worker       break;
167*9880d681SAndroid Build Coastguard Worker   }
168*9880d681SAndroid Build Coastguard Worker 
169*9880d681SAndroid Build Coastguard Worker   // Sign bit of byte is 2nd high order bit (0x40)
170*9880d681SAndroid Build Coastguard Worker   if (shift < 64 && (byte & 0x40))
171*9880d681SAndroid Build Coastguard Worker     result |= -(1ULL << shift);
172*9880d681SAndroid Build Coastguard Worker 
173*9880d681SAndroid Build Coastguard Worker   *offset_ptr = offset;
174*9880d681SAndroid Build Coastguard Worker   return result;
175*9880d681SAndroid Build Coastguard Worker }
176