Skip to content

Commit c9c687d

Browse files
[NFC] Split portions of DWARFDataExtractor into new class (#140096)
Currently, DWARFDataExtractor can extract data without performing relocations, (eg, by checking if the section pointer is null) but is coded such that it still depends on all the relocation machinery, like DWARFSections and similar. All at build time. Extract most functionality into a new class, DWARFDataExtractorBase, and have DWARFDataExtractor add the relocation dependent pieces via CRTP. Add a new class, DWARFDataExtractorSimple, which does no relocation at all. This will allow moving DWARFDataExtractorSimple into a new lower-level, lighter-weight library with fewer external build-time dependencies. This is another in a series of refactoring changes to create a new better-layered, low-level Dwarf library that can be called from lower-level code without circular dependencies.
1 parent cb3d77d commit c9c687d

File tree

4 files changed

+229
-191
lines changed

4 files changed

+229
-191
lines changed

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

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,81 +10,59 @@
1010
#define LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H
1111

1212
#include "llvm/BinaryFormat/Dwarf.h"
13+
#include "llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h"
14+
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
15+
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
1316
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
1417
#include "llvm/Support/Compiler.h"
15-
#include "llvm/Support/DataExtractor.h"
1618

1719
namespace llvm {
18-
class DWARFObject;
1920

20-
/// A DataExtractor (typically for an in-memory copy of an object-file section)
21-
/// plus a relocation map for that section, if there is one.
22-
class DWARFDataExtractor : public DataExtractor {
21+
/// A DWARFDataExtractor (typically for an in-memory copy of an object-file
22+
/// section) plus a relocation map for that section, if there is one.
23+
class DWARFDataExtractor : public DWARFDataExtractorBase<DWARFDataExtractor> {
2324
const DWARFObject *Obj = nullptr;
2425
const DWARFSection *Section = nullptr;
2526

2627
public:
28+
using DWARFDataExtractorBase::DWARFDataExtractorBase;
29+
2730
/// Constructor for the normal case of extracting data from a DWARF section.
2831
/// The DWARFSection's lifetime must be at least as long as the extractor's.
2932
DWARFDataExtractor(const DWARFObject &Obj, const DWARFSection &Section,
3033
bool IsLittleEndian, uint8_t AddressSize)
31-
: DataExtractor(Section.Data, IsLittleEndian, AddressSize), Obj(&Obj),
32-
Section(&Section) {}
33-
34-
/// Constructor for cases when there are no relocations.
35-
DWARFDataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
36-
: DataExtractor(Data, IsLittleEndian, AddressSize) {}
37-
DWARFDataExtractor(ArrayRef<uint8_t> Data, bool IsLittleEndian,
38-
uint8_t AddressSize)
39-
: DataExtractor(
40-
StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()),
41-
IsLittleEndian, AddressSize) {}
34+
: DWARFDataExtractorBase(Section.Data, IsLittleEndian, AddressSize),
35+
Obj(&Obj), Section(&Section) {}
4236

4337
/// Truncating constructor
4438
DWARFDataExtractor(const DWARFDataExtractor &Other, size_t Length)
45-
: DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(),
46-
Other.getAddressSize()),
39+
: DWARFDataExtractorBase(Other.getData().substr(0, Length),
40+
Other.isLittleEndian(), Other.getAddressSize()),
4741
Obj(Other.Obj), Section(Other.Section) {}
4842

49-
/// Extracts the DWARF "initial length" field, which can either be a 32-bit
50-
/// value smaller than 0xfffffff0, or the value 0xffffffff followed by a
51-
/// 64-bit length. Returns the actual length, and the DWARF format which is
52-
/// encoded in the field. In case of errors, it returns {0, DWARF32} and
53-
/// leaves the offset unchanged.
54-
LLVM_ABI std::pair<uint64_t, dwarf::DwarfFormat>
55-
getInitialLength(uint64_t *Off, Error *Err = nullptr) const;
56-
57-
std::pair<uint64_t, dwarf::DwarfFormat> getInitialLength(Cursor &C) const {
58-
return getInitialLength(&getOffset(C), &getError(C));
59-
}
60-
6143
/// Extracts a value and applies a relocation to the result if
6244
/// one exists for the given offset.
63-
LLVM_ABI uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
64-
uint64_t *SectionIndex = nullptr,
65-
Error *Err = nullptr) const;
66-
uint64_t getRelocatedValue(Cursor &C, uint32_t Size,
67-
uint64_t *SectionIndex = nullptr) const {
68-
return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C));
69-
}
45+
LLVM_ABI uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off,
46+
uint64_t *SecNdx, Error *Err) const {
47+
if (SecNdx)
48+
*SecNdx = object::SectionedAddress::UndefSection;
49+
if (!Section)
50+
return getUnsigned(Off, Size, Err);
51+
ErrorAsOutParameter ErrAsOut(Err);
52+
std::optional<RelocAddrEntry> E = Obj->find(*Section, *Off);
53+
uint64_t LocData = getUnsigned(Off, Size, Err);
54+
if (!E || (Err && *Err))
55+
return LocData;
56+
if (SecNdx)
57+
*SecNdx = E->SectionIndex;
7058

71-
/// Extracts an address-sized value and applies a relocation to the result if
72-
/// one exists for the given offset.
73-
uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const {
74-
return getRelocatedValue(getAddressSize(), Off, SecIx);
59+
uint64_t R = object::resolveRelocation(E->Resolver, E->Reloc,
60+
E->SymbolValue, LocData);
61+
if (E->Reloc2)
62+
R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2,
63+
R);
64+
return R;
7565
}
76-
uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const {
77-
return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx,
78-
&getError(C));
79-
}
80-
81-
/// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
82-
/// There is a DWARF encoding that uses a PC-relative adjustment.
83-
/// For these values, \p AbsPosOffset is used to fix them, which should
84-
/// reflect the absolute address of this pointer.
85-
LLVM_ABI std::optional<uint64_t>
86-
getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
87-
uint64_t AbsPosOffset = 0) const;
8866
};
8967

9068
} // end namespace llvm
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
//===- DWARFDataExtractorSimple.h -------------------------------*- C++ -*-===//
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+
#ifndef LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTORSIMPLE_H
10+
#define LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTORSIMPLE_H
11+
12+
#include "llvm/BinaryFormat/Dwarf.h"
13+
#include "llvm/Support/Compiler.h"
14+
#include "llvm/Support/DataExtractor.h"
15+
#include "llvm/Support/Errc.h"
16+
#include "llvm/Support/MathExtras.h"
17+
18+
namespace llvm {
19+
20+
/// A DataExtractor suitable use for parsing dwarf from memory. Clients use
21+
/// Relocator::getRelocatedValueImpl to relocate values as appropriate.
22+
23+
template <typename Relocator>
24+
class DWARFDataExtractorBase : public DataExtractor {
25+
26+
public:
27+
DWARFDataExtractorBase(StringRef Data, bool IsLittleEndian,
28+
uint8_t AddressSize)
29+
: DataExtractor(Data, IsLittleEndian, AddressSize) {}
30+
DWARFDataExtractorBase(ArrayRef<uint8_t> Data, bool IsLittleEndian,
31+
uint8_t AddressSize)
32+
: DataExtractor(
33+
StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()),
34+
IsLittleEndian, AddressSize) {}
35+
36+
/// Truncating constructor
37+
DWARFDataExtractorBase(const DWARFDataExtractorBase &Other, size_t Length)
38+
: DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(),
39+
Other.getAddressSize()) {}
40+
41+
/// Extracts a value and returns it as adjusted by the Relocator
42+
LLVM_ABI uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off,
43+
uint64_t *SectionIndex = nullptr,
44+
Error *Err = nullptr) const {
45+
return static_cast<const Relocator *>(this)->getRelocatedValueImpl(
46+
Size, Off, SectionIndex, Err);
47+
}
48+
49+
LLVM_ABI uint64_t getRelocatedValue(Cursor &C, uint32_t Size,
50+
uint64_t *SectionIndex = nullptr) const {
51+
return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C));
52+
}
53+
54+
/// Extracts an address-sized value.
55+
LLVM_ABI uint64_t getRelocatedAddress(uint64_t *Off,
56+
uint64_t *SecIx = nullptr) const {
57+
return getRelocatedValue(getAddressSize(), Off, SecIx);
58+
}
59+
60+
LLVM_ABI uint64_t getRelocatedAddress(Cursor &C,
61+
uint64_t *SecIx = nullptr) const {
62+
return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx,
63+
&getError(C));
64+
}
65+
66+
/// Extracts the DWARF "initial length" field, which can either be a 32-bit
67+
/// value smaller than 0xfffffff0, or the value 0xffffffff followed by a
68+
/// 64-bit length. Returns the actual length, and the DWARF format which is
69+
/// encoded in the field. In case of errors, it returns {0, DWARF32} and
70+
/// leaves the offset unchanged.
71+
LLVM_ABI std::pair<uint64_t, dwarf::DwarfFormat>
72+
getInitialLength(uint64_t *Off, Error *Err = nullptr) const {
73+
ErrorAsOutParameter ErrAsOut(Err);
74+
if (Err && *Err)
75+
return {0, dwarf::DWARF32};
76+
77+
Cursor C(*Off);
78+
uint64_t Length = getRelocatedValue(C, 4);
79+
dwarf::DwarfFormat Format = dwarf::DWARF32;
80+
if (Length == dwarf::DW_LENGTH_DWARF64) {
81+
Length = getRelocatedValue(C, 8);
82+
Format = dwarf::DWARF64;
83+
} else if (Length >= dwarf::DW_LENGTH_lo_reserved) {
84+
cantFail(C.takeError());
85+
if (Err)
86+
*Err = createStringError(
87+
std::errc::invalid_argument,
88+
"unsupported reserved unit length of value 0x%8.8" PRIx64, Length);
89+
return {0, dwarf::DWARF32};
90+
}
91+
92+
if (C) {
93+
*Off = C.tell();
94+
return {Length, Format};
95+
}
96+
if (Err)
97+
*Err = C.takeError();
98+
else
99+
consumeError(C.takeError());
100+
return {0, dwarf::DWARF32};
101+
}
102+
103+
LLVM_ABI std::pair<uint64_t, dwarf::DwarfFormat>
104+
getInitialLength(Cursor &C) const {
105+
return getInitialLength(&getOffset(C), &getError(C));
106+
}
107+
108+
/// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding.
109+
/// There is a DWARF encoding that uses a PC-relative adjustment.
110+
/// For these values, \p AbsPosOffset is used to fix them, which should
111+
/// reflect the absolute address of this pointer.
112+
LLVM_ABI std::optional<uint64_t>
113+
getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
114+
uint64_t PCRelOffset) const {
115+
if (Encoding == dwarf::DW_EH_PE_omit)
116+
return std::nullopt;
117+
118+
uint64_t Result = 0;
119+
uint64_t OldOffset = *Offset;
120+
// First get value
121+
switch (Encoding & 0x0F) {
122+
case dwarf::DW_EH_PE_absptr:
123+
switch (getAddressSize()) {
124+
case 2:
125+
case 4:
126+
case 8:
127+
Result = getUnsigned(Offset, getAddressSize());
128+
break;
129+
default:
130+
return std::nullopt;
131+
}
132+
break;
133+
case dwarf::DW_EH_PE_uleb128:
134+
Result = getULEB128(Offset);
135+
break;
136+
case dwarf::DW_EH_PE_sleb128:
137+
Result = getSLEB128(Offset);
138+
break;
139+
case dwarf::DW_EH_PE_udata2:
140+
Result = getUnsigned(Offset, 2);
141+
break;
142+
case dwarf::DW_EH_PE_udata4:
143+
Result = getUnsigned(Offset, 4);
144+
break;
145+
case dwarf::DW_EH_PE_udata8:
146+
Result = getUnsigned(Offset, 8);
147+
break;
148+
case dwarf::DW_EH_PE_sdata2:
149+
Result = getSigned(Offset, 2);
150+
break;
151+
case dwarf::DW_EH_PE_sdata4:
152+
Result = SignExtend64<32>(getRelocatedValue(4, Offset));
153+
break;
154+
case dwarf::DW_EH_PE_sdata8:
155+
Result = getRelocatedValue(8, Offset);
156+
break;
157+
default:
158+
return std::nullopt;
159+
}
160+
// Then add relative offset, if required
161+
switch (Encoding & 0x70) {
162+
case dwarf::DW_EH_PE_absptr:
163+
// do nothing
164+
break;
165+
case dwarf::DW_EH_PE_pcrel:
166+
Result += PCRelOffset;
167+
break;
168+
case dwarf::DW_EH_PE_datarel:
169+
case dwarf::DW_EH_PE_textrel:
170+
case dwarf::DW_EH_PE_funcrel:
171+
case dwarf::DW_EH_PE_aligned:
172+
default:
173+
*Offset = OldOffset;
174+
return std::nullopt;
175+
}
176+
177+
return Result;
178+
}
179+
};
180+
181+
// Non relocating, low-level dwarf-data extractor. Suitable for use from
182+
// libraries that cannot have build-time dependencies on relocation providers.
183+
184+
class DWARFDataExtractorSimple
185+
: public DWARFDataExtractorBase<DWARFDataExtractorSimple> {
186+
using DWARFDataExtractorBase::DWARFDataExtractorBase;
187+
188+
LLVM_ABI uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off,
189+
uint64_t *SectionIndex = nullptr,
190+
Error *Err = nullptr) const {
191+
assert(SectionIndex == nullptr &&
192+
"DWARFDATAExtractorSimple cannot take section indices.");
193+
return getUnsigned(Off, Size, Err);
194+
}
195+
};
196+
197+
} // end namespace llvm
198+
#endif // LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H

llvm/lib/DebugInfo/DWARF/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ add_llvm_component_library(LLVMDebugInfoDWARF
55
DWARFCFIProgram.cpp
66
DWARFCompileUnit.cpp
77
DWARFContext.cpp
8-
DWARFDataExtractor.cpp
98
DWARFDebugAbbrev.cpp
109
DWARFDebugAddr.cpp
1110
DWARFDebugArangeSet.cpp

0 commit comments

Comments
 (0)