Aggregate errors from llvm-dwarfdump --verify (#79648)
The amount and format of output from `llvm-dwarfdump --verify` makes it quite difficult to know if a change to a tool that produces or modifies DWARF is causing new problems, or is fixing existing problems. This diff adds a categorized summary of issues found by the DWARF verifier, on by default, at the bottom of the error output. The change includes a new `--error-display` option with 4 settings: * `--error-display=quiet`: Only display if errors occurred, but no details or summary are printed. * `--error-display=summary`: Only display the aggregated summary of errors with no error detail. * `--error-display=details`: Only display the detailed error messages with no summary (previous behavior) * `--error-display=full`: Display both the detailed error messages and the aggregated summary of errors (the default) I changed a handful of tests that were failing due to new output, adding the flag to use the old behavior for all but a couple. For those two I added the new aggregated output to the expected output of the test. The `OutputCategoryAggregator` is a pretty simple little class that @clayborg suggested to allow code to only be run to dump detail if it's enabled, while still collating counts of the category. Knowing that the lambda passed in is only conditionally executed is pretty important (handling errors has to be done *outside* the lambda). I'm happy to move this somewhere else (and change/improve it) to be more broadly useful if folks would like. --------- Co-authored-by: Kevin Frei <freik@meta.com>
This commit is contained in:
parent
09b4649ea5
commit
bfdd78233f
@ -205,6 +205,7 @@ struct DIDumpOptions {
|
||||
bool DisplayRawContents = false;
|
||||
bool IsEH = false;
|
||||
bool DumpNonSkeleton = false;
|
||||
bool ShowAggregateErrors = false;
|
||||
std::function<llvm::StringRef(uint64_t DwarfRegNum, bool IsEH)>
|
||||
GetNameForDWARFReg;
|
||||
|
||||
|
@ -30,6 +30,20 @@ class DWARFDebugAbbrev;
|
||||
class DataExtractor;
|
||||
struct DWARFSection;
|
||||
|
||||
class OutputCategoryAggregator {
|
||||
private:
|
||||
std::map<std::string, unsigned> Aggregation;
|
||||
bool IncludeDetail;
|
||||
|
||||
public:
|
||||
OutputCategoryAggregator(bool includeDetail = false)
|
||||
: IncludeDetail(includeDetail) {}
|
||||
void ShowDetail(bool showDetail) { IncludeDetail = showDetail; }
|
||||
size_t GetNumCategories() const { return Aggregation.size(); }
|
||||
void Report(StringRef s, std::function<void()> detailCallback);
|
||||
void EnumerateResults(std::function<void(StringRef, unsigned)> handleCounts);
|
||||
};
|
||||
|
||||
/// A class that verifies DWARF debug information given a DWARF Context.
|
||||
class DWARFVerifier {
|
||||
public:
|
||||
@ -81,6 +95,7 @@ private:
|
||||
DWARFContext &DCtx;
|
||||
DIDumpOptions DumpOpts;
|
||||
uint32_t NumDebugLineErrors = 0;
|
||||
OutputCategoryAggregator ErrorCategory;
|
||||
// Used to relax some checks that do not currently work portably
|
||||
bool IsObjectFile;
|
||||
bool IsMachOObject;
|
||||
@ -348,6 +363,9 @@ public:
|
||||
bool verifyDebugStrOffsets(
|
||||
StringRef SectionName, const DWARFSection &Section, StringRef StrData,
|
||||
void (DWARFObject::*)(function_ref<void(const DWARFSection &)>) const);
|
||||
|
||||
/// Emits any aggregate information collected, depending on the dump options
|
||||
void summarize();
|
||||
};
|
||||
|
||||
static inline bool operator<(const DWARFVerifier::DieRangeInfo &LHS,
|
||||
|
@ -1408,6 +1408,7 @@ bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
|
||||
if (DumpOpts.DumpType & DIDT_DebugStrOffsets)
|
||||
Success &= verifier.handleDebugStrOffsets();
|
||||
Success &= verifier.handleAccelTables();
|
||||
verifier.summarize();
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o
|
||||
# RUN: not llvm-dwarfdump --verify %t.o | FileCheck %s
|
||||
# RUN: not llvm-dwarfdump --error-display=details --verify %t.o | FileCheck %s
|
||||
|
||||
# CHECK: Verifying .debug_abbrev...
|
||||
# CHECK-NEXT: Verifying .debug_info Unit Header Chain...
|
||||
@ -51,5 +51,3 @@
|
||||
.byte 2 # Abbrev [2]
|
||||
.byte 0
|
||||
.Lcu_end1:
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
RUN: llvm-dwarfdump -v %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s
|
||||
RUN: not llvm-dwarfdump -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY
|
||||
RUN: not llvm-dwarfdump -error-display=details -verify %p/Inputs/dwarfdump-objc.x86_64.o | FileCheck %s --check-prefix=VERIFY
|
||||
|
||||
Gather some DIE indexes to verify the accelerator table contents.
|
||||
CHECK: .debug_info contents
|
||||
|
@ -1,4 +1,4 @@
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has DW_AT_decl_file with an invalid file index 2 (valid values are [1-1]){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000001e: DW_TAG_subprogram
|
||||
|
@ -1,4 +1,4 @@
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has DW_AT_decl_file with an invalid file index 2 (the file table in the prologue is empty){{[[:space:]]}}
|
||||
# CHECK-NEXT: 0x0000001e: DW_TAG_subprogram
|
||||
|
@ -50,7 +50,11 @@
|
||||
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_sdata] (3)
|
||||
# CHECK-NEXT: DW_AT_call_file [DW_FORM_sdata] (4)
|
||||
# CHECK-NEXT: DW_AT_call_line [DW_FORM_sdata] (5){{[[:space:]]}}
|
||||
|
||||
# CHECK-NEXT: Verifying dwo Units...
|
||||
# CHECK-NEXT: error: Aggregated error counts:
|
||||
# CHECK-NEXT: error: Invalid encoding in DW_AT_decl_file occurred 4 time(s).
|
||||
# CHECK-NEXT: error: Invalid file index in DW_AT_call_line occurred 1 time(s).
|
||||
# CHECK-NEXT: error: Invalid file index in DW_AT_decl_line occurred 1 time(s).
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
|
@ -39,7 +39,7 @@
|
||||
#
|
||||
# 0x00000066: NULL
|
||||
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: error: DIE has overlapping ranges in DW_AT_ranges attribute: [0x0000000000000000, 0x0000000000000020) and [0x0000000000000000, 0x0000000000000030)
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
# 0x00000056: NULL
|
||||
|
||||
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
|
||||
# RUN: yaml2obj %s | not llvm-dwarfdump --error-display=details --verify - | FileCheck %s --implicit-check-not=error:
|
||||
|
||||
# CHECK: Verifying -: file format Mach-O 64-bit x86-64
|
||||
# CHECK: Verifying .debug_abbrev...
|
||||
|
@ -8,7 +8,12 @@
|
||||
# CHECK: error: Unsupported DW_AT_location encoding: DW_FORM_data1
|
||||
# FIXME: This should read "type unit" or just "unit" to be correct for this case/in general
|
||||
# CHECK: error: DIE has DW_AT_decl_file that references a file with index 1 and the compile unit has no line table
|
||||
# CHECK: Errors detected
|
||||
# CHECK: error: Aggregated error counts:
|
||||
# CHECK: error: Compilation unit root DIE is not a unit DIE occurred 1 time(s).
|
||||
# CHECK: error: File index in DW_AT_decl_file reference CU with no line table occurred 1 time(s).
|
||||
# CHECK: error: Invalid DW_AT_location occurred 1 time(s).
|
||||
# CHECK: error: Mismatched unit type occurred 1 time(s).
|
||||
# CHECK: Errors detected.
|
||||
.section .debug_info.dwo,"e",@progbits
|
||||
.long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit
|
||||
.Ldebug_info_dwo_start1:
|
||||
|
@ -124,6 +124,14 @@ public:
|
||||
namespace {
|
||||
using namespace cl;
|
||||
|
||||
enum ErrorDetailLevel {
|
||||
OnlyDetailsNoSummary,
|
||||
NoDetailsOnlySummary,
|
||||
NoDetailsOrSummary,
|
||||
BothDetailsAndSummary,
|
||||
Unspecified
|
||||
};
|
||||
|
||||
OptionCategory DwarfDumpCategory("Specific Options");
|
||||
static list<std::string>
|
||||
InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
|
||||
@ -276,6 +284,17 @@ static cl::opt<bool>
|
||||
cat(DwarfDumpCategory));
|
||||
static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
|
||||
cat(DwarfDumpCategory));
|
||||
static opt<ErrorDetailLevel> ErrorDetails(
|
||||
"error-display", init(Unspecified),
|
||||
values(clEnumValN(NoDetailsOrSummary, "quiet",
|
||||
"Only display whether errors occurred."),
|
||||
clEnumValN(NoDetailsOnlySummary, "summary",
|
||||
"Display only a summary of the errors found."),
|
||||
clEnumValN(OnlyDetailsNoSummary, "details",
|
||||
"Display each error in detail but no summary."),
|
||||
clEnumValN(BothDetailsAndSummary, "full",
|
||||
"Display each error as well as a summary. [default]")),
|
||||
cat(DwarfDumpCategory));
|
||||
static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
|
||||
cat(DwarfDumpCategory));
|
||||
static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),
|
||||
@ -326,7 +345,10 @@ static DIDumpOptions getDumpOpts(DWARFContext &C) {
|
||||
DumpOpts.RecoverableErrorHandler = C.getRecoverableErrorHandler();
|
||||
// In -verify mode, print DIEs without children in error messages.
|
||||
if (Verify) {
|
||||
DumpOpts.Verbose = true;
|
||||
DumpOpts.Verbose = ErrorDetails != NoDetailsOnlySummary &&
|
||||
ErrorDetails != NoDetailsOrSummary;
|
||||
DumpOpts.ShowAggregateErrors = ErrorDetails != OnlyDetailsNoSummary &&
|
||||
ErrorDetails != NoDetailsOnlySummary;
|
||||
return DumpOpts.noImplicitRecursion();
|
||||
}
|
||||
return DumpOpts;
|
||||
@ -812,6 +834,8 @@ int main(int argc, char **argv) {
|
||||
"-verbose is currently not supported";
|
||||
return 1;
|
||||
}
|
||||
if (!Verify && ErrorDetails != Unspecified)
|
||||
WithColor::warning() << "-error-detail has no affect without -verify";
|
||||
|
||||
std::error_code EC;
|
||||
ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_TextWithCRLF);
|
||||
|
Loading…
x
Reference in New Issue
Block a user