Skip to content

Commit 1027992

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 (cherry picked from commit 409c515)
1 parent 698e047 commit 1027992

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
Flags(Flags), 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
@@ -2358,6 +2358,10 @@ bool DWARFLinker::link() {
23582358

23592359
if (!OptContext.File.Dwarf)
23602360
continue;
2361+
2362+
if (Options.VerifyInputDWARF)
2363+
verify(OptContext.File);
2364+
23612365
// Look for relocations that correspond to address map entries.
23622366

23632367
// there was findvalidrelocations previously ... probably we need to gather
@@ -2627,4 +2631,15 @@ bool DWARFLinker::link() {
26272631
return true;
26282632
}
26292633

2634+
bool DWARFLinker::verify(const DWARFFile &File) {
2635+
assert(File.Dwarf);
2636+
2637+
DIDumpOptions DumpOpts;
2638+
if (!File.Dwarf->verify(llvm::outs(), DumpOpts.noImplicitRecursion())) {
2639+
reportWarning("input verification failed", File);
2640+
return false;
2641+
}
2642+
return true;
2643+
}
2644+
26302645
} // 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
@@ -84,13 +84,23 @@ class DsymutilOptTable : public opt::OptTable {
8484
};
8585
} // namespace
8686

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

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

228265
Options.LinkOpts.NoODR = Args.hasArg(OPT_no_odr);
266+
Options.LinkOpts.VerifyInputDWARF =
267+
flagIsSet(Options.Verify, DWARFVerify::Input);
229268
Options.LinkOpts.NoOutput = Args.hasArg(OPT_no_output);
230269
Options.LinkOpts.NoTimestamp = Args.hasArg(OPT_no_swiftmodule_timestamp);
231270
Options.LinkOpts.Update = Args.hasArg(OPT_update);
@@ -387,7 +426,7 @@ static Error createBundleDir(StringRef BundleBase) {
387426
return Error::success();
388427
}
389428

390-
static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
429+
static bool verifyOutput(StringRef OutputFile, StringRef Arch, bool Verbose) {
391430
if (OutputFile == "-") {
392431
WithColor::warning() << "verification skipped for " << Arch
393432
<< "because writing to stdout.\n";
@@ -408,7 +447,7 @@ static bool verify(StringRef OutputFile, StringRef Arch, bool Verbose) {
408447
DIDumpOptions DumpOpts;
409448
bool success = DICtx->verify(os, DumpOpts.noImplicitRecursion());
410449
if (!success)
411-
WithColor::error() << "verification failed for " << Arch << '\n';
450+
WithColor::error() << "output verification failed for " << Arch << '\n';
412451
return success;
413452
}
414453

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

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

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

0 commit comments

Comments
 (0)