1111
1212#include " llvm/ADT/StringRef.h"
1313#include " llvm/Support/DataTypes.h"
14+ #include " llvm/Support/Error.h"
1415
1516namespace llvm {
1617
@@ -42,6 +43,38 @@ class DataExtractor {
4243 uint8_t IsLittleEndian;
4344 uint8_t AddressSize;
4445public:
46+ // / A class representing a position in a DataExtractor, as well as any error
47+ // / encountered during extraction. It enables one to extract a sequence of
48+ // / values without error-checking and then checking for errors in bulk at the
49+ // / end. The class holds an Error object, so failing to check the result of
50+ // / the parse will result in a runtime error. The error flag is sticky and
51+ // / will cause all subsequent extraction functions to fail without even
52+ // / attempting to parse and without updating the Cursor offset. After clearing
53+ // / the error flag, one can again use the Cursor object for parsing.
54+ class Cursor {
55+ uint64_t Offset;
56+ Error Err;
57+
58+ friend class DataExtractor ;
59+
60+ public:
61+ // / Construct a cursor for extraction from the given offset.
62+ explicit Cursor (uint64_t Offset) : Offset(Offset), Err(Error::success()) {}
63+
64+ // / Checks whether the cursor is valid (i.e. no errors were encountered). In
65+ // / case of errors, this does not clear the error flag -- one must call
66+ // / takeError() instead.
67+ explicit operator bool () { return !Err; }
68+
69+ // / Return the current position of this Cursor. In the error state this is
70+ // / the position of the Cursor before the first error was encountered.
71+ uint64_t tell () const { return Offset; }
72+
73+ // / Return error contained inside this Cursor, if any. Clears the internal
74+ // / Cursor state.
75+ Error takeError () { return std::move (Err); }
76+ };
77+
4578 // / Construct with a buffer that is owned by the caller.
4679 // /
4780 // / This constructor allows us to use data that is owned by the
@@ -124,10 +157,24 @@ class DataExtractor {
124157 // / @param[in] byte_size
125158 // / The size in byte of the integer to extract.
126159 // /
160+ // / @param[in,out] Err
161+ // / A pointer to an Error object. Upon return the Error object is set to
162+ // / indicate the result (success/failure) of the function. If the Error
163+ // / object is already set when calling this function, no extraction is
164+ // / performed.
165+ // /
127166 // / @return
128167 // / The unsigned integer value that was extracted, or zero on
129168 // / failure.
130- uint64_t getUnsigned (uint64_t *offset_ptr, uint32_t byte_size) const ;
169+ uint64_t getUnsigned (uint64_t *offset_ptr, uint32_t byte_size,
170+ Error *Err = nullptr ) const ;
171+
172+ // / Extract an unsigned integer of the given size from the location given by
173+ // / the cursor. In case of an extraction error, or if the cursor is already in
174+ // / an error state, zero is returned.
175+ uint64_t getUnsigned (Cursor &C, uint32_t Size) const {
176+ return getUnsigned (&C.Offset , Size, &C.Err );
177+ }
131178
132179 // / Extract an signed integer of size \a byte_size from \a *offset_ptr.
133180 // /
@@ -175,6 +222,11 @@ class DataExtractor {
175222 return getUnsigned (offset_ptr, AddressSize);
176223 }
177224
225+ // / Extract a pointer-sized unsigned integer from the location given by the
226+ // / cursor. In case of an extraction error, or if the cursor is already in
227+ // / an error state, zero is returned.
228+ uint64_t getAddress (Cursor &C) const { return getUnsigned (C, AddressSize); }
229+
178230 // / Extract a uint8_t value from \a *offset_ptr.
179231 // /
180232 // / Extract a single uint8_t from the binary data at the offset
@@ -187,9 +239,20 @@ class DataExtractor {
187239 // / enough bytes to extract this value, the offset will be left
188240 // / unmodified.
189241 // /
242+ // / @param[in,out] Err
243+ // / A pointer to an Error object. Upon return the Error object is set to
244+ // / indicate the result (success/failure) of the function. If the Error
245+ // / object is already set when calling this function, no extraction is
246+ // / performed.
247+ // /
190248 // / @return
191249 // / The extracted uint8_t value.
192- uint8_t getU8 (uint64_t *offset_ptr) const ;
250+ uint8_t getU8 (uint64_t *offset_ptr, Error *Err = nullptr ) const ;
251+
252+ // / Extract a single uint8_t value from the location given by the cursor. In
253+ // / case of an extraction error, or if the cursor is already in an error
254+ // / state, zero is returned.
255+ uint8_t getU8 (Cursor &C) const { return getU8 (&C.Offset , &C.Err ); }
193256
194257 // / Extract \a count uint8_t values from \a *offset_ptr.
195258 // /
@@ -216,6 +279,26 @@ class DataExtractor {
216279 // / NULL otherise.
217280 uint8_t *getU8 (uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const ;
218281
282+ // / Extract \a Count uint8_t values from the location given by the cursor and
283+ // / store them into the destination buffer. In case of an extraction error, or
284+ // / if the cursor is already in an error state, a nullptr is returned and the
285+ // / destination buffer is left unchanged.
286+ uint8_t *getU8 (Cursor &C, uint8_t *Dst, uint32_t Count) const ;
287+
288+ // / Extract \a Count uint8_t values from the location given by the cursor and
289+ // / store them into the destination vector. The vector is resized to fit the
290+ // / extracted data. In case of an extraction error, or if the cursor is
291+ // / already in an error state, the destination vector is left unchanged and
292+ // / cursor is placed into an error state.
293+ void getU8 (Cursor &C, SmallVectorImpl<uint8_t > &Dst, uint32_t Count) const {
294+ if (isValidOffsetForDataOfSize (C.Offset , Count))
295+ Dst.resize (Count);
296+
297+ // This relies on the fact that getU8 will not attempt to write to the
298+ // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false.
299+ getU8 (C, Dst.data (), Count);
300+ }
301+
219302 // ------------------------------------------------------------------
220303 // / Extract a uint16_t value from \a *offset_ptr.
221304 // /
@@ -229,10 +312,21 @@ class DataExtractor {
229312 // / enough bytes to extract this value, the offset will be left
230313 // / unmodified.
231314 // /
315+ // / @param[in,out] Err
316+ // / A pointer to an Error object. Upon return the Error object is set to
317+ // / indicate the result (success/failure) of the function. If the Error
318+ // / object is already set when calling this function, no extraction is
319+ // / performed.
320+ // /
232321 // / @return
233322 // / The extracted uint16_t value.
234323 // ------------------------------------------------------------------
235- uint16_t getU16 (uint64_t *offset_ptr) const ;
324+ uint16_t getU16 (uint64_t *offset_ptr, Error *Err = nullptr ) const ;
325+
326+ // / Extract a single uint16_t value from the location given by the cursor. In
327+ // / case of an extraction error, or if the cursor is already in an error
328+ // / state, zero is returned.
329+ uint16_t getU16 (Cursor &C) const { return getU16 (&C.Offset , &C.Err ); }
236330
237331 // / Extract \a count uint16_t values from \a *offset_ptr.
238332 // /
@@ -288,9 +382,20 @@ class DataExtractor {
288382 // / enough bytes to extract this value, the offset will be left
289383 // / unmodified.
290384 // /
385+ // / @param[in,out] Err
386+ // / A pointer to an Error object. Upon return the Error object is set to
387+ // / indicate the result (success/failure) of the function. If the Error
388+ // / object is already set when calling this function, no extraction is
389+ // / performed.
390+ // /
291391 // / @return
292392 // / The extracted uint32_t value.
293- uint32_t getU32 (uint64_t *offset_ptr) const ;
393+ uint32_t getU32 (uint64_t *offset_ptr, Error *Err = nullptr ) const ;
394+
395+ // / Extract a single uint32_t value from the location given by the cursor. In
396+ // / case of an extraction error, or if the cursor is already in an error
397+ // / state, zero is returned.
398+ uint32_t getU32 (Cursor &C) const { return getU32 (&C.Offset , &C.Err ); }
294399
295400 // / Extract \a count uint32_t values from \a *offset_ptr.
296401 // /
@@ -329,9 +434,20 @@ class DataExtractor {
329434 // / enough bytes to extract this value, the offset will be left
330435 // / unmodified.
331436 // /
437+ // / @param[in,out] Err
438+ // / A pointer to an Error object. Upon return the Error object is set to
439+ // / indicate the result (success/failure) of the function. If the Error
440+ // / object is already set when calling this function, no extraction is
441+ // / performed.
442+ // /
332443 // / @return
333444 // / The extracted uint64_t value.
334- uint64_t getU64 (uint64_t *offset_ptr) const ;
445+ uint64_t getU64 (uint64_t *offset_ptr, Error *Err = nullptr ) const ;
446+
447+ // / Extract a single uint64_t value from the location given by the cursor. In
448+ // / case of an extraction error, or if the cursor is already in an error
449+ // / state, zero is returned.
450+ uint64_t getU64 (Cursor &C) const { return getU64 (&C.Offset , &C.Err ); }
335451
336452 // / Extract \a count uint64_t values from \a *offset_ptr.
337453 // /
@@ -390,9 +506,30 @@ class DataExtractor {
390506 // / enough bytes to extract this value, the offset will be left
391507 // / unmodified.
392508 // /
509+ // / @param[in,out] Err
510+ // / A pointer to an Error object. Upon return the Error object is set to
511+ // / indicate the result (success/failure) of the function. If the Error
512+ // / object is already set when calling this function, no extraction is
513+ // / performed.
514+ // /
393515 // / @return
394516 // / The extracted unsigned integer value.
395- uint64_t getULEB128 (uint64_t *offset_ptr) const ;
517+ uint64_t getULEB128 (uint64_t *offset_ptr, llvm::Error *Err = nullptr ) const ;
518+
519+ // / Extract an unsigned ULEB128 value from the location given by the cursor.
520+ // / In case of an extraction error, or if the cursor is already in an error
521+ // / state, zero is returned.
522+ uint64_t getULEB128 (Cursor &C) const { return getULEB128 (&C.Offset , &C.Err ); }
523+
524+ // / Advance the Cursor position by the given number of bytes. No-op if the
525+ // / cursor is in an error state.
526+ void skip (Cursor &C, uint64_t Length) const ;
527+
528+ // / Return true iff the cursor is at the end of the buffer, regardless of the
529+ // / error state of the cursor. The only way both eof and error states can be
530+ // / true is if one attempts a read while the cursor is at the very end of the
531+ // / data buffer.
532+ bool eof (const Cursor &C) const { return Data.size () == C.Offset ; }
396533
397534 // / Test the validity of \a offset.
398535 // /
@@ -420,6 +557,12 @@ class DataExtractor {
420557 bool isValidOffsetForAddress (uint64_t offset) const {
421558 return isValidOffsetForDataOfSize (offset, AddressSize);
422559 }
560+
561+ protected:
562+ // Make it possible for subclasses to access these fields without making them
563+ // public.
564+ static uint64_t &getOffset (Cursor &C) { return C.Offset ; }
565+ static Error &getError (Cursor &C) { return C.Err ; }
423566};
424567
425568} // namespace llvm
0 commit comments