11
11
12
12
#include " llvm/ADT/StringRef.h"
13
13
#include " llvm/Support/DataTypes.h"
14
+ #include " llvm/Support/Error.h"
14
15
15
16
namespace llvm {
16
17
@@ -42,6 +43,38 @@ class DataExtractor {
42
43
uint8_t IsLittleEndian;
43
44
uint8_t AddressSize;
44
45
public:
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
+
45
78
// / Construct with a buffer that is owned by the caller.
46
79
// /
47
80
// / This constructor allows us to use data that is owned by the
@@ -124,10 +157,24 @@ class DataExtractor {
124
157
// / @param[in] byte_size
125
158
// / The size in byte of the integer to extract.
126
159
// /
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
+ // /
127
166
// / @return
128
167
// / The unsigned integer value that was extracted, or zero on
129
168
// / 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
+ }
131
178
132
179
// / Extract an signed integer of size \a byte_size from \a *offset_ptr.
133
180
// /
@@ -175,6 +222,11 @@ class DataExtractor {
175
222
return getUnsigned (offset_ptr, AddressSize);
176
223
}
177
224
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
+
178
230
// / Extract a uint8_t value from \a *offset_ptr.
179
231
// /
180
232
// / Extract a single uint8_t from the binary data at the offset
@@ -187,9 +239,20 @@ class DataExtractor {
187
239
// / enough bytes to extract this value, the offset will be left
188
240
// / unmodified.
189
241
// /
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
+ // /
190
248
// / @return
191
249
// / 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 ); }
193
256
194
257
// / Extract \a count uint8_t values from \a *offset_ptr.
195
258
// /
@@ -216,6 +279,26 @@ class DataExtractor {
216
279
// / NULL otherise.
217
280
uint8_t *getU8 (uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const ;
218
281
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
+
219
302
// ------------------------------------------------------------------
220
303
// / Extract a uint16_t value from \a *offset_ptr.
221
304
// /
@@ -229,10 +312,21 @@ class DataExtractor {
229
312
// / enough bytes to extract this value, the offset will be left
230
313
// / unmodified.
231
314
// /
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
+ // /
232
321
// / @return
233
322
// / The extracted uint16_t value.
234
323
// ------------------------------------------------------------------
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 ); }
236
330
237
331
// / Extract \a count uint16_t values from \a *offset_ptr.
238
332
// /
@@ -288,9 +382,20 @@ class DataExtractor {
288
382
// / enough bytes to extract this value, the offset will be left
289
383
// / unmodified.
290
384
// /
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
+ // /
291
391
// / @return
292
392
// / 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 ); }
294
399
295
400
// / Extract \a count uint32_t values from \a *offset_ptr.
296
401
// /
@@ -329,9 +434,20 @@ class DataExtractor {
329
434
// / enough bytes to extract this value, the offset will be left
330
435
// / unmodified.
331
436
// /
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
+ // /
332
443
// / @return
333
444
// / 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 ); }
335
451
336
452
// / Extract \a count uint64_t values from \a *offset_ptr.
337
453
// /
@@ -390,9 +506,30 @@ class DataExtractor {
390
506
// / enough bytes to extract this value, the offset will be left
391
507
// / unmodified.
392
508
// /
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
+ // /
393
515
// / @return
394
516
// / 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 ; }
396
533
397
534
// / Test the validity of \a offset.
398
535
// /
@@ -420,6 +557,12 @@ class DataExtractor {
420
557
bool isValidOffsetForAddress (uint64_t offset) const {
421
558
return isValidOffsetForDataOfSize (offset, AddressSize);
422
559
}
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 ; }
423
566
};
424
567
425
568
} // namespace llvm
0 commit comments