llvm-dwarfdump.cpp 24 KB

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