llvm-dwarfdump.cpp 25 KB

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