Skip to content

Commit 409c515

Browse files
committed
[dsymutil] Add the ability to run the DWARF verifier on the input
Currently you can run the DWARF verifier on the linked dsymutil output. This patch extends this functionality and makes it possible to run the DWARF verifier on the input as well. A new option --verify-dwarf allows you to specify input, output, all and none. The existing --verify flag remains unchanged and acts and alias for --verify-dwarf=output. Input verification issues do not result in a non-zero exit code because dsymutil is capable of taking invalid DWARF as input and producing valid DWARF as output. Differential revision: https://reviews.llvm.org/D89216
1 parent f89319b commit 409c515

File tree

7 files changed

+106
-14
lines changed

7 files changed

+106
-14
lines changed

llvm/include/llvm/DWARFLinker/DWARFLinker.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ class DWARFLinker {
272272
/// Print statistics to standard output.
273273
void setStatistics(bool Statistics) { Options.Statistics = Statistics; }
274274

275+
/// Verify the input DWARF.
276+
void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; }
277+
275278
/// Do not emit linked dwarf info.
276279
void setNoOutput(bool NoOut) { Options.NoOutput = NoOut; }
277280

@@ -389,6 +392,9 @@ class DWARFLinker {
389392
AncestorIdx(AncestorIdx) {}
390393
};
391394

395+
/// Verify the given DWARF file.
396+
bool verify(const DWARFFile &File);
397+
392398
/// returns true if we need to translate strings.
393399
bool needToTranslateStrings() { return StringsTranslator != nullptr; }
394400

@@ -778,6 +784,9 @@ class DWARFLinker {
778784
/// Print statistics.
779785
bool Statistics = false;
780786

787+
/// Verify the input DWARF.
788+
bool VerifyInputDWARF = false;
789+
781790
/// Skip emitting output
782791
bool NoOutput = false;
783792

llvm/lib/DWARFLinker/DWARFLinker.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,10 @@ bool DWARFLinker::link() {
23622362

23632363
if (!OptContext.File.Dwarf)
23642364
continue;
2365+
2366+
if (Options.VerifyInputDWARF)
2367+
verify(OptContext.File);
2368+
23652369
// Look for relocations that correspond to address map entries.
23662370

23672371
// there was findvalidrelocations previously ... probably we need to gather
@@ -2631,4 +2635,15 @@ bool DWARFLinker::link() {
26312635
return true;
26322636
}
26332637

2638+
bool DWARFLinker::verify(const DWARFFile &File) {
2639+
assert(File.Dwarf);
2640+
2641+
DIDumpOptions DumpOpts;
2642+
if (!File.Dwarf->verify(llvm::outs(), DumpOpts.noImplicitRecursion())) {
2643+
reportWarning("input verification failed", File);
2644+
return false;
2645+
}
2646+
return true;
2647+
}
2648+
26342649
} // namespace llvm

llvm/test/tools/dsymutil/X86/verify.test

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,27 @@
33
# RUN: dsymutil -verify -verbose -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 %p/../Inputs/basic-archive.macho.x86_64 %p/../Inputs/basic-lto.macho.x86_64 %p/../Inputs/basic-lto-dw4.macho.x86_64 -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-SUCCESS,VERBOSE
44

55
# VERBOSE: Verifying DWARF for architecture: x86_64
6-
# QUIET-SUCCESS-NOT: error: verification failed
6+
# QUIET-SUCCESS-NOT: error: output verification failed
77

8-
# Negative tests in regular and verbose mode.
8+
# Negative output tests in regular and verbose mode.
99
# (Invalid object generated from ../Inputs/invalid.s by modified the low PC.)
10-
# RUN: not dsymutil -verify -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-FAIL
11-
# RUN: not dsymutil -verify -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-FAIL,VERBOSE
10+
# RUN: not dsymutil -verify -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-OUTPUT-FAIL
11+
# RUN: not dsymutil -verify-dwarf=output -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-OUTPUT-FAIL
12+
# RUN: not dsymutil -verify -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-OUTPUT-FAIL,VERBOSE
1213

13-
# QUIET-FAIL: error: verification failed
14+
# Negative input & output tests in regular and verbose mode. Only output failures result in a non-zero exit code.
15+
# RUN: dsymutil -verify-dwarf=input -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-INPUT-FAIL
16+
# RUN: dsymutil -verify-dwarf=input -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-INPUT-FAIL
17+
# RUN: dsymutil -verify-dwarf=none -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-SUCCESS
18+
# RUN: not dsymutil -verify-dwarf=bogus -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=BOGUS
19+
# RUN: not dsymutil -verify-dwarf=all -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-OUTPUT-FAIL,QUIET-INPUT-FAIL,VERBOSE-INPUT-FAIL
20+
21+
# VERBOSE-INPUT-FAIL: error: Abbreviation declaration contains multiple DW_AT_language attributes.
22+
# QUIET-INPUT-FAIL: warning: input verification failed
23+
# QUIET-OUTPUT-FAIL: error: output verification failed
24+
# QUIET-SUCCESS-NOT: input verification failed
25+
# QUIET-SUCCESS-NOT: output verification failed
26+
# BOGUS: error: invalid verify type specified: 'bogus'
1427

1528
---
1629
triple: 'x86_64-apple-darwin'

llvm/tools/dsymutil/DwarfLinkerForBinary.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
391391

392392
GeneralLinker.setVerbosity(Options.Verbose);
393393
GeneralLinker.setStatistics(Options.Statistics);
394+
GeneralLinker.setVerifyInputDWARF(Options.VerifyInputDWARF);
394395
GeneralLinker.setNoOutput(Options.NoOutput);
395396
GeneralLinker.setNoODR(Options.NoODR);
396397
GeneralLinker.setUpdate(Options.Update);

llvm/tools/dsymutil/LinkUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ struct LinkOptions {
3030
/// Statistics
3131
bool Statistics = false;
3232

33+
/// Verify the input DWARF.
34+
bool VerifyInputDWARF = false;
35+
3336
/// Skip emitting output
3437
bool NoOutput = false;
3538

llvm/tools/dsymutil/Options.td

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,15 @@ def statistics: F<"statistics">,
3838
Group<grp_general>;
3939

4040
def verify: F<"verify">,
41-
HelpText<"Run the DWARF verifier on the linked DWARF debug info.">,
41+
HelpText<"Alias for --verify-dwarf=output">,
4242
Group<grp_general>;
4343

44+
def verify_dwarf: Separate<["--", "-"], "verify-dwarf">,
45+
MetaVarName<"<verification mode>">,
46+
HelpText<"Run the DWARF verifier on the input and/or output. Valid options are 'input', 'output', 'all' or 'none'.">,
47+
Group<grp_general>;
48+
def: Joined<["--", "-"], "verify-dwarf=">, Alias<verify_dwarf>;
49+
4450
def no_output: F<"no-output">,
4551
HelpText<"Do the link in memory, but do not emit the result file.">,
4652
Group<grp_general>;

llvm/tools/dsymutil/dsymutil.cpp

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,23 @@ class DsymutilOptTable : public opt::OptTable {
8585
};
8686
} // namespace
8787

88+
enum class DWARFVerify : uint8_t {
89+
None = 0,
90+
Input = 1 << 0,
91+
Output = 1 << 1,
92+
All = Input | Output,
93+
};
94+
95+
inline bool flagIsSet(DWARFVerify Flags, DWARFVerify SingleFlag) {
96+
return static_cast<uint8_t>(Flags) & static_cast<uint8_t>(SingleFlag);
97+
}
98+
8899
struct DsymutilOptions {
89100
bool DumpDebugMap = false;
90101
bool DumpStab = false;
91102
bool Flat = false;
92103
bool InputIsYAMLDebugMap = false;
93104
bool PaperTrailWarnings = false;
94-
bool Verify = false;
95105
bool ForceKeepFunctionForStatic = false;
96106
std::string SymbolMap;
97107
std::string OutputFile;
@@ -100,6 +110,7 @@ struct DsymutilOptions {
100110
std::vector<std::string> Archs;
101111
std::vector<std::string> InputFiles;
102112
unsigned NumThreads;
113+
DWARFVerify Verify = DWARFVerify::None;
103114
ReproducerMode ReproMode = ReproducerMode::Off;
104115
dsymutil::LinkOptions LinkOpts;
105116
};
@@ -214,6 +225,27 @@ static Expected<AccelTableKind> getAccelTableKind(opt::InputArgList &Args) {
214225
return AccelTableKind::Default;
215226
}
216227

228+
static Expected<DWARFVerify> getVerifyKind(opt::InputArgList &Args) {
229+
if (Args.hasArg(OPT_verify))
230+
return DWARFVerify::Output;
231+
if (opt::Arg *Verify = Args.getLastArg(OPT_verify_dwarf)) {
232+
StringRef S = Verify->getValue();
233+
if (S == "input")
234+
return DWARFVerify::Input;
235+
if (S == "output")
236+
return DWARFVerify::Output;
237+
if (S == "all")
238+
return DWARFVerify::All;
239+
if (S == "none")
240+
return DWARFVerify::None;
241+
return make_error<StringError>(
242+
"invalid verify type specified: '" + S +
243+
"'. Support values are 'input', 'output', 'all' and 'none'.",
244+
inconvertibleErrorCode());
245+
}
246+
return DWARFVerify::None;
247+
}
248+
217249
/// Parses the command line options into the LinkOptions struct and performs
218250
/// some sanity checking. Returns an error in case the latter fails.
219251
static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
@@ -224,9 +256,16 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
224256
Options.Flat = Args.hasArg(OPT_flat);
225257
Options.InputIsYAMLDebugMap = Args.hasArg(OPT_yaml_input);
226258
Options.PaperTrailWarnings = Args.hasArg(OPT_papertrail);
227-
Options.Verify = Args.hasArg(OPT_verify);
259+
260+
if (Expected<DWARFVerify> Verify = getVerifyKind(Args)) {
261+
Options.Verify = *Verify;
262+
} else {
263+
return Verify.takeError();
264+
}
228265

229266
Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr);
267+
Options.LinkOpts.VerifyInputDWARF =
268+
flagIsSet(Options.Verify, DWARFVerify::Input);
230269
Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output);
231270
Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
232271
Options.LinkOpts.Update = Args.hasArg(OPT_update);
@@ -388,7 +427,7 @@ static Error createBundleDir(StringRef BundleBase) {
388427
return Error::success();
389428
}
390429

391-
static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
430+
static bool verifyOutput(StringRef OutputFile, StringRef Arch, bool Verbose) {
392431
if (OutputFile == "-") {
393432
WithColor::warning() << "verification skipped for " << Arch
394433
<< "because writing to stdout.\n";
@@ -409,7 +448,7 @@ static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
409448
DIDumpOptions DumpOpts;
410449
bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
411450
if (!success)
412-
WithColor::error() << "verification failed for " << Arch << '\n';
451+
WithColor::error() << "output verification failed for " << Arch << '\n';
413452
return success;
414453
}
415454

@@ -613,7 +652,12 @@ int main(int argc, char **argv) {
613652
const bool NeedsTempFiles =
614653
!Options.DumpDebugMap && (Options.OutputFile != "-") &&
615654
(DebugMapPtrsOrErr->size() != 1 || Options.LinkOpts.Update);
616-
const bool Verify = Options.Verify && !Options.LinkOpts.NoOutput;
655+
bool VerifyOutput = flagIsSet(Options.Verify, DWARFVerify::Output);
656+
if (VerifyOutput && Options.LinkOpts.NoOutput) {
657+
WithColor::warning()
658+
<< "skipping output verification because --no-output was passed\n";
659+
VerifyOutput = false;
660+
}
617661

618662
SmallVector<MachOUtils::ArchAndFile, 4> TempFiles;
619663
std::atomic_char AllOK(1);
@@ -665,9 +709,10 @@ int main(int argc, char **argv) {
665709
AllOK.fetch_and(
666710
linkDwarf(*Stream, BinHolder, *Map, std::move(Options)));
667711
Stream->flush();
668-
if (Verify)
669-
AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName(),
670-
Options.Verbose));
712+
if (VerifyOutput) {
713+
AllOK.fetch_and(verifyOutput(
714+
OutputFile, Map->getTriple().getArchName(), Options.Verbose));
715+
}
671716
};
672717

673718
// FIXME: The DwarfLinker can have some very deep recursion that can max

0 commit comments

Comments
 (0)