Skip to content

[DebugInfo] Add fast path for parsing DW_TAG_compile_unit abbrevs #108757

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,17 @@ class DWARFDebugAbbrev {
mutable DWARFAbbreviationDeclarationSetMap AbbrDeclSets;
mutable DWARFAbbreviationDeclarationSetMap::const_iterator PrevAbbrOffsetPos;
mutable std::optional<DataExtractor> Data;
mutable std::map<uint64_t, DWARFAbbreviationDeclaration> CUAbbrevs;

public:
DWARFDebugAbbrev(DataExtractor Data);

Expected<const DWARFAbbreviationDeclarationSet *>
getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const;

Expected<const DWARFAbbreviationDeclaration *>
tryExtractCUAbbrevFast(uint64_t CUAbbrOffset) const;

void dump(raw_ostream &OS) const;
Error parse() const;

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,10 @@ class DWARFUnit {

uint64_t getAbbreviationsOffset() const { return Header.getAbbrOffset(); }

/// Extracts only the abbreviation declaration with code 1, which is
/// typically the compile unit DIE (DW_TAG_compile_unit).
Expected<const DWARFAbbreviationDeclaration *> tryExtractCUAbbrevFast() const;

const DWARFAbbreviationDeclarationSet *getAbbreviations() const;

static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) {
Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,25 @@ DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
.first;
return &PrevAbbrOffsetPos->second;
}

Expected<const DWARFAbbreviationDeclaration *>
DWARFDebugAbbrev::tryExtractCUAbbrevFast(uint64_t CUAbbrOffset) const {
if (auto AbbrevDecl = CUAbbrevs.find(CUAbbrOffset);
AbbrevDecl != CUAbbrevs.end())
return &AbbrevDecl->second;

if (!Data || CUAbbrOffset >= Data->getData().size())
return make_error<llvm::object::GenericBinaryError>(
"the abbreviation offset into the .debug_abbrev section is not valid");

DWARFAbbreviationDeclaration Decl;
uint64_t Offset = CUAbbrOffset;
Expected<DWARFAbbreviationDeclaration::ExtractState> ES =
Decl.extract(*Data, &Offset);
if (!ES)
return ES.takeError();
if (Decl.getCode() != 1)
return nullptr;

return &(CUAbbrevs[CUAbbrOffset] = std::move(Decl));
}
64 changes: 42 additions & 22 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
#include <cstddef>
#include <cstdint>

Expand All @@ -34,36 +35,55 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
return false;
}
assert(DebugInfoData.isValidOffset(UEndOffset - 1));
AbbrevDecl = nullptr;

uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
if (0 == AbbrCode) {
// NULL debug tag entry.
AbbrevDecl = nullptr;
return true;
}
const auto *AbbrevSet = U.getAbbreviations();
if (!AbbrevSet) {
U.getContext().getWarningHandler()(
createStringError(errc::invalid_argument,
"DWARF unit at offset 0x%8.8" PRIx64 " "
"contains invalid abbreviation set offset 0x%" PRIx64,
U.getOffset(), U.getAbbreviationsOffset()));
// Restore the original offset.
*OffsetPtr = Offset;
return false;

// Fast path: parsing the entire abbreviation table is wasteful if we only
// need the unit DIE (typically AbbrCode == 1).
if (AbbrCode == 1) {
Expected<const DWARFAbbreviationDeclaration *> DeclOrError =
U.tryExtractCUAbbrevFast();
if (DeclOrError)
AbbrevDecl = *DeclOrError;
else
consumeError(DeclOrError.takeError()); // Retry full parsing below.
}
AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode);

if (!AbbrevDecl) {
U.getContext().getWarningHandler()(
createStringError(errc::invalid_argument,
"DWARF unit at offset 0x%8.8" PRIx64 " "
"contains invalid abbreviation %" PRIu64 " at "
"offset 0x%8.8" PRIx64 ", valid abbreviations are %s",
U.getOffset(), AbbrCode, *OffsetPtr,
AbbrevSet->getCodeRange().c_str()));
// Restore the original offset.
*OffsetPtr = Offset;
return false;
const auto *AbbrevSet = U.getAbbreviations();
if (!AbbrevSet) {
U.getContext().getWarningHandler()(createStringError(
errc::invalid_argument,
"DWARF unit at offset 0x%8.8" PRIx64 " "
"contains invalid abbreviation set offset 0x%" PRIx64,
U.getOffset(), U.getAbbreviationsOffset()));
// Restore the original offset.
*OffsetPtr = Offset;
return false;
}
AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode);

if (!AbbrevDecl) {
U.getContext().getWarningHandler()(createStringError(
errc::invalid_argument,
"DWARF unit at offset 0x%8.8" PRIx64 " "
"contains invalid abbreviation %" PRIu64 " at "
"offset 0x%8.8" PRIx64 ", valid abbreviations are %s",
U.getOffset(), AbbrCode, *OffsetPtr,
AbbrevSet->getCodeRange().c_str()));
// Restore the original offset.
*OffsetPtr = Offset;
return false;
}
}

assert(AbbrevDecl && AbbrevDecl->getCode() == AbbrCode);

// See if all attributes in this DIE have fixed byte sizes. If so, we can
// just add this size to the offset to skip to the next DIE.
if (std::optional<size_t> FixedSize =
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,11 @@ DWARFUnit::getLastChildEntry(const DWARFDebugInfoEntry *Die) const {
return nullptr;
}

Expected<const DWARFAbbreviationDeclaration *>
DWARFUnit::tryExtractCUAbbrevFast() const {
return Abbrev->tryExtractCUAbbrevFast(getAbbreviationsOffset());
}

const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
if (!Abbrevs) {
Expected<const DWARFAbbreviationDeclarationSet *> AbbrevsOrError =
Expand Down
Loading