Skip to content

Commit 1df72ae

Browse files
authored
Merge pull request #3943 from apple/🍒/austria/409c515f3f9e2228ee10648011943d307ccd8860
[dsymutil] Add the ability to run the DWARF verifier on the input
2 parents 5e0087f + 1027992 commit 1df72ae

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)