summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp')
-rw-r--r--llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp646
1 files changed, 646 insertions, 0 deletions
diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
new file mode 100644
index 000000000000..e20f6041f98d
--- /dev/null
+++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -0,0 +1,646 @@
+//===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that works like "dwarfdump".
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace object;
+
+/// Parser for options that take an optional offest argument.
+/// @{
+struct OffsetOption {
+ uint64_t Val = 0;
+ bool HasValue = false;
+ bool IsRequested = false;
+};
+
+namespace llvm {
+namespace cl {
+template <>
+class parser<OffsetOption> final : public basic_parser<OffsetOption> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ /// Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, OffsetOption &Val) {
+ if (Arg == "") {
+ Val.Val = 0;
+ Val.HasValue = false;
+ Val.IsRequested = true;
+ return false;
+ }
+ if (Arg.getAsInteger(0, Val.Val))
+ return O.error("'" + Arg + "' value invalid for integer argument!");
+ Val.HasValue = true;
+ Val.IsRequested = true;
+ return false;
+ }
+
+ enum ValueExpected getValueExpectedFlagDefault() const {
+ return ValueOptional;
+ }
+
+ void printOptionInfo(const Option &O, size_t GlobalWidth) const {
+ outs() << " -" << O.ArgStr;
+ Option::printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
+ }
+
+ void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,
+ size_t GlobalWidth) const {
+ printOptionName(O, GlobalWidth);
+ outs() << "[=offset]";
+ }
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override {};
+};
+} // cl
+} // llvm
+
+/// @}
+/// Command line options.
+/// @{
+
+namespace {
+using namespace cl;
+
+OptionCategory DwarfDumpCategory("Specific Options");
+static list<std::string>
+ InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
+ ZeroOrMore, cat(DwarfDumpCategory));
+
+cl::OptionCategory SectionCategory("Section-specific Dump Options",
+ "These control which sections are dumped. "
+ "Where applicable these parameters take an "
+ "optional =<offset> argument to dump only "
+ "the entry at the specified offset.");
+
+static opt<bool> DumpAll("all", desc("Dump all debug info sections"),
+ cat(SectionCategory));
+static alias DumpAllAlias("a", desc("Alias for -all"), aliasopt(DumpAll));
+
+// Options for dumping specific sections.
+static unsigned DumpType = DIDT_Null;
+static std::array<llvm::Optional<uint64_t>, (unsigned)DIDT_ID_Count>
+ DumpOffsets;
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
+ static opt<OffsetOption> Dump##ENUM_NAME( \
+ CMDLINE_NAME, desc("Dump the " ELF_NAME " section"), \
+ cat(SectionCategory));
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+
+static alias DumpDebugFrameAlias("eh-frame", desc("Alias for -debug-frame"),
+ NotHidden, cat(SectionCategory),
+ aliasopt(DumpDebugFrame));
+static list<std::string>
+ ArchFilters("arch",
+ desc("Dump debug information for the specified CPU "
+ "architecture only. Architectures may be specified by "
+ "name or by number. This option can be specified "
+ "multiple times, once for each desired architecture."),
+ cat(DwarfDumpCategory));
+static opt<bool>
+ Diff("diff",
+ desc("Emit diff-friendly output by omitting offsets and addresses."),
+ cat(DwarfDumpCategory));
+static list<std::string>
+ Find("find",
+ desc("Search for the exact match for <name> in the accelerator tables "
+ "and print the matching debug information entries. When no "
+ "accelerator tables are available, the slower but more complete "
+ "-name option can be used instead."),
+ value_desc("name"), cat(DwarfDumpCategory));
+static alias FindAlias("f", desc("Alias for -find."), aliasopt(Find));
+static opt<bool> IgnoreCase("ignore-case",
+ desc("Ignore case distinctions when searching."),
+ value_desc("i"), cat(DwarfDumpCategory));
+static alias IgnoreCaseAlias("i", desc("Alias for -ignore-case."),
+ aliasopt(IgnoreCase));
+static list<std::string> Name(
+ "name",
+ desc("Find and print all debug info entries whose name (DW_AT_name "
+ "attribute) matches the exact text in <pattern>. When used with the "
+ "the -regex option <pattern> is interpreted as a regular expression."),
+ value_desc("pattern"), cat(DwarfDumpCategory));
+static alias NameAlias("n", desc("Alias for -name"), aliasopt(Name));
+static opt<uint64_t>
+ Lookup("lookup",
+ desc("Lookup <address> in the debug information and print out any "
+ "available file, function, block and line table details."),
+ value_desc("address"), cat(DwarfDumpCategory));
+static opt<std::string>
+ OutputFilename("o", cl::init("-"),
+ cl::desc("Redirect output to the specified file."),
+ cl::value_desc("filename"), cat(DwarfDumpCategory));
+static alias OutputFilenameAlias("out-file", desc("Alias for -o."),
+ aliasopt(OutputFilename));
+static opt<bool>
+ UseRegex("regex",
+ desc("Treat any <pattern> strings as regular expressions when "
+ "searching instead of just as an exact string match."),
+ cat(DwarfDumpCategory));
+static alias RegexAlias("x", desc("Alias for -regex"), aliasopt(UseRegex));
+static opt<bool>
+ ShowChildren("show-children",
+ desc("Show a debug info entry's children when selectively "
+ "printing entries."),
+ cat(DwarfDumpCategory));
+static alias ShowChildrenAlias("c", desc("Alias for -show-children."),
+ aliasopt(ShowChildren));
+static opt<bool>
+ ShowParents("show-parents",
+ desc("Show a debug info entry's parents when selectively "
+ "printing entries."),
+ cat(DwarfDumpCategory));
+static alias ShowParentsAlias("p", desc("Alias for -show-parents."),
+ aliasopt(ShowParents));
+static opt<bool>
+ ShowForm("show-form",
+ desc("Show DWARF form types after the DWARF attribute types."),
+ cat(DwarfDumpCategory));
+static alias ShowFormAlias("F", desc("Alias for -show-form."),
+ aliasopt(ShowForm), cat(DwarfDumpCategory));
+static opt<unsigned>
+ ChildRecurseDepth("recurse-depth",
+ desc("Only recurse to a depth of N when displaying "
+ "children of debug info entries."),
+ cat(DwarfDumpCategory), init(-1U), value_desc("N"));
+static alias ChildRecurseDepthAlias("r", desc("Alias for -recurse-depth."),
+ aliasopt(ChildRecurseDepth));
+static opt<unsigned>
+ ParentRecurseDepth("parent-recurse-depth",
+ desc("Only recurse to a depth of N when displaying "
+ "parents of debug info entries."),
+ cat(DwarfDumpCategory), init(-1U), value_desc("N"));
+static opt<bool>
+ SummarizeTypes("summarize-types",
+ desc("Abbreviate the description of type unit entries."),
+ cat(DwarfDumpCategory));
+static cl::opt<bool>
+ Statistics("statistics",
+ cl::desc("Emit JSON-formatted debug info quality metrics."),
+ cat(DwarfDumpCategory));
+static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
+ cat(DwarfDumpCategory));
+static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
+ cat(DwarfDumpCategory));
+static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),
+ cat(DwarfDumpCategory));
+static alias DumpUUIDAlias("u", desc("Alias for -uuid."), aliasopt(DumpUUID));
+static opt<bool> Verbose("verbose",
+ desc("Print more low-level encoding details."),
+ cat(DwarfDumpCategory));
+static alias VerboseAlias("v", desc("Alias for -verbose."), aliasopt(Verbose),
+ cat(DwarfDumpCategory));
+static cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
+} // namespace
+/// @}
+//===----------------------------------------------------------------------===//
+
+static void error(StringRef Prefix, std::error_code EC) {
+ if (!EC)
+ return;
+ WithColor::error() << Prefix << ": " << EC.message() << "\n";
+ exit(1);
+}
+
+static DIDumpOptions getDumpOpts() {
+ DIDumpOptions DumpOpts;
+ DumpOpts.DumpType = DumpType;
+ DumpOpts.ChildRecurseDepth = ChildRecurseDepth;
+ DumpOpts.ParentRecurseDepth = ParentRecurseDepth;
+ DumpOpts.ShowAddresses = !Diff;
+ DumpOpts.ShowChildren = ShowChildren;
+ DumpOpts.ShowParents = ShowParents;
+ DumpOpts.ShowForm = ShowForm;
+ DumpOpts.SummarizeTypes = SummarizeTypes;
+ DumpOpts.Verbose = Verbose;
+ // In -verify mode, print DIEs without children in error messages.
+ if (Verify)
+ return DumpOpts.noImplicitRecursion();
+ return DumpOpts;
+}
+
+static uint32_t getCPUType(MachOObjectFile &MachO) {
+ if (MachO.is64Bit())
+ return MachO.getHeader64().cputype;
+ else
+ return MachO.getHeader().cputype;
+}
+
+/// Return true if the object file has not been filtered by an --arch option.
+static bool filterArch(ObjectFile &Obj) {
+ if (ArchFilters.empty())
+ return true;
+
+ if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
+ for (auto Arch : ArchFilters) {
+ // Match architecture number.
+ unsigned Value;
+ if (!StringRef(Arch).getAsInteger(0, Value))
+ if (Value == getCPUType(*MachO))
+ return true;
+
+ // Match as name.
+ if (MachO->getArchTriple().getArch() == Triple(Arch).getArch())
+ return true;
+ }
+ }
+ return false;
+}
+
+using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx, Twine,
+ raw_ostream &)>;
+
+/// Print only DIEs that have a certain name.
+static bool filterByName(const StringSet<> &Names, DWARFDie Die,
+ StringRef NameRef, raw_ostream &OS) {
+ std::string Name =
+ (IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();
+ if (UseRegex) {
+ // Match regular expression.
+ for (auto Pattern : Names.keys()) {
+ Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags);
+ std::string Error;
+ if (!RE.isValid(Error)) {
+ errs() << "error in regular expression: " << Error << "\n";
+ exit(1);
+ }
+ if (RE.match(Name)) {
+ Die.dump(OS, 0, getDumpOpts());
+ return true;
+ }
+ }
+ } else if (Names.count(Name)) {
+ // Match full text.
+ Die.dump(OS, 0, getDumpOpts());
+ return true;
+ }
+ return false;
+}
+
+/// Print only DIEs that have a certain name.
+static void filterByName(const StringSet<> &Names,
+ DWARFContext::unit_iterator_range CUs,
+ raw_ostream &OS) {
+ for (const auto &CU : CUs)
+ for (const auto &Entry : CU->dies()) {
+ DWARFDie Die = {CU.get(), &Entry};
+ if (const char *Name = Die.getName(DINameKind::ShortName))
+ if (filterByName(Names, Die, Name, OS))
+ continue;
+ if (const char *Name = Die.getName(DINameKind::LinkageName))
+ filterByName(Names, Die, Name, OS);
+ }
+}
+
+static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
+ StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
+ for (const auto &Entry : Accel.equal_range(Name)) {
+ if (llvm::Optional<uint64_t> Off = Entry.getDIESectionOffset()) {
+ if (DWARFDie Die = DICtx.getDIEForOffset(*Off))
+ Dies.push_back(Die);
+ }
+ }
+}
+
+static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,
+ DWARFContext &DICtx) {
+ llvm::Optional<uint64_t> CUOff = Entry.getCUOffset();
+ llvm::Optional<uint64_t> Off = Entry.getDIEUnitOffset();
+ if (!CUOff || !Off)
+ return DWARFDie();
+
+ DWARFCompileUnit *CU = DICtx.getCompileUnitForOffset(*CUOff);
+ if (!CU)
+ return DWARFDie();
+
+ if (llvm::Optional<uint64_t> DWOId = CU->getDWOId()) {
+ // This is a skeleton unit. Look up the DIE in the DWO unit.
+ CU = DICtx.getDWOCompileUnitForHash(*DWOId);
+ if (!CU)
+ return DWARFDie();
+ }
+
+ return CU->getDIEForOffset(CU->getOffset() + *Off);
+}
+
+static void getDies(DWARFContext &DICtx, const DWARFDebugNames &Accel,
+ StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
+ for (const auto &Entry : Accel.equal_range(Name)) {
+ if (DWARFDie Die = toDie(Entry, DICtx))
+ Dies.push_back(Die);
+ }
+}
+
+/// Print only DIEs that have a certain name.
+static void filterByAccelName(ArrayRef<std::string> Names, DWARFContext &DICtx,
+ raw_ostream &OS) {
+ SmallVector<DWARFDie, 4> Dies;
+ for (const auto &Name : Names) {
+ getDies(DICtx, DICtx.getAppleNames(), Name, Dies);
+ getDies(DICtx, DICtx.getAppleTypes(), Name, Dies);
+ getDies(DICtx, DICtx.getAppleNamespaces(), Name, Dies);
+ getDies(DICtx, DICtx.getDebugNames(), Name, Dies);
+ }
+ llvm::sort(Dies);
+ Dies.erase(std::unique(Dies.begin(), Dies.end()), Dies.end());
+
+ for (DWARFDie Die : Dies)
+ Die.dump(OS, 0, getDumpOpts());
+}
+
+/// Handle the --lookup option and dump the DIEs and line info for the given
+/// address.
+/// TODO: specified Address for --lookup option could relate for several
+/// different sections(in case not-linked object file). llvm-dwarfdump
+/// need to do something with this: extend lookup option with section
+/// information or probably display all matched entries, or something else...
+static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
+ raw_ostream &OS) {
+ auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup);
+
+ if (!DIEsForAddr)
+ return false;
+
+ DIDumpOptions DumpOpts = getDumpOpts();
+ DumpOpts.ChildRecurseDepth = 0;
+ DIEsForAddr.CompileUnit->dump(OS, DumpOpts);
+ if (DIEsForAddr.FunctionDIE) {
+ DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);
+ if (DIEsForAddr.BlockDIE)
+ DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);
+ }
+
+ // TODO: it is neccessary to set proper SectionIndex here.
+ // object::SectionedAddress::UndefSection works for only absolute addresses.
+ if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
+ {Lookup, object::SectionedAddress::UndefSection}))
+ LineInfo.dump(OS);
+
+ return true;
+}
+
+bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
+ Twine Filename, raw_ostream &OS);
+
+static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename,
+ raw_ostream &OS) {
+ logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(),
+ Filename.str() + ": ");
+ // The UUID dump already contains all the same information.
+ if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
+ OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
+
+ // Handle the --lookup option.
+ if (Lookup)
+ return lookup(Obj, DICtx, Lookup, OS);
+
+ // Handle the --name option.
+ if (!Name.empty()) {
+ StringSet<> Names;
+ for (auto name : Name)
+ Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
+
+ filterByName(Names, DICtx.normal_units(), OS);
+ filterByName(Names, DICtx.dwo_units(), OS);
+ return true;
+ }
+
+ // Handle the --find option and lower it to --debug-info=<offset>.
+ if (!Find.empty()) {
+ filterByAccelName(Find, DICtx, OS);
+ return true;
+ }
+
+ // Dump the complete DWARF structure.
+ DICtx.dump(OS, getDumpOpts(), DumpOffsets);
+ return true;
+}
+
+static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
+ Twine Filename, raw_ostream &OS) {
+ // Verify the DWARF and exit with non-zero exit status if verification
+ // fails.
+ raw_ostream &stream = Quiet ? nulls() : OS;
+ stream << "Verifying " << Filename.str() << ":\tfile format "
+ << Obj.getFileFormatName() << "\n";
+ bool Result = DICtx.verify(stream, getDumpOpts());
+ if (Result)
+ stream << "No errors.\n";
+ else
+ stream << "Errors detected.\n";
+ return Result;
+}
+
+static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
+ HandlerFn HandleObj, raw_ostream &OS);
+
+static bool handleArchive(StringRef Filename, Archive &Arch,
+ HandlerFn HandleObj, raw_ostream &OS) {
+ bool Result = true;
+ Error Err = Error::success();
+ for (auto Child : Arch.children(Err)) {
+ auto BuffOrErr = Child.getMemoryBufferRef();
+ error(Filename, errorToErrorCode(BuffOrErr.takeError()));
+ auto NameOrErr = Child.getName();
+ error(Filename, errorToErrorCode(NameOrErr.takeError()));
+ std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
+ Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);
+ }
+ error(Filename, errorToErrorCode(std::move(Err)));
+
+ return Result;
+}
+
+static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
+ HandlerFn HandleObj, raw_ostream &OS) {
+ Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
+ error(Filename, errorToErrorCode(BinOrErr.takeError()));
+
+ bool Result = true;
+ if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
+ if (filterArch(*Obj)) {
+ std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(*Obj);
+ Result = HandleObj(*Obj, *DICtx, Filename, OS);
+ }
+ }
+ else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
+ for (auto &ObjForArch : Fat->objects()) {
+ std::string ObjName =
+ (Filename + "(" + ObjForArch.getArchFlagName() + ")").str();
+ if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {
+ auto &Obj = **MachOOrErr;
+ if (filterArch(Obj)) {
+ std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(Obj);
+ Result &= HandleObj(Obj, *DICtx, ObjName, OS);
+ }
+ continue;
+ } else
+ consumeError(MachOOrErr.takeError());
+ if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {
+ error(ObjName, errorToErrorCode(ArchiveOrErr.takeError()));
+ Result &= handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS);
+ continue;
+ } else
+ consumeError(ArchiveOrErr.takeError());
+ }
+ else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))
+ Result = handleArchive(Filename, *Arch, HandleObj, OS);
+ return Result;
+}
+
+static bool handleFile(StringRef Filename, HandlerFn HandleObj,
+ raw_ostream &OS) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ error(Filename, BuffOrErr.getError());
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
+ return handleBuffer(Filename, *Buffer, HandleObj, OS);
+}
+
+/// If the input path is a .dSYM bundle (as created by the dsymutil tool),
+/// replace it with individual entries for each of the object files inside the
+/// bundle otherwise return the input path.
+static std::vector<std::string> expandBundle(const std::string &InputPath) {
+ std::vector<std::string> BundlePaths;
+ SmallString<256> BundlePath(InputPath);
+ // Normalize input path. This is necessary to accept `bundle.dSYM/`.
+ sys::path::remove_dots(BundlePath);
+ // Manually open up the bundle to avoid introducing additional dependencies.
+ if (sys::fs::is_directory(BundlePath) &&
+ sys::path::extension(BundlePath) == ".dSYM") {
+ std::error_code EC;
+ sys::path::append(BundlePath, "Contents", "Resources", "DWARF");
+ for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ const std::string &Path = Dir->path();
+ sys::fs::file_status Status;
+ EC = sys::fs::status(Path, Status);
+ error(Path, EC);
+ switch (Status.type()) {
+ case sys::fs::file_type::regular_file:
+ case sys::fs::file_type::symlink_file:
+ case sys::fs::file_type::type_unknown:
+ BundlePaths.push_back(Path);
+ break;
+ default: /*ignore*/;
+ }
+ }
+ error(BundlePath, EC);
+ }
+ if (!BundlePaths.size())
+ BundlePaths.push_back(InputPath);
+ return BundlePaths;
+}
+
+int main(int argc, char **argv) {
+ InitLLVM X(argc, argv);
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+
+ HideUnrelatedOptions({&DwarfDumpCategory, &SectionCategory, &ColorCategory});
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "pretty-print DWARF debug information in object files"
+ " and debug info archives.\n");
+
+ // FIXME: Audit interactions between these two options and make them
+ // compatible.
+ if (Diff && Verbose) {
+ WithColor::error() << "incompatible arguments: specifying both -diff and "
+ "-verbose is currently not supported";
+ return 0;
+ }
+
+ std::error_code EC;
+ ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_Text);
+ error("Unable to open output file" + OutputFilename, EC);
+ // Don't remove output file if we exit with an error.
+ OutputFile.keep();
+
+ bool OffsetRequested = false;
+
+ // Defaults to dumping all sections, unless brief mode is specified in which
+ // case only the .debug_info section in dumped.
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \
+ if (Dump##ENUM_NAME.IsRequested) { \
+ DumpType |= DIDT_##ENUM_NAME; \
+ if (Dump##ENUM_NAME.HasValue) { \
+ DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val; \
+ OffsetRequested = true; \
+ } \
+ }
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+ if (DumpUUID)
+ DumpType |= DIDT_UUID;
+ if (DumpAll)
+ DumpType = DIDT_All;
+ if (DumpType == DIDT_Null) {
+ if (Verbose)
+ DumpType = DIDT_All;
+ else
+ DumpType = DIDT_DebugInfo;
+ }
+
+ // Unless dumping a specific DIE, default to --show-children.
+ if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() && Find.empty())
+ ShowChildren = true;
+
+ // Defaults to a.out if no filenames specified.
+ if (InputFilenames.empty())
+ InputFilenames.push_back("a.out");
+
+ // Expand any .dSYM bundles to the individual object files contained therein.
+ std::vector<std::string> Objects;
+ for (const auto &F : InputFilenames) {
+ auto Objs = expandBundle(F);
+ Objects.insert(Objects.end(), Objs.begin(), Objs.end());
+ }
+
+ if (Verify) {
+ // If we encountered errors during verify, exit with a non-zero exit status.
+ if (!all_of(Objects, [&](std::string Object) {
+ return handleFile(Object, verifyObjectFile, OutputFile.os());
+ }))
+ return 1;
+ } else if (Statistics)
+ for (auto Object : Objects)
+ handleFile(Object, collectStatsForObjectFile, OutputFile.os());
+ else
+ for (auto Object : Objects)
+ handleFile(Object, dumpObjectFile, OutputFile.os());
+
+ return EXIT_SUCCESS;
+}