From 632b6e81b8e87e7bad47d556b52e5261549dcb8a Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Tue, 16 Jul 2024 12:55:38 +0200 Subject: [PATCH] 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 --- .../llvm/DebugInfo/DWARF/DWARFFormValue.h | 107 ++++++++-- llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp | 18 +- .../Parallel/DWARFLinkerCompileUnit.cpp | 58 +++--- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 13 +- llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp | 38 ++-- llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp | 7 +- .../LogicalView/Readers/LVDWARFReader.cpp | 15 +- .../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 187 +++++++++++++----- 8 files changed, 317 insertions(+), 126 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index dbb658940eef12..563887d1149a8c 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -107,12 +107,10 @@ class DWARFFormValue { /// getAsFoo functions below return the extracted value as Foo if only /// DWARFFormValue has form class is suitable for representing Foo. - std::optional getAsReference() const; - struct UnitOffset { - DWARFUnit *Unit; - uint64_t Offset; - }; - std::optional getAsRelativeReference() const; + std::optional getAsRelativeReference() const; + std::optional getAsDebugInfoReference() const; + std::optional getAsSignatureReference() const; + std::optional getAsSupplementaryReference() const; std::optional getAsUnsignedConstant() const; std::optional getAsSignedConstant() const; Expected getAsCString() const; @@ -242,27 +240,102 @@ inline uint64_t toUnsigned(const std::optional &V, return toUnsigned(V).value_or(Default); } -/// Take an optional DWARFFormValue and try to extract an reference. +/// Take an optional DWARFFormValue and try to extract a relative offset +/// reference. /// -/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param V an optional DWARFFormValue to attempt to extract the value from. /// \returns an optional value that contains a value if the form value -/// was valid and has a reference form. +/// was valid and has a relative reference form. inline std::optional -toReference(const std::optional &V) { +toRelativeReference(const std::optional &V) { if (V) - return V->getAsReference(); + return V->getAsRelativeReference(); return std::nullopt; } -/// Take an optional DWARFFormValue and extract a reference. +/// Take an optional DWARFFormValue and extract a relative offset reference. /// -/// \param V and optional DWARFFormValue to attempt to extract the value from. +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted reference value or Default if the V doesn't have a +/// value or the form value's encoding wasn't a relative offset reference form. +inline uint64_t toRelativeReference(const std::optional &V, + uint64_t Default) { + return toRelativeReference(V).value_or(Default); +} + +/// Take an optional DWARFFormValue and try to extract an absolute debug info +/// offset reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has an (absolute) debug info offset reference form. +inline std::optional +toDebugInfoReference(const std::optional &V) { + if (V) + return V->getAsDebugInfoReference(); + return std::nullopt; +} + +/// Take an optional DWARFFormValue and extract an absolute debug info offset +/// reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted reference value or Default if the V doesn't have a +/// value or the form value's encoding wasn't an absolute debug info offset +/// reference form. +inline uint64_t toDebugInfoReference(const std::optional &V, + uint64_t Default) { + return toDebugInfoReference(V).value_or(Default); +} + +/// Take an optional DWARFFormValue and try to extract a signature reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a signature reference form. +inline std::optional +toSignatureReference(const std::optional &V) { + if (V) + return V->getAsSignatureReference(); + return std::nullopt; +} + +/// Take an optional DWARFFormValue and extract a signature reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \param Default the default value to return in case of failure. +/// \returns the extracted reference value or Default if the V doesn't have a +/// value or the form value's encoding wasn't a signature reference form. +inline uint64_t toSignatureReference(const std::optional &V, + uint64_t Default) { + return toSignatureReference(V).value_or(Default); +} + +/// Take an optional DWARFFormValue and try to extract a supplementary debug +/// info reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. +/// \returns an optional value that contains a value if the form value +/// was valid and has a supplementary reference form. +inline std::optional +toSupplementaryReference(const std::optional &V) { + if (V) + return V->getAsSupplementaryReference(); + return std::nullopt; +} + +/// Take an optional DWARFFormValue and extract a supplementary debug info +/// reference. +/// +/// \param V an optional DWARFFormValue to attempt to extract the value from. /// \param Default the default value to return in case of failure. /// \returns the extracted reference value or Default if the V doesn't have a -/// value or the form value's encoding wasn't a reference form. -inline uint64_t toReference(const std::optional &V, - uint64_t Default) { - return toReference(V).value_or(Default); +/// value or the form value's encoding wasn't a supplementary reference form. +inline uint64_t toSupplementaryReference(const std::optional &V, + uint64_t Default) { + return toSupplementaryReference(V).value_or(Default); } /// Take an optional DWARFFormValue and try to extract an signed constant. diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp index c6312c387744aa..7510326f2e1b34 100644 --- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp @@ -77,7 +77,15 @@ DWARFDie DWARFLinker::resolveDIEReference(const DWARFFile &File, const DWARFDie &DIE, CompileUnit *&RefCU) { assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); - uint64_t RefOffset = *RefValue.getAsReference(); + uint64_t RefOffset; + if (std::optional Off = RefValue.getAsRelativeReference()) { + RefOffset = RefValue.getUnit()->getOffset() + *Off; + } else if (Off = RefValue.getAsDebugInfoReference(); Off) { + RefOffset = *Off; + } else { + reportWarning("Unsupported reference type", File, &DIE); + return DWARFDie(); + } if ((RefCU = getUnitForOffset(Units, RefOffset))) if (const auto RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) { // In a file with broken references, an attribute might point to a NULL @@ -1073,7 +1081,13 @@ unsigned DWARFLinker::DIECloner::cloneDieReferenceAttribute( unsigned AttrSize, const DWARFFormValue &Val, const DWARFFile &File, CompileUnit &Unit) { const DWARFUnit &U = Unit.getOrigUnit(); - uint64_t Ref = *Val.getAsReference(); + uint64_t Ref; + if (std::optional Off = Val.getAsRelativeReference()) + Ref = Val.getUnit()->getOffset() + *Off; + else if (Off = Val.getAsDebugInfoReference(); Off) + Ref = *Off; + else + return 0; DIE *NewRefDie = nullptr; CompileUnit *RefUnit = nullptr; diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp index 6f659eb8576b79..4daf781a2b53fa 100644 --- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp +++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp @@ -381,38 +381,36 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() { std::optional CompileUnit::resolveDIEReference( const DWARFFormValue &RefValue, ResolveInterCUReferencesMode CanResolveInterCUReferences) { - if (std::optional Ref = - *RefValue.getAsRelativeReference()) { - if (Ref->Unit == OrigUnit) { - // Referenced DIE is in current compile unit. - if (std::optional RefDieIdx = - getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset)) - return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)}; - } - uint64_t RefDIEOffset = - Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset; - if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) { - if (RefCU == this) { - // Referenced DIE is in current compile unit. - if (std::optional RefDieIdx = - getDIEIndexForOffset(RefDIEOffset)) - return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)}; - } else if (CanResolveInterCUReferences) { - // Referenced DIE is in other compile unit. - - // Check whether DIEs are loaded for that compile unit. - enum Stage ReferredCUStage = RefCU->getStage(); - if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned) - return UnitEntryPairTy{RefCU, nullptr}; - - if (std::optional RefDieIdx = - RefCU->getDIEIndexForOffset(RefDIEOffset)) - return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)}; - } else - return UnitEntryPairTy{RefCU, nullptr}; - } + CompileUnit *RefCU; + uint64_t RefDIEOffset; + if (std::optional Offset = RefValue.getAsRelativeReference()) { + RefCU = this; + RefDIEOffset = RefValue.getUnit()->getOffset() + *Offset; + } else if (Offset = RefValue.getAsDebugInfoReference(); Offset) { + RefCU = getUnitFromOffset(*Offset); + RefDIEOffset = *Offset; + } else { + return std::nullopt; } + if (RefCU == this) { + // Referenced DIE is in current compile unit. + if (std::optional RefDieIdx = getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)}; + } else if (RefCU && CanResolveInterCUReferences) { + // Referenced DIE is in other compile unit. + + // Check whether DIEs are loaded for that compile unit. + enum Stage ReferredCUStage = RefCU->getStage(); + if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned) + return UnitEntryPairTy{RefCU, nullptr}; + + if (std::optional RefDieIdx = + RefCU->getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)}; + } else { + return UnitEntryPairTy{RefCU, nullptr}; + } return std::nullopt; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 410842a80b0151..72e7464b689716 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -313,13 +313,12 @@ DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { DWARFDie DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const { DWARFDie Result; - if (auto SpecRef = V.getAsRelativeReference()) { - if (SpecRef->Unit) - Result = SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() + - SpecRef->Offset); - else if (auto SpecUnit = - U->getUnitVector().getUnitForOffset(SpecRef->Offset)) - Result = SpecUnit->getDIEForOffset(SpecRef->Offset); + if (std::optional Offset = V.getAsRelativeReference()) { + Result = const_cast(V.getUnit()) + ->getDIEForOffset(V.getUnit()->getOffset() + *Offset); + } else if (Offset = V.getAsDebugInfoReference(); Offset) { + if (DWARFUnit *SpecUnit = U->getUnitVector().getUnitForOffset(*Offset)) + Result = SpecUnit->getDIEForOffset(*Offset); } return Result; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index b9cf7d22c80d4b..bc4badc7713802 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -665,16 +665,7 @@ DWARFFormValue::getAsSectionedAddress() const { return getAsSectionedAddress(Value, Form, U); } -std::optional DWARFFormValue::getAsReference() const { - if (auto R = getAsRelativeReference()) - return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset; - return std::nullopt; -} - -std::optional -DWARFFormValue::getAsRelativeReference() const { - if (!isFormClass(FC_Reference)) - return std::nullopt; +std::optional DWARFFormValue::getAsRelativeReference() const { switch (Form) { case DW_FORM_ref1: case DW_FORM_ref2: @@ -683,11 +674,30 @@ DWARFFormValue::getAsRelativeReference() const { case DW_FORM_ref_udata: if (!U) return std::nullopt; - return UnitOffset{const_cast(U), Value.uval}; - case DW_FORM_ref_addr: - case DW_FORM_ref_sig8: + return Value.uval; + default: + return std::nullopt; + } +} + +std::optional DWARFFormValue::getAsDebugInfoReference() const { + if (Form == DW_FORM_ref_addr) + return Value.uval; + return std::nullopt; +} + +std::optional DWARFFormValue::getAsSignatureReference() const { + if (Form == DW_FORM_ref_sig8) + return Value.uval; + return std::nullopt; +} + +std::optional DWARFFormValue::getAsSupplementaryReference() const { + switch (Form) { case DW_FORM_GNU_ref_alt: - return UnitOffset{nullptr, Value.uval}; + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: + return Value.uval; default: return std::nullopt; } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 4ef6c80ed0289d..a804deb446186d 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -836,7 +836,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, case DW_FORM_ref8: case DW_FORM_ref_udata: { // Verify all CU relative references are valid CU offsets. - std::optional RefVal = AttrValue.Value.getAsReference(); + std::optional RefVal = AttrValue.Value.getAsRelativeReference(); assert(RefVal); if (RefVal) { auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); @@ -854,7 +854,8 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, } else { // Valid reference, but we will verify it points to an actual // DIE later. - LocalReferences[*RefVal].insert(Die.getOffset()); + LocalReferences[AttrValue.Value.getUnit()->getOffset() + *RefVal] + .insert(Die.getOffset()); } } break; @@ -862,7 +863,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, case DW_FORM_ref_addr: { // Verify all absolute DIE references have valid offsets in the // .debug_info section. - std::optional RefVal = AttrValue.Value.getAsReference(); + std::optional RefVal = AttrValue.Value.getAsDebugInfoReference(); assert(RefVal); if (RefVal) { if (*RefVal >= DieCU->getInfoSection().Data.size()) { diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp index 6a97bed9e3a838..68a14b8b0ad33e 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp @@ -1082,10 +1082,17 @@ void LVDWARFReader::updateReference(dwarf::Attribute Attr, // FIXME: We are assuming that at most one Reference (DW_AT_specification, // DW_AT_abstract_origin, ...) and at most one Type (DW_AT_import, DW_AT_type) // appear in any single DIE, but this may not be true. - uint64_t Reference = *FormValue.getAsReference(); + uint64_t Offset; + if (std::optional Off = FormValue.getAsRelativeReference()) + Offset = FormValue.getUnit()->getOffset() + *Off; + else if (Off = FormValue.getAsDebugInfoReference(); Off) + Offset = *Off; + else + llvm_unreachable("Unsupported reference type"); + // Get target for the given reference, if already created. LVElement *Target = getElementForOffset( - Reference, CurrentElement, + Offset, CurrentElement, /*IsType=*/Attr == dwarf::DW_AT_import || Attr == dwarf::DW_AT_type); // Check if we are dealing with cross CU references. if (FormValue.getForm() == dwarf::DW_FORM_ref_addr) { @@ -1093,10 +1100,10 @@ void LVDWARFReader::updateReference(dwarf::Attribute Attr, // The global reference is ready. Mark it as global. Target->setIsGlobalReference(); // Remove global reference from the unseen list. - removeGlobalOffset(Reference); + removeGlobalOffset(Offset); } else // Record the unseen cross CU reference. - addGlobalOffset(Reference); + addGlobalOffset(Offset); } // At this point, 'Target' can be null, in the case of the target element diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp index 5cb0310c0ad097..373a58d259af5e 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -384,15 +384,18 @@ void TestAllForms() { //---------------------------------------------------------------------- // Test reference forms //---------------------------------------------------------------------- - EXPECT_EQ(RefAddr, toReference(DieDG.find(Attr_DW_FORM_ref_addr), 0)); - EXPECT_EQ(Data1, toReference(DieDG.find(Attr_DW_FORM_ref1), 0)); - EXPECT_EQ(Data2, toReference(DieDG.find(Attr_DW_FORM_ref2), 0)); - EXPECT_EQ(Data4, toReference(DieDG.find(Attr_DW_FORM_ref4), 0)); - EXPECT_EQ(Data8, toReference(DieDG.find(Attr_DW_FORM_ref8), 0)); + EXPECT_EQ(RefAddr, + toDebugInfoReference(DieDG.find(Attr_DW_FORM_ref_addr), 0)); + EXPECT_EQ(Data1, toRelativeReference(DieDG.find(Attr_DW_FORM_ref1), 0)); + EXPECT_EQ(Data2, toRelativeReference(DieDG.find(Attr_DW_FORM_ref2), 0)); + EXPECT_EQ(Data4, toRelativeReference(DieDG.find(Attr_DW_FORM_ref4), 0)); + EXPECT_EQ(Data8, toRelativeReference(DieDG.find(Attr_DW_FORM_ref8), 0)); if (Version >= 4) { - EXPECT_EQ(Data8_2, toReference(DieDG.find(Attr_DW_FORM_ref_sig8), 0)); + EXPECT_EQ(Data8_2, + toSignatureReference(DieDG.find(Attr_DW_FORM_ref_sig8), 0)); } - EXPECT_EQ(UData[0], toReference(DieDG.find(Attr_DW_FORM_ref_udata), 0)); + EXPECT_EQ(UData[0], + toRelativeReference(DieDG.find(Attr_DW_FORM_ref_udata), 0)); //---------------------------------------------------------------------- // Test flag forms @@ -420,7 +423,7 @@ void TestAllForms() { // Test DWARF32/DWARF64 forms //---------------------------------------------------------------------- EXPECT_EQ(Dwarf32Values[0], - toReference(DieDG.find(Attr_DW_FORM_GNU_ref_alt), 0)); + toSupplementaryReference(DieDG.find(Attr_DW_FORM_GNU_ref_alt), 0)); if (Version >= 4) { EXPECT_EQ(Dwarf32Values[1], toSectionOffset(DieDG.find(Attr_DW_FORM_sec_offset), 0)); @@ -761,14 +764,14 @@ template void TestReferences() { EXPECT_TRUE(CU1Ref1DieDG.isValid()); EXPECT_EQ(CU1Ref1DieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU1Ref1DieDG.find(DW_AT_type), -1ULL)); + toRelativeReference(CU1Ref1DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our // base type DIE in CU1. auto CU1Ref2DieDG = CU1Ref1DieDG.getSibling(); EXPECT_TRUE(CU1Ref2DieDG.isValid()); EXPECT_EQ(CU1Ref2DieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU1Ref2DieDG.find(DW_AT_type), -1ULL)); + toRelativeReference(CU1Ref2DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our // base type DIE in CU1. @@ -776,7 +779,7 @@ template void TestReferences() { EXPECT_TRUE(CU1Ref4DieDG.isValid()); EXPECT_EQ(CU1Ref4DieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU1Ref4DieDG.find(DW_AT_type), -1ULL)); + toRelativeReference(CU1Ref4DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our // base type DIE in CU1. @@ -784,7 +787,7 @@ template void TestReferences() { EXPECT_TRUE(CU1Ref8DieDG.isValid()); EXPECT_EQ(CU1Ref8DieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU1Ref8DieDG.find(DW_AT_type), -1ULL)); + toRelativeReference(CU1Ref8DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our // base type DIE in CU1. @@ -792,7 +795,7 @@ template void TestReferences() { EXPECT_TRUE(CU1RefAddrDieDG.isValid()); EXPECT_EQ(CU1RefAddrDieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU1RefAddrDieDG.find(DW_AT_type), -1ULL)); + toDebugInfoReference(CU1RefAddrDieDG.find(DW_AT_type), -1ULL)); // Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its // DW_AT_type points to our base type DIE. @@ -800,38 +803,38 @@ template void TestReferences() { EXPECT_TRUE(CU1ToCU2RefAddrDieDG.isValid()); EXPECT_EQ(CU1ToCU2RefAddrDieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU1ToCU2RefAddrDieDG.find(DW_AT_type), -1ULL)); + toDebugInfoReference(CU1ToCU2RefAddrDieDG.find(DW_AT_type), -1ULL)); // Verify the sibling of the base type DIE is our Ref1 DIE and that its // DW_AT_type points to our base type DIE. auto CU2Ref1DieDG = CU2TypeDieDG.getSibling(); EXPECT_TRUE(CU2Ref1DieDG.isValid()); EXPECT_EQ(CU2Ref1DieDG.getTag(), DW_TAG_variable); - EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU2Ref1DieDG.find(DW_AT_type), -1ULL)); + EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(), + toRelativeReference(CU2Ref1DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref2 DIE and that its DW_AT_type points to our // base type DIE in CU2. auto CU2Ref2DieDG = CU2Ref1DieDG.getSibling(); EXPECT_TRUE(CU2Ref2DieDG.isValid()); EXPECT_EQ(CU2Ref2DieDG.getTag(), DW_TAG_variable); - EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU2Ref2DieDG.find(DW_AT_type), -1ULL)); + EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(), + toRelativeReference(CU2Ref2DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref4 DIE and that its DW_AT_type points to our // base type DIE in CU2. auto CU2Ref4DieDG = CU2Ref2DieDG.getSibling(); EXPECT_TRUE(CU2Ref4DieDG.isValid()); EXPECT_EQ(CU2Ref4DieDG.getTag(), DW_TAG_variable); - EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU2Ref4DieDG.find(DW_AT_type), -1ULL)); + EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(), + toRelativeReference(CU2Ref4DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our Ref8 DIE and that its DW_AT_type points to our // base type DIE in CU2. auto CU2Ref8DieDG = CU2Ref4DieDG.getSibling(); EXPECT_TRUE(CU2Ref8DieDG.isValid()); EXPECT_EQ(CU2Ref8DieDG.getTag(), DW_TAG_variable); - EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU2Ref8DieDG.find(DW_AT_type), -1ULL)); + EXPECT_EQ(CU2TypeDieDG.getOffset() - CU2TypeDieDG.getDwarfUnit()->getOffset(), + toRelativeReference(CU2Ref8DieDG.find(DW_AT_type), -1ULL)); // Verify the sibling is our RefAddr DIE and that its DW_AT_type points to our // base type DIE in CU2. @@ -839,7 +842,7 @@ template void TestReferences() { EXPECT_TRUE(CU2RefAddrDieDG.isValid()); EXPECT_EQ(CU2RefAddrDieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU2TypeDieDG.getOffset(), - toReference(CU2RefAddrDieDG.find(DW_AT_type), -1ULL)); + toDebugInfoReference(CU2RefAddrDieDG.find(DW_AT_type), -1ULL)); // Verify the sibling of the Ref4 DIE is our RefAddr DIE and that its // DW_AT_type points to our base type DIE. @@ -847,7 +850,7 @@ template void TestReferences() { EXPECT_TRUE(CU2ToCU1RefAddrDieDG.isValid()); EXPECT_EQ(CU2ToCU1RefAddrDieDG.getTag(), DW_TAG_variable); EXPECT_EQ(CU1TypeDieDG.getOffset(), - toReference(CU2ToCU1RefAddrDieDG.find(DW_AT_type), -1ULL)); + toDebugInfoReference(CU2ToCU1RefAddrDieDG.find(DW_AT_type), -1ULL)); } TEST(DWARFDebugInfo, TestDWARF32Version2Addr4References) { @@ -1662,14 +1665,20 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { std::optional FormValOpt1 = DWARFFormValue(); EXPECT_FALSE(toString(FormValOpt1).has_value()); EXPECT_FALSE(toUnsigned(FormValOpt1).has_value()); - EXPECT_FALSE(toReference(FormValOpt1).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt1).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt1).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt1).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt1).has_value()); EXPECT_FALSE(toSigned(FormValOpt1).has_value()); EXPECT_FALSE(toAddress(FormValOpt1).has_value()); EXPECT_FALSE(toSectionOffset(FormValOpt1).has_value()); EXPECT_FALSE(toBlock(FormValOpt1).has_value()); EXPECT_EQ(nullptr, toString(FormValOpt1, nullptr)); EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt1, InvalidU64)); - EXPECT_EQ(InvalidU64, toReference(FormValOpt1, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt1, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt1, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt1, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt1, InvalidU64)); EXPECT_EQ(InvalidU64, toAddress(FormValOpt1, InvalidU64)); EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt1, InvalidU64)); EXPECT_EQ(InvalidS64, toSigned(FormValOpt1, InvalidS64)); @@ -1681,14 +1690,20 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { EXPECT_FALSE(toString(FormValOpt2).has_value()); EXPECT_FALSE(toUnsigned(FormValOpt2).has_value()); - EXPECT_FALSE(toReference(FormValOpt2).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt2).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt2).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt2).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt2).has_value()); EXPECT_FALSE(toSigned(FormValOpt2).has_value()); EXPECT_TRUE(toAddress(FormValOpt2).has_value()); EXPECT_FALSE(toSectionOffset(FormValOpt2).has_value()); EXPECT_FALSE(toBlock(FormValOpt2).has_value()); EXPECT_EQ(nullptr, toString(FormValOpt2, nullptr)); EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt2, InvalidU64)); - EXPECT_EQ(InvalidU64, toReference(FormValOpt2, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt2, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt2, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt2, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt2, InvalidU64)); EXPECT_EQ(Address, toAddress(FormValOpt2, InvalidU64)); EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt2, InvalidU64)); EXPECT_EQ(InvalidS64, toSigned(FormValOpt2, InvalidU64)); @@ -1700,36 +1715,98 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { EXPECT_FALSE(toString(FormValOpt3).has_value()); EXPECT_TRUE(toUnsigned(FormValOpt3).has_value()); - EXPECT_FALSE(toReference(FormValOpt3).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt3).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt3).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt3).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt3).has_value()); EXPECT_TRUE(toSigned(FormValOpt3).has_value()); EXPECT_FALSE(toAddress(FormValOpt3).has_value()); EXPECT_FALSE(toSectionOffset(FormValOpt3).has_value()); EXPECT_FALSE(toBlock(FormValOpt3).has_value()); EXPECT_EQ(nullptr, toString(FormValOpt3, nullptr)); EXPECT_EQ(UData8, toUnsigned(FormValOpt3, InvalidU64)); - EXPECT_EQ(InvalidU64, toReference(FormValOpt3, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt3, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt3, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt3, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt3, InvalidU64)); EXPECT_EQ(InvalidU64, toAddress(FormValOpt3, InvalidU64)); EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt3, InvalidU64)); EXPECT_EQ((int64_t)UData8, toSigned(FormValOpt3, InvalidU64)); - // Test successful and unsuccessful reference decoding. + // Test successful and unsuccessful ref_addr decoding. uint32_t RefData = 0x11223344U; - std::optional FormValOpt4 = + std::optional FormValOpt4Addr = DWARFFormValue::createFromUValue(DW_FORM_ref_addr, RefData); - EXPECT_FALSE(toString(FormValOpt4).has_value()); - EXPECT_FALSE(toUnsigned(FormValOpt4).has_value()); - EXPECT_TRUE(toReference(FormValOpt4).has_value()); - EXPECT_FALSE(toSigned(FormValOpt4).has_value()); - EXPECT_FALSE(toAddress(FormValOpt4).has_value()); - EXPECT_FALSE(toSectionOffset(FormValOpt4).has_value()); - EXPECT_FALSE(toBlock(FormValOpt4).has_value()); - EXPECT_EQ(nullptr, toString(FormValOpt4, nullptr)); - EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4, InvalidU64)); - EXPECT_EQ(RefData, toReference(FormValOpt4, InvalidU64)); - EXPECT_EQ(InvalidU64, toAddress(FormValOpt4, InvalidU64)); - EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4, InvalidU64)); - EXPECT_EQ(InvalidS64, toSigned(FormValOpt4, InvalidU64)); + EXPECT_FALSE(toString(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toUnsigned(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt4Addr).has_value()); + EXPECT_TRUE(toDebugInfoReference(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toSigned(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toAddress(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toSectionOffset(FormValOpt4Addr).has_value()); + EXPECT_FALSE(toBlock(FormValOpt4Addr).has_value()); + EXPECT_EQ(nullptr, toString(FormValOpt4Addr, nullptr)); + EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(RefData, toDebugInfoReference(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Addr, InvalidU64)); + EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Addr, InvalidU64)); + + // Test successful and unsuccessful ref_sig8 decoding. + std::optional FormValOpt4Sig = + DWARFFormValue::createFromUValue(DW_FORM_ref_sig8, RefData); + + EXPECT_FALSE(toString(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toUnsigned(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt4Sig).has_value()); + EXPECT_TRUE(toSignatureReference(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toSigned(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toAddress(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toSectionOffset(FormValOpt4Sig).has_value()); + EXPECT_FALSE(toBlock(FormValOpt4Sig).has_value()); + EXPECT_EQ(nullptr, toString(FormValOpt4Sig, nullptr)); + EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(RefData, toSignatureReference(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Sig, InvalidU64)); + EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Sig, InvalidU64)); + + // Test successful and unsuccessful ref_alt decoding. + // Not testing relative reference forms here, as they require a valid + // DWARFUnit object. + std::optional FormValOpt4Alt = + DWARFFormValue::createFromUValue(DW_FORM_GNU_ref_alt, RefData); + + EXPECT_FALSE(toString(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toUnsigned(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt4Alt).has_value()); + EXPECT_TRUE(toSupplementaryReference(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toSigned(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toAddress(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toSectionOffset(FormValOpt4Alt).has_value()); + EXPECT_FALSE(toBlock(FormValOpt4Alt).has_value()); + EXPECT_EQ(nullptr, toString(FormValOpt4Alt, nullptr)); + EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(RefData, toSupplementaryReference(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidU64, toAddress(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt4Alt, InvalidU64)); + EXPECT_EQ(InvalidS64, toSigned(FormValOpt4Alt, InvalidU64)); // Test successful and unsuccessful signed constant decoding. int64_t SData8 = 0x1020304050607080ULL; @@ -1738,14 +1815,20 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { EXPECT_FALSE(toString(FormValOpt5).has_value()); EXPECT_TRUE(toUnsigned(FormValOpt5).has_value()); - EXPECT_FALSE(toReference(FormValOpt5).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt5).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt5).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt5).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt5).has_value()); EXPECT_TRUE(toSigned(FormValOpt5).has_value()); EXPECT_FALSE(toAddress(FormValOpt5).has_value()); EXPECT_FALSE(toSectionOffset(FormValOpt5).has_value()); EXPECT_FALSE(toBlock(FormValOpt5).has_value()); EXPECT_EQ(nullptr, toString(FormValOpt5, nullptr)); EXPECT_EQ((uint64_t)SData8, toUnsigned(FormValOpt5, InvalidU64)); - EXPECT_EQ(InvalidU64, toReference(FormValOpt5, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt5, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt5, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt5, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt5, InvalidU64)); EXPECT_EQ(InvalidU64, toAddress(FormValOpt5, InvalidU64)); EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt5, InvalidU64)); EXPECT_EQ(SData8, toSigned(FormValOpt5, InvalidU64)); @@ -1758,7 +1841,10 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { EXPECT_FALSE(toString(FormValOpt6).has_value()); EXPECT_FALSE(toUnsigned(FormValOpt6).has_value()); - EXPECT_FALSE(toReference(FormValOpt6).has_value()); + EXPECT_FALSE(toRelativeReference(FormValOpt6).has_value()); + EXPECT_FALSE(toDebugInfoReference(FormValOpt6).has_value()); + EXPECT_FALSE(toSignatureReference(FormValOpt6).has_value()); + EXPECT_FALSE(toSupplementaryReference(FormValOpt6).has_value()); EXPECT_FALSE(toSigned(FormValOpt6).has_value()); EXPECT_FALSE(toAddress(FormValOpt6).has_value()); EXPECT_FALSE(toSectionOffset(FormValOpt6).has_value()); @@ -1767,7 +1853,10 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { EXPECT_EQ(*BlockOpt, Array); EXPECT_EQ(nullptr, toString(FormValOpt6, nullptr)); EXPECT_EQ(InvalidU64, toUnsigned(FormValOpt6, InvalidU64)); - EXPECT_EQ(InvalidU64, toReference(FormValOpt6, InvalidU64)); + EXPECT_EQ(InvalidU64, toRelativeReference(FormValOpt6, InvalidU64)); + EXPECT_EQ(InvalidU64, toDebugInfoReference(FormValOpt6, InvalidU64)); + EXPECT_EQ(InvalidU64, toSignatureReference(FormValOpt6, InvalidU64)); + EXPECT_EQ(InvalidU64, toSupplementaryReference(FormValOpt6, InvalidU64)); EXPECT_EQ(InvalidU64, toAddress(FormValOpt6, InvalidU64)); EXPECT_EQ(InvalidU64, toSectionOffset(FormValOpt6, InvalidU64)); EXPECT_EQ(InvalidS64, toSigned(FormValOpt6, InvalidU64));