xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- llvm-dwarfdump.cpp - Debug info dumping utility for llvm ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This program is a utility that works like "dwarfdump".
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
135ffd83dbSDimitry Andric #include "llvm-dwarfdump.h"
1406c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1606c3fb27SDimitry Andric #include "llvm/ADT/SmallSet.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/DIContext.h"
1981ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
2081ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h"
22bdd1243dSDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
23bdd1243dSDimitry Andric #include "llvm/MC/TargetRegistry.h"
240b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
250b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
260b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
270b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include "llvm/Support/Format.h"
3006c3fb27SDimitry Andric #include "llvm/Support/FormatVariadic.h"
310b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
320b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
3381ad6265SDimitry Andric #include "llvm/Support/Path.h"
340b57cec5SDimitry Andric #include "llvm/Support/Regex.h"
350b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
360b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h"
370b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
380b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
3906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
405ffd83dbSDimitry Andric #include <cstdlib>
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric using namespace llvm;
435ffd83dbSDimitry Andric using namespace llvm::dwarfdump;
445ffd83dbSDimitry Andric using namespace llvm::object;
450b57cec5SDimitry Andric 
465ffd83dbSDimitry Andric namespace {
470b57cec5SDimitry Andric /// Parser for options that take an optional offest argument.
480b57cec5SDimitry Andric /// @{
490b57cec5SDimitry Andric struct OffsetOption {
500b57cec5SDimitry Andric   uint64_t Val = 0;
510b57cec5SDimitry Andric   bool HasValue = false;
520b57cec5SDimitry Andric   bool IsRequested = false;
530b57cec5SDimitry Andric };
545ffd83dbSDimitry Andric struct BoolOption : public OffsetOption {};
555ffd83dbSDimitry Andric } // namespace
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric namespace llvm {
580b57cec5SDimitry Andric namespace cl {
590b57cec5SDimitry Andric template <>
600b57cec5SDimitry Andric class parser<OffsetOption> final : public basic_parser<OffsetOption> {
610b57cec5SDimitry Andric public:
620b57cec5SDimitry Andric   parser(Option &O) : basic_parser(O) {}
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   /// Return true on error.
650b57cec5SDimitry Andric   bool parse(Option &O, StringRef ArgName, StringRef Arg, OffsetOption &Val) {
660b57cec5SDimitry Andric     if (Arg == "") {
670b57cec5SDimitry Andric       Val.Val = 0;
680b57cec5SDimitry Andric       Val.HasValue = false;
690b57cec5SDimitry Andric       Val.IsRequested = true;
700b57cec5SDimitry Andric       return false;
710b57cec5SDimitry Andric     }
720b57cec5SDimitry Andric     if (Arg.getAsInteger(0, Val.Val))
735ffd83dbSDimitry Andric       return O.error("'" + Arg + "' value invalid for integer argument");
740b57cec5SDimitry Andric     Val.HasValue = true;
750b57cec5SDimitry Andric     Val.IsRequested = true;
760b57cec5SDimitry Andric     return false;
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   enum ValueExpected getValueExpectedFlagDefault() const {
800b57cec5SDimitry Andric     return ValueOptional;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
835ffd83dbSDimitry Andric   StringRef getValueName() const override { return StringRef("offset"); }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,
860b57cec5SDimitry Andric                        size_t GlobalWidth) const {
870b57cec5SDimitry Andric     printOptionName(O, GlobalWidth);
880b57cec5SDimitry Andric     outs() << "[=offset]";
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric };
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric template <> class parser<BoolOption> final : public basic_parser<BoolOption> {
935ffd83dbSDimitry Andric public:
945ffd83dbSDimitry Andric   parser(Option &O) : basic_parser(O) {}
955ffd83dbSDimitry Andric 
965ffd83dbSDimitry Andric   /// Return true on error.
975ffd83dbSDimitry Andric   bool parse(Option &O, StringRef ArgName, StringRef Arg, BoolOption &Val) {
985ffd83dbSDimitry Andric     if (Arg != "")
995ffd83dbSDimitry Andric       return O.error("this is a flag and does not take a value");
1005ffd83dbSDimitry Andric     Val.Val = 0;
1015ffd83dbSDimitry Andric     Val.HasValue = false;
1025ffd83dbSDimitry Andric     Val.IsRequested = true;
1035ffd83dbSDimitry Andric     return false;
1045ffd83dbSDimitry Andric   }
1055ffd83dbSDimitry Andric 
1065ffd83dbSDimitry Andric   enum ValueExpected getValueExpectedFlagDefault() const {
1075ffd83dbSDimitry Andric     return ValueOptional;
1085ffd83dbSDimitry Andric   }
1095ffd83dbSDimitry Andric 
1105ffd83dbSDimitry Andric   StringRef getValueName() const override { return StringRef(); }
1115ffd83dbSDimitry Andric 
1125ffd83dbSDimitry Andric   void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,
1135ffd83dbSDimitry Andric                        size_t GlobalWidth) const {
1145ffd83dbSDimitry Andric     printOptionName(O, GlobalWidth);
1155ffd83dbSDimitry Andric   }
1165ffd83dbSDimitry Andric };
1175ffd83dbSDimitry Andric } // namespace cl
1185ffd83dbSDimitry Andric } // namespace llvm
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric /// @}
1210b57cec5SDimitry Andric /// Command line options.
1220b57cec5SDimitry Andric /// @{
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric namespace {
1250b57cec5SDimitry Andric using namespace cl;
1260b57cec5SDimitry Andric 
127*0fca6ea1SDimitry Andric enum ErrorDetailLevel {
128*0fca6ea1SDimitry Andric   OnlyDetailsNoSummary,
129*0fca6ea1SDimitry Andric   NoDetailsOnlySummary,
130*0fca6ea1SDimitry Andric   NoDetailsOrSummary,
131*0fca6ea1SDimitry Andric   BothDetailsAndSummary,
132*0fca6ea1SDimitry Andric   Unspecified
133*0fca6ea1SDimitry Andric };
134*0fca6ea1SDimitry Andric 
1350b57cec5SDimitry Andric OptionCategory DwarfDumpCategory("Specific Options");
1360b57cec5SDimitry Andric static list<std::string>
1370b57cec5SDimitry Andric     InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),
13881ad6265SDimitry Andric                    cat(DwarfDumpCategory));
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric cl::OptionCategory SectionCategory("Section-specific Dump Options",
1410b57cec5SDimitry Andric                                    "These control which sections are dumped. "
1420b57cec5SDimitry Andric                                    "Where applicable these parameters take an "
1430b57cec5SDimitry Andric                                    "optional =<offset> argument to dump only "
1440b57cec5SDimitry Andric                                    "the entry at the specified offset.");
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric static opt<bool> DumpAll("all", desc("Dump all debug info sections"),
1470b57cec5SDimitry Andric                          cat(SectionCategory));
148fe6060f1SDimitry Andric static alias DumpAllAlias("a", desc("Alias for --all"), aliasopt(DumpAll),
149fe6060f1SDimitry Andric                           cl::NotHidden);
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric // Options for dumping specific sections.
1520b57cec5SDimitry Andric static unsigned DumpType = DIDT_Null;
153bdd1243dSDimitry Andric static std::array<std::optional<uint64_t>, (unsigned)DIDT_ID_Count> DumpOffsets;
1545ffd83dbSDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
1555ffd83dbSDimitry Andric   static opt<OPTION> Dump##ENUM_NAME(CMDLINE_NAME,                             \
1565ffd83dbSDimitry Andric                                      desc("Dump the " ELF_NAME " section"),    \
1570b57cec5SDimitry Andric                                      cat(SectionCategory));
1580b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def"
1590b57cec5SDimitry Andric #undef HANDLE_DWARF_SECTION
1600b57cec5SDimitry Andric 
161fe6060f1SDimitry Andric // The aliased DumpDebugFrame is created by the Dwarf.def x-macro just above.
162fe6060f1SDimitry Andric static alias DumpDebugFrameAlias("eh-frame", desc("Alias for --debug-frame"),
1630b57cec5SDimitry Andric                                  NotHidden, cat(SectionCategory),
1640b57cec5SDimitry Andric                                  aliasopt(DumpDebugFrame));
1650b57cec5SDimitry Andric static list<std::string>
1660b57cec5SDimitry Andric     ArchFilters("arch",
1670b57cec5SDimitry Andric                 desc("Dump debug information for the specified CPU "
1680b57cec5SDimitry Andric                      "architecture only. Architectures may be specified by "
1690b57cec5SDimitry Andric                      "name or by number. This option can be specified "
1700b57cec5SDimitry Andric                      "multiple times, once for each desired architecture."),
1710b57cec5SDimitry Andric                 cat(DwarfDumpCategory));
1720b57cec5SDimitry Andric static opt<bool>
1730b57cec5SDimitry Andric     Diff("diff",
1740b57cec5SDimitry Andric          desc("Emit diff-friendly output by omitting offsets and addresses."),
1750b57cec5SDimitry Andric          cat(DwarfDumpCategory));
1760b57cec5SDimitry Andric static list<std::string>
1770b57cec5SDimitry Andric     Find("find",
1780b57cec5SDimitry Andric          desc("Search for the exact match for <name> in the accelerator tables "
1790b57cec5SDimitry Andric               "and print the matching debug information entries. When no "
1800b57cec5SDimitry Andric               "accelerator tables are available, the slower but more complete "
1810b57cec5SDimitry Andric               "-name option can be used instead."),
1820b57cec5SDimitry Andric          value_desc("name"), cat(DwarfDumpCategory));
183fe6060f1SDimitry Andric static alias FindAlias("f", desc("Alias for --find."), aliasopt(Find),
184fe6060f1SDimitry Andric                        cl::NotHidden);
18506c3fb27SDimitry Andric static opt<bool> FindAllApple(
18606c3fb27SDimitry Andric     "find-all-apple",
18706c3fb27SDimitry Andric     desc("Print every debug information entry in the accelerator tables."),
18806c3fb27SDimitry Andric     cat(DwarfDumpCategory));
1890b57cec5SDimitry Andric static opt<bool> IgnoreCase("ignore-case",
190349cc55cSDimitry Andric                             desc("Ignore case distinctions when using --name."),
1910b57cec5SDimitry Andric                             value_desc("i"), cat(DwarfDumpCategory));
1927a6dacacSDimitry Andric static opt<bool> DumpNonSkeleton(
1937a6dacacSDimitry Andric     "dwo",
1947a6dacacSDimitry Andric     desc("Dump the non skeleton DIE in the .dwo or .dwp file after dumping the "
1957a6dacacSDimitry Andric          "skeleton DIE from the main executable. This allows dumping the .dwo "
1967a6dacacSDimitry Andric          "files with resolved addresses."),
1977a6dacacSDimitry Andric     value_desc("d"), cat(DwarfDumpCategory));
1987a6dacacSDimitry Andric 
199fe6060f1SDimitry Andric static alias IgnoreCaseAlias("i", desc("Alias for --ignore-case."),
200fe6060f1SDimitry Andric                              aliasopt(IgnoreCase), cl::NotHidden);
2010b57cec5SDimitry Andric static list<std::string> Name(
2020b57cec5SDimitry Andric     "name",
2030b57cec5SDimitry Andric     desc("Find and print all debug info entries whose name (DW_AT_name "
2040b57cec5SDimitry Andric          "attribute) matches the exact text in <pattern>.  When used with the "
2050b57cec5SDimitry Andric          "the -regex option <pattern> is interpreted as a regular expression."),
2060b57cec5SDimitry Andric     value_desc("pattern"), cat(DwarfDumpCategory));
207fe6060f1SDimitry Andric static alias NameAlias("n", desc("Alias for --name"), aliasopt(Name),
208fe6060f1SDimitry Andric                        cl::NotHidden);
2090b57cec5SDimitry Andric static opt<uint64_t>
2100b57cec5SDimitry Andric     Lookup("lookup",
2110b57cec5SDimitry Andric            desc("Lookup <address> in the debug information and print out any "
2120b57cec5SDimitry Andric                 "available file, function, block and line table details."),
2130b57cec5SDimitry Andric            value_desc("address"), cat(DwarfDumpCategory));
2140b57cec5SDimitry Andric static opt<std::string>
2150b57cec5SDimitry Andric     OutputFilename("o", cl::init("-"),
2160b57cec5SDimitry Andric                    cl::desc("Redirect output to the specified file."),
2170b57cec5SDimitry Andric                    cl::value_desc("filename"), cat(DwarfDumpCategory));
2180b57cec5SDimitry Andric static alias OutputFilenameAlias("out-file", desc("Alias for -o."),
2190b57cec5SDimitry Andric                                  aliasopt(OutputFilename));
220349cc55cSDimitry Andric static opt<bool> UseRegex(
221349cc55cSDimitry Andric     "regex",
222349cc55cSDimitry Andric     desc("Treat any <pattern> strings as regular "
223349cc55cSDimitry Andric          "expressions when searching with --name. If --ignore-case is also "
224349cc55cSDimitry Andric          "specified, the regular expression becomes case-insensitive."),
2250b57cec5SDimitry Andric     cat(DwarfDumpCategory));
226fe6060f1SDimitry Andric static alias RegexAlias("x", desc("Alias for --regex"), aliasopt(UseRegex),
227fe6060f1SDimitry Andric                         cl::NotHidden);
2280b57cec5SDimitry Andric static opt<bool>
2290b57cec5SDimitry Andric     ShowChildren("show-children",
2300b57cec5SDimitry Andric                  desc("Show a debug info entry's children when selectively "
2310b57cec5SDimitry Andric                       "printing entries."),
2320b57cec5SDimitry Andric                  cat(DwarfDumpCategory));
233fe6060f1SDimitry Andric static alias ShowChildrenAlias("c", desc("Alias for --show-children."),
234fe6060f1SDimitry Andric                                aliasopt(ShowChildren), cl::NotHidden);
2350b57cec5SDimitry Andric static opt<bool>
2360b57cec5SDimitry Andric     ShowParents("show-parents",
2370b57cec5SDimitry Andric                 desc("Show a debug info entry's parents when selectively "
2380b57cec5SDimitry Andric                      "printing entries."),
2390b57cec5SDimitry Andric                 cat(DwarfDumpCategory));
240fe6060f1SDimitry Andric static alias ShowParentsAlias("p", desc("Alias for --show-parents."),
241fe6060f1SDimitry Andric                               aliasopt(ShowParents), cl::NotHidden);
2420b57cec5SDimitry Andric static opt<bool>
2430b57cec5SDimitry Andric     ShowForm("show-form",
2440b57cec5SDimitry Andric              desc("Show DWARF form types after the DWARF attribute types."),
2450b57cec5SDimitry Andric              cat(DwarfDumpCategory));
246fe6060f1SDimitry Andric static alias ShowFormAlias("F", desc("Alias for --show-form."),
247fe6060f1SDimitry Andric                            aliasopt(ShowForm), cat(DwarfDumpCategory),
248fe6060f1SDimitry Andric                            cl::NotHidden);
2490b57cec5SDimitry Andric static opt<unsigned>
2500b57cec5SDimitry Andric     ChildRecurseDepth("recurse-depth",
2510b57cec5SDimitry Andric                       desc("Only recurse to a depth of N when displaying "
2520b57cec5SDimitry Andric                            "children of debug info entries."),
2530b57cec5SDimitry Andric                       cat(DwarfDumpCategory), init(-1U), value_desc("N"));
254fe6060f1SDimitry Andric static alias ChildRecurseDepthAlias("r", desc("Alias for --recurse-depth."),
255fe6060f1SDimitry Andric                                     aliasopt(ChildRecurseDepth), cl::NotHidden);
2560b57cec5SDimitry Andric static opt<unsigned>
2570b57cec5SDimitry Andric     ParentRecurseDepth("parent-recurse-depth",
2580b57cec5SDimitry Andric                        desc("Only recurse to a depth of N when displaying "
2590b57cec5SDimitry Andric                             "parents of debug info entries."),
2600b57cec5SDimitry Andric                        cat(DwarfDumpCategory), init(-1U), value_desc("N"));
2610b57cec5SDimitry Andric static opt<bool>
2620b57cec5SDimitry Andric     SummarizeTypes("summarize-types",
2630b57cec5SDimitry Andric                    desc("Abbreviate the description of type unit entries."),
2640b57cec5SDimitry Andric                    cat(DwarfDumpCategory));
2650b57cec5SDimitry Andric static cl::opt<bool>
2660b57cec5SDimitry Andric     Statistics("statistics",
2670b57cec5SDimitry Andric                cl::desc("Emit JSON-formatted debug info quality metrics."),
2680b57cec5SDimitry Andric                cat(DwarfDumpCategory));
2695ffd83dbSDimitry Andric static cl::opt<bool>
2705ffd83dbSDimitry Andric     ShowSectionSizes("show-section-sizes",
2715ffd83dbSDimitry Andric                      cl::desc("Show the sizes of all debug sections, "
2725ffd83dbSDimitry Andric                               "expressed in bytes."),
2735ffd83dbSDimitry Andric                      cat(DwarfDumpCategory));
274bdd1243dSDimitry Andric static cl::opt<bool> ManuallyGenerateUnitIndex(
275bdd1243dSDimitry Andric     "manaully-generate-unit-index",
276bdd1243dSDimitry Andric     cl::desc("if the input is dwp file, parse .debug_info "
277bdd1243dSDimitry Andric              "section and use it to populate "
278bdd1243dSDimitry Andric              "DW_SECT_INFO contributions in cu-index. "
279bdd1243dSDimitry Andric              "For DWARF5 it also populated TU Index."),
280bdd1243dSDimitry Andric     cl::init(false), cl::Hidden, cl::cat(DwarfDumpCategory));
28181ad6265SDimitry Andric static cl::opt<bool>
28281ad6265SDimitry Andric     ShowSources("show-sources",
28381ad6265SDimitry Andric                 cl::desc("Show the sources across all compilation units."),
28481ad6265SDimitry Andric                 cat(DwarfDumpCategory));
2850b57cec5SDimitry Andric static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),
2860b57cec5SDimitry Andric                         cat(DwarfDumpCategory));
287*0fca6ea1SDimitry Andric static opt<ErrorDetailLevel> ErrorDetails(
288*0fca6ea1SDimitry Andric     "error-display", init(Unspecified),
289*0fca6ea1SDimitry Andric     desc("Set the level of detail and summary to display when verifying "
290*0fca6ea1SDimitry Andric          "(implies --verify)"),
291*0fca6ea1SDimitry Andric     values(clEnumValN(NoDetailsOrSummary, "quiet",
292*0fca6ea1SDimitry Andric                       "Only display whether errors occurred."),
293*0fca6ea1SDimitry Andric            clEnumValN(NoDetailsOnlySummary, "summary",
294*0fca6ea1SDimitry Andric                       "Display only a summary of the errors found."),
295*0fca6ea1SDimitry Andric            clEnumValN(OnlyDetailsNoSummary, "details",
296*0fca6ea1SDimitry Andric                       "Display each error in detail but no summary."),
297*0fca6ea1SDimitry Andric            clEnumValN(BothDetailsAndSummary, "full",
298*0fca6ea1SDimitry Andric                       "Display each error as well as a summary. [default]")),
299*0fca6ea1SDimitry Andric     cat(DwarfDumpCategory));
300*0fca6ea1SDimitry Andric static opt<std::string> JsonErrSummaryFile(
301*0fca6ea1SDimitry Andric     "verify-json", init(""),
302*0fca6ea1SDimitry Andric     desc("Output JSON-formatted error summary to the specified file. "
303*0fca6ea1SDimitry Andric          "(Implies --verify)"),
304*0fca6ea1SDimitry Andric     value_desc("filename.json"), cat(DwarfDumpCategory));
3050b57cec5SDimitry Andric static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),
3060b57cec5SDimitry Andric                        cat(DwarfDumpCategory));
3070b57cec5SDimitry Andric static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),
3080b57cec5SDimitry Andric                           cat(DwarfDumpCategory));
309fe6060f1SDimitry Andric static alias DumpUUIDAlias("u", desc("Alias for --uuid."), aliasopt(DumpUUID),
310fe6060f1SDimitry Andric                            cl::NotHidden);
3110b57cec5SDimitry Andric static opt<bool> Verbose("verbose",
3120b57cec5SDimitry Andric                          desc("Print more low-level encoding details."),
3130b57cec5SDimitry Andric                          cat(DwarfDumpCategory));
314fe6060f1SDimitry Andric static alias VerboseAlias("v", desc("Alias for --verbose."), aliasopt(Verbose),
315fe6060f1SDimitry Andric                           cat(DwarfDumpCategory), cl::NotHidden);
3160b57cec5SDimitry Andric static cl::extrahelp
3170b57cec5SDimitry Andric     HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
3180b57cec5SDimitry Andric } // namespace
3190b57cec5SDimitry Andric /// @}
3200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3210b57cec5SDimitry Andric 
3220eae32dcSDimitry Andric static void error(Error Err) {
3230eae32dcSDimitry Andric   if (!Err)
3240eae32dcSDimitry Andric     return;
3250eae32dcSDimitry Andric   WithColor::error() << toString(std::move(Err)) << "\n";
3260eae32dcSDimitry Andric   exit(1);
3270eae32dcSDimitry Andric }
3280eae32dcSDimitry Andric 
329fe6060f1SDimitry Andric static void error(StringRef Prefix, Error Err) {
330fe6060f1SDimitry Andric   if (!Err)
3310b57cec5SDimitry Andric     return;
332fe6060f1SDimitry Andric   WithColor::error() << Prefix << ": " << toString(std::move(Err)) << "\n";
3330b57cec5SDimitry Andric   exit(1);
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric 
336fe6060f1SDimitry Andric static void error(StringRef Prefix, std::error_code EC) {
337fe6060f1SDimitry Andric   error(Prefix, errorCodeToError(EC));
338fe6060f1SDimitry Andric }
339fe6060f1SDimitry Andric 
3405ffd83dbSDimitry Andric static DIDumpOptions getDumpOpts(DWARFContext &C) {
3410b57cec5SDimitry Andric   DIDumpOptions DumpOpts;
3420b57cec5SDimitry Andric   DumpOpts.DumpType = DumpType;
3430b57cec5SDimitry Andric   DumpOpts.ChildRecurseDepth = ChildRecurseDepth;
3440b57cec5SDimitry Andric   DumpOpts.ParentRecurseDepth = ParentRecurseDepth;
3450b57cec5SDimitry Andric   DumpOpts.ShowAddresses = !Diff;
3460b57cec5SDimitry Andric   DumpOpts.ShowChildren = ShowChildren;
3470b57cec5SDimitry Andric   DumpOpts.ShowParents = ShowParents;
3480b57cec5SDimitry Andric   DumpOpts.ShowForm = ShowForm;
3490b57cec5SDimitry Andric   DumpOpts.SummarizeTypes = SummarizeTypes;
3500b57cec5SDimitry Andric   DumpOpts.Verbose = Verbose;
3517a6dacacSDimitry Andric   DumpOpts.DumpNonSkeleton = DumpNonSkeleton;
3525ffd83dbSDimitry Andric   DumpOpts.RecoverableErrorHandler = C.getRecoverableErrorHandler();
3530b57cec5SDimitry Andric   // In -verify mode, print DIEs without children in error messages.
3540eae32dcSDimitry Andric   if (Verify) {
355*0fca6ea1SDimitry Andric     DumpOpts.Verbose = ErrorDetails != NoDetailsOnlySummary &&
356*0fca6ea1SDimitry Andric                        ErrorDetails != NoDetailsOrSummary;
357*0fca6ea1SDimitry Andric     DumpOpts.ShowAggregateErrors = ErrorDetails != OnlyDetailsNoSummary &&
358*0fca6ea1SDimitry Andric                                    ErrorDetails != NoDetailsOnlySummary;
359*0fca6ea1SDimitry Andric     DumpOpts.JsonErrSummaryFile = JsonErrSummaryFile;
3600b57cec5SDimitry Andric     return DumpOpts.noImplicitRecursion();
3610eae32dcSDimitry Andric   }
3620b57cec5SDimitry Andric   return DumpOpts;
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric static uint32_t getCPUType(MachOObjectFile &MachO) {
3660b57cec5SDimitry Andric   if (MachO.is64Bit())
3670b57cec5SDimitry Andric     return MachO.getHeader64().cputype;
3680b57cec5SDimitry Andric   else
3690b57cec5SDimitry Andric     return MachO.getHeader().cputype;
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric /// Return true if the object file has not been filtered by an --arch option.
3730b57cec5SDimitry Andric static bool filterArch(ObjectFile &Obj) {
3740b57cec5SDimitry Andric   if (ArchFilters.empty())
3750b57cec5SDimitry Andric     return true;
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric   if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {
3785f757f3fSDimitry Andric     for (const StringRef Arch : ArchFilters) {
3790b57cec5SDimitry Andric       // Match architecture number.
3800b57cec5SDimitry Andric       unsigned Value;
3815f757f3fSDimitry Andric       if (!Arch.getAsInteger(0, Value))
3820b57cec5SDimitry Andric         if (Value == getCPUType(*MachO))
3830b57cec5SDimitry Andric           return true;
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric       // Match as name.
386480093f4SDimitry Andric       if (MachO->getArchTriple().getArchName() == Triple(Arch).getArchName())
3870b57cec5SDimitry Andric         return true;
3880b57cec5SDimitry Andric     }
3890b57cec5SDimitry Andric   }
3900b57cec5SDimitry Andric   return false;
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
3935ffd83dbSDimitry Andric using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx,
3945ffd83dbSDimitry Andric                                      const Twine &, raw_ostream &)>;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
397bdd1243dSDimitry Andric static bool filterByName(
398bdd1243dSDimitry Andric     const StringSet<> &Names, DWARFDie Die, StringRef NameRef, raw_ostream &OS,
399bdd1243dSDimitry Andric     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
4005ffd83dbSDimitry Andric   DIDumpOptions DumpOpts = getDumpOpts(Die.getDwarfUnit()->getContext());
401bdd1243dSDimitry Andric   DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
4020b57cec5SDimitry Andric   std::string Name =
4030b57cec5SDimitry Andric       (IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();
4040b57cec5SDimitry Andric   if (UseRegex) {
4050b57cec5SDimitry Andric     // Match regular expression.
4060b57cec5SDimitry Andric     for (auto Pattern : Names.keys()) {
4070b57cec5SDimitry Andric       Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags);
4080b57cec5SDimitry Andric       std::string Error;
4090b57cec5SDimitry Andric       if (!RE.isValid(Error)) {
4100b57cec5SDimitry Andric         errs() << "error in regular expression: " << Error << "\n";
4110b57cec5SDimitry Andric         exit(1);
4120b57cec5SDimitry Andric       }
4130b57cec5SDimitry Andric       if (RE.match(Name)) {
4145ffd83dbSDimitry Andric         Die.dump(OS, 0, DumpOpts);
4150b57cec5SDimitry Andric         return true;
4160b57cec5SDimitry Andric       }
4170b57cec5SDimitry Andric     }
4180b57cec5SDimitry Andric   } else if (Names.count(Name)) {
4190b57cec5SDimitry Andric     // Match full text.
4205ffd83dbSDimitry Andric     Die.dump(OS, 0, DumpOpts);
4210b57cec5SDimitry Andric     return true;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric   return false;
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
427bdd1243dSDimitry Andric static void filterByName(
428bdd1243dSDimitry Andric     const StringSet<> &Names, DWARFContext::unit_iterator_range CUs,
429bdd1243dSDimitry Andric     raw_ostream &OS,
430bdd1243dSDimitry Andric     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
4317a6dacacSDimitry Andric   auto filterDieNames = [&](DWARFUnit *Unit) {
4327a6dacacSDimitry Andric     for (const auto &Entry : Unit->dies()) {
4337a6dacacSDimitry Andric       DWARFDie Die = {Unit, &Entry};
4340b57cec5SDimitry Andric       if (const char *Name = Die.getName(DINameKind::ShortName))
435bdd1243dSDimitry Andric         if (filterByName(Names, Die, Name, OS, GetNameForDWARFReg))
4360b57cec5SDimitry Andric           continue;
4370b57cec5SDimitry Andric       if (const char *Name = Die.getName(DINameKind::LinkageName))
438bdd1243dSDimitry Andric         filterByName(Names, Die, Name, OS, GetNameForDWARFReg);
4390b57cec5SDimitry Andric     }
4407a6dacacSDimitry Andric   };
4417a6dacacSDimitry Andric   for (const auto &CU : CUs) {
4427a6dacacSDimitry Andric     filterDieNames(CU.get());
4437a6dacacSDimitry Andric     if (DumpNonSkeleton) {
4447a6dacacSDimitry Andric       // If we have split DWARF, then recurse down into the .dwo files as well.
4457a6dacacSDimitry Andric       DWARFDie CUDie = CU->getUnitDIE(false);
4467a6dacacSDimitry Andric       DWARFDie CUNonSkeletonDie = CU->getNonSkeletonUnitDIE(false);
4477a6dacacSDimitry Andric       // If we have a DWO file, we need to search it as well
4487a6dacacSDimitry Andric       if (CUNonSkeletonDie && CUDie != CUNonSkeletonDie)
4497a6dacacSDimitry Andric         filterDieNames(CUNonSkeletonDie.getDwarfUnit());
4507a6dacacSDimitry Andric     }
4517a6dacacSDimitry Andric   }
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,
4550b57cec5SDimitry Andric                     StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
4560b57cec5SDimitry Andric   for (const auto &Entry : Accel.equal_range(Name)) {
457bdd1243dSDimitry Andric     if (std::optional<uint64_t> Off = Entry.getDIESectionOffset()) {
4580b57cec5SDimitry Andric       if (DWARFDie Die = DICtx.getDIEForOffset(*Off))
4590b57cec5SDimitry Andric         Dies.push_back(Die);
4600b57cec5SDimitry Andric     }
4610b57cec5SDimitry Andric   }
4620b57cec5SDimitry Andric }
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,
4650b57cec5SDimitry Andric                       DWARFContext &DICtx) {
466bdd1243dSDimitry Andric   std::optional<uint64_t> CUOff = Entry.getCUOffset();
467bdd1243dSDimitry Andric   std::optional<uint64_t> Off = Entry.getDIEUnitOffset();
4680b57cec5SDimitry Andric   if (!CUOff || !Off)
4690b57cec5SDimitry Andric     return DWARFDie();
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   DWARFCompileUnit *CU = DICtx.getCompileUnitForOffset(*CUOff);
4720b57cec5SDimitry Andric   if (!CU)
4730b57cec5SDimitry Andric     return DWARFDie();
4740b57cec5SDimitry Andric 
475bdd1243dSDimitry Andric   if (std::optional<uint64_t> DWOId = CU->getDWOId()) {
4760b57cec5SDimitry Andric     // This is a skeleton unit. Look up the DIE in the DWO unit.
4770b57cec5SDimitry Andric     CU = DICtx.getDWOCompileUnitForHash(*DWOId);
4780b57cec5SDimitry Andric     if (!CU)
4790b57cec5SDimitry Andric       return DWARFDie();
4800b57cec5SDimitry Andric   }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric   return CU->getDIEForOffset(CU->getOffset() + *Off);
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric 
4850b57cec5SDimitry Andric static void getDies(DWARFContext &DICtx, const DWARFDebugNames &Accel,
4860b57cec5SDimitry Andric                     StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {
4870b57cec5SDimitry Andric   for (const auto &Entry : Accel.equal_range(Name)) {
4880b57cec5SDimitry Andric     if (DWARFDie Die = toDie(Entry, DICtx))
4890b57cec5SDimitry Andric       Dies.push_back(Die);
4900b57cec5SDimitry Andric   }
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric /// Print only DIEs that have a certain name.
494bdd1243dSDimitry Andric static void filterByAccelName(
495bdd1243dSDimitry Andric     ArrayRef<std::string> Names, DWARFContext &DICtx, raw_ostream &OS,
496bdd1243dSDimitry Andric     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
4970b57cec5SDimitry Andric   SmallVector<DWARFDie, 4> Dies;
4980b57cec5SDimitry Andric   for (const auto &Name : Names) {
4990b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleNames(), Name, Dies);
5000b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleTypes(), Name, Dies);
5010b57cec5SDimitry Andric     getDies(DICtx, DICtx.getAppleNamespaces(), Name, Dies);
5020b57cec5SDimitry Andric     getDies(DICtx, DICtx.getDebugNames(), Name, Dies);
5030b57cec5SDimitry Andric   }
5040b57cec5SDimitry Andric   llvm::sort(Dies);
505*0fca6ea1SDimitry Andric   Dies.erase(llvm::unique(Dies), Dies.end());
5060b57cec5SDimitry Andric 
5075ffd83dbSDimitry Andric   DIDumpOptions DumpOpts = getDumpOpts(DICtx);
508bdd1243dSDimitry Andric   DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
5090b57cec5SDimitry Andric   for (DWARFDie Die : Dies)
5105ffd83dbSDimitry Andric     Die.dump(OS, 0, DumpOpts);
5110b57cec5SDimitry Andric }
5120b57cec5SDimitry Andric 
51306c3fb27SDimitry Andric /// Print all DIEs in apple accelerator tables
51406c3fb27SDimitry Andric static void findAllApple(
51506c3fb27SDimitry Andric     DWARFContext &DICtx, raw_ostream &OS,
51606c3fb27SDimitry Andric     std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {
51706c3fb27SDimitry Andric   MapVector<StringRef, llvm::SmallSet<DWARFDie, 2>> NameToDies;
51806c3fb27SDimitry Andric 
51906c3fb27SDimitry Andric   auto PushDIEs = [&](const AppleAcceleratorTable &Accel) {
52006c3fb27SDimitry Andric     for (const auto &Entry : Accel.entries()) {
52106c3fb27SDimitry Andric       if (std::optional<uint64_t> Off = Entry.BaseEntry.getDIESectionOffset()) {
52206c3fb27SDimitry Andric         std::optional<StringRef> MaybeName = Entry.readName();
52306c3fb27SDimitry Andric         DWARFDie Die = DICtx.getDIEForOffset(*Off);
52406c3fb27SDimitry Andric         if (Die && MaybeName)
52506c3fb27SDimitry Andric           NameToDies[*MaybeName].insert(Die);
52606c3fb27SDimitry Andric       }
52706c3fb27SDimitry Andric     }
52806c3fb27SDimitry Andric   };
52906c3fb27SDimitry Andric 
53006c3fb27SDimitry Andric   PushDIEs(DICtx.getAppleNames());
53106c3fb27SDimitry Andric   PushDIEs(DICtx.getAppleNamespaces());
53206c3fb27SDimitry Andric   PushDIEs(DICtx.getAppleTypes());
53306c3fb27SDimitry Andric 
53406c3fb27SDimitry Andric   DIDumpOptions DumpOpts = getDumpOpts(DICtx);
53506c3fb27SDimitry Andric   DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;
53606c3fb27SDimitry Andric   for (const auto &[Name, Dies] : NameToDies) {
53706c3fb27SDimitry Andric     OS << llvm::formatv("\nApple accelerator entries with name = \"{0}\":\n",
53806c3fb27SDimitry Andric                         Name);
53906c3fb27SDimitry Andric     for (DWARFDie Die : Dies)
54006c3fb27SDimitry Andric       Die.dump(OS, 0, DumpOpts);
54106c3fb27SDimitry Andric   }
54206c3fb27SDimitry Andric }
54306c3fb27SDimitry Andric 
5440b57cec5SDimitry Andric /// Handle the --lookup option and dump the DIEs and line info for the given
5450b57cec5SDimitry Andric /// address.
5460b57cec5SDimitry Andric /// TODO: specified Address for --lookup option could relate for several
5470b57cec5SDimitry Andric /// different sections(in case not-linked object file). llvm-dwarfdump
5480b57cec5SDimitry Andric /// need to do something with this: extend lookup option with section
5490b57cec5SDimitry Andric /// information or probably display all matched entries, or something else...
5500b57cec5SDimitry Andric static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,
5510b57cec5SDimitry Andric                    raw_ostream &OS) {
5527a6dacacSDimitry Andric   auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup, DumpNonSkeleton);
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric   if (!DIEsForAddr)
5550b57cec5SDimitry Andric     return false;
5560b57cec5SDimitry Andric 
5575ffd83dbSDimitry Andric   DIDumpOptions DumpOpts = getDumpOpts(DICtx);
5580b57cec5SDimitry Andric   DumpOpts.ChildRecurseDepth = 0;
5590b57cec5SDimitry Andric   DIEsForAddr.CompileUnit->dump(OS, DumpOpts);
5600b57cec5SDimitry Andric   if (DIEsForAddr.FunctionDIE) {
5610b57cec5SDimitry Andric     DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);
5620b57cec5SDimitry Andric     if (DIEsForAddr.BlockDIE)
5630b57cec5SDimitry Andric       DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);
5640b57cec5SDimitry Andric   }
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric   // TODO: it is neccessary to set proper SectionIndex here.
5670b57cec5SDimitry Andric   // object::SectionedAddress::UndefSection works for only absolute addresses.
5680b57cec5SDimitry Andric   if (DILineInfo LineInfo = DICtx.getLineInfoForAddress(
5690b57cec5SDimitry Andric           {Lookup, object::SectionedAddress::UndefSection}))
5700b57cec5SDimitry Andric     LineInfo.dump(OS);
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric   return true;
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric 
57581ad6265SDimitry Andric // Collect all sources referenced from the given line table, scoped to the given
57681ad6265SDimitry Andric // CU compilation directory.
57781ad6265SDimitry Andric static bool collectLineTableSources(const DWARFDebugLine::LineTable &LT,
57881ad6265SDimitry Andric                                     StringRef CompDir,
57981ad6265SDimitry Andric                                     std::vector<std::string> &Sources) {
58081ad6265SDimitry Andric   bool Result = true;
581bdd1243dSDimitry Andric   std::optional<uint64_t> LastIndex = LT.getLastValidFileIndex();
58281ad6265SDimitry Andric   for (uint64_t I = LT.hasFileAtIndex(0) ? 0 : 1,
58381ad6265SDimitry Andric                 E = LastIndex ? *LastIndex + 1 : 0;
58481ad6265SDimitry Andric        I < E; ++I) {
58581ad6265SDimitry Andric     std::string Path;
58681ad6265SDimitry Andric     Result &= LT.getFileNameByIndex(
58781ad6265SDimitry Andric         I, CompDir, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
58881ad6265SDimitry Andric         Path);
58981ad6265SDimitry Andric     Sources.push_back(std::move(Path));
59081ad6265SDimitry Andric   }
59181ad6265SDimitry Andric   return Result;
59281ad6265SDimitry Andric }
59381ad6265SDimitry Andric 
59481ad6265SDimitry Andric static bool collectObjectSources(ObjectFile &Obj, DWARFContext &DICtx,
59581ad6265SDimitry Andric                                  const Twine &Filename, raw_ostream &OS) {
59681ad6265SDimitry Andric   bool Result = true;
59781ad6265SDimitry Andric   std::vector<std::string> Sources;
59881ad6265SDimitry Andric 
59981ad6265SDimitry Andric   bool HasCompileUnits = false;
60081ad6265SDimitry Andric   for (const auto &CU : DICtx.compile_units()) {
60181ad6265SDimitry Andric     HasCompileUnits = true;
60281ad6265SDimitry Andric     // Extract paths from the line table for this CU. This allows combining the
60381ad6265SDimitry Andric     // compilation directory with the line information, in case both the include
60481ad6265SDimitry Andric     // directory and file names in the line table are relative.
60581ad6265SDimitry Andric     const DWARFDebugLine::LineTable *LT = DICtx.getLineTableForUnit(CU.get());
60681ad6265SDimitry Andric     StringRef CompDir = CU->getCompilationDir();
60781ad6265SDimitry Andric     if (LT) {
60881ad6265SDimitry Andric       Result &= collectLineTableSources(*LT, CompDir, Sources);
60981ad6265SDimitry Andric     } else {
61081ad6265SDimitry Andric       // Since there's no line table for this CU, collect the name from the CU
61181ad6265SDimitry Andric       // itself.
61281ad6265SDimitry Andric       const char *Name = CU->getUnitDIE().getShortName();
61381ad6265SDimitry Andric       if (!Name) {
61481ad6265SDimitry Andric         WithColor::warning()
61581ad6265SDimitry Andric             << Filename << ": missing name for compilation unit\n";
61681ad6265SDimitry Andric         continue;
61781ad6265SDimitry Andric       }
61881ad6265SDimitry Andric       SmallString<64> AbsName;
61981ad6265SDimitry Andric       if (sys::path::is_relative(Name, sys::path::Style::posix) &&
62081ad6265SDimitry Andric           sys::path::is_relative(Name, sys::path::Style::windows))
62181ad6265SDimitry Andric         AbsName = CompDir;
62281ad6265SDimitry Andric       sys::path::append(AbsName, Name);
62381ad6265SDimitry Andric       Sources.push_back(std::string(AbsName));
62481ad6265SDimitry Andric     }
62581ad6265SDimitry Andric   }
62681ad6265SDimitry Andric 
62781ad6265SDimitry Andric   if (!HasCompileUnits) {
62881ad6265SDimitry Andric     // Since there's no compile units available, walk the line tables and
62981ad6265SDimitry Andric     // extract out any referenced paths.
63081ad6265SDimitry Andric     DWARFDataExtractor LineData(DICtx.getDWARFObj(),
63181ad6265SDimitry Andric                                 DICtx.getDWARFObj().getLineSection(),
63281ad6265SDimitry Andric                                 DICtx.isLittleEndian(), 0);
63381ad6265SDimitry Andric     DWARFDebugLine::SectionParser Parser(LineData, DICtx, DICtx.normal_units());
63481ad6265SDimitry Andric     while (!Parser.done()) {
63581ad6265SDimitry Andric       const auto RecoverableErrorHandler = [&](Error Err) {
63681ad6265SDimitry Andric         Result = false;
63781ad6265SDimitry Andric         WithColor::defaultErrorHandler(std::move(Err));
63881ad6265SDimitry Andric       };
63981ad6265SDimitry Andric       void (*UnrecoverableErrorHandler)(Error Err) = error;
64081ad6265SDimitry Andric 
64181ad6265SDimitry Andric       DWARFDebugLine::LineTable LT =
64281ad6265SDimitry Andric           Parser.parseNext(RecoverableErrorHandler, UnrecoverableErrorHandler);
64381ad6265SDimitry Andric       Result &= collectLineTableSources(LT, /*CompDir=*/"", Sources);
64481ad6265SDimitry Andric     }
64581ad6265SDimitry Andric   }
64681ad6265SDimitry Andric 
64781ad6265SDimitry Andric   // Dedup and order the sources.
648fcaf7f86SDimitry Andric   llvm::sort(Sources);
649*0fca6ea1SDimitry Andric   Sources.erase(llvm::unique(Sources), Sources.end());
65081ad6265SDimitry Andric 
65181ad6265SDimitry Andric   for (StringRef Name : Sources)
65281ad6265SDimitry Andric     OS << Name << "\n";
65381ad6265SDimitry Andric   return Result;
65481ad6265SDimitry Andric }
65581ad6265SDimitry Andric 
656bdd1243dSDimitry Andric static std::unique_ptr<MCRegisterInfo>
657bdd1243dSDimitry Andric createRegInfo(const object::ObjectFile &Obj) {
658bdd1243dSDimitry Andric   std::unique_ptr<MCRegisterInfo> MCRegInfo;
659bdd1243dSDimitry Andric   Triple TT;
660bdd1243dSDimitry Andric   TT.setArch(Triple::ArchType(Obj.getArch()));
661bdd1243dSDimitry Andric   TT.setVendor(Triple::UnknownVendor);
662bdd1243dSDimitry Andric   TT.setOS(Triple::UnknownOS);
663bdd1243dSDimitry Andric   std::string TargetLookupError;
664bdd1243dSDimitry Andric   const Target *TheTarget =
665bdd1243dSDimitry Andric       TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
666bdd1243dSDimitry Andric   if (!TargetLookupError.empty())
667bdd1243dSDimitry Andric     return nullptr;
668bdd1243dSDimitry Andric   MCRegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
669bdd1243dSDimitry Andric   return MCRegInfo;
670bdd1243dSDimitry Andric }
671bdd1243dSDimitry Andric 
6725ffd83dbSDimitry Andric static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
6735ffd83dbSDimitry Andric                            const Twine &Filename, raw_ostream &OS) {
674bdd1243dSDimitry Andric 
675bdd1243dSDimitry Andric   auto MCRegInfo = createRegInfo(Obj);
676bdd1243dSDimitry Andric   if (!MCRegInfo)
677bdd1243dSDimitry Andric     logAllUnhandledErrors(createStringError(inconvertibleErrorCode(),
678bdd1243dSDimitry Andric                                             "Error in creating MCRegInfo"),
679bdd1243dSDimitry Andric                           errs(), Filename.str() + ": ");
680bdd1243dSDimitry Andric 
681bdd1243dSDimitry Andric   auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum, bool IsEH) -> StringRef {
682bdd1243dSDimitry Andric     if (!MCRegInfo)
683bdd1243dSDimitry Andric       return {};
684bdd1243dSDimitry Andric     if (std::optional<unsigned> LLVMRegNum =
685bdd1243dSDimitry Andric             MCRegInfo->getLLVMRegNum(DwarfRegNum, IsEH))
686bdd1243dSDimitry Andric       if (const char *RegName = MCRegInfo->getName(*LLVMRegNum))
687bdd1243dSDimitry Andric         return StringRef(RegName);
688bdd1243dSDimitry Andric     return {};
689bdd1243dSDimitry Andric   };
690bdd1243dSDimitry Andric 
6910b57cec5SDimitry Andric   // The UUID dump already contains all the same information.
6920b57cec5SDimitry Andric   if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)
6930b57cec5SDimitry Andric     OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric   // Handle the --lookup option.
6960b57cec5SDimitry Andric   if (Lookup)
6970b57cec5SDimitry Andric     return lookup(Obj, DICtx, Lookup, OS);
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric   // Handle the --name option.
7000b57cec5SDimitry Andric   if (!Name.empty()) {
7010b57cec5SDimitry Andric     StringSet<> Names;
7025f757f3fSDimitry Andric     for (const auto &name : Name)
7030b57cec5SDimitry Andric       Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);
7040b57cec5SDimitry Andric 
705bdd1243dSDimitry Andric     filterByName(Names, DICtx.normal_units(), OS, GetRegName);
706bdd1243dSDimitry Andric     filterByName(Names, DICtx.dwo_units(), OS, GetRegName);
7070b57cec5SDimitry Andric     return true;
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   // Handle the --find option and lower it to --debug-info=<offset>.
7110b57cec5SDimitry Andric   if (!Find.empty()) {
712bdd1243dSDimitry Andric     filterByAccelName(Find, DICtx, OS, GetRegName);
7130b57cec5SDimitry Andric     return true;
7140b57cec5SDimitry Andric   }
7150b57cec5SDimitry Andric 
71606c3fb27SDimitry Andric   // Handle the --find-all-apple option and lower it to --debug-info=<offset>.
71706c3fb27SDimitry Andric   if (FindAllApple) {
71806c3fb27SDimitry Andric     findAllApple(DICtx, OS, GetRegName);
71906c3fb27SDimitry Andric     return true;
72006c3fb27SDimitry Andric   }
72106c3fb27SDimitry Andric 
7220b57cec5SDimitry Andric   // Dump the complete DWARF structure.
723bdd1243dSDimitry Andric   auto DumpOpts = getDumpOpts(DICtx);
724bdd1243dSDimitry Andric   DumpOpts.GetNameForDWARFReg = GetRegName;
725bdd1243dSDimitry Andric   DICtx.dump(OS, DumpOpts, DumpOffsets);
7260b57cec5SDimitry Andric   return true;
7270b57cec5SDimitry Andric }
7280b57cec5SDimitry Andric 
7290b57cec5SDimitry Andric static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
7305ffd83dbSDimitry Andric                              const Twine &Filename, raw_ostream &OS) {
7310b57cec5SDimitry Andric   // Verify the DWARF and exit with non-zero exit status if verification
7320b57cec5SDimitry Andric   // fails.
7330b57cec5SDimitry Andric   raw_ostream &stream = Quiet ? nulls() : OS;
7340b57cec5SDimitry Andric   stream << "Verifying " << Filename.str() << ":\tfile format "
7350b57cec5SDimitry Andric          << Obj.getFileFormatName() << "\n";
7365ffd83dbSDimitry Andric   bool Result = DICtx.verify(stream, getDumpOpts(DICtx));
7370b57cec5SDimitry Andric   if (Result)
7380b57cec5SDimitry Andric     stream << "No errors.\n";
7390b57cec5SDimitry Andric   else
7400b57cec5SDimitry Andric     stream << "Errors detected.\n";
7410b57cec5SDimitry Andric   return Result;
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
7450b57cec5SDimitry Andric                          HandlerFn HandleObj, raw_ostream &OS);
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric static bool handleArchive(StringRef Filename, Archive &Arch,
7480b57cec5SDimitry Andric                           HandlerFn HandleObj, raw_ostream &OS) {
7490b57cec5SDimitry Andric   bool Result = true;
7500b57cec5SDimitry Andric   Error Err = Error::success();
7515f757f3fSDimitry Andric   for (const auto &Child : Arch.children(Err)) {
7520b57cec5SDimitry Andric     auto BuffOrErr = Child.getMemoryBufferRef();
753fe6060f1SDimitry Andric     error(Filename, BuffOrErr.takeError());
7540b57cec5SDimitry Andric     auto NameOrErr = Child.getName();
755fe6060f1SDimitry Andric     error(Filename, NameOrErr.takeError());
7560b57cec5SDimitry Andric     std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
7570b57cec5SDimitry Andric     Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);
7580b57cec5SDimitry Andric   }
759fe6060f1SDimitry Andric   error(Filename, std::move(Err));
7600b57cec5SDimitry Andric 
7610b57cec5SDimitry Andric   return Result;
7620b57cec5SDimitry Andric }
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
7650b57cec5SDimitry Andric                          HandlerFn HandleObj, raw_ostream &OS) {
7660b57cec5SDimitry Andric   Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
767fe6060f1SDimitry Andric   error(Filename, BinOrErr.takeError());
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   bool Result = true;
7705ffd83dbSDimitry Andric   auto RecoverableErrorHandler = [&](Error E) {
7715ffd83dbSDimitry Andric     Result = false;
7725ffd83dbSDimitry Andric     WithColor::defaultErrorHandler(std::move(E));
7735ffd83dbSDimitry Andric   };
7740b57cec5SDimitry Andric   if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
7750b57cec5SDimitry Andric     if (filterArch(*Obj)) {
776349cc55cSDimitry Andric       std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
777349cc55cSDimitry Andric           *Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
778349cc55cSDimitry Andric           RecoverableErrorHandler);
779bdd1243dSDimitry Andric       DICtx->setParseCUTUIndexManually(ManuallyGenerateUnitIndex);
7805ffd83dbSDimitry Andric       if (!HandleObj(*Obj, *DICtx, Filename, OS))
7815ffd83dbSDimitry Andric         Result = false;
7820b57cec5SDimitry Andric     }
783fe6060f1SDimitry Andric   } else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))
7840b57cec5SDimitry Andric     for (auto &ObjForArch : Fat->objects()) {
7850b57cec5SDimitry Andric       std::string ObjName =
7860b57cec5SDimitry Andric           (Filename + "(" + ObjForArch.getArchFlagName() + ")").str();
7870b57cec5SDimitry Andric       if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {
7880b57cec5SDimitry Andric         auto &Obj = **MachOOrErr;
7890b57cec5SDimitry Andric         if (filterArch(Obj)) {
790349cc55cSDimitry Andric           std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
791349cc55cSDimitry Andric               Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
792349cc55cSDimitry Andric               RecoverableErrorHandler);
7935ffd83dbSDimitry Andric           if (!HandleObj(Obj, *DICtx, ObjName, OS))
7945ffd83dbSDimitry Andric             Result = false;
7950b57cec5SDimitry Andric         }
7960b57cec5SDimitry Andric         continue;
7970b57cec5SDimitry Andric       } else
7980b57cec5SDimitry Andric         consumeError(MachOOrErr.takeError());
7990b57cec5SDimitry Andric       if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {
800fe6060f1SDimitry Andric         error(ObjName, ArchiveOrErr.takeError());
8015ffd83dbSDimitry Andric         if (!handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS))
8025ffd83dbSDimitry Andric           Result = false;
8030b57cec5SDimitry Andric         continue;
8040b57cec5SDimitry Andric       } else
8050b57cec5SDimitry Andric         consumeError(ArchiveOrErr.takeError());
8060b57cec5SDimitry Andric     }
8070b57cec5SDimitry Andric   else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))
8080b57cec5SDimitry Andric     Result = handleArchive(Filename, *Arch, HandleObj, OS);
8090b57cec5SDimitry Andric   return Result;
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric static bool handleFile(StringRef Filename, HandlerFn HandleObj,
8130b57cec5SDimitry Andric                        raw_ostream &OS) {
8140b57cec5SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
8150b57cec5SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Filename);
8160b57cec5SDimitry Andric   error(Filename, BuffOrErr.getError());
8170b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
8180b57cec5SDimitry Andric   return handleBuffer(Filename, *Buffer, HandleObj, OS);
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric int main(int argc, char **argv) {
8220b57cec5SDimitry Andric   InitLLVM X(argc, argv);
8230b57cec5SDimitry Andric 
8245ffd83dbSDimitry Andric   // Flush outs() when printing to errs(). This avoids interleaving output
8255ffd83dbSDimitry Andric   // between the two.
8265ffd83dbSDimitry Andric   errs().tie(&outs());
8275ffd83dbSDimitry Andric 
8280b57cec5SDimitry Andric   llvm::InitializeAllTargetInfos();
8290b57cec5SDimitry Andric   llvm::InitializeAllTargetMCs();
8300b57cec5SDimitry Andric 
831fe6060f1SDimitry Andric   HideUnrelatedOptions(
832fe6060f1SDimitry Andric       {&DwarfDumpCategory, &SectionCategory, &getColorCategory()});
8330b57cec5SDimitry Andric   cl::ParseCommandLineOptions(
8340b57cec5SDimitry Andric       argc, argv,
8350b57cec5SDimitry Andric       "pretty-print DWARF debug information in object files"
8360b57cec5SDimitry Andric       " and debug info archives.\n");
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric   // FIXME: Audit interactions between these two options and make them
8390b57cec5SDimitry Andric   //        compatible.
8400b57cec5SDimitry Andric   if (Diff && Verbose) {
8410b57cec5SDimitry Andric     WithColor::error() << "incompatible arguments: specifying both -diff and "
8420b57cec5SDimitry Andric                           "-verbose is currently not supported";
843e8d8bef9SDimitry Andric     return 1;
8440b57cec5SDimitry Andric   }
845*0fca6ea1SDimitry Andric   // -error-detail and -json-summary-file both imply -verify
846*0fca6ea1SDimitry Andric   if (ErrorDetails != Unspecified || !JsonErrSummaryFile.empty()) {
847*0fca6ea1SDimitry Andric     Verify = true;
848*0fca6ea1SDimitry Andric   }
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric   std::error_code EC;
851fe6060f1SDimitry Andric   ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_TextWithCRLF);
852fe6060f1SDimitry Andric   error("unable to open output file " + OutputFilename, EC);
8530b57cec5SDimitry Andric   // Don't remove output file if we exit with an error.
8540b57cec5SDimitry Andric   OutputFile.keep();
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric   bool OffsetRequested = false;
8570b57cec5SDimitry Andric 
858*0fca6ea1SDimitry Andric   // Defaults to dumping only debug_info, unless: A) verbose mode is specified,
859*0fca6ea1SDimitry Andric   // in which case all sections are dumped, or B) a specific section is
860*0fca6ea1SDimitry Andric   // requested.
8615ffd83dbSDimitry Andric #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
8620b57cec5SDimitry Andric   if (Dump##ENUM_NAME.IsRequested) {                                           \
8630b57cec5SDimitry Andric     DumpType |= DIDT_##ENUM_NAME;                                              \
8640b57cec5SDimitry Andric     if (Dump##ENUM_NAME.HasValue) {                                            \
8650b57cec5SDimitry Andric       DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val;                  \
8660b57cec5SDimitry Andric       OffsetRequested = true;                                                  \
8670b57cec5SDimitry Andric     }                                                                          \
8680b57cec5SDimitry Andric   }
8690b57cec5SDimitry Andric #include "llvm/BinaryFormat/Dwarf.def"
8700b57cec5SDimitry Andric #undef HANDLE_DWARF_SECTION
8710b57cec5SDimitry Andric   if (DumpUUID)
8720b57cec5SDimitry Andric     DumpType |= DIDT_UUID;
8730b57cec5SDimitry Andric   if (DumpAll)
8740b57cec5SDimitry Andric     DumpType = DIDT_All;
8750b57cec5SDimitry Andric   if (DumpType == DIDT_Null) {
876*0fca6ea1SDimitry Andric     if (Verbose || Verify)
8770b57cec5SDimitry Andric       DumpType = DIDT_All;
8780b57cec5SDimitry Andric     else
8790b57cec5SDimitry Andric       DumpType = DIDT_DebugInfo;
8800b57cec5SDimitry Andric   }
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric   // Unless dumping a specific DIE, default to --show-children.
883fe6060f1SDimitry Andric   if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() &&
88406c3fb27SDimitry Andric       Find.empty() && !FindAllApple)
8850b57cec5SDimitry Andric     ShowChildren = true;
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   // Defaults to a.out if no filenames specified.
8880b57cec5SDimitry Andric   if (InputFilenames.empty())
8890b57cec5SDimitry Andric     InputFilenames.push_back("a.out");
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric   // Expand any .dSYM bundles to the individual object files contained therein.
8920b57cec5SDimitry Andric   std::vector<std::string> Objects;
8930b57cec5SDimitry Andric   for (const auto &F : InputFilenames) {
8940eae32dcSDimitry Andric     if (auto DsymObjectsOrErr = MachOObjectFile::findDsymObjectMembers(F)) {
8950eae32dcSDimitry Andric       if (DsymObjectsOrErr->empty())
8960eae32dcSDimitry Andric         Objects.push_back(F);
8970eae32dcSDimitry Andric       else
8980eae32dcSDimitry Andric         llvm::append_range(Objects, *DsymObjectsOrErr);
8990eae32dcSDimitry Andric     } else {
9000eae32dcSDimitry Andric       error(DsymObjectsOrErr.takeError());
9010eae32dcSDimitry Andric     }
9020b57cec5SDimitry Andric   }
9030b57cec5SDimitry Andric 
9045ffd83dbSDimitry Andric   bool Success = true;
9050b57cec5SDimitry Andric   if (Verify) {
9065f757f3fSDimitry Andric     for (StringRef Object : Objects)
9075ffd83dbSDimitry Andric       Success &= handleFile(Object, verifyObjectFile, OutputFile.os());
9085ffd83dbSDimitry Andric   } else if (Statistics) {
9095f757f3fSDimitry Andric     for (StringRef Object : Objects)
9105ffd83dbSDimitry Andric       Success &= handleFile(Object, collectStatsForObjectFile, OutputFile.os());
9115ffd83dbSDimitry Andric   } else if (ShowSectionSizes) {
9125f757f3fSDimitry Andric     for (StringRef Object : Objects)
9135ffd83dbSDimitry Andric       Success &= handleFile(Object, collectObjectSectionSizes, OutputFile.os());
91481ad6265SDimitry Andric   } else if (ShowSources) {
9155f757f3fSDimitry Andric     for (StringRef Object : Objects)
91681ad6265SDimitry Andric       Success &= handleFile(Object, collectObjectSources, OutputFile.os());
9175ffd83dbSDimitry Andric   } else {
9185f757f3fSDimitry Andric     for (StringRef Object : Objects)
9195ffd83dbSDimitry Andric       Success &= handleFile(Object, dumpObjectFile, OutputFile.os());
9205ffd83dbSDimitry Andric   }
9210b57cec5SDimitry Andric 
9225ffd83dbSDimitry Andric   return Success ? EXIT_SUCCESS : EXIT_FAILURE;
9230b57cec5SDimitry Andric }
924