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