llvm-dwarfdump.cpp 30 KB

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