Skip to content

Modify dwarf verification JSON to include detailed counts by sub-category #128018

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

Merged
merged 1 commit into from
Mar 4, 2025

Conversation

youngd007
Copy link
Contributor

Details:
To help make better use of dwarfdump verification for identifying and fixing issues with debug information, the JSON will now emit details (sub-categories) where relevant. First modification concerns missing tags as those were recently missing for BOLT debug names.

Test:
test files for JSON output were previously added, so modify here to expect the new JSON keys. One test has sub-categories and another is empty.
ninja check-llvm-tools-llvm-dwarfdump
Also build the tool and run with a local executable to verify.
ninja llvm-dwarfdump

@llvmbot
Copy link
Member

llvmbot commented Feb 20, 2025

@llvm/pr-subscribers-debuginfo

Author: None (youngd007)

Changes

Details:
To help make better use of dwarfdump verification for identifying and fixing issues with debug information, the JSON will now emit details (sub-categories) where relevant. First modification concerns missing tags as those were recently missing for BOLT debug names.

Test:
test files for JSON output were previously added, so modify here to expect the new JSON keys. One test has sub-categories and another is empty.
ninja check-llvm-tools-llvm-dwarfdump
Also build the tool and run with a local executable to verify.
ninja llvm-dwarfdump


Full diff: https://github.com/llvm/llvm-project/pull/128018.diff

4 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h (+13-2)
  • (modified) llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp (+37-9)
  • (modified) llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness-json-output.s (+1-1)
  • (modified) llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-cu-lists-json-output.s (+1-1)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index 7b51bb63cd15b..6e79619e156cb 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -30,9 +30,15 @@ class DWARFDebugAbbrev;
 class DataExtractor;
 struct DWARFSection;
 
+struct AggregationData {
+  unsigned OverallCount;
+  std::map<std::string, unsigned> DetailedCounts;
+  AggregationData() = default;
+};
+
 class OutputCategoryAggregator {
 private:
-  std::map<std::string, unsigned> Aggregation;
+  std::map<std::string, AggregationData> Aggregation;
   bool IncludeDetail;
 
 public:
@@ -40,8 +46,13 @@ class OutputCategoryAggregator {
       : IncludeDetail(includeDetail) {}
   void ShowDetail(bool showDetail) { IncludeDetail = showDetail; }
   size_t GetNumCategories() const { return Aggregation.size(); }
-  void Report(StringRef s, std::function<void()> detailCallback);
+  void Report(StringRef category, std::function<void()> detailCallback);
+  void Report(StringRef category, StringRef sub_category,
+              std::function<void()> detailCallback);
   void EnumerateResults(std::function<void(StringRef, unsigned)> handleCounts);
+  void EnumerateDetailedResultsFor(
+      StringRef category,
+      std::function<void(StringRef, unsigned)> handleCounts);
 };
 
 /// A class that verifies DWARF debug information given a DWARF Context.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 107e79cc5a05a..211d736206563 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -1941,12 +1941,14 @@ unsigned DWARFVerifier::verifyNameIndexCompleteness(
     if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
           return E.getDIEUnitOffset() == DieUnitOffset;
         })) {
-      ErrorCategory.Report("Name Index DIE entry missing name", [&]() {
-        error() << formatv(
-            "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
-            "name {3} missing.\n",
-            NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
-      });
+      ErrorCategory.Report(
+          "Name Index DIE entry missing name",
+          llvm::dwarf::TagString(Die.getTag()), [&]() {
+            error() << formatv(
+                "Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
+                "name {3} missing.\n",
+                NI.getUnitOffset(), Die.getOffset(), Die.getTag(), Name);
+          });
       ++NumErrors;
     }
   }
@@ -2168,15 +2170,35 @@ bool DWARFVerifier::verifyDebugStrOffsets(
 
 void OutputCategoryAggregator::Report(
     StringRef s, std::function<void(void)> detailCallback) {
-  Aggregation[std::string(s)]++;
+  this->Report(s, "", detailCallback);
+}
+
+void OutputCategoryAggregator::Report(
+    StringRef category, StringRef sub_category,
+    std::function<void(void)> detailCallback) {
+  std::string category_str = std::string(category);
+  AggregationData *Agg = &Aggregation[category_str];
+  Agg->OverallCount++;
+  if (!sub_category.empty()) {
+    Agg->DetailedCounts[std::string(sub_category)]++;
+  }
   if (IncludeDetail)
     detailCallback();
 }
 
 void OutputCategoryAggregator::EnumerateResults(
     std::function<void(StringRef, unsigned)> handleCounts) {
-  for (auto &&[name, count] : Aggregation) {
-    handleCounts(name, count);
+  for (auto &&[name, aggData] : Aggregation) {
+    handleCounts(name, aggData.OverallCount);
+  }
+}
+void OutputCategoryAggregator::EnumerateDetailedResultsFor(
+    StringRef category, std::function<void(StringRef, unsigned)> handleCounts) {
+  auto Agg = Aggregation.find(std::string(category));
+  if (Agg != Aggregation.end()) {
+    for (auto &&[name, count] : Agg->second.DetailedCounts) {
+      handleCounts(name, count);
+    }
   }
 }
 
@@ -2203,6 +2225,12 @@ void DWARFVerifier::summarize() {
     ErrorCategory.EnumerateResults([&](StringRef Category, unsigned Count) {
       llvm::json::Object Val;
       Val.try_emplace("count", Count);
+      llvm::json::Object Details;
+      ErrorCategory.EnumerateDetailedResultsFor(
+          Category, [&](StringRef SubCategory, unsigned SubCount) {
+            Details.try_emplace(SubCategory, SubCount);
+          });
+      Val.try_emplace("details", std::move(Details));
       Categories.try_emplace(Category, std::move(Val));
       ErrorCount += Count;
     });
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness-json-output.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness-json-output.s
index c4b7ffe1d2d8e..9c9658308c2f9 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness-json-output.s
+++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-completeness-json-output.s
@@ -1,7 +1,7 @@
 # RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o - | not llvm-dwarfdump -verify --verify-json=%t.json -
 # RUN: FileCheck %s --input-file %t.json
 
-# CHECK: {"error-categories":{"Name Index DIE entry missing name":{"count":10}},"error-count":10}
+# CHECK: {"error-categories":{"Name Index DIE entry missing name":{"count":10,"details":{"DW_TAG_inlined_subroutine":1,"DW_TAG_label":1,"DW_TAG_namespace":2,"DW_TAG_subprogram":2,"DW_TAG_variable":4}}},"error-count":10}
 # CHECK-NOT: error: Name Index @ 0x0: Entry for DIE @ {{.*}} (DW_TAG_variable) with name var_block_addr missing.
 
         .section        .debug_loc,"",@progbits
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-cu-lists-json-output.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-cu-lists-json-output.s
index dfbfe04943a83..872fff801576c 100644
--- a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-cu-lists-json-output.s
+++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify-cu-lists-json-output.s
@@ -2,7 +2,7 @@
 # RUN:   not llvm-dwarfdump -verify -verify-json=%t.json -
 # RUN: FileCheck %s --input-file %t.json
 
-# CHECK: {"error-categories":{"Duplicate Name Index":{"count":1},"Name Index doesn't index any CU":{"count":1},"Name Index references non-existing CU":{"count":1}},"error-count":3}
+# CHECK: {"error-categories":{"Duplicate Name Index":{"count":1,"details":{}},"Name Index doesn't index any CU":{"count":1,"details":{}},"Name Index references non-existing CU":{"count":1,"details":{}}},"error-count":3}
 # CHECK-NOT : error: Name Index @ 0x58 references a CU @ 0x0, but this CU is already indexed by Name Index @ 0x28
 # CHECK-NOT: warning: CU @ 0x13 not covered by any Name Index
 

@youngd007
Copy link
Contributor Author

This is a redo of #125062 that was reverted in Icohedron@3c1b8aa

@youngd007
Copy link
Contributor Author

The original was failing on
ninja check-llvm
I just ran that
Screenshot 2025-02-20 at 10 33 37 AM
I don't see any new failures, so I hope it is good this time. I sort of assume it was a race condition of #125062 landing with #126587 that got rid of a failing test that was not modified in the first PR due to file names being different and messed up.
And then yesterday, I added back the deleted test before this PR: #127685

@youngd007
Copy link
Contributor Author

@clayborg

struct AggregationData {
unsigned OverallCount;
std::map<std::string, unsigned> DetailedCounts;
AggregationData() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the ctor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can double check, but the original PR would not build or run without the constructor defined.

if (IncludeDetail)
detailCallback();
}

void OutputCategoryAggregator::EnumerateResults(
std::function<void(StringRef, unsigned)> handleCounts) {
for (auto &&[name, count] : Aggregation) {
handleCounts(name, count);
for (auto &&[name, aggData] : Aggregation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be const auto&

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember you mentioning that before original PR and when I tried, it did not build.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any benefit of && here?

StringRef category, std::function<void(StringRef, unsigned)> handleCounts) {
auto Agg = Aggregation.find(std::string(category));
if (Agg != Aggregation.end()) {
for (auto &&[name, count] : Agg->second.DetailedCounts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

}
void OutputCategoryAggregator::EnumerateDetailedResultsFor(
StringRef category, std::function<void(StringRef, unsigned)> handleCounts) {
auto Agg = Aggregation.find(std::string(category));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const on which part? All three (two params and the Agg?)?

StringRef category, StringRef sub_category,
std::function<void(void)> detailCallback) {
std::string category_str = std::string(category);
AggregationData *Agg = &Aggregation[category_str];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it a pointer?
Can you just do:
AggregationData &Agg = Aggregation[category_str];

…gory

Details:
To help make better use of dwarfdump verification for identifying and
fixing issues with debug information, the JSON will now emit details
(sub-categories) where relevant.  First modification concerns missing tags
as those were recently missing for BOLT debug names.

Test:
test files for JSON output were previously added, so modify here to expect
the new JSON keys.  One test has sub-categories and another is empty.
  ninja check-llvm-tools-llvm-dwarfdump
Also build the tool and run with a local executable to verify.
  ninja llvm-dwarfdump
@youngd007
Copy link
Contributor Author

Okay, I stand corrected! I was able to apply the suggestions from @ayermolo & @mbucko and rebuild successfully as well as run the tests

@clayborg clayborg merged commit b08769c into llvm:main Mar 4, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 4, 2025

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building llvm at step 6 "test-openmp".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/88/builds/8741

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
...
PASS: ompd-test :: openmp_examples/example_3.c (440 of 450)
PASS: ompd-test :: openmp_examples/example_4.c (441 of 450)
PASS: ompd-test :: openmp_examples/example_5.c (442 of 450)
PASS: ompd-test :: openmp_examples/example_task.c (443 of 450)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_bt.c (444 of 450)
PASS: ompd-test :: openmp_examples/fibonacci.c (445 of 450)
UNSUPPORTED: ompd-test :: openmp_examples/ompd_parallel.c (446 of 450)
PASS: ompd-test :: openmp_examples/parallel.c (447 of 450)
PASS: ompd-test :: openmp_examples/nested.c (448 of 450)
PASS: ompd-test :: openmp_examples/ompd_icvs.c (449 of 450)
command timed out: 1200 seconds without output running [b'ninja', b'-j 4', b'check-openmp'], attempting to kill
process killed by signal 9
program finished with exit code -1
elapsedTime=1321.028949

jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
…gory (llvm#128018)

To help make better use of dwarfdump verification for identifying and
fixing issues with debug information, the JSON will now emit details
(sub-categories) where relevant. First modification concerns missing
tags as those were recently missing for BOLT debug names.

Test:
test files for JSON output were previously added, so modify here to
expect the new JSON keys. One test has sub-categories and another is
empty.
  ninja check-llvm-tools-llvm-dwarfdump
Also build the tool and run with a local executable to verify.
  ninja llvm-dwarfdump
@youngd007 youngd007 deleted the addback branch April 3, 2025 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants