xref: /freebsd/contrib/llvm-project/llvm/lib/Support/DataExtractor.cpp (revision 5469a9953005a9a4d4aad7be88545d441622e9a0)
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  
9  #include "llvm/Support/DataExtractor.h"
10  #include "llvm/Support/Errc.h"
11  #include "llvm/Support/ErrorHandling.h"
12  #include "llvm/Support/Host.h"
13  #include "llvm/Support/LEB128.h"
14  #include "llvm/Support/SwapByteOrder.h"
15  
16  using namespace llvm;
17  
18  bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size,
19                                  Error *E) const {
20    if (isValidOffsetForDataOfSize(Offset, Size))
21      return true;
22    if (E) {
23      if (Offset <= Data.size())
24        *E = createStringError(
25            errc::illegal_byte_sequence,
26            "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64
27            ", 0x%" PRIx64 ")",
28            Data.size(), Offset, Offset + Size);
29      else
30        *E = createStringError(errc::invalid_argument,
31                               "offset 0x%" PRIx64
32                               " is beyond the end of data at 0x%zx",
33                               Offset, Data.size());
34    }
35    return false;
36  }
37  
38  static bool isError(Error *E) { return E && *E; }
39  
40  template <typename T>
41  T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const {
42    ErrorAsOutParameter ErrAsOut(Err);
43    T val = 0;
44    if (isError(Err))
45      return val;
46  
47    uint64_t offset = *offset_ptr;
48    if (!prepareRead(offset, sizeof(T), Err))
49      return val;
50    std::memcpy(&val, &Data.data()[offset], sizeof(val));
51    if (sys::IsLittleEndianHost != IsLittleEndian)
52      sys::swapByteOrder(val);
53  
54    // Advance the offset
55    *offset_ptr += sizeof(val);
56    return val;
57  }
58  
59  template <typename T>
60  T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
61                          Error *Err) const {
62    ErrorAsOutParameter ErrAsOut(Err);
63    if (isError(Err))
64      return nullptr;
65  
66    uint64_t offset = *offset_ptr;
67  
68    if (!prepareRead(offset, sizeof(*dst) * count, Err))
69      return nullptr;
70    for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
71         ++value_ptr, offset += sizeof(*dst))
72      *value_ptr = getU<T>(offset_ptr, Err);
73    // Advance the offset
74    *offset_ptr = offset;
75    // Return a non-NULL pointer to the converted data as an indicator of
76    // success
77    return dst;
78  }
79  
80  uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
81    return getU<uint8_t>(offset_ptr, Err);
82  }
83  
84  uint8_t *DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst,
85                                uint32_t count) const {
86    return getUs<uint8_t>(offset_ptr, dst, count, nullptr);
87  }
88  
89  uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
90    return getUs<uint8_t>(&C.Offset, Dst, Count, &C.Err);
91  }
92  
93  uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
94    return getU<uint16_t>(offset_ptr, Err);
95  }
96  
97  uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
98                                  uint32_t count) const {
99    return getUs<uint16_t>(offset_ptr, dst, count, nullptr);
100  }
101  
102  uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const {
103    uint24_t ExtractedVal = getU<uint24_t>(OffsetPtr, Err);
104    // The 3 bytes are in the correct byte order for the host.
105    return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
106  }
107  
108  uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
109    return getU<uint32_t>(offset_ptr, Err);
110  }
111  
112  uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
113                                  uint32_t count) const {
114    return getUs<uint32_t>(offset_ptr, dst, count, nullptr);
115  }
116  
117  uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
118    return getU<uint64_t>(offset_ptr, Err);
119  }
120  
121  uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
122                                  uint32_t count) const {
123    return getUs<uint64_t>(offset_ptr, dst, count, nullptr);
124  }
125  
126  uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
127                                      llvm::Error *Err) const {
128    switch (byte_size) {
129    case 1:
130      return getU8(offset_ptr, Err);
131    case 2:
132      return getU16(offset_ptr, Err);
133    case 4:
134      return getU32(offset_ptr, Err);
135    case 8:
136      return getU64(offset_ptr, Err);
137    }
138    llvm_unreachable("getUnsigned unhandled case!");
139  }
140  
141  int64_t
142  DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
143    switch (byte_size) {
144    case 1:
145      return (int8_t)getU8(offset_ptr);
146    case 2:
147      return (int16_t)getU16(offset_ptr);
148    case 4:
149      return (int32_t)getU32(offset_ptr);
150    case 8:
151      return (int64_t)getU64(offset_ptr);
152    }
153    llvm_unreachable("getSigned unhandled case!");
154  }
155  
156  StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {
157    ErrorAsOutParameter ErrAsOut(Err);
158    if (isError(Err))
159      return StringRef();
160  
161    uint64_t Start = *OffsetPtr;
162    StringRef::size_type Pos = Data.find('\0', Start);
163    if (Pos != StringRef::npos) {
164      *OffsetPtr = Pos + 1;
165      return StringRef(Data.data() + Start, Pos - Start);
166    }
167    if (Err)
168      *Err = createStringError(errc::illegal_byte_sequence,
169                               "no null terminated string at offset 0x%" PRIx64,
170                               Start);
171    return StringRef();
172  }
173  
174  StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,
175                                                uint64_t Length,
176                                                StringRef TrimChars) const {
177    StringRef Bytes(getBytes(OffsetPtr, Length));
178    return Bytes.trim(TrimChars);
179  }
180  
181  StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,
182                                    Error *Err) const {
183    ErrorAsOutParameter ErrAsOut(Err);
184    if (isError(Err))
185      return StringRef();
186  
187    if (!prepareRead(*OffsetPtr, Length, Err))
188      return StringRef();
189  
190    StringRef Result = Data.substr(*OffsetPtr, Length);
191    *OffsetPtr += Length;
192    return Result;
193  }
194  
195  template <typename T>
196  static T getLEB128(StringRef Data, uint64_t *OffsetPtr, Error *Err,
197                     T (&Decoder)(const uint8_t *p, unsigned *n,
198                                  const uint8_t *end, const char **error)) {
199    ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Data);
200    assert(*OffsetPtr <= Bytes.size());
201    ErrorAsOutParameter ErrAsOut(Err);
202    if (isError(Err))
203      return T();
204  
205    const char *error;
206    unsigned bytes_read;
207    T result =
208        Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);
209    if (error) {
210      if (Err)
211        *Err = createStringError(errc::illegal_byte_sequence,
212                                 "unable to decode LEB128 at offset 0x%8.8" PRIx64
213                                 ": %s",
214                                 *OffsetPtr, error);
215      return T();
216    }
217    *OffsetPtr += bytes_read;
218    return result;
219  }
220  
221  uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {
222    return getLEB128(Data, offset_ptr, Err, decodeULEB128);
223  }
224  
225  int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {
226    return getLEB128(Data, offset_ptr, Err, decodeSLEB128);
227  }
228  
229  void DataExtractor::skip(Cursor &C, uint64_t Length) const {
230    ErrorAsOutParameter ErrAsOut(&C.Err);
231    if (isError(&C.Err))
232      return;
233  
234    if (prepareRead(C.Offset, Length, &C.Err))
235      C.Offset += Length;
236  }
237