llvm-dwarfdump.cpp 25 KB

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