Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split DWARFFormValue::getReference into four functions #98905

Merged
merged 2 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 90 additions & 17 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t> getAsReference() const;
struct UnitOffset {
DWARFUnit *Unit;
uint64_t Offset;
};
std::optional<UnitOffset> getAsRelativeReference() const;
std::optional<uint64_t> getAsRelativeReference() const;
std::optional<uint64_t> getAsDebugInfoReference() const;
std::optional<uint64_t> getAsSignatureReference() const;
std::optional<uint64_t> getAsSupplementaryReference() const;
std::optional<uint64_t> getAsUnsignedConstant() const;
std::optional<int64_t> getAsSignedConstant() const;
Expected<const char *> getAsCString() const;
Expand Down Expand Up @@ -242,27 +240,102 @@ inline uint64_t toUnsigned(const std::optional<DWARFFormValue> &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<uint64_t>
toReference(const std::optional<DWARFFormValue> &V) {
toRelativeReference(const std::optional<DWARFFormValue> &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<DWARFFormValue> &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<uint64_t>
toDebugInfoReference(const std::optional<DWARFFormValue> &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<DWARFFormValue> &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<uint64_t>
toSignatureReference(const std::optional<DWARFFormValue> &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<DWARFFormValue> &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<uint64_t>
toSupplementaryReference(const std::optional<DWARFFormValue> &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<DWARFFormValue> &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<DWARFFormValue> &V,
uint64_t Default) {
return toSupplementaryReference(V).value_or(Default);
}

/// Take an optional DWARFFormValue and try to extract an signed constant.
Expand Down
18 changes: 16 additions & 2 deletions llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t> 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
Expand Down Expand Up @@ -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<uint64_t> 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;
Expand Down
58 changes: 28 additions & 30 deletions llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,38 +381,36 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() {
std::optional<UnitEntryPairTy> CompileUnit::resolveDIEReference(
const DWARFFormValue &RefValue,
ResolveInterCUReferencesMode CanResolveInterCUReferences) {
if (std::optional<DWARFFormValue::UnitOffset> Ref =
*RefValue.getAsRelativeReference()) {
if (Ref->Unit == OrigUnit) {
// Referenced DIE is in current compile unit.
if (std::optional<uint32_t> 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<uint32_t> 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<uint32_t> RefDieIdx =
RefCU->getDIEIndexForOffset(RefDIEOffset))
return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
} else
return UnitEntryPairTy{RefCU, nullptr};
}
CompileUnit *RefCU;
uint64_t RefDIEOffset;
if (std::optional<uint64_t> 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<uint32_t> 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<uint32_t> RefDieIdx =
RefCU->getDIEIndexForOffset(RefDIEOffset))
return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)};
} else {
return UnitEntryPairTy{RefCU, nullptr};
}
return std::nullopt;
}

Expand Down
13 changes: 6 additions & 7 deletions llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t> Offset = V.getAsRelativeReference()) {
Result = const_cast<DWARFUnit *>(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;
}
Expand Down
38 changes: 24 additions & 14 deletions llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,16 +665,7 @@ DWARFFormValue::getAsSectionedAddress() const {
return getAsSectionedAddress(Value, Form, U);
}

std::optional<uint64_t> DWARFFormValue::getAsReference() const {
if (auto R = getAsRelativeReference())
return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset;
return std::nullopt;
}

std::optional<DWARFFormValue::UnitOffset>
DWARFFormValue::getAsRelativeReference() const {
if (!isFormClass(FC_Reference))
return std::nullopt;
std::optional<uint64_t> DWARFFormValue::getAsRelativeReference() const {
switch (Form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
Expand All @@ -683,11 +674,30 @@ DWARFFormValue::getAsRelativeReference() const {
case DW_FORM_ref_udata:
if (!U)
return std::nullopt;
return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval};
case DW_FORM_ref_addr:
case DW_FORM_ref_sig8:
return Value.uval;
default:
return std::nullopt;
}
}

std::optional<uint64_t> DWARFFormValue::getAsDebugInfoReference() const {
if (Form == DW_FORM_ref_addr)
return Value.uval;
return std::nullopt;
}

std::optional<uint64_t> DWARFFormValue::getAsSignatureReference() const {
if (Form == DW_FORM_ref_sig8)
return Value.uval;
return std::nullopt;
}

std::optional<uint64_t> 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;
}
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t> RefVal = AttrValue.Value.getAsReference();
std::optional<uint64_t> RefVal = AttrValue.Value.getAsRelativeReference();
assert(RefVal);
if (RefVal) {
auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
Expand All @@ -854,15 +854,16 @@ 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;
}
case DW_FORM_ref_addr: {
// Verify all absolute DIE references have valid offsets in the
// .debug_info section.
std::optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
std::optional<uint64_t> RefVal = AttrValue.Value.getAsDebugInfoReference();
assert(RefVal);
if (RefVal) {
if (*RefVal >= DieCU->getInfoSection().Data.size()) {
Expand Down
15 changes: 11 additions & 4 deletions llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1082,21 +1082,28 @@ 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<uint64_t> 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) {
if (Target) {
// 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
Expand Down
Loading
Loading