LLVM  10.0.0svn
DataExtractor.cpp
Go to the documentation of this file.
1 //===-- DataExtractor.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/Host.h"
13 #include "llvm/Support/LEB128.h"
15 
16 using namespace llvm;
17 
18 static void unexpectedEndReached(Error *E) {
19  if (E)
21  "unexpected end of data");
22 }
23 
24 static bool isError(Error *E) { return E && *E; }
25 
26 template <typename T>
27 static T getU(uint64_t *offset_ptr, const DataExtractor *de,
28  bool isLittleEndian, const char *Data, llvm::Error *Err) {
29  ErrorAsOutParameter ErrAsOut(Err);
30  T val = 0;
31  if (isError(Err))
32  return val;
33 
34  uint64_t offset = *offset_ptr;
35  if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) {
37  return val;
38  }
39  std::memcpy(&val, &Data[offset], sizeof(val));
40  if (sys::IsLittleEndianHost != isLittleEndian)
41  sys::swapByteOrder(val);
42 
43  // Advance the offset
44  *offset_ptr += sizeof(val);
45  return val;
46 }
47 
48 template <typename T>
49 static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
50  const DataExtractor *de, bool isLittleEndian, const char *Data,
51  llvm::Error *Err) {
52  ErrorAsOutParameter ErrAsOut(Err);
53  if (isError(Err))
54  return nullptr;
55 
56  uint64_t offset = *offset_ptr;
57 
58  if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) {
60  return nullptr;
61  }
62  for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
63  ++value_ptr, offset += sizeof(*dst))
64  *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err);
65  // Advance the offset
66  *offset_ptr = offset;
67  // Return a non-NULL pointer to the converted data as an indicator of
68  // success
69  return dst;
70 }
71 
72 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
73  return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
74 }
75 
76 uint8_t *
77 DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const {
78  return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
79  Data.data(), nullptr);
80 }
81 
82 uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
83  return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian,
84  Data.data(), &C.Err);
85 }
86 
87 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
88  return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
89 }
90 
91 uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
92  uint32_t count) const {
93  return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
94  Data.data(), nullptr);
95 }
96 
97 uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const {
98  uint24_t ExtractedVal =
99  getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data(), nullptr);
100  // The 3 bytes are in the correct byte order for the host.
101  return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
102 }
103 
104 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
105  return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
106 }
107 
108 uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
109  uint32_t count) const {
110  return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
111  Data.data(), nullptr);
112 }
113 
114 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
115  return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
116 }
117 
118 uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
119  uint32_t count) const {
120  return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
121  Data.data(), nullptr);
122 }
123 
124 uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
125  llvm::Error *Err) const {
126  switch (byte_size) {
127  case 1:
128  return getU8(offset_ptr, Err);
129  case 2:
130  return getU16(offset_ptr, Err);
131  case 4:
132  return getU32(offset_ptr, Err);
133  case 8:
134  return getU64(offset_ptr, Err);
135  }
136  llvm_unreachable("getUnsigned unhandled case!");
137 }
138 
139 int64_t
140 DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
141  switch (byte_size) {
142  case 1:
143  return (int8_t)getU8(offset_ptr);
144  case 2:
145  return (int16_t)getU16(offset_ptr);
146  case 4:
147  return (int32_t)getU32(offset_ptr);
148  case 8:
149  return (int64_t)getU64(offset_ptr);
150  }
151  llvm_unreachable("getSigned unhandled case!");
152 }
153 
154 const char *DataExtractor::getCStr(uint64_t *offset_ptr) const {
155  uint64_t offset = *offset_ptr;
156  StringRef::size_type pos = Data.find('\0', offset);
157  if (pos != StringRef::npos) {
158  *offset_ptr = pos + 1;
159  return Data.data() + offset;
160  }
161  return nullptr;
162 }
163 
164 StringRef DataExtractor::getCStrRef(uint64_t *offset_ptr) const {
165  uint64_t Start = *offset_ptr;
166  StringRef::size_type Pos = Data.find('\0', Start);
167  if (Pos != StringRef::npos) {
168  *offset_ptr = Pos + 1;
169  return StringRef(Data.data() + Start, Pos - Start);
170  }
171  return StringRef();
172 }
173 
174 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr,
175  llvm::Error *Err) const {
176  assert(*offset_ptr <= Data.size());
177  ErrorAsOutParameter ErrAsOut(Err);
178  if (isError(Err))
179  return 0;
180 
181  const char *error;
182  unsigned bytes_read;
183  uint64_t result = decodeULEB128(
184  reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read,
185  reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error);
186  if (error) {
187  if (Err)
189  return 0;
190  }
191  *offset_ptr += bytes_read;
192  return result;
193 }
194 
195 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const {
196  assert(*offset_ptr <= Data.size());
197 
198  const char *error;
199  unsigned bytes_read;
200  int64_t result = decodeSLEB128(
201  reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read,
202  reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error);
203  if (error)
204  return 0;
205  *offset_ptr += bytes_read;
206  return result;
207 }
208 
209 void DataExtractor::skip(Cursor &C, uint64_t Length) const {
210  ErrorAsOutParameter ErrAsOut(&C.Err);
211  if (isError(&C.Err))
212  return;
213 
214  if (isValidOffsetForDataOfSize(C.Offset, Length))
215  C.Offset += Length;
216  else
217  unexpectedEndReached(&C.Err);
218 }
uint64_t CallInst * C
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:233
uint32_t getU24(uint64_t *offset_ptr) const
Extract a 24-bit unsigned value from *offset_ptr and return it in a uint32_t.
static void unexpectedEndReached(Error *E)
void swapByteOrder(T &Value)
uint16_t getU16(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint16_t value from *offset_ptr.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
void skip(Cursor &C, uint64_t Length) const
Advance the Cursor position by the given number of bytes.
const char * getCStr(uint64_t *offset_ptr) const
Extract a C string from *offset_ptr.
uint32_t getAsUint32(bool IsLittleEndian) const
Definition: DataExtractor.h:27
uint32_t getU32(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint32_t value from *offset_ptr.
#define error(X)
static T getU(uint64_t *offset_ptr, const DataExtractor *de, bool isLittleEndian, const char *Data, llvm::Error *Err)
int64_t getSLEB128(uint64_t *offset_ptr) const
Extract a signed LEB128 value from *offset_ptr.
An auxiliary type to facilitate extraction of 3-byte entities.
Definition: DataExtractor.h:19
int64_t decodeSLEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a SLEB128 value.
Definition: LEB128.h:161
static const bool IsLittleEndianHost
Definition: SwapByteOrder.h:54
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:144
auto count(R &&Range, const E &Element) -> typename std::iterator_traits< decltype(adl_begin(Range))>::difference_type
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:1231
static T * getUs(uint64_t *offset_ptr, T *dst, uint32_t count, const DataExtractor *de, bool isLittleEndian, const char *Data, llvm::Error *Err)
uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, Error *Err=nullptr) const
Extract an unsigned integer of size byte_size from *offset_ptr.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_NODISCARD size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:299
uint64_t decodeULEB128(const uint8_t *p, unsigned *n=nullptr, const uint8_t *end=nullptr, const char **error=nullptr)
Utility function to decode a ULEB128 value.
Definition: LEB128.h:128
A class representing a position in a DataExtractor, as well as any error encountered during extractio...
Definition: DataExtractor.h:54
uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err=nullptr) const
Extract a unsigned LEB128 value from *offset_ptr.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const
Test the availability of length bytes of data from offset.
static bool isError(Error *E)
Helper for Errors used as out-parameters.
Definition: Error.h:1055
static const size_t npos
Definition: StringRef.h:50
LLVM_NODISCARD const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:136
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
uint64_t getU64(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint64_t value from *offset_ptr.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
StringRef getCStrRef(uint64_t *offset_ptr) const
Extract a C string from *offset_ptr.
int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const
Extract an signed integer of size byte_size from *offset_ptr.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1197