[llvm] [DebugInfo] Avoid std::function in DWARF verifier internals (PR #202866)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 06:21:21 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-debuginfo

Author: David Zbarsky (dzbarsky)

<details>
<summary>Changes</summary>

Avoid constructing `std::function` at DWARF verifier diagnostic sites by routing internal synchronous callbacks through private `function_ref` helpers. The public `LLVM_ABI` methods and class layout remain unchanged.

On arm64 Release builds, this reduces stripped `llvm-dwarfdump` by 33,536 bytes, `DWARFVerifier.cpp.o` by 175,736 bytes, and object relocations by 2,333. Diagnostics were byte-identical across 66 generated verifier inputs; valid and malformed verification benchmarks were neutral within their 95% confidence intervals.

Work towards #<!-- -->202616

AI tool disclosure: Co-authored with OpenAI Codex.


---

Patch is 39.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/202866.diff


2 Files Affected:

- (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h (+11) 
- (modified) llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp (+100-80) 


``````````diff
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index f667496ab1059..08a149579b2a5 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 
+#include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
@@ -31,6 +32,7 @@ struct DWARFAttribute;
 class DWARFContext;
 class DWARFDataExtractor;
 class DWARFDebugAbbrev;
+class DWARFVerifier;
 class DataExtractor;
 struct DWARFSection;
 
@@ -41,11 +43,20 @@ struct AggregationData {
 
 class OutputCategoryAggregator {
 private:
+  friend class DWARFVerifier;
+
   std::mutex WriteMutex;
   std::map<std::string, AggregationData, std::less<>> Aggregation;
   uint64_t NumErrors = 0;
   bool IncludeDetail;
 
+  void report(StringRef category, function_ref<void()> detailCallback);
+  void report(StringRef category, StringRef sub_category,
+              function_ref<void()> detailCallback);
+  void enumerateResults(function_ref<void(StringRef, unsigned)> handleCounts);
+  void enumerateDetailedResultsFor(
+      StringRef category, function_ref<void(StringRef, unsigned)> handleCounts);
+
 public:
   OutputCategoryAggregator(bool includeDetail = false)
       : IncludeDetail(includeDetail) {}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 17d1bfb3f575c..d9a15fb5a998f 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -207,26 +207,26 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
       }
     };
     if (!ValidLength)
-      ErrorCategory.Report(
+      ErrorCategory.report(
           "Unit Header Length: Unit too large for .debug_info provided", [&]() {
             ShowHeaderOnce();
             note() << "The length for this unit is too "
                       "large for the .debug_info provided.\n";
           });
     if (!ValidVersion)
-      ErrorCategory.Report(
+      ErrorCategory.report(
           "Unit Header Length: 16 bit unit header version is not valid", [&]() {
             ShowHeaderOnce();
             note() << "The 16 bit unit header version is not valid.\n";
           });
     if (!ValidType)
-      ErrorCategory.Report(
+      ErrorCategory.report(
           "Unit Header Length: Unit type encoding is not valid", [&]() {
             ShowHeaderOnce();
             note() << "The unit type encoding is not valid.\n";
           });
     if (!ValidAbbrevOffset)
-      ErrorCategory.Report(
+      ErrorCategory.report(
           "Unit Header Length: Offset into the .debug_abbrev section is not "
           "valid",
           [&]() {
@@ -235,7 +235,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
                       "not valid.\n";
           });
     if (!ValidAddrSize)
-      ErrorCategory.Report("Unit Header Length: Address size is unsupported",
+      ErrorCategory.report("Unit Header Length: Address size is unsupported",
                            [&]() {
                              ShowHeaderOnce();
                              note() << "The address size is unsupported.\n";
@@ -256,7 +256,7 @@ bool DWARFVerifier::verifyName(const DWARFDie &Die) {
   if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
     return false;
 
-  ErrorCategory.Report(
+  ErrorCategory.report(
       "Simplified template DW_AT_name could not be reconstituted", [&]() {
         error()
             << "Simplified template DW_AT_name could not be reconstituted:\n"
@@ -302,7 +302,7 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
 
   DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
   if (!Die) {
-    ErrorCategory.Report("Compilation unit missing DIE", [&]() {
+    ErrorCategory.report("Compilation unit missing DIE", [&]() {
       error() << "Compilation unit without DIE.\n";
     });
     NumUnitErrors++;
@@ -310,7 +310,7 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
   }
 
   if (!dwarf::isUnitType(Die.getTag())) {
-    ErrorCategory.Report("Compilation unit root DIE is not a unit DIE", [&]() {
+    ErrorCategory.report("Compilation unit root DIE is not a unit DIE", [&]() {
       error() << formatv("Compilation unit root DIE is not a unit DIE: {0}.\n",
                          dwarf::TagString(Die.getTag()));
     });
@@ -319,7 +319,7 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
 
   uint8_t UnitType = Unit.getUnitType();
   if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
-    ErrorCategory.Report("Mismatched unit type", [&]() {
+    ErrorCategory.report("Mismatched unit type", [&]() {
       error() << formatv(
           "Compilation unit type ({0}) and root DIE ({1}) do not match.\n",
           dwarf::UnitTypeString(UnitType), dwarf::TagString(Die.getTag()));
@@ -331,7 +331,7 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
   //  3.1.2 Skeleton Compilation Unit Entries:
   //  "A skeleton compilation unit has no children."
   if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) {
-    ErrorCategory.Report("Skeleton CU has children", [&]() {
+    ErrorCategory.report("Skeleton CU has children", [&]() {
       error() << "Skeleton compilation unit has children.\n";
     });
     NumUnitErrors++;
@@ -350,7 +350,7 @@ unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
   DWARFDie Curr = Die.getParent();
   for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Curr.getParent()) {
     if (Curr.getTag() == DW_TAG_inlined_subroutine) {
-      ErrorCategory.Report(
+      ErrorCategory.report(
           "Call site nested entry within inlined subroutine", [&]() {
             error() << "Call site entry nested within inlined subroutine:";
             Curr.dump(OS);
@@ -360,7 +360,7 @@ unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
   }
 
   if (!Curr.isValid()) {
-    ErrorCategory.Report(
+    ErrorCategory.report(
         "Call site entry not nested within valid subprogram", [&]() {
           error() << "Call site entry not nested within a valid subprogram:";
           Die.dump(OS);
@@ -373,7 +373,7 @@ unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
        DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
        DW_AT_GNU_all_source_call_sites, DW_AT_GNU_all_tail_call_sites});
   if (!CallAttr) {
-    ErrorCategory.Report(
+    ErrorCategory.report(
         "Subprogram with call site entry has no DW_AT_call attribute", [&]() {
           error()
               << "Subprogram with call site entry has no DW_AT_call attribute:";
@@ -394,7 +394,7 @@ unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
       Abbrev->getAbbreviationDeclarationSet(0);
   if (!AbbrDeclsOrErr) {
     std::string ErrMsg = toString(AbbrDeclsOrErr.takeError());
-    ErrorCategory.Report("Abbreviation Declaration error",
+    ErrorCategory.report("Abbreviation Declaration error",
                          [&]() { error() << ErrMsg << "\n"; });
     return 1;
   }
@@ -406,7 +406,7 @@ unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
     for (auto Attribute : AbbrDecl.attributes()) {
       auto Result = AttributeSet.insert(Attribute.Attr);
       if (!Result.second) {
-        ErrorCategory.Report(
+        ErrorCategory.report(
             "Abbreviation declartion contains multiple attributes", [&]() {
               error() << formatv("Abbreviation declaration contains multiple "
                                  "{0} attributes.\n",
@@ -526,7 +526,7 @@ unsigned DWARFVerifier::verifyIndex(StringRef Name,
         StringRef Category = InfoColumnKind == DWARFSectionKind::DW_SECT_INFO
                                  ? "Overlapping CU index entries"
                                  : "Overlapping TU index entries";
-        ErrorCategory.Report(Category, [&]() {
+        ErrorCategory.report(Category, [&]() {
           error() << llvm::formatv(
               "overlapping index entries for entries {0:x16} "
               "and {1:x16} for column {2}\n",
@@ -618,7 +618,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
     for (const auto &Range : Ranges) {
       if (!Range.valid()) {
         ++NumErrors;
-        ErrorCategory.Report("Invalid address range", [&]() {
+        ErrorCategory.report("Invalid address range", [&]() {
           error() << formatv("Invalid address range {0}\n", Range);
           DumpDieAfterError = true;
         });
@@ -633,7 +633,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
       // address: 0 or -1.
       if (auto PrevRange = RI.insert(Range)) {
         ++NumErrors;
-        ErrorCategory.Report("DIE has overlapping DW_AT_ranges", [&]() {
+        ErrorCategory.report("DIE has overlapping DW_AT_ranges", [&]() {
           error() << formatv("DIE has overlapping ranges in DW_AT_ranges "
                              "attribute: {0} and {1}\n",
                              *PrevRange, Range);
@@ -649,7 +649,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
   const auto IntersectingChild = ParentRI.insert(RI);
   if (IntersectingChild != ParentRI.Children.end()) {
     ++NumErrors;
-    ErrorCategory.Report("DIEs have overlapping address ranges", [&]() {
+    ErrorCategory.report("DIEs have overlapping address ranges", [&]() {
       error() << "DIEs have overlapping address ranges:";
       dump(Die);
       dump(IntersectingChild->Die) << '\n';
@@ -662,7 +662,7 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
                              ParentRI.Die.getTag() == DW_TAG_subprogram);
   if (ShouldBeContained && !ParentRI.contains(RI)) {
     ++NumErrors;
-    ErrorCategory.Report(
+    ErrorCategory.report(
         "DIE address ranges are not contained by parent ranges", [&]() {
           error()
               << "DIE address ranges are not contained in its parent's ranges:";
@@ -712,7 +712,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
   unsigned NumErrors = 0;
   auto ReportError = [&](StringRef category, const Twine &TitleMsg) {
     ++NumErrors;
-    ErrorCategory.Report(category, [&]() {
+    ErrorCategory.report(category, [&]() {
       error() << formatv("{0}\n", TitleMsg);
       dump(Die) << '\n';
     });
@@ -974,7 +974,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
       auto CUOffset = AttrValue.Value.getRawUValue();
       if (CUOffset >= CUSize) {
         ++NumErrors;
-        ErrorCategory.Report("Invalid CU offset", [&]() {
+        ErrorCategory.report("Invalid CU offset", [&]() {
           error() << formatv("{0} CU offset {1:x+8} is invalid (must be less "
                              "than CU size of {2:x+8}):\n",
                              FormEncodingString(Form), CUOffset, CUSize);
@@ -998,7 +998,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
     if (RefVal) {
       if (*RefVal >= DieCU->getInfoSection().Data.size()) {
         ++NumErrors;
-        ErrorCategory.Report("DW_FORM_ref_addr offset out of bounds", [&]() {
+        ErrorCategory.report("DW_FORM_ref_addr offset out of bounds", [&]() {
           error() << "DW_FORM_ref_addr offset beyond .debug_info "
                      "bounds:\n";
           dump(Die) << '\n';
@@ -1021,7 +1021,7 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
     if (Error E = AttrValue.Value.getAsCString().takeError()) {
       ++NumErrors;
       std::string ErrMsg = toString(std::move(E));
-      ErrorCategory.Report("Invalid DW_FORM attribute", [&]() {
+      ErrorCategory.report("Invalid DW_FORM attribute", [&]() {
         error() << formatv("{0}:\n", ErrMsg);
         dump(Die) << '\n';
       });
@@ -1047,7 +1047,7 @@ unsigned DWARFVerifier::verifyDebugInfoReferences(
     if (GetDIEForOffset(Pair.first))
       continue;
     ++NumErrors;
-    ErrorCategory.Report("Invalid DIE reference", [&]() {
+    ErrorCategory.report("Invalid DIE reference", [&]() {
       error() << formatv(
           "invalid DIE reference {0:x+8}. Offset is in between DIEs:\n",
           Pair.first);
@@ -1074,7 +1074,7 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() {
     if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
       if (!LineTable) {
         ++NumDebugLineErrors;
-        ErrorCategory.Report("Unparsable .debug_line entry", [&]() {
+        ErrorCategory.report("Unparsable .debug_line entry", [&]() {
           error() << formatv(
               ".debug_line[{0:x+8}] was not able to be parsed for CU:\n",
               LineTableOffset);
@@ -1093,7 +1093,7 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() {
     if (!Inserted) {
       ++NumDebugLineErrors;
       const auto &OldDie = Iter->second;
-      ErrorCategory.Report("Identical DW_AT_stmt_list section offset", [&]() {
+      ErrorCategory.report("Identical DW_AT_stmt_list section offset", [&]() {
         error() << formatv("two compile unit DIEs, {0:x+8} and {1:x+8}, have "
                            "the same DW_AT_stmt_list section offset:\n",
                            OldDie.getOffset(), Die.getOffset());
@@ -1124,7 +1124,7 @@ void DWARFVerifier::verifyDebugLineRows() {
       // Verify directory index.
       if (FileName.DirIdx > MaxDirIndex) {
         ++NumDebugLineErrors;
-        ErrorCategory.Report(
+        ErrorCategory.report(
             "Invalid index in .debug_line->prologue.file_names->dir_idx",
             [&]() {
               error() << formatv(".debug_line[{0:x+8}].prologue.file_names[{1}]"
@@ -1164,7 +1164,7 @@ void DWARFVerifier::verifyDebugLineRows() {
       // Verify row address.
       if (Row.Address.Address < PrevAddress) {
         ++NumDebugLineErrors;
-        ErrorCategory.Report(
+        ErrorCategory.report(
             "decreasing address between debug_line rows", [&]() {
               error() << formatv(".debug_line[{0:x+8}] row[{1}] decreases in "
                                  "address from previous row:\n",
@@ -1181,7 +1181,7 @@ void DWARFVerifier::verifyDebugLineRows() {
 
       if (!LineTable->hasFileAtIndex(Row.File)) {
         ++NumDebugLineErrors;
-        ErrorCategory.Report("Invalid file index in debug_line", [&]() {
+        ErrorCategory.report("Invalid file index in debug_line", [&]() {
           error() << formatv(".debug_line[{0:x+8}][{1}] has invalid file index "
                              "{2}  (valid values are [{3},{4}{5}):\n",
                              *toSectionOffset(Die.find(DW_AT_stmt_list)),
@@ -1233,7 +1233,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
 
   // Verify that the fixed part of the header is not too short.
   if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
-    ErrorCategory.Report("Section is too small to fit a section header", [&]() {
+    ErrorCategory.report("Section is too small to fit a section header", [&]() {
       error() << "Section is too small to fit a section header.\n";
     });
     return;
@@ -1242,7 +1242,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
   // Verify that the section is not too short.
   if (Error E = AccelTable.extract()) {
     std::string Msg = toString(std::move(E));
-    ErrorCategory.Report("Section is too small to fit a section header",
+    ErrorCategory.report("Section is too small to fit a section header",
                          [&]() { error() << Msg << '\n'; });
     return;
   }
@@ -1258,7 +1258,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
   for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
     uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
     if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
-      ErrorCategory.Report("Invalid hash index", [&]() {
+      ErrorCategory.report("Invalid hash index", [&]() {
         error() << formatv("Bucket[{0}] has invalid hash index: {1}.\n",
                            BucketIdx, HashIdx);
       });
@@ -1266,13 +1266,13 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
   }
   uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
   if (NumAtoms == 0) {
-    ErrorCategory.Report("No atoms", [&]() {
+    ErrorCategory.report("No atoms", [&]() {
       error() << "No atoms: failed to read HashData.\n";
     });
     return;
   }
   if (!AccelTable.validateForms()) {
-    ErrorCategory.Report("Unsupported form", [&]() {
+    ErrorCategory.report("Unsupported form", [&]() {
       error() << "Unsupported form: failed to read HashData.\n";
     });
     return;
@@ -1285,7 +1285,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
     uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
     if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
                                                      sizeof(uint64_t))) {
-      ErrorCategory.Report("Invalid HashData offset", [&]() {
+      ErrorCategory.report("Invalid HashData offset", [&]() {
         error() << formatv("Hash[{0}] has invalid HashData offset: {1:x+8}.\n",
                            HashIdx, HashDataOffset);
       });
@@ -1311,7 +1311,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
           if (!Name)
             Name = "<NULL>";
 
-          ErrorCategory.Report("Invalid DIE offset", [&]() {
+          ErrorCategory.report("Invalid DIE offset", [&]() {
             error() << formatv("{0} Bucket[{1}] Hash[{2}] = {3:x+8} "
                                "Str[{4}] = {5:x+8} DIE[{6}] = {7:x+8} "
                                "is not a valid DIE offset for \"{8}\".\n",
@@ -1322,7 +1322,7 @@ void DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
           continue;
         }
         if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
-          ErrorCategory.Report("Mismatched Tag in accellerator table", [&]() {
+          ErrorCategory.report("Mismatched Tag in accellerator table", [&]() {
             error() << formatv("Tag {0} in accelerator table does not match "
                                "Tag {1} of DIE[{2}].\n",
                                dwarf::TagString(Tag),
@@ -1346,7 +1346,7 @@ void DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
 
   parallelForEach(AccelTable, [&](const DWARFDebugNames::NameIndex &NI) {
     if (NI.getCUCount() == 0) {
-      ErrorCategory.Report("Name Index doesn't index any CU", [&]() {
+      ErrorCategory.report("Name Index doesn't index any CU", [&]() {
         error() << formatv("Name Index @ {0:x} does not index any CU\n",
                            NI.getUnitOffset());
       });
@@ -1355,7 +1355,7 @@ void DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
     for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {
       uint64_t Offset = NI.getCUOffset(CU);
       if (!CUOffsets.count(Offset)) {
-        ErrorCategory.Report("Name Index references non-existing CU", [&]() {
+        ErrorCategory.report("Name Index references non-existing CU", [&]() {
           error() << formatv(
               "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
               NI.getUnitOffset(), Offset);
@@ -1372,7 +1372,7 @@ void DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
           CUMap[Offset] = NI.getUnitOffset();
       }
       if (DuplicateCUOffset) {
-        ErrorCategory.Report("Duplicate Name Index", [&]() {
+        ErrorCategory.report("Duplicate Name Index", [&]() {
           error() << formatv(
               "Name Index @ {0:x} references a CU @ {1:x}, but "
               "this CU is already indexed by Name Index @ {2:x}\n",
@@ -1415,7 +1415,7 @@ void DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
   for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {
     uint32_t Index = NI.getBucketArrayEntry(Bucket);
     if (Index > NI.getNameCount()) {
-      ErrorCategory.Repor...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/202866


More information about the llvm-commits mailing list