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 <, 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