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