Skip to content

Commit 506e24c

Browse files
authored
Merge pull request #25 from JDevlieghere/dwarfdump-base-addr-entry-support
Dwarfdump base addr entry support
2 parents c1a1515 + b13da17 commit 506e24c

14 files changed

+888
-145
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,18 @@ class DWARFDataExtractor : public DataExtractor {
3636
/// Extracts a value and applies a relocation to the result if
3737
/// one exists for the given offset.
3838
uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
39-
uint64_t *SectionIndex = nullptr) const;
39+
uint64_t *SectionIndex = nullptr,
40+
Error *Err = nullptr) const;
4041

4142
/// Extracts an address-sized value and applies a relocation to the result if
4243
/// one exists for the given offset.
4344
uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const {
4445
return getRelocatedValue(getAddressSize(), Off, SecIx);
4546
}
47+
uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const {
48+
return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx,
49+
&getError(C));
50+
}
4651

4752
/// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
4853
/// There is a DWARF encoding that uses a PC-relative adjustment.

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h

+9-8
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class DWARFDebugLoc {
2929
/// The ending address of the instruction range.
3030
uint64_t End;
3131
/// The location of the variable within the specified range.
32-
SmallVector<char, 4> Loc;
32+
SmallVector<uint8_t, 4> Loc;
3333
};
3434

3535
/// A list of locations that contain one variable.
@@ -40,8 +40,8 @@ class DWARFDebugLoc {
4040
/// All the locations in which the variable is stored.
4141
SmallVector<Entry, 2> Entries;
4242
/// Dump this list on OS.
43-
void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize,
44-
const MCRegisterInfo *MRI, DWARFUnit *U, uint64_t BaseAddress,
43+
void dump(raw_ostream &OS, uint64_t BaseAddress, bool IsLittleEndian,
44+
unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U,
4545
unsigned Indent) const;
4646
};
4747

@@ -68,8 +68,8 @@ class DWARFDebugLoc {
6868
/// Return the location list at the given offset or nullptr.
6969
LocationList const *getLocationListAtOffset(uint64_t Offset) const;
7070

71-
Optional<LocationList> parseOneLocationList(DWARFDataExtractor Data,
72-
uint64_t *Offset);
71+
Expected<LocationList>
72+
parseOneLocationList(const DWARFDataExtractor &Data, uint64_t *Offset);
7373
};
7474

7575
class DWARFDebugLoclists {
@@ -78,7 +78,7 @@ class DWARFDebugLoclists {
7878
uint8_t Kind;
7979
uint64_t Value0;
8080
uint64_t Value1;
81-
SmallVector<char, 4> Loc;
81+
SmallVector<uint8_t, 4> Loc;
8282
};
8383

8484
struct LocationList {
@@ -106,8 +106,9 @@ class DWARFDebugLoclists {
106106
/// Return the location list at the given offset or nullptr.
107107
LocationList const *getLocationListAtOffset(uint64_t Offset) const;
108108

109-
static Optional<LocationList>
110-
parseOneLocationList(DataExtractor Data, uint64_t *Offset, unsigned Version);
109+
static Expected<LocationList> parseOneLocationList(const DataExtractor &Data,
110+
uint64_t *Offset,
111+
unsigned Version);
111112
};
112113

113114
} // end namespace llvm

llvm/include/llvm/Support/DataExtractor.h

+149-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "llvm/ADT/StringRef.h"
1313
#include "llvm/Support/DataTypes.h"
14+
#include "llvm/Support/Error.h"
1415

1516
namespace llvm {
1617

@@ -42,6 +43,38 @@ class DataExtractor {
4243
uint8_t IsLittleEndian;
4344
uint8_t AddressSize;
4445
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+
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

llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313
using namespace llvm;
1414

1515
uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off,
16-
uint64_t *SecNdx) const {
16+
uint64_t *SecNdx,
17+
Error *Err) const {
1718
if (SecNdx)
1819
*SecNdx = object::SectionedAddress::UndefSection;
1920
if (!Section)
20-
return getUnsigned(Off, Size);
21+
return getUnsigned(Off, Size, Err);
2122
Optional<RelocAddrEntry> E = Obj->find(*Section, *Off);
22-
uint64_t A = getUnsigned(Off, Size);
23+
uint64_t A = getUnsigned(Off, Size, Err);
2324
if (!E)
2425
return A;
2526
if (SecNdx)

0 commit comments

Comments
 (0)