1226584Sdim//===-- DataExtractor.h -----------------------------------------*- C++ -*-===//
2226584Sdim//
3226584Sdim//                     The LLVM Compiler Infrastructure
4226584Sdim//
5226584Sdim// This file is distributed under the University of Illinois Open Source
6226584Sdim// License. See LICENSE.TXT for details.
7226584Sdim//
8226584Sdim//===----------------------------------------------------------------------===//
9226584Sdim
10226584Sdim#ifndef LLVM_SUPPORT_DATAEXTRACTOR_H
11226584Sdim#define LLVM_SUPPORT_DATAEXTRACTOR_H
12226584Sdim
13243830Sdim#include "llvm/ADT/DenseMap.h"
14226584Sdim#include "llvm/ADT/StringRef.h"
15226584Sdim#include "llvm/Support/DataTypes.h"
16226584Sdim
17226584Sdimnamespace llvm {
18226584Sdimclass DataExtractor {
19226584Sdim  StringRef Data;
20226584Sdim  uint8_t IsLittleEndian;
21249423Sdim  uint8_t AddressSize;
22226584Sdimpublic:
23226584Sdim  /// Construct with a buffer that is owned by the caller.
24226584Sdim  ///
25226584Sdim  /// This constructor allows us to use data that is owned by the
26226584Sdim  /// caller. The data must stay around as long as this object is
27226584Sdim  /// valid.
28249423Sdim  DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
29249423Sdim    : Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
30226584Sdim
31249423Sdim  /// \brief Get the data pointed to by this extractor.
32226584Sdim  StringRef getData() const { return Data; }
33249423Sdim  /// \brief Get the endianess for this extractor.
34226584Sdim  bool isLittleEndian() const { return IsLittleEndian; }
35249423Sdim  /// \brief Get the address size for this extractor.
36249423Sdim  uint8_t getAddressSize() const { return AddressSize; }
37249423Sdim  /// \brief Set the address size for this extractor.
38249423Sdim  void setAddressSize(uint8_t Size) { AddressSize = Size; }
39226584Sdim
40226584Sdim  /// Extract a C string from \a *offset_ptr.
41226584Sdim  ///
42226584Sdim  /// Returns a pointer to a C String from the data at the offset
43226584Sdim  /// pointed to by \a offset_ptr. A variable length NULL terminated C
44226584Sdim  /// string will be extracted and the \a offset_ptr will be
45226584Sdim  /// updated with the offset of the byte that follows the NULL
46226584Sdim  /// terminator byte.
47226584Sdim  ///
48226584Sdim  /// @param[in,out] offset_ptr
49226584Sdim  ///     A pointer to an offset within the data that will be advanced
50226584Sdim  ///     by the appropriate number of bytes if the value is extracted
51226584Sdim  ///     correctly. If the offset is out of bounds or there are not
52226584Sdim  ///     enough bytes to extract this value, the offset will be left
53226584Sdim  ///     unmodified.
54226584Sdim  ///
55226584Sdim  /// @return
56226584Sdim  ///     A pointer to the C string value in the data. If the offset
57226584Sdim  ///     pointed to by \a offset_ptr is out of bounds, or if the
58226584Sdim  ///     offset plus the length of the C string is out of bounds,
59226584Sdim  ///     NULL will be returned.
60226584Sdim  const char *getCStr(uint32_t *offset_ptr) const;
61226584Sdim
62226584Sdim  /// Extract an unsigned integer of size \a byte_size from \a
63226584Sdim  /// *offset_ptr.
64226584Sdim  ///
65226584Sdim  /// Extract a single unsigned integer value and update the offset
66226584Sdim  /// pointed to by \a offset_ptr. The size of the extracted integer
67226584Sdim  /// is specified by the \a byte_size argument. \a byte_size should
68226584Sdim  /// have a value greater than or equal to one and less than or equal
69226584Sdim  /// to eight since the return value is 64 bits wide. Any
70226584Sdim  /// \a byte_size values less than 1 or greater than 8 will result in
71226584Sdim  /// nothing being extracted, and zero being returned.
72226584Sdim  ///
73226584Sdim  /// @param[in,out] offset_ptr
74226584Sdim  ///     A pointer to an offset within the data that will be advanced
75226584Sdim  ///     by the appropriate number of bytes if the value is extracted
76226584Sdim  ///     correctly. If the offset is out of bounds or there are not
77226584Sdim  ///     enough bytes to extract this value, the offset will be left
78226584Sdim  ///     unmodified.
79226584Sdim  ///
80226584Sdim  /// @param[in] byte_size
81226584Sdim  ///     The size in byte of the integer to extract.
82226584Sdim  ///
83226584Sdim  /// @return
84226584Sdim  ///     The unsigned integer value that was extracted, or zero on
85226584Sdim  ///     failure.
86226584Sdim  uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const;
87226584Sdim
88226584Sdim  /// Extract an signed integer of size \a byte_size from \a *offset_ptr.
89226584Sdim  ///
90226584Sdim  /// Extract a single signed integer value (sign extending if required)
91226584Sdim  /// and update the offset pointed to by \a offset_ptr. The size of
92226584Sdim  /// the extracted integer is specified by the \a byte_size argument.
93226584Sdim  /// \a byte_size should have a value greater than or equal to one
94226584Sdim  /// and less than or equal to eight since the return value is 64
95226584Sdim  /// bits wide. Any \a byte_size values less than 1 or greater than
96226584Sdim  /// 8 will result in nothing being extracted, and zero being returned.
97226584Sdim  ///
98226584Sdim  /// @param[in,out] offset_ptr
99226584Sdim  ///     A pointer to an offset within the data that will be advanced
100226584Sdim  ///     by the appropriate number of bytes if the value is extracted
101226584Sdim  ///     correctly. If the offset is out of bounds or there are not
102226584Sdim  ///     enough bytes to extract this value, the offset will be left
103226584Sdim  ///     unmodified.
104226584Sdim  ///
105243830Sdim  /// @param[in] size
106243830Sdim  ///     The size in bytes of the integer to extract.
107226584Sdim  ///
108226584Sdim  /// @return
109226584Sdim  ///     The sign extended signed integer value that was extracted,
110226584Sdim  ///     or zero on failure.
111226584Sdim  int64_t getSigned(uint32_t *offset_ptr, uint32_t size) const;
112226584Sdim
113226584Sdim  //------------------------------------------------------------------
114226584Sdim  /// Extract an pointer from \a *offset_ptr.
115226584Sdim  ///
116226584Sdim  /// Extract a single pointer from the data and update the offset
117226584Sdim  /// pointed to by \a offset_ptr. The size of the extracted pointer
118249423Sdim  /// is \a getAddressSize(), so the address size has to be
119226584Sdim  /// set correctly prior to extracting any pointer values.
120226584Sdim  ///
121226584Sdim  /// @param[in,out] offset_ptr
122226584Sdim  ///     A pointer to an offset within the data that will be advanced
123226584Sdim  ///     by the appropriate number of bytes if the value is extracted
124226584Sdim  ///     correctly. If the offset is out of bounds or there are not
125226584Sdim  ///     enough bytes to extract this value, the offset will be left
126226584Sdim  ///     unmodified.
127226584Sdim  ///
128226584Sdim  /// @return
129226584Sdim  ///     The extracted pointer value as a 64 integer.
130226584Sdim  uint64_t getAddress(uint32_t *offset_ptr) const {
131249423Sdim    return getUnsigned(offset_ptr, AddressSize);
132226584Sdim  }
133226584Sdim
134226584Sdim  /// Extract a uint8_t value from \a *offset_ptr.
135226584Sdim  ///
136226584Sdim  /// Extract a single uint8_t from the binary data at the offset
137226584Sdim  /// pointed to by \a offset_ptr, and advance the offset on success.
138226584Sdim  ///
139226584Sdim  /// @param[in,out] offset_ptr
140226584Sdim  ///     A pointer to an offset within the data that will be advanced
141226584Sdim  ///     by the appropriate number of bytes if the value is extracted
142226584Sdim  ///     correctly. If the offset is out of bounds or there are not
143226584Sdim  ///     enough bytes to extract this value, the offset will be left
144226584Sdim  ///     unmodified.
145226584Sdim  ///
146226584Sdim  /// @return
147226584Sdim  ///     The extracted uint8_t value.
148226584Sdim  uint8_t getU8(uint32_t *offset_ptr) const;
149226584Sdim
150226584Sdim  /// Extract \a count uint8_t values from \a *offset_ptr.
151226584Sdim  ///
152226584Sdim  /// Extract \a count uint8_t values from the binary data at the
153226584Sdim  /// offset pointed to by \a offset_ptr, and advance the offset on
154226584Sdim  /// success. The extracted values are copied into \a dst.
155226584Sdim  ///
156226584Sdim  /// @param[in,out] offset_ptr
157226584Sdim  ///     A pointer to an offset within the data that will be advanced
158226584Sdim  ///     by the appropriate number of bytes if the value is extracted
159226584Sdim  ///     correctly. If the offset is out of bounds or there are not
160226584Sdim  ///     enough bytes to extract this value, the offset will be left
161226584Sdim  ///     unmodified.
162226584Sdim  ///
163226584Sdim  /// @param[out] dst
164226584Sdim  ///     A buffer to copy \a count uint8_t values into. \a dst must
165226584Sdim  ///     be large enough to hold all requested data.
166226584Sdim  ///
167226584Sdim  /// @param[in] count
168226584Sdim  ///     The number of uint8_t values to extract.
169226584Sdim  ///
170226584Sdim  /// @return
171226584Sdim  ///     \a dst if all values were properly extracted and copied,
172226584Sdim  ///     NULL otherise.
173226584Sdim  uint8_t *getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const;
174226584Sdim
175226584Sdim  //------------------------------------------------------------------
176226584Sdim  /// Extract a uint16_t value from \a *offset_ptr.
177226584Sdim  ///
178226584Sdim  /// Extract a single uint16_t from the binary data at the offset
179226584Sdim  /// pointed to by \a offset_ptr, and update the offset on success.
180226584Sdim  ///
181226584Sdim  /// @param[in,out] offset_ptr
182226584Sdim  ///     A pointer to an offset within the data that will be advanced
183226584Sdim  ///     by the appropriate number of bytes if the value is extracted
184226584Sdim  ///     correctly. If the offset is out of bounds or there are not
185226584Sdim  ///     enough bytes to extract this value, the offset will be left
186226584Sdim  ///     unmodified.
187226584Sdim  ///
188226584Sdim  /// @return
189226584Sdim  ///     The extracted uint16_t value.
190226584Sdim  //------------------------------------------------------------------
191226584Sdim  uint16_t getU16(uint32_t *offset_ptr) const;
192226584Sdim
193226584Sdim  /// Extract \a count uint16_t values from \a *offset_ptr.
194226584Sdim  ///
195226584Sdim  /// Extract \a count uint16_t values from the binary data at the
196226584Sdim  /// offset pointed to by \a offset_ptr, and advance the offset on
197226584Sdim  /// success. The extracted values are copied into \a dst.
198226584Sdim  ///
199226584Sdim  /// @param[in,out] offset_ptr
200226584Sdim  ///     A pointer to an offset within the data that will be advanced
201226584Sdim  ///     by the appropriate number of bytes if the value is extracted
202226584Sdim  ///     correctly. If the offset is out of bounds or there are not
203226584Sdim  ///     enough bytes to extract this value, the offset will be left
204226584Sdim  ///     unmodified.
205226584Sdim  ///
206226584Sdim  /// @param[out] dst
207226584Sdim  ///     A buffer to copy \a count uint16_t values into. \a dst must
208226584Sdim  ///     be large enough to hold all requested data.
209226584Sdim  ///
210226584Sdim  /// @param[in] count
211226584Sdim  ///     The number of uint16_t values to extract.
212226584Sdim  ///
213226584Sdim  /// @return
214226584Sdim  ///     \a dst if all values were properly extracted and copied,
215226584Sdim  ///     NULL otherise.
216226584Sdim  uint16_t *getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const;
217226584Sdim
218226584Sdim  /// Extract a uint32_t value from \a *offset_ptr.
219226584Sdim  ///
220226584Sdim  /// Extract a single uint32_t from the binary data at the offset
221226584Sdim  /// pointed to by \a offset_ptr, and update the offset on success.
222226584Sdim  ///
223226584Sdim  /// @param[in,out] offset_ptr
224226584Sdim  ///     A pointer to an offset within the data that will be advanced
225226584Sdim  ///     by the appropriate number of bytes if the value is extracted
226226584Sdim  ///     correctly. If the offset is out of bounds or there are not
227226584Sdim  ///     enough bytes to extract this value, the offset will be left
228226584Sdim  ///     unmodified.
229226584Sdim  ///
230226584Sdim  /// @return
231226584Sdim  ///     The extracted uint32_t value.
232226584Sdim  uint32_t getU32(uint32_t *offset_ptr) const;
233226584Sdim
234226584Sdim  /// Extract \a count uint32_t values from \a *offset_ptr.
235226584Sdim  ///
236226584Sdim  /// Extract \a count uint32_t values from the binary data at the
237226584Sdim  /// offset pointed to by \a offset_ptr, and advance the offset on
238226584Sdim  /// success. The extracted values are copied into \a dst.
239226584Sdim  ///
240226584Sdim  /// @param[in,out] offset_ptr
241226584Sdim  ///     A pointer to an offset within the data that will be advanced
242226584Sdim  ///     by the appropriate number of bytes if the value is extracted
243226584Sdim  ///     correctly. If the offset is out of bounds or there are not
244226584Sdim  ///     enough bytes to extract this value, the offset will be left
245226584Sdim  ///     unmodified.
246226584Sdim  ///
247226584Sdim  /// @param[out] dst
248226584Sdim  ///     A buffer to copy \a count uint32_t values into. \a dst must
249226584Sdim  ///     be large enough to hold all requested data.
250226584Sdim  ///
251226584Sdim  /// @param[in] count
252226584Sdim  ///     The number of uint32_t values to extract.
253226584Sdim  ///
254226584Sdim  /// @return
255226584Sdim  ///     \a dst if all values were properly extracted and copied,
256226584Sdim  ///     NULL otherise.
257226584Sdim  uint32_t *getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const;
258226584Sdim
259226584Sdim  /// Extract a uint64_t value from \a *offset_ptr.
260226584Sdim  ///
261226584Sdim  /// Extract a single uint64_t from the binary data at the offset
262226584Sdim  /// pointed to by \a offset_ptr, and update the offset on success.
263226584Sdim  ///
264226584Sdim  /// @param[in,out] offset_ptr
265226584Sdim  ///     A pointer to an offset within the data that will be advanced
266226584Sdim  ///     by the appropriate number of bytes if the value is extracted
267226584Sdim  ///     correctly. If the offset is out of bounds or there are not
268226584Sdim  ///     enough bytes to extract this value, the offset will be left
269226584Sdim  ///     unmodified.
270226584Sdim  ///
271226584Sdim  /// @return
272226584Sdim  ///     The extracted uint64_t value.
273226584Sdim  uint64_t getU64(uint32_t *offset_ptr) const;
274226584Sdim
275226584Sdim  /// Extract \a count uint64_t values from \a *offset_ptr.
276226584Sdim  ///
277226584Sdim  /// Extract \a count uint64_t values from the binary data at the
278226584Sdim  /// offset pointed to by \a offset_ptr, and advance the offset on
279226584Sdim  /// success. The extracted values are copied into \a dst.
280226584Sdim  ///
281226584Sdim  /// @param[in,out] offset_ptr
282226584Sdim  ///     A pointer to an offset within the data that will be advanced
283226584Sdim  ///     by the appropriate number of bytes if the value is extracted
284226584Sdim  ///     correctly. If the offset is out of bounds or there are not
285226584Sdim  ///     enough bytes to extract this value, the offset will be left
286226584Sdim  ///     unmodified.
287226584Sdim  ///
288226584Sdim  /// @param[out] dst
289226584Sdim  ///     A buffer to copy \a count uint64_t values into. \a dst must
290226584Sdim  ///     be large enough to hold all requested data.
291226584Sdim  ///
292226584Sdim  /// @param[in] count
293226584Sdim  ///     The number of uint64_t values to extract.
294226584Sdim  ///
295226584Sdim  /// @return
296226584Sdim  ///     \a dst if all values were properly extracted and copied,
297226584Sdim  ///     NULL otherise.
298226584Sdim  uint64_t *getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const;
299226584Sdim
300226584Sdim  /// Extract a signed LEB128 value from \a *offset_ptr.
301226584Sdim  ///
302226584Sdim  /// Extracts an signed LEB128 number from this object's data
303226584Sdim  /// starting at the offset pointed to by \a offset_ptr. The offset
304226584Sdim  /// pointed to by \a offset_ptr will be updated with the offset of
305226584Sdim  /// the byte following the last extracted byte.
306226584Sdim  ///
307226584Sdim  /// @param[in,out] offset_ptr
308226584Sdim  ///     A pointer to an offset within the data that will be advanced
309226584Sdim  ///     by the appropriate number of bytes if the value is extracted
310226584Sdim  ///     correctly. If the offset is out of bounds or there are not
311226584Sdim  ///     enough bytes to extract this value, the offset will be left
312226584Sdim  ///     unmodified.
313226584Sdim  ///
314226584Sdim  /// @return
315226584Sdim  ///     The extracted signed integer value.
316226584Sdim  int64_t getSLEB128(uint32_t *offset_ptr) const;
317226584Sdim
318226584Sdim  /// Extract a unsigned LEB128 value from \a *offset_ptr.
319226584Sdim  ///
320226584Sdim  /// Extracts an unsigned LEB128 number from this object's data
321226584Sdim  /// starting at the offset pointed to by \a offset_ptr. The offset
322226584Sdim  /// pointed to by \a offset_ptr will be updated with the offset of
323226584Sdim  /// the byte following the last extracted byte.
324226584Sdim  ///
325226584Sdim  /// @param[in,out] offset_ptr
326226584Sdim  ///     A pointer to an offset within the data that will be advanced
327226584Sdim  ///     by the appropriate number of bytes if the value is extracted
328226584Sdim  ///     correctly. If the offset is out of bounds or there are not
329226584Sdim  ///     enough bytes to extract this value, the offset will be left
330226584Sdim  ///     unmodified.
331226584Sdim  ///
332226584Sdim  /// @return
333226584Sdim  ///     The extracted unsigned integer value.
334226584Sdim  uint64_t getULEB128(uint32_t *offset_ptr) const;
335226584Sdim
336226584Sdim  /// Test the validity of \a offset.
337226584Sdim  ///
338226584Sdim  /// @return
339226584Sdim  ///     \b true if \a offset is a valid offset into the data in this
340226584Sdim  ///     object, \b false otherwise.
341226584Sdim  bool isValidOffset(uint32_t offset) const { return Data.size() > offset; }
342226584Sdim
343226584Sdim  /// Test the availability of \a length bytes of data from \a offset.
344226584Sdim  ///
345226584Sdim  /// @return
346226584Sdim  ///     \b true if \a offset is a valid offset and there are \a
347226584Sdim  ///     length bytes available at that offset, \b false otherwise.
348226584Sdim  bool isValidOffsetForDataOfSize(uint32_t offset, uint32_t length) const {
349226584Sdim    return offset + length >= offset && isValidOffset(offset + length - 1);
350226584Sdim  }
351226584Sdim};
352226584Sdim
353226584Sdim} // namespace llvm
354226584Sdim
355226584Sdim#endif
356