xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This program is a utility that works like "dwarfdump".
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
15*0b57cec5SDimitry Andric #include "llvm/ADT/Triple.h"
16*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DIContext.h"
17*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
18*0b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
19*0b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
20*0b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/Format.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
26*0b57cec5SDimitry Andric #include "llvm/Support/Path.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
29*0b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h"
30*0b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
31*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric using namespace llvm;
34*0b57cec5SDimitry Andric using namespace object;
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric /// Parser for options that take an optional offest argument.
37*0b57cec5SDimitry Andric /// @{
38*0b57cec5SDimitry Andric struct OffsetOption {
39*0b57cec5SDimitry Andric   uint64_t Val = 0;
40*0b57cec5SDimitry Andric   bool HasValue = false;
41*0b57cec5SDimitry Andric   bool IsRequested = false;
42*0b57cec5SDimitry Andric };
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric namespace llvm {
45*0b57cec5SDimitry Andric namespace cl {
46*0b57cec5SDimitry Andric template <>
47*0b57cec5SDimitry Andric class parser<OffsetOption> final : public basic_parser<OffsetOption> {
48*0b57cec5SDimitry Andric public:
49*0b57cec5SDimitry Andric   parser(Option &O) : basic_parser(O) {}
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   /// Return true on error.
52*0b57cec5SDimitry Andric   bool parse(Option &O, StringRef ArgName, StringRef Arg, OffsetOption &Val) {
53*0b57cec5SDimitry Andric     if (Arg == "") {
54*0b57cec5SDimitry Andric       Val.Val = 0;
55*0b57cec5SDimitry Andric       Val.HasValue = false;
56*0b57cec5SDimitry Andric       Val.IsRequested = true;
57*0b57cec5SDimitry Andric       return false;
58*0b57cec5SDimitry Andric     }
59*0b57cec5SDimitry Andric     if (Arg.getAsInteger(0, Val.Val))
60*0b57cec5SDimitry Andric       return O.error("'" + Arg + "' value invalid for integer argument!");
61*0b57cec5SDimitry Andric     Val.HasValue = true;
62*0b57cec5SDimitry Andric     Val.IsRequested = true;
63*0b57cec5SDimitry Andric     return false;
64*0b57cec5SDimitry Andric   }
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric   enum ValueExpected getValueExpectedFlagDefault() const {
67*0b57cec5SDimitry Andric     return ValueOptional;
68*0b57cec5SDimitry Andric   }
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric   void printOptionInfo(const Option &O, size_t GlobalWidth) const {
71*0b57cec5SDimitry Andric     outs() << "  -" << O.ArgStr;
72*0b57cec5SDimitry Andric     Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
73*0b57cec5SDimitry Andric   }
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric   void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,
76*0b57cec5SDimitry Andric                        size_t GlobalWidth) const {
77*0b57cec5SDimitry Andric     printOptionName(O, GlobalWidth);
78*0b57cec5SDimitry Andric     outs() << "[=offset]";
79*0b57cec5SDimitry Andric   }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric   // An out-of-line virtual method to provide a 'home' for this class.
82*0b57cec5SDimitry Andric   void anchor() override {};
83*0b57cec5SDimitry Andric };
84*0b57cec5SDimitry Andric } // cl
85*0b57cec5SDimitry Andric } // llvm
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric /// @}
88*0b57cec5SDimitry Andric /// Command line options.
89*0b57cec5SDimitry Andric /// @{
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric namespace {
92*0b57cec5SDimitry Andric using namespace cl;
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric OptionCategory DwarfDumpCategory("Specific Options");
95*0b57cec5SDimitry Andric static list<std::string>
96*0b57cec5SDimitry Andric     InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
97*0b57cec5SDimitry Andric                    ZeroOrMore, cat(DwarfDumpCategory));
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric cl::OptionCategory SectionCategory("Section-specific Dump Options",
100*0b57cec5SDimitry Andric                                    "These control which sections are dumped. "
101*0b57cec5SDimitry Andric                                    "Where applicable these parameters take an "
102*0b57cec5SDimitry Andric                                    "optional =<offset> argument to dump only "
103*0b57cec5SDimitry Andric                                    "the entry at the specified offset.");
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric static opt<bool> DumpAll("all", desc("Dump all debug info sections"),
106*0b57cec5SDimitry Andric                          cat(SectionCategory));
107*0b57cec5SDimitry Andric static alias DumpAllAlias("a", desc("Alias for -all"), aliasopt(DumpAll));
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric // Options for dumping specific sections.
110*0b57cec5SDimitry Andric static unsigned DumpType = DIDT_Null;
111*0b57cec5SDimitry Andric static std::array<llvm::Optional<uint64_t>, (unsigned)DIDT_ID_Count>
112*0b57cec5SDimitry Andric     DumpOffsets;
113*0b57cec5SDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME)                \
114*0b57cec5SDimitry Andric   static opt<OffsetOption> Dump##ENUM_NAME(                                    \
115*0b57cec5SDimitry Andric       CMDLINE_NAME, desc("Dump the " ELF_NAME " section"),                     \
116*0b57cec5SDimitry Andric       cat(SectionCategory));
117*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def"
118*0b57cec5SDimitry Andric #undef HANDLE_DWARF_SECTION
119*0b57cec5SDimitry Andric 
120*0b57cec5SDimitry Andric static alias DumpDebugFrameAlias("eh-frame", desc("Alias for -debug-frame"),
121*0b57cec5SDimitry Andric                                  NotHidden, cat(SectionCategory),
122*0b57cec5SDimitry Andric                                  aliasopt(DumpDebugFrame));
123*0b57cec5SDimitry Andric static list<std::string>
124*0b57cec5SDimitry Andric     ArchFilters("arch",
125*0b57cec5SDimitry Andric                 desc("Dump debug information for the specified CPU "
126*0b57cec5SDimitry Andric                      "architecture only. Architectures may be specified by "
127*0b57cec5SDimitry Andric                      "name or by number. This option can be specified "
128*0b57cec5SDimitry Andric                      "multiple times, once for each desired architecture."),
129*0b57cec5SDimitry Andric                 cat(DwarfDumpCategory));
130*0b57cec5SDimitry Andric static opt<bool>
131*0b57cec5SDimitry Andric     Diff("diff",
132*0b57cec5SDimitry Andric          desc("Emit diff-friendly output by omitting offsets and addresses."),
133*0b57cec5SDimitry Andric          cat(DwarfDumpCategory));
134*0b57cec5SDimitry Andric static list<std::string>
135*0b57cec5SDimitry Andric     Find("find",
136*0b57cec5SDimitry Andric          desc("Search for the exact match for <name> in the accelerator tables "
137*0b57cec5SDimitry Andric               "and print the matching debug information entries. When no "
138*0b57cec5SDimitry Andric               "accelerator tables are available, the slower but more complete "
139*0b57cec5SDimitry Andric               "-name option can be used instead."),
140*0b57cec5SDimitry Andric          value_desc("name"), cat(DwarfDumpCategory));
141*0b57cec5SDimitry Andric static alias FindAlias("f", desc("Alias for -find."), aliasopt(Find));
142*0b57cec5SDimitry Andric static opt<bool> IgnoreCase("ignore-case",
143*0b57cec5SDimitry Andric                             desc("Ignore case distinctions when searching."),
144*0b57cec5SDimitry Andric                             value_desc("i"), cat(DwarfDumpCategory));
145*0b57cec5SDimitry Andric static alias IgnoreCaseAlias("i", desc("Alias for -ignore-case."),
146*0b57cec5SDimitry Andric                              aliasopt(IgnoreCase));
147*0b57cec5SDimitry Andric static list<std::string> Name(
148*0b57cec5SDimitry Andric     "name",
149*0b57cec5SDimitry Andric     desc("Find and print all debug info entries whose name (DW_AT_name "
150*0b57cec5SDimitry Andric          "attribute) matches the exact text in <pattern>.  When used with the "
151*0b57cec5SDimitry Andric          "the -regex option <pattern> is interpreted as a regular expression."),
152*0b57cec5SDimitry Andric     value_desc("pattern"), cat(DwarfDumpCategory));
153*0b57cec5SDimitry Andric static alias NameAlias("n", desc("Alias for -name"), aliasopt(Name));
154*0b57cec5SDimitry Andric static opt<uint64_t>
155*0b57cec5SDimitry Andric     Lookup("lookup",
156*0b57cec5SDimitry Andric            desc("Lookup <address> in the debug information and print out any "
157*0b57cec5SDimitry Andric                 "available file, function, block and line table details."),
158*0b57cec5SDimitry Andric            value_desc("address"), cat(DwarfDumpCategory));
159*0b57cec5SDimitry Andric static opt<std::string>
160*0b57cec5SDimitry Andric     OutputFilename("o", cl::init("-"),
161*0b57cec5SDimitry Andric                    cl::desc("Redirect output to the specified file."),
162*0b57cec5SDimitry Andric                    cl::value_desc("filename"), cat(DwarfDumpCategory));
163*0b57cec5SDimitry Andric static alias OutputFilenameAlias("out-file", desc("Alias for -o."),
164*0b57cec5SDimitry Andric                                  aliasopt(OutputFilename));
165*0b57cec5SDimitry Andric static opt<bool>
166*0b57cec5SDimitry Andric     UseRegex("regex",
167*0b57cec5SDimitry Andric              desc("Treat any <pattern> strings as regular expressions when "
168*0b57cec5SDimitry Andric                   "searching instead of just as an exact string match."),
169*0b57cec5SDimitry Andric              cat(DwarfDumpCategory));
170*0b57cec5SDimitry Andric static alias RegexAlias("x", desc("Alias for -regex"), aliasopt(UseRegex));
171*0b57cec5SDimitry Andric static opt<bool>
172*0b57cec5SDimitry Andric     ShowChildren("show-children",
173*0b57cec5SDimitry Andric                  desc("Show a debug info entry's children when selectively "
174*0b57cec5SDimitry Andric                       "printing entries."),
175*0b57cec5SDimitry Andric                  cat(DwarfDumpCategory));
176*0b57cec5SDimitry Andric static alias ShowChildrenAlias("c", desc("Alias for -show-children."),
177*0b57cec5SDimitry Andric                                aliasopt(ShowChildren));
178*0b57cec5SDimitry Andric static opt<bool>
179*0b57cec5SDimitry Andric     ShowParents("show-parents",
180*0b57cec5SDimitry Andric                 desc("Show a debug info entry's parents when selectively "
181*0b57cec5SDimitry Andric                      "printing entries."),
182*0b57cec5SDimitry Andric                 cat(DwarfDumpCategory));
183*0b57cec5SDimitry Andric static alias ShowParentsAlias("p", desc("Alias for -show-parents."),
184*0b57cec5SDimitry Andric                               aliasopt(ShowParents));
185*0b57cec5SDimitry Andric static opt<bool>
186*0b57cec5SDimitry Andric     ShowForm("show-form",
187*0b57cec5SDimitry Andric              desc("Show DWARF form types after the DWARF attribute types."),
188*0b57cec5SDimitry Andric              cat(DwarfDumpCategory));
189*0b57cec5SDimitry Andric static alias ShowFormAlias("F", desc("Alias for -show-form."),
190*0b57cec5SDimitry Andric                            aliasopt(ShowForm), cat(DwarfDumpCategory));
191*0b57cec5SDimitry Andric static opt<unsigned>
192*0b57cec5SDimitry Andric     ChildRecurseDepth("recurse-depth",
193*0b57cec5SDimitry Andric                       desc("Only recurse to a depth of N when displaying "
194*0b57cec5SDimitry Andric                            "children of debug info entries."),
195*0b57cec5SDimitry Andric                       cat(DwarfDumpCategory), init(-1U), value_desc("N"));
196*0b57cec5SDimitry Andric static alias ChildRecurseDepthAlias("r", desc("Alias for -recurse-depth."),
197*0b57cec5SDimitry Andric                                     aliasopt(ChildRecurseDepth));
198*0b57cec5SDimitry Andric static opt<unsigned>
199*0b57cec5SDimitry Andric     ParentRecurseDepth("parent-recurse-depth",
200*0b57cec5SDimitry Andric                        desc("Only recurse to a depth of N when displaying "
201*0b57cec5SDimitry Andric                             "parents of debug info entries."),
202*0b57cec5SDimitry Andric                        cat(DwarfDumpCategory), init(-1U), value_desc("N"));
203*0b57cec5SDimitry Andric static opt<bool>
204*0b57cec5SDimitry Andric     SummarizeTypes("summarize-types",
205*0b57cec5SDimitry Andric                    desc("Abbreviate the description of type unit entries."),
206*0b57cec5SDimitry Andric                    cat(DwarfDumpCategory));
207*0b57cec5SDimitry Andric static cl::opt<bool>
208*0b57cec5SDimitry Andric     Statistics("statistics",
209*0b57cec5SDimitry Andric                cl::desc("Emit JSON-formatted debug info quality metrics."),
210*0b57cec5SDimitry Andric                cat(DwarfDumpCategory));
211*0b57cec5SDimitry Andric static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
212*0b57cec5SDimitry Andric                         cat(DwarfDumpCategory));
213*0b57cec5SDimitry Andric static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
214*0b57cec5SDimitry Andric                        cat(DwarfDumpCategory));
215*0b57cec5SDimitry Andric static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),
216*0b57cec5SDimitry Andric                           cat(DwarfDumpCategory));
217*0b57cec5SDimitry Andric static alias DumpUUIDAlias("u", desc("Alias for -uuid."), aliasopt(DumpUUID));
218*0b57cec5SDimitry Andric static opt<bool> Verbose("verbose",
219*0b57cec5SDimitry Andric                          desc("Print more low-level encoding details."),
220*0b57cec5SDimitry Andric                          cat(DwarfDumpCategory));
221*0b57cec5SDimitry Andric static alias VerboseAlias("v", desc("Alias for -verbose."), aliasopt(Verbose),
222*0b57cec5SDimitry Andric                           cat(DwarfDumpCategory));
223*0b57cec5SDimitry Andric static cl::extrahelp
224*0b57cec5SDimitry Andric     HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
225*0b57cec5SDimitry Andric } // namespace
226*0b57cec5SDimitry Andric /// @}
227*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric static void error(StringRef Prefix, std::error_code EC) {
230*0b57cec5SDimitry Andric   if (!EC)
231*0b57cec5SDimitry Andric     return;
232*0b57cec5SDimitry Andric   WithColor::error() << Prefix << ": " << EC.message() << "\n";
233*0b57cec5SDimitry Andric   exit(1);
234*0b57cec5SDimitry Andric }
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric static DIDumpOptions getDumpOpts() {
237*0b57cec5SDimitry Andric   DIDumpOptions DumpOpts;
238*0b57cec5SDimitry Andric   DumpOpts.DumpType = DumpType;
239*0b57cec5SDimitry Andric   DumpOpts.ChildRecurseDepth = ChildRecurseDepth;
240*0b57cec5SDimitry Andric   DumpOpts.ParentRecurseDepth = ParentRecurseDepth;
241*0b57cec5SDimitry Andric   DumpOpts.ShowAddresses = !Diff;
242*0b57cec5SDimitry Andric   DumpOpts.ShowChildren = ShowChildren;
243*0b57cec5SDimitry Andric   DumpOpts.ShowParents = ShowParents;
244*0b57cec5SDimitry Andric   DumpOpts.ShowForm = ShowForm;
245*0b57cec5SDimitry Andric   DumpOpts.SummarizeTypes = SummarizeTypes;
246*0b57cec5SDimitry Andric   DumpOpts.Verbose = Verbose;
247*0b57cec5SDimitry Andric   // In -verify mode, print DIEs without children in error messages.
248*0b57cec5SDimitry Andric   if (Verify)
249*0b57cec5SDimitry Andric     return DumpOpts.noImplicitRecursion();
250*0b57cec5SDimitry Andric   return DumpOpts;
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric static uint32_t getCPUType(MachOObjectFile &MachO) {
254*0b57cec5SDimitry Andric   if (MachO.is64Bit())
255*0b57cec5SDimitry Andric     return MachO.getHeader64().cputype;
256*0b57cec5SDimitry Andric   else
257*0b57cec5SDimitry Andric     return MachO.getHeader().cputype;
258*0b57cec5SDimitry Andric }
259*0b57cec5SDimitry Andric 
260*0b57cec5SDimitry Andric /// Return true if the object file has not been filtered by an --arch option.
261*0b57cec5SDimitry Andric static bool filterArch(ObjectFile &Obj) {
262*0b57cec5SDimitry Andric   if (ArchFilters.empty())
263*0b57cec5SDimitry Andric     return true;
264*0b57cec5SDimitry Andric 
265*0b57cec5SDimitry Andric   if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
266*0b57cec5SDimitry Andric     for (auto Arch : ArchFilters) {
267*0b57cec5SDimitry Andric       // Match architecture number.
268*0b57cec5SDimitry Andric       unsigned Value;
269*0b57cec5SDimitry Andric       if (!StringRef(Arch).getAsInteger(0, Value))
270*0b57cec5SDimitry Andric         if (Value == getCPUType(*MachO))
271*0b57cec5SDimitry Andric           return true;
272*0b57cec5SDimitry Andric 
273*0b57cec5SDimitry Andric       // Match as name.
274*0b57cec5SDimitry Andric       if (MachO->getArchTriple().getArch() == Triple(Arch).getArch())
275*0b57cec5SDimitry Andric         return true;
276*0b57cec5SDimitry Andric     }
277*0b57cec5SDimitry Andric   }
278*0b57cec5SDimitry Andric   return false;
279*0b57cec5SDimitry Andric }
280*0b57cec5SDimitry Andric 
281*0b57cec5SDimitry Andric using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx, Twine,
282*0b57cec5SDimitry Andric                                      raw_ostream &)>;
283*0b57cec5SDimitry Andric 
284*0b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
285*0b57cec5SDimitry Andric static bool filterByName(const StringSet<> &Names, DWARFDie Die,
286*0b57cec5SDimitry Andric                          StringRef NameRef, raw_ostream &OS) {
287*0b57cec5SDimitry Andric   std::string Name =
288*0b57cec5SDimitry Andric       (IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();
289*0b57cec5SDimitry Andric   if (UseRegex) {
290*0b57cec5SDimitry Andric     // Match regular expression.
291*0b57cec5SDimitry Andric     for (auto Pattern : Names.keys()) {
292*0b57cec5SDimitry Andric       Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags);
293*0b57cec5SDimitry Andric       std::string Error;
294*0b57cec5SDimitry Andric       if (!RE.isValid(Error)) {
295*0b57cec5SDimitry Andric         errs() << "error in regular expression: " << Error << "\n";
296*0b57cec5SDimitry Andric         exit(1);
297*0b57cec5SDimitry Andric       }
298*0b57cec5SDimitry Andric       if (RE.match(Name)) {
299*0b57cec5SDimitry Andric         Die.dump(OS, 0, getDumpOpts());
300*0b57cec5SDimitry Andric         return true;
301*0b57cec5SDimitry Andric       }
302*0b57cec5SDimitry Andric     }
303*0b57cec5SDimitry Andric   } else if (Names.count(Name)) {
304*0b57cec5SDimitry Andric     // Match full text.
305*0b57cec5SDimitry Andric     Die.dump(OS, 0, getDumpOpts());
306*0b57cec5SDimitry Andric     return true;
307*0b57cec5SDimitry Andric   }
308*0b57cec5SDimitry Andric   return false;
309*0b57cec5SDimitry Andric }
310*0b57cec5SDimitry Andric 
311*0b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
312*0b57cec5SDimitry Andric static void filterByName(const StringSet<> &Names,
313*0b57cec5SDimitry Andric                          DWARFContext::unit_iterator_range CUs,
314*0b57cec5SDimitry Andric                          raw_ostream &OS) {
315*0b57cec5SDimitry Andric   for (const auto &CU : CUs)
316*0b57cec5SDimitry Andric     for (const auto &Entry : CU->dies()) {
317*0b57cec5SDimitry Andric       DWARFDie Die = {CU.get(), &Entry};
318*0b57cec5SDimitry Andric       if (const char *Name = Die.getName(DINameKind::ShortName))
319*0b57cec5SDimitry Andric         if (filterByName(Names, Die, Name, OS))
320*0b57cec5SDimitry Andric           continue;
321*0b57cec5SDimitry Andric       if (const char *Name = Die.getName(DINameKind::LinkageName))
322*0b57cec5SDimitry Andric         filterByName(Names, Die, Name, OS);
323*0b57cec5SDimitry Andric     }
324*0b57cec5SDimitry Andric }
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
327*0b57cec5SDimitry Andric                     StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
328*0b57cec5SDimitry Andric   for (const auto &Entry : Accel.equal_range(Name)) {
329*0b57cec5SDimitry Andric     if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset()) {
330*0b57cec5SDimitry Andric       if (DWARFDie Die = DICtx.getDIEForOffset(*Off))
331*0b57cec5SDimitry Andric         Dies.push_back(Die);
332*0b57cec5SDimitry Andric     }
333*0b57cec5SDimitry Andric   }
334*0b57cec5SDimitry Andric }
335*0b57cec5SDimitry Andric 
336*0b57cec5SDimitry Andric static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,
337*0b57cec5SDimitry Andric                       DWARFContext &DICtx) {
338*0b57cec5SDimitry Andric   llvm::Optional<uint64_t> CUOff = Entry.getCUOffset();
339*0b57cec5SDimitry Andric   llvm::Optional<uint64_t> Off = Entry.getDIEUnitOffset();
340*0b57cec5SDimitry Andric   if (!CUOff || !Off)
341*0b57cec5SDimitry Andric     return DWARFDie();
342*0b57cec5SDimitry Andric 
343*0b57cec5SDimitry Andric   DWARFCompileUnit *CU = DICtx.getCompileUnitForOffset(*CUOff);
344*0b57cec5SDimitry Andric   if (!CU)
345*0b57cec5SDimitry Andric     return DWARFDie();
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric   if (llvm::Optional<uint64_t> DWOId = CU->getDWOId()) {
348*0b57cec5SDimitry Andric     // This is a skeleton unit. Look up the DIE in the DWO unit.
349*0b57cec5SDimitry Andric     CU = DICtx.getDWOCompileUnitForHash(*DWOId);
350*0b57cec5SDimitry Andric     if (!CU)
351*0b57cec5SDimitry Andric       return DWARFDie();
352*0b57cec5SDimitry Andric   }
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric   return CU->getDIEForOffset(CU->getOffset() + *Off);
355*0b57cec5SDimitry Andric }
356*0b57cec5SDimitry Andric 
357*0b57cec5SDimitry Andric static void getDies(DWARFContext &DICtx, const DWARFDebugNames &Accel,
358*0b57cec5SDimitry Andric                     StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
359*0b57cec5SDimitry Andric   for (const auto &Entry : Accel.equal_range(Name)) {
360*0b57cec5SDimitry Andric     if (DWARFDie Die = toDie(Entry, DICtx))
361*0b57cec5SDimitry Andric       Dies.push_back(Die);
362*0b57cec5SDimitry Andric   }
363*0b57cec5SDimitry Andric }
364*0b57cec5SDimitry Andric 
365*0b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
366*0b57cec5SDimitry Andric static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
367*0b57cec5SDimitry Andric                               raw_ostream &OS) {
368*0b57cec5SDimitry Andric   SmallVector<DWARFDie, 4> Dies;
369*0b57cec5SDimitry Andric   for (const auto &Name : Names) {
370*0b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleNames(), Name, Dies);
371*0b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleTypes(), Name, Dies);
372*0b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleNamespaces(), Name, Dies);
373*0b57cec5SDimitry Andric     getDies(DICtx, DICtx.getDebugNames(), Name, Dies);
374*0b57cec5SDimitry Andric   }
375*0b57cec5SDimitry Andric   llvm::sort(Dies);
376*0b57cec5SDimitry Andric   Dies.erase(std::unique(Dies.begin(), Dies.end()), Dies.end());
377*0b57cec5SDimitry Andric 
378*0b57cec5SDimitry Andric   for (DWARFDie Die : Dies)
379*0b57cec5SDimitry Andric     Die.dump(OS, 0, getDumpOpts());
380*0b57cec5SDimitry Andric }
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric /// Handle the --lookup option and dump the DIEs and line info for the given
383*0b57cec5SDimitry Andric /// address.
384*0b57cec5SDimitry Andric /// TODO: specified Address for --lookup option could relate for several
385*0b57cec5SDimitry Andric /// different sections(in case not-linked object file). llvm-dwarfdump
386*0b57cec5SDimitry Andric /// need to do something with this: extend lookup option with section
387*0b57cec5SDimitry Andric /// information or probably display all matched entries, or something else...
388*0b57cec5SDimitry Andric static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
389*0b57cec5SDimitry Andric                    raw_ostream &OS) {
390*0b57cec5SDimitry Andric   auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup);
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric   if (!DIEsForAddr)
393*0b57cec5SDimitry Andric     return false;
394*0b57cec5SDimitry Andric 
395*0b57cec5SDimitry Andric   DIDumpOptions DumpOpts = getDumpOpts();
396*0b57cec5SDimitry Andric   DumpOpts.ChildRecurseDepth = 0;
397*0b57cec5SDimitry Andric   DIEsForAddr.CompileUnit->dump(OS, DumpOpts);
398*0b57cec5SDimitry Andric   if (DIEsForAddr.FunctionDIE) {
399*0b57cec5SDimitry Andric     DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);
400*0b57cec5SDimitry Andric     if (DIEsForAddr.BlockDIE)
401*0b57cec5SDimitry Andric       DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);
402*0b57cec5SDimitry Andric   }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric   // TODO: it is neccessary to set proper SectionIndex here.
405*0b57cec5SDimitry Andric   // object::SectionedAddress::UndefSection works for only absolute addresses.
406*0b57cec5SDimitry Andric   if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
407*0b57cec5SDimitry Andric           {Lookup, object::SectionedAddress::UndefSection}))
408*0b57cec5SDimitry Andric     LineInfo.dump(OS);
409*0b57cec5SDimitry Andric 
410*0b57cec5SDimitry Andric   return true;
411*0b57cec5SDimitry Andric }
412*0b57cec5SDimitry Andric 
413*0b57cec5SDimitry Andric bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
414*0b57cec5SDimitry Andric                                Twine Filename, raw_ostream &OS);
415*0b57cec5SDimitry Andric 
416*0b57cec5SDimitry Andric static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
417*0b57cec5SDimitry Andric                            raw_ostream &OS) {
418*0b57cec5SDimitry Andric   logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
419*0b57cec5SDimitry Andric                         Filename.str() + ": ");
420*0b57cec5SDimitry Andric   // The UUID dump already contains all the same information.
421*0b57cec5SDimitry Andric   if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
422*0b57cec5SDimitry Andric     OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
423*0b57cec5SDimitry Andric 
424*0b57cec5SDimitry Andric   // Handle the --lookup option.
425*0b57cec5SDimitry Andric   if (Lookup)
426*0b57cec5SDimitry Andric     return lookup(Obj, DICtx, Lookup, OS);
427*0b57cec5SDimitry Andric 
428*0b57cec5SDimitry Andric   // Handle the --name option.
429*0b57cec5SDimitry Andric   if (!Name.empty()) {
430*0b57cec5SDimitry Andric     StringSet<> Names;
431*0b57cec5SDimitry Andric     for (auto name : Name)
432*0b57cec5SDimitry Andric       Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
433*0b57cec5SDimitry Andric 
434*0b57cec5SDimitry Andric     filterByName(Names, DICtx.normal_units(), OS);
435*0b57cec5SDimitry Andric     filterByName(Names, DICtx.dwo_units(), OS);
436*0b57cec5SDimitry Andric     return true;
437*0b57cec5SDimitry Andric   }
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric   // Handle the --find option and lower it to --debug-info=<offset>.
440*0b57cec5SDimitry Andric   if (!Find.empty()) {
441*0b57cec5SDimitry Andric     filterByAccelName(Find, DICtx, OS);
442*0b57cec5SDimitry Andric     return true;
443*0b57cec5SDimitry Andric   }
444*0b57cec5SDimitry Andric 
445*0b57cec5SDimitry Andric   // Dump the complete DWARF structure.
446*0b57cec5SDimitry Andric   DICtx.dump(OS, getDumpOpts(), DumpOffsets);
447*0b57cec5SDimitry Andric   return true;
448*0b57cec5SDimitry Andric }
449*0b57cec5SDimitry Andric 
450*0b57cec5SDimitry Andric static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
451*0b57cec5SDimitry Andric                              Twine Filename, raw_ostream &OS) {
452*0b57cec5SDimitry Andric   // Verify the DWARF and exit with non-zero exit status if verification
453*0b57cec5SDimitry Andric   // fails.
454*0b57cec5SDimitry Andric   raw_ostream &stream = Quiet ? nulls() : OS;
455*0b57cec5SDimitry Andric   stream << "Verifying " << Filename.str() << ":\tfile format "
456*0b57cec5SDimitry Andric   << Obj.getFileFormatName() << "\n";
457*0b57cec5SDimitry Andric   bool Result = DICtx.verify(stream, getDumpOpts());
458*0b57cec5SDimitry Andric   if (Result)
459*0b57cec5SDimitry Andric     stream << "No errors.\n";
460*0b57cec5SDimitry Andric   else
461*0b57cec5SDimitry Andric     stream << "Errors detected.\n";
462*0b57cec5SDimitry Andric   return Result;
463*0b57cec5SDimitry Andric }
464*0b57cec5SDimitry Andric 
465*0b57cec5SDimitry Andric static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
466*0b57cec5SDimitry Andric                          HandlerFn HandleObj, raw_ostream &OS);
467*0b57cec5SDimitry Andric 
468*0b57cec5SDimitry Andric static bool handleArchive(StringRef Filename, Archive &Arch,
469*0b57cec5SDimitry Andric                           HandlerFn HandleObj, raw_ostream &OS) {
470*0b57cec5SDimitry Andric   bool Result = true;
471*0b57cec5SDimitry Andric   Error Err = Error::success();
472*0b57cec5SDimitry Andric   for (auto Child : Arch.children(Err)) {
473*0b57cec5SDimitry Andric     auto BuffOrErr = Child.getMemoryBufferRef();
474*0b57cec5SDimitry Andric     error(Filename, errorToErrorCode(BuffOrErr.takeError()));
475*0b57cec5SDimitry Andric     auto NameOrErr = Child.getName();
476*0b57cec5SDimitry Andric     error(Filename, errorToErrorCode(NameOrErr.takeError()));
477*0b57cec5SDimitry Andric     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
478*0b57cec5SDimitry Andric     Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);
479*0b57cec5SDimitry Andric   }
480*0b57cec5SDimitry Andric   error(Filename, errorToErrorCode(std::move(Err)));
481*0b57cec5SDimitry Andric 
482*0b57cec5SDimitry Andric   return Result;
483*0b57cec5SDimitry Andric }
484*0b57cec5SDimitry Andric 
485*0b57cec5SDimitry Andric static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
486*0b57cec5SDimitry Andric                          HandlerFn HandleObj, raw_ostream &OS) {
487*0b57cec5SDimitry Andric   Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
488*0b57cec5SDimitry Andric   error(Filename, errorToErrorCode(BinOrErr.takeError()));
489*0b57cec5SDimitry Andric 
490*0b57cec5SDimitry Andric   bool Result = true;
491*0b57cec5SDimitry Andric   if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
492*0b57cec5SDimitry Andric     if (filterArch(*Obj)) {
493*0b57cec5SDimitry Andric       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
494*0b57cec5SDimitry Andric       Result = HandleObj(*Obj, *DICtx, Filename, OS);
495*0b57cec5SDimitry Andric     }
496*0b57cec5SDimitry Andric   }
497*0b57cec5SDimitry Andric   else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
498*0b57cec5SDimitry Andric     for (auto &ObjForArch : Fat->objects()) {
499*0b57cec5SDimitry Andric       std::string ObjName =
500*0b57cec5SDimitry Andric           (Filename + "(" + ObjForArch.getArchFlagName() + ")").str();
501*0b57cec5SDimitry Andric       if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {
502*0b57cec5SDimitry Andric         auto &Obj = **MachOOrErr;
503*0b57cec5SDimitry Andric         if (filterArch(Obj)) {
504*0b57cec5SDimitry Andric           std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
505*0b57cec5SDimitry Andric           Result &= HandleObj(Obj, *DICtx, ObjName, OS);
506*0b57cec5SDimitry Andric         }
507*0b57cec5SDimitry Andric         continue;
508*0b57cec5SDimitry Andric       } else
509*0b57cec5SDimitry Andric         consumeError(MachOOrErr.takeError());
510*0b57cec5SDimitry Andric       if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {
511*0b57cec5SDimitry Andric         error(ObjName, errorToErrorCode(ArchiveOrErr.takeError()));
512*0b57cec5SDimitry Andric         Result &= handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS);
513*0b57cec5SDimitry Andric         continue;
514*0b57cec5SDimitry Andric       } else
515*0b57cec5SDimitry Andric         consumeError(ArchiveOrErr.takeError());
516*0b57cec5SDimitry Andric     }
517*0b57cec5SDimitry Andric   else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))
518*0b57cec5SDimitry Andric     Result = handleArchive(Filename, *Arch, HandleObj, OS);
519*0b57cec5SDimitry Andric   return Result;
520*0b57cec5SDimitry Andric }
521*0b57cec5SDimitry Andric 
522*0b57cec5SDimitry Andric static bool handleFile(StringRef Filename, HandlerFn HandleObj,
523*0b57cec5SDimitry Andric                        raw_ostream &OS) {
524*0b57cec5SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
525*0b57cec5SDimitry Andric   MemoryBuffer::getFileOrSTDIN(Filename);
526*0b57cec5SDimitry Andric   error(Filename, BuffOrErr.getError());
527*0b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
528*0b57cec5SDimitry Andric   return handleBuffer(Filename, *Buffer, HandleObj, OS);
529*0b57cec5SDimitry Andric }
530*0b57cec5SDimitry Andric 
531*0b57cec5SDimitry Andric /// If the input path is a .dSYM bundle (as created by the dsymutil tool),
532*0b57cec5SDimitry Andric /// replace it with individual entries for each of the object files inside the
533*0b57cec5SDimitry Andric /// bundle otherwise return the input path.
534*0b57cec5SDimitry Andric static std::vector<std::string> expandBundle(const std::string &InputPath) {
535*0b57cec5SDimitry Andric   std::vector<std::string> BundlePaths;
536*0b57cec5SDimitry Andric   SmallString<256> BundlePath(InputPath);
537*0b57cec5SDimitry Andric   // Normalize input path. This is necessary to accept `bundle.dSYM/`.
538*0b57cec5SDimitry Andric   sys::path::remove_dots(BundlePath);
539*0b57cec5SDimitry Andric   // Manually open up the bundle to avoid introducing additional dependencies.
540*0b57cec5SDimitry Andric   if (sys::fs::is_directory(BundlePath) &&
541*0b57cec5SDimitry Andric       sys::path::extension(BundlePath) == ".dSYM") {
542*0b57cec5SDimitry Andric     std::error_code EC;
543*0b57cec5SDimitry Andric     sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
544*0b57cec5SDimitry Andric     for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
545*0b57cec5SDimitry Andric          Dir != DirEnd && !EC; Dir.increment(EC)) {
546*0b57cec5SDimitry Andric       const std::string &Path = Dir->path();
547*0b57cec5SDimitry Andric       sys::fs::file_status Status;
548*0b57cec5SDimitry Andric       EC = sys::fs::status(Path, Status);
549*0b57cec5SDimitry Andric       error(Path, EC);
550*0b57cec5SDimitry Andric       switch (Status.type()) {
551*0b57cec5SDimitry Andric       case sys::fs::file_type::regular_file:
552*0b57cec5SDimitry Andric       case sys::fs::file_type::symlink_file:
553*0b57cec5SDimitry Andric       case sys::fs::file_type::type_unknown:
554*0b57cec5SDimitry Andric         BundlePaths.push_back(Path);
555*0b57cec5SDimitry Andric         break;
556*0b57cec5SDimitry Andric       default: /*ignore*/;
557*0b57cec5SDimitry Andric       }
558*0b57cec5SDimitry Andric     }
559*0b57cec5SDimitry Andric     error(BundlePath, EC);
560*0b57cec5SDimitry Andric   }
561*0b57cec5SDimitry Andric   if (!BundlePaths.size())
562*0b57cec5SDimitry Andric     BundlePaths.push_back(InputPath);
563*0b57cec5SDimitry Andric   return BundlePaths;
564*0b57cec5SDimitry Andric }
565*0b57cec5SDimitry Andric 
566*0b57cec5SDimitry Andric int main(int argc, char **argv) {
567*0b57cec5SDimitry Andric   InitLLVM X(argc, argv);
568*0b57cec5SDimitry Andric 
569*0b57cec5SDimitry Andric   llvm::InitializeAllTargetInfos();
570*0b57cec5SDimitry Andric   llvm::InitializeAllTargetMCs();
571*0b57cec5SDimitry Andric 
572*0b57cec5SDimitry Andric   HideUnrelatedOptions({&DwarfDumpCategory, &SectionCategory, &ColorCategory});
573*0b57cec5SDimitry Andric   cl::ParseCommandLineOptions(
574*0b57cec5SDimitry Andric       argc, argv,
575*0b57cec5SDimitry Andric       "pretty-print DWARF debug information in object files"
576*0b57cec5SDimitry Andric       " and debug info archives.\n");
577*0b57cec5SDimitry Andric 
578*0b57cec5SDimitry Andric   // FIXME: Audit interactions between these two options and make them
579*0b57cec5SDimitry Andric   //        compatible.
580*0b57cec5SDimitry Andric   if (Diff && Verbose) {
581*0b57cec5SDimitry Andric     WithColor::error() << "incompatible arguments: specifying both -diff and "
582*0b57cec5SDimitry Andric                           "-verbose is currently not supported";
583*0b57cec5SDimitry Andric     return 0;
584*0b57cec5SDimitry Andric   }
585*0b57cec5SDimitry Andric 
586*0b57cec5SDimitry Andric   std::error_code EC;
587*0b57cec5SDimitry Andric   ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None);
588*0b57cec5SDimitry Andric   error("Unable to open output file" + OutputFilename, EC);
589*0b57cec5SDimitry Andric   // Don't remove output file if we exit with an error.
590*0b57cec5SDimitry Andric   OutputFile.keep();
591*0b57cec5SDimitry Andric 
592*0b57cec5SDimitry Andric   bool OffsetRequested = false;
593*0b57cec5SDimitry Andric 
594*0b57cec5SDimitry Andric   // Defaults to dumping all sections, unless brief mode is specified in which
595*0b57cec5SDimitry Andric   // case only the .debug_info section in dumped.
596*0b57cec5SDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME)                \
597*0b57cec5SDimitry Andric   if (Dump##ENUM_NAME.IsRequested) {                                           \
598*0b57cec5SDimitry Andric     DumpType |= DIDT_##ENUM_NAME;                                              \
599*0b57cec5SDimitry Andric     if (Dump##ENUM_NAME.HasValue) {                                            \
600*0b57cec5SDimitry Andric       DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val;                  \
601*0b57cec5SDimitry Andric       OffsetRequested = true;                                                  \
602*0b57cec5SDimitry Andric     }                                                                          \
603*0b57cec5SDimitry Andric   }
604*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def"
605*0b57cec5SDimitry Andric #undef HANDLE_DWARF_SECTION
606*0b57cec5SDimitry Andric   if (DumpUUID)
607*0b57cec5SDimitry Andric     DumpType |= DIDT_UUID;
608*0b57cec5SDimitry Andric   if (DumpAll)
609*0b57cec5SDimitry Andric     DumpType = DIDT_All;
610*0b57cec5SDimitry Andric   if (DumpType == DIDT_Null) {
611*0b57cec5SDimitry Andric     if (Verbose)
612*0b57cec5SDimitry Andric       DumpType = DIDT_All;
613*0b57cec5SDimitry Andric     else
614*0b57cec5SDimitry Andric       DumpType = DIDT_DebugInfo;
615*0b57cec5SDimitry Andric   }
616*0b57cec5SDimitry Andric 
617*0b57cec5SDimitry Andric   // Unless dumping a specific DIE, default to --show-children.
618*0b57cec5SDimitry Andric   if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() && Find.empty())
619*0b57cec5SDimitry Andric     ShowChildren = true;
620*0b57cec5SDimitry Andric 
621*0b57cec5SDimitry Andric   // Defaults to a.out if no filenames specified.
622*0b57cec5SDimitry Andric   if (InputFilenames.empty())
623*0b57cec5SDimitry Andric     InputFilenames.push_back("a.out");
624*0b57cec5SDimitry Andric 
625*0b57cec5SDimitry Andric   // Expand any .dSYM bundles to the individual object files contained therein.
626*0b57cec5SDimitry Andric   std::vector<std::string> Objects;
627*0b57cec5SDimitry Andric   for (const auto &F : InputFilenames) {
628*0b57cec5SDimitry Andric     auto Objs = expandBundle(F);
629*0b57cec5SDimitry Andric     Objects.insert(Objects.end(), Objs.begin(), Objs.end());
630*0b57cec5SDimitry Andric   }
631*0b57cec5SDimitry Andric 
632*0b57cec5SDimitry Andric   if (Verify) {
633*0b57cec5SDimitry Andric     // If we encountered errors during verify, exit with a non-zero exit status.
634*0b57cec5SDimitry Andric     if (!all_of(Objects, [&](std::string Object) {
635*0b57cec5SDimitry Andric           return handleFile(Object, verifyObjectFile, OutputFile.os());
636*0b57cec5SDimitry Andric         }))
637*0b57cec5SDimitry Andric       return 1;
638*0b57cec5SDimitry Andric   } else if (Statistics)
639*0b57cec5SDimitry Andric     for (auto Object : Objects)
640*0b57cec5SDimitry Andric       handleFile(Object, collectStatsForObjectFile, OutputFile.os());
641*0b57cec5SDimitry Andric   else
642*0b57cec5SDimitry Andric     for (auto Object : Objects)
643*0b57cec5SDimitry Andric       handleFile(Object, dumpObjectFile, OutputFile.os());
644*0b57cec5SDimitry Andric 
645*0b57cec5SDimitry Andric   return EXIT_SUCCESS;
646*0b57cec5SDimitry Andric }
647