Skip to content

Commit 632b6e8

Browse files
labathyuxuanchen1997
authored andcommitted
Split DWARFFormValue::getReference into four functions (#98905)
Summary: The result of the function cannot be correctly interpreted without knowing the precise form type (a type signature needs to be looked up very differently from a supplementary debug info reference). The function sort of worked because the two reference types (unit-relative and section-relative) that can be handled uniformly are also the most common types of references, but this setup made it easy to write code which does not support other kinds of reference (and if one tried to support them, the result didn't look pretty -- https://github.com/llvm/llvm-project/pull/97423/files#r1676217081). The split is based on the reference type classification from DWARFv5 (Section 7.5.5 Classes and Forms), and it should enable uniform (if slightly more verbose) hadling. Note that this only affects users which want more control of how (or if) the references are resolved. Users which just want to access the referenced DIE can use the higher level API (DWARFDie::GetAttributeValueAsReferencedDie) which returns (or will return after #97423 is merged) the correct die for all reference types (except for supplementary references, which we don't support right now). Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251742
1 parent 2d8c6b3 commit 632b6e8

File tree

8 files changed

+317
-126
lines changed

8 files changed

+317
-126
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h

+90-17
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,10 @@ class DWARFFormValue {
107107

108108
/// getAsFoo functions below return the extracted value as Foo if only
109109
/// DWARFFormValue has form class is suitable for representing Foo.
110-
std::optional<uint64_t> getAsReference() const;
111-
struct UnitOffset {
112-
DWARFUnit *Unit;
113-
uint64_t Offset;
114-
};
115-
std::optional<UnitOffset> getAsRelativeReference() const;
110+
std::optional<uint64_t> getAsRelativeReference() const;
111+
std::optional<uint64_t> getAsDebugInfoReference() const;
112+
std::optional<uint64_t> getAsSignatureReference() const;
113+
std::optional<uint64_t> getAsSupplementaryReference() const;
116114
std::optional<uint64_t> getAsUnsignedConstant() const;
117115
std::optional<int64_t> getAsSignedConstant() const;
118116
Expected<const char *> getAsCString() const;
@@ -242,27 +240,102 @@ inline uint64_t toUnsigned(const std::optional<DWARFFormValue> &V,
242240
return toUnsigned(V).value_or(Default);
243241
}
244242

245-
/// Take an optional DWARFFormValue and try to extract an reference.
243+
/// Take an optional DWARFFormValue and try to extract a relative offset
244+
/// reference.
246245
///
247-
/// \param V and optional DWARFFormValue to attempt to extract the value from.
246+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
248247
/// \returns an optional value that contains a value if the form value
249-
/// was valid and has a reference form.
248+
/// was valid and has a relative reference form.
250249
inline std::optional<uint64_t>
251-
toReference(const std::optional<DWARFFormValue> &V) {
250+
toRelativeReference(const std::optional<DWARFFormValue> &V) {
252251
if (V)
253-
return V->getAsReference();
252+
return V->getAsRelativeReference();
254253
return std::nullopt;
255254
}
256255

257-
/// Take an optional DWARFFormValue and extract a reference.
256+
/// Take an optional DWARFFormValue and extract a relative offset reference.
258257
///
259-
/// \param V and optional DWARFFormValue to attempt to extract the value from.
258+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
259+
/// \param Default the default value to return in case of failure.
260+
/// \returns the extracted reference value or Default if the V doesn't have a
261+
/// value or the form value's encoding wasn't a relative offset reference form.
262+
inline uint64_t toRelativeReference(const std::optional<DWARFFormValue> &V,
263+
uint64_t Default) {
264+
return toRelativeReference(V).value_or(Default);
265+
}
266+
267+
/// Take an optional DWARFFormValue and try to extract an absolute debug info
268+
/// offset reference.
269+
///
270+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
271+
/// \returns an optional value that contains a value if the form value
272+
/// was valid and has an (absolute) debug info offset reference form.
273+
inline std::optional<uint64_t>
274+
toDebugInfoReference(const std::optional<DWARFFormValue> &V) {
275+
if (V)
276+
return V->getAsDebugInfoReference();
277+
return std::nullopt;
278+
}
279+
280+
/// Take an optional DWARFFormValue and extract an absolute debug info offset
281+
/// reference.
282+
///
283+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
284+
/// \param Default the default value to return in case of failure.
285+
/// \returns the extracted reference value or Default if the V doesn't have a
286+
/// value or the form value's encoding wasn't an absolute debug info offset
287+
/// reference form.
288+
inline uint64_t toDebugInfoReference(const std::optional<DWARFFormValue> &V,
289+
uint64_t Default) {
290+
return toDebugInfoReference(V).value_or(Default);
291+
}
292+
293+
/// Take an optional DWARFFormValue and try to extract a signature reference.
294+
///
295+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
296+
/// \returns an optional value that contains a value if the form value
297+
/// was valid and has a signature reference form.
298+
inline std::optional<uint64_t>
299+
toSignatureReference(const std::optional<DWARFFormValue> &V) {
300+
if (V)
301+
return V->getAsSignatureReference();
302+
return std::nullopt;
303+
}
304+
305+
/// Take an optional DWARFFormValue and extract a signature reference.
306+
///
307+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
308+
/// \param Default the default value to return in case of failure.
309+
/// \returns the extracted reference value or Default if the V doesn't have a
310+
/// value or the form value's encoding wasn't a signature reference form.
311+
inline uint64_t toSignatureReference(const std::optional<DWARFFormValue> &V,
312+
uint64_t Default) {
313+
return toSignatureReference(V).value_or(Default);
314+
}
315+
316+
/// Take an optional DWARFFormValue and try to extract a supplementary debug
317+
/// info reference.
318+
///
319+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
320+
/// \returns an optional value that contains a value if the form value
321+
/// was valid and has a supplementary reference form.
322+
inline std::optional<uint64_t>
323+
toSupplementaryReference(const std::optional<DWARFFormValue> &V) {
324+
if (V)
325+
return V->getAsSupplementaryReference();
326+
return std::nullopt;
327+
}
328+
329+
/// Take an optional DWARFFormValue and extract a supplementary debug info
330+
/// reference.
331+
///
332+
/// \param V an optional DWARFFormValue to attempt to extract the value from.
260333
/// \param Default the default value to return in case of failure.
261334
/// \returns the extracted reference value or Default if the V doesn't have a
262-
/// value or the form value's encoding wasn't a reference form.
263-
inline uint64_t toReference(const std::optional<DWARFFormValue> &V,
264-
uint64_t Default) {
265-
return toReference(V).value_or(Default);
335+
/// value or the form value's encoding wasn't a supplementary reference form.
336+
inline uint64_t toSupplementaryReference(const std::optional<DWARFFormValue> &V,
337+
uint64_t Default) {
338+
return toSupplementaryReference(V).value_or(Default);
266339
}
267340

268341
/// Take an optional DWARFFormValue and try to extract an signed constant.

llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,15 @@ DWARFDie DWARFLinker::resolveDIEReference(const DWARFFile &File,
7777
const DWARFDie &DIE,
7878
CompileUnit *&RefCU) {
7979
assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
80-
uint64_t RefOffset = *RefValue.getAsReference();
80+
uint64_t RefOffset;
81+
if (std::optional<uint64_t> Off = RefValue.getAsRelativeReference()) {
82+
RefOffset = RefValue.getUnit()->getOffset() + *Off;
83+
} else if (Off = RefValue.getAsDebugInfoReference(); Off) {
84+
RefOffset = *Off;
85+
} else {
86+
reportWarning("Unsupported reference type", File, &DIE);
87+
return DWARFDie();
88+
}
8189
if ((RefCU = getUnitForOffset(Units, RefOffset)))
8290
if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) {
8391
// In a file with broken references, an attribute might point to a NULL
@@ -1073,7 +1081,13 @@ unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute(
10731081
unsigned AttrSize, const DWARFFormValue &Val, const DWARFFile &File,
10741082
CompileUnit &Unit) {
10751083
const DWARFUnit &U = Unit.getOrigUnit();
1076-
uint64_t Ref = *Val.getAsReference();
1084+
uint64_t Ref;
1085+
if (std::optional<uint64_t> Off = Val.getAsRelativeReference())
1086+
Ref = Val.getUnit()->getOffset() + *Off;
1087+
else if (Off = Val.getAsDebugInfoReference(); Off)
1088+
Ref = *Off;
1089+
else
1090+
return 0;
10771091

10781092
DIE *NewRefDie = nullptr;
10791093
CompileUnit *RefUnit = nullptr;

llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp

+28-30
Original file line numberDiff line numberDiff line change
@@ -381,38 +381,36 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
381381
std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
382382
const DWARFFormValue &RefValue,
383383
ResolveInterCUReferencesMode CanResolveInterCUReferences) {
384-
if (std::optional<DWARFFormValue::UnitOffset> Ref =
385-
*RefValue.getAsRelativeReference()) {
386-
if (Ref->Unit == OrigUnit) {
387-
// Referenced DIE is in current compile unit.
388-
if (std::optional<uint32_t> RefDieIdx =
389-
getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset))
390-
return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)};
391-
}
392-
uint64_t RefDIEOffset =
393-
Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset;
394-
if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) {
395-
if (RefCU == this) {
396-
// Referenced DIE is in current compile unit.
397-
if (std::optional<uint32_t> RefDieIdx =
398-
getDIEIndexForOffset(RefDIEOffset))
399-
return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)};
400-
} else if (CanResolveInterCUReferences) {
401-
// Referenced DIE is in other compile unit.
402-
403-
// Check whether DIEs are loaded for that compile unit.
404-
enum Stage ReferredCUStage = RefCU->getStage();
405-
if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned)
406-
return UnitEntryPairTy{RefCU, nullptr};
407-
408-
if (std::optional<uint32_t> RefDieIdx =
409-
RefCU->getDIEIndexForOffset(RefDIEOffset))
410-
return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
411-
} else
412-
return UnitEntryPairTy{RefCU, nullptr};
413-
}
384+
CompileUnit *RefCU;
385+
uint64_t RefDIEOffset;
386+
if (std::optional<uint64_t> Offset = RefValue.getAsRelativeReference()) {
387+
RefCU = this;
388+
RefDIEOffset = RefValue.getUnit()->getOffset() + *Offset;
389+
} else if (Offset = RefValue.getAsDebugInfoReference(); Offset) {
390+
RefCU = getUnitFromOffset(*Offset);
391+
RefDIEOffset = *Offset;
392+
} else {
393+
return std::nullopt;
414394
}
415395

396+
if (RefCU == this) {
397+
// Referenced DIE is in current compile unit.
398+
if (std::optional<uint32_t> RefDieIdx = getDIEIndexForOffset(RefDIEOffset))
399+
return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)};
400+
} else if (RefCU && CanResolveInterCUReferences) {
401+
// Referenced DIE is in other compile unit.
402+
403+
// Check whether DIEs are loaded for that compile unit.
404+
enum Stage ReferredCUStage = RefCU->getStage();
405+
if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned)
406+
return UnitEntryPairTy{RefCU, nullptr};
407+
408+
if (std::optional<uint32_t> RefDieIdx =
409+
RefCU->getDIEIndexForOffset(RefDIEOffset))
410+
return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
411+
} else {
412+
return UnitEntryPairTy{RefCU, nullptr};
413+
}
416414
return std::nullopt;
417415
}
418416

llvm/lib/DebugInfo/DWARF/DWARFDie.cpp

+6-7
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,12 @@ DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
313313
DWARFDie
314314
DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
315315
DWARFDie Result;
316-
if (auto SpecRef = V.getAsRelativeReference()) {
317-
if (SpecRef->Unit)
318-
Result = SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() +
319-
SpecRef->Offset);
320-
else if (auto SpecUnit =
321-
U->getUnitVector().getUnitForOffset(SpecRef->Offset))
322-
Result = SpecUnit->getDIEForOffset(SpecRef->Offset);
316+
if (std::optional<uint64_t> Offset = V.getAsRelativeReference()) {
317+
Result = const_cast<DWARFUnit *>(V.getUnit())
318+
->getDIEForOffset(V.getUnit()->getOffset() + *Offset);
319+
} else if (Offset = V.getAsDebugInfoReference(); Offset) {
320+
if (DWARFUnit *SpecUnit = U->getUnitVector().getUnitForOffset(*Offset))
321+
Result = SpecUnit->getDIEForOffset(*Offset);
323322
}
324323
return Result;
325324
}

llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp

+24-14
Original file line numberDiff line numberDiff line change
@@ -665,16 +665,7 @@ DWARFFormValue::getAsSectionedAddress() const {
665665
return getAsSectionedAddress(Value, Form, U);
666666
}
667667

668-
std::optional<uint64_t> DWARFFormValue::getAsReference() const {
669-
if (auto R = getAsRelativeReference())
670-
return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset;
671-
return std::nullopt;
672-
}
673-
674-
std::optional<DWARFFormValue::UnitOffset>
675-
DWARFFormValue::getAsRelativeReference() const {
676-
if (!isFormClass(FC_Reference))
677-
return std::nullopt;
668+
std::optional<uint64_t> DWARFFormValue::getAsRelativeReference() const {
678669
switch (Form) {
679670
case DW_FORM_ref1:
680671
case DW_FORM_ref2:
@@ -683,11 +674,30 @@ DWARFFormValue::getAsRelativeReference() const {
683674
case DW_FORM_ref_udata:
684675
if (!U)
685676
return std::nullopt;
686-
return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval};
687-
case DW_FORM_ref_addr:
688-
case DW_FORM_ref_sig8:
677+
return Value.uval;
678+
default:
679+
return std::nullopt;
680+
}
681+
}
682+
683+
std::optional<uint64_t> DWARFFormValue::getAsDebugInfoReference() const {
684+
if (Form == DW_FORM_ref_addr)
685+
return Value.uval;
686+
return std::nullopt;
687+
}
688+
689+
std::optional<uint64_t> DWARFFormValue::getAsSignatureReference() const {
690+
if (Form == DW_FORM_ref_sig8)
691+
return Value.uval;
692+
return std::nullopt;
693+
}
694+
695+
std::optional<uint64_t> DWARFFormValue::getAsSupplementaryReference() const {
696+
switch (Form) {
689697
case DW_FORM_GNU_ref_alt:
690-
return UnitOffset{nullptr, Value.uval};
698+
case DW_FORM_ref_sup4:
699+
case DW_FORM_ref_sup8:
700+
return Value.uval;
691701
default:
692702
return std::nullopt;
693703
}

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
836836
case DW_FORM_ref8:
837837
case DW_FORM_ref_udata: {
838838
// Verify all CU relative references are valid CU offsets.
839-
std::optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
839+
std::optional<uint64_t> RefVal = AttrValue.Value.getAsRelativeReference();
840840
assert(RefVal);
841841
if (RefVal) {
842842
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
@@ -854,15 +854,16 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
854854
} else {
855855
// Valid reference, but we will verify it points to an actual
856856
// DIE later.
857-
LocalReferences[*RefVal].insert(Die.getOffset());
857+
LocalReferences[AttrValue.Value.getUnit()->getOffset() + *RefVal]
858+
.insert(Die.getOffset());
858859
}
859860
}
860861
break;
861862
}
862863
case DW_FORM_ref_addr: {
863864
// Verify all absolute DIE references have valid offsets in the
864865
// .debug_info section.
865-
std::optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
866+
std::optional<uint64_t> RefVal = AttrValue.Value.getAsDebugInfoReference();
866867
assert(RefVal);
867868
if (RefVal) {
868869
if (*RefVal >= DieCU->getInfoSection().Data.size()) {

llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp

+11-4
Original file line numberDiff line numberDiff line change
@@ -1082,21 +1082,28 @@ void LVDWARFReader::updateReference(dwarf::Attribute Attr,
10821082
// FIXME: We are assuming that at most one Reference (DW_AT_specification,
10831083
// DW_AT_abstract_origin, ...) and at most one Type (DW_AT_import, DW_AT_type)
10841084
// appear in any single DIE, but this may not be true.
1085-
uint64_t Reference = *FormValue.getAsReference();
1085+
uint64_t Offset;
1086+
if (std::optional<uint64_t> Off = FormValue.getAsRelativeReference())
1087+
Offset = FormValue.getUnit()->getOffset() + *Off;
1088+
else if (Off = FormValue.getAsDebugInfoReference(); Off)
1089+
Offset = *Off;
1090+
else
1091+
llvm_unreachable("Unsupported reference type");
1092+
10861093
// Get target for the given reference, if already created.
10871094
LVElement *Target = getElementForOffset(
1088-
Reference, CurrentElement,
1095+
Offset, CurrentElement,
10891096
/*IsType=*/Attr == dwarf::DW_AT_import || Attr == dwarf::DW_AT_type);
10901097
// Check if we are dealing with cross CU references.
10911098
if (FormValue.getForm() == dwarf::DW_FORM_ref_addr) {
10921099
if (Target) {
10931100
// The global reference is ready. Mark it as global.
10941101
Target->setIsGlobalReference();
10951102
// Remove global reference from the unseen list.
1096-
removeGlobalOffset(Reference);
1103+
removeGlobalOffset(Offset);
10971104
} else
10981105
// Record the unseen cross CU reference.
1099-
addGlobalOffset(Reference);
1106+
addGlobalOffset(Offset);
11001107
}
11011108

11021109
// At this point, 'Target' can be null, in the case of the target element

0 commit comments

Comments
 (0)