brintos

brintos / llvm-project-archived public Read only

0
0
Text · 35.8 KiB · 6f120f9 Raw
962 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This program is a utility that works like "dwarfdump".10//11//===----------------------------------------------------------------------===//12 13#include "llvm-dwarfdump.h"14#include "llvm/ADT/MapVector.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/SmallSet.h"17#include "llvm/ADT/SmallVectorExtras.h"18#include "llvm/ADT/StringSet.h"19#include "llvm/DebugInfo/DIContext.h"20#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"21#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"22#include "llvm/DebugInfo/DWARF/DWARFContext.h"23#include "llvm/MC/MCRegisterInfo.h"24#include "llvm/MC/TargetRegistry.h"25#include "llvm/Object/Archive.h"26#include "llvm/Object/MachOUniversal.h"27#include "llvm/Object/ObjectFile.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/Debug.h"30#include "llvm/Support/Format.h"31#include "llvm/Support/FormatVariadic.h"32#include "llvm/Support/InitLLVM.h"33#include "llvm/Support/MemoryBuffer.h"34#include "llvm/Support/Parallel.h"35#include "llvm/Support/Path.h"36#include "llvm/Support/Regex.h"37#include "llvm/Support/TargetSelect.h"38#include "llvm/Support/Threading.h"39#include "llvm/Support/ToolOutputFile.h"40#include "llvm/Support/WithColor.h"41#include "llvm/Support/raw_ostream.h"42#include "llvm/TargetParser/Triple.h"43#include <cstdlib>44 45using namespace llvm;46using namespace llvm::dwarfdump;47using namespace llvm::object;48 49namespace {50/// Parser for options that take an optional offest argument.51/// @{52struct OffsetOption {53  uint64_t Val = 0;54  bool HasValue = false;55  bool IsRequested = false;56};57struct BoolOption : public OffsetOption {};58} // namespace59 60namespace llvm {61namespace cl {62template <>63class parser<OffsetOption> final : public basic_parser<OffsetOption> {64public:65  parser(Option &O) : basic_parser(O) {}66 67  /// Return true on error.68  bool parse(Option &O, StringRef ArgName, StringRef Arg, OffsetOption &Val) {69    if (Arg == "") {70      Val.Val = 0;71      Val.HasValue = false;72      Val.IsRequested = true;73      return false;74    }75    if (Arg.getAsInteger(0, Val.Val))76      return O.error("'" + Arg + "' value invalid for integer argument");77    Val.HasValue = true;78    Val.IsRequested = true;79    return false;80  }81 82  enum ValueExpected getValueExpectedFlagDefault() const {83    return ValueOptional;84  }85 86  StringRef getValueName() const override { return StringRef("offset"); }87 88  void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,89                       size_t GlobalWidth) const {90    printOptionName(O, GlobalWidth);91    outs() << "[=offset]";92  }93};94 95template <> class parser<BoolOption> final : public basic_parser<BoolOption> {96public:97  parser(Option &O) : basic_parser(O) {}98 99  /// Return true on error.100  bool parse(Option &O, StringRef ArgName, StringRef Arg, BoolOption &Val) {101    if (Arg != "")102      return O.error("this is a flag and does not take a value");103    Val.Val = 0;104    Val.HasValue = false;105    Val.IsRequested = true;106    return false;107  }108 109  enum ValueExpected getValueExpectedFlagDefault() const {110    return ValueOptional;111  }112 113  StringRef getValueName() const override { return StringRef(); }114 115  void printOptionDiff(const Option &O, OffsetOption V, OptVal Default,116                       size_t GlobalWidth) const {117    printOptionName(O, GlobalWidth);118  }119};120} // namespace cl121} // namespace llvm122 123/// @}124/// Command line options.125/// @{126 127namespace {128using namespace cl;129 130enum ErrorDetailLevel {131  OnlyDetailsNoSummary,132  NoDetailsOnlySummary,133  NoDetailsOrSummary,134  BothDetailsAndSummary,135  Unspecified136};137 138OptionCategory DwarfDumpCategory("Specific Options");139static list<std::string>140    InputFilenames(Positional, desc("<input object files or .dSYM bundles>"),141                   cat(DwarfDumpCategory));142 143cl::OptionCategory SectionCategory("Section-specific Dump Options",144                                   "These control which sections are dumped. "145                                   "Where applicable these parameters take an "146                                   "optional =<offset> argument to dump only "147                                   "the entry at the specified offset.");148 149static opt<bool> DumpAll("all", desc("Dump all debug info sections"),150                         cat(SectionCategory));151static alias DumpAllAlias("a", desc("Alias for --all"), aliasopt(DumpAll),152                          cl::NotHidden);153 154// Options for dumping specific sections.155static unsigned DumpType = DIDT_Null;156static std::array<std::optional<uint64_t>, (unsigned)DIDT_ID_Count> DumpOffsets;157#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \158  static opt<OPTION> Dump##ENUM_NAME(CMDLINE_NAME,                             \159                                     desc("Dump the " ELF_NAME " section"),    \160                                     cat(SectionCategory));161#include "llvm/BinaryFormat/Dwarf.def"162#undef HANDLE_DWARF_SECTION163 164// The aliased DumpDebugFrame is created by the Dwarf.def x-macro just above.165static alias DumpDebugFrameAlias("eh-frame", desc("Alias for --debug-frame"),166                                 NotHidden, cat(SectionCategory),167                                 aliasopt(DumpDebugFrame));168static list<std::string>169    ArchFilters("arch",170                desc("Dump debug information for the specified CPU "171                     "architecture only. Architectures may be specified by "172                     "name or by number. This option can be specified "173                     "multiple times, once for each desired architecture."),174                cat(DwarfDumpCategory));175static opt<bool>176    Diff("diff",177         desc("Emit diff-friendly output by omitting offsets and addresses."),178         cat(DwarfDumpCategory));179static list<std::string>180    Find("find",181         desc("Search for the exact match for <name> in the accelerator tables "182              "and print the matching debug information entries. When no "183              "accelerator tables are available, the slower but more complete "184              "-name option can be used instead."),185         value_desc("name"), cat(DwarfDumpCategory));186static alias FindAlias("f", desc("Alias for --find."), aliasopt(Find),187                       cl::NotHidden);188static opt<bool> FindAllApple(189    "find-all-apple",190    desc("Print every debug information entry in the accelerator tables."),191    cat(DwarfDumpCategory));192static opt<bool> IgnoreCase("ignore-case",193                            desc("Ignore case distinctions when using --name."),194                            value_desc("i"), cat(DwarfDumpCategory));195static opt<bool> DumpNonSkeleton(196    "dwo",197    desc("Dump the non skeleton DIE in the .dwo or .dwp file after dumping the "198         "skeleton DIE from the main executable. This allows dumping the .dwo "199         "files with resolved addresses."),200    value_desc("d"), cat(DwarfDumpCategory));201 202static alias IgnoreCaseAlias("i", desc("Alias for --ignore-case."),203                             aliasopt(IgnoreCase), cl::NotHidden);204static list<std::string> Name(205    "name",206    desc("Find and print all debug info entries whose name "207         "(DW_AT_name/DW_AT_linkage_name attribute) matches the exact text "208         "in <pattern>.  When used with the the -regex option <pattern> is "209         "interpreted as a regular expression."),210    value_desc("pattern"), cat(DwarfDumpCategory));211static alias NameAlias("n", desc("Alias for --name"), aliasopt(Name),212                       cl::NotHidden);213static opt<uint64_t>214    Lookup("lookup",215           desc("Lookup <address> in the debug information and print out any "216                "available file, function, block and line table details."),217           value_desc("address"), cat(DwarfDumpCategory));218static opt<std::string>219    OutputFilename("o", cl::init("-"),220                   cl::desc("Redirect output to the specified file."),221                   cl::value_desc("filename"), cat(DwarfDumpCategory));222static alias OutputFilenameAlias("out-file", desc("Alias for -o."),223                                 aliasopt(OutputFilename));224static opt<bool> UseRegex(225    "regex",226    desc("Treat any <pattern> strings as regular "227         "expressions when searching with --name. If --ignore-case is also "228         "specified, the regular expression becomes case-insensitive."),229    cat(DwarfDumpCategory));230static alias RegexAlias("x", desc("Alias for --regex"), aliasopt(UseRegex),231                        cl::NotHidden);232static opt<bool>233    ShowChildren("show-children",234                 desc("Show a debug info entry's children when selectively "235                      "printing entries."),236                 cat(DwarfDumpCategory));237static alias ShowChildrenAlias("c", desc("Alias for --show-children."),238                               aliasopt(ShowChildren), cl::NotHidden);239static opt<bool>240    ShowParents("show-parents",241                desc("Show a debug info entry's parents when selectively "242                     "printing entries."),243                cat(DwarfDumpCategory));244static alias ShowParentsAlias("p", desc("Alias for --show-parents."),245                              aliasopt(ShowParents), cl::NotHidden);246 247static list<std::string> FilterChildTag(248    "filter-child-tag",249    desc("When --show-children is specified, show only DIEs with the "250         "specified DWARF tags."),251    value_desc("list of DWARF tags"), cat(DwarfDumpCategory));252static alias FilterChildTagAlias("t", desc("Alias for --filter-child-tag."),253                                 aliasopt(FilterChildTag), cl::NotHidden);254 255static opt<bool>256    ShowForm("show-form",257             desc("Show DWARF form types after the DWARF attribute types."),258             cat(DwarfDumpCategory));259static alias ShowFormAlias("F", desc("Alias for --show-form."),260                           aliasopt(ShowForm), cat(DwarfDumpCategory),261                           cl::NotHidden);262static opt<unsigned>263    ChildRecurseDepth("recurse-depth",264                      desc("Only recurse to a depth of N when displaying "265                           "children of debug info entries."),266                      cat(DwarfDumpCategory), init(-1U), value_desc("N"));267static alias ChildRecurseDepthAlias("r", desc("Alias for --recurse-depth."),268                                    aliasopt(ChildRecurseDepth), cl::NotHidden);269static opt<unsigned>270    ParentRecurseDepth("parent-recurse-depth",271                       desc("Only recurse to a depth of N when displaying "272                            "parents of debug info entries."),273                       cat(DwarfDumpCategory), init(-1U), value_desc("N"));274static opt<bool>275    SummarizeTypes("summarize-types",276                   desc("Abbreviate the description of type unit entries."),277                   cat(DwarfDumpCategory));278static cl::opt<bool>279    Statistics("statistics",280               cl::desc("Emit JSON-formatted debug info quality metrics."),281               cat(DwarfDumpCategory));282static cl::opt<bool>283    ShowSectionSizes("show-section-sizes",284                     cl::desc("Show the sizes of all debug sections, "285                              "expressed in bytes."),286                     cat(DwarfDumpCategory));287static cl::opt<bool> ManuallyGenerateUnitIndex(288    "manually-generate-unit-index",289    cl::desc("if the input is dwp file, parse .debug_info "290             "section and use it to populate "291             "DW_SECT_INFO contributions in cu-index. "292             "For DWARF5 it also populated TU Index."),293    cl::init(false), cl::Hidden, cl::cat(DwarfDumpCategory));294static cl::opt<bool>295    ShowSources("show-sources",296                cl::desc("Show the sources across all compilation units."),297                cat(DwarfDumpCategory));298static opt<bool> Verify("verify", desc("Verify the DWARF debug info."),299                        cat(DwarfDumpCategory));300static opt<unsigned> VerifyNumThreads(301    "verify-num-threads", init(1),302    desc("Number of threads to use for --verify. Single threaded verification "303         "is the default unless this option is specified. If 0 is specified, "304         "maximum hardware threads will be used. This can cause the "305         "output to be non determinisitic, but can speed up verification and "306         "is useful when running with the summary only or JSON summary modes."),307    cat(DwarfDumpCategory));308static opt<ErrorDetailLevel> ErrorDetails(309    "error-display", init(Unspecified),310    desc("Set the level of detail and summary to display when verifying "311         "(implies --verify)"),312    values(clEnumValN(NoDetailsOrSummary, "quiet",313                      "Only display whether errors occurred."),314           clEnumValN(NoDetailsOnlySummary, "summary",315                      "Display only a summary of the errors found."),316           clEnumValN(OnlyDetailsNoSummary, "details",317                      "Display each error in detail but no summary."),318           clEnumValN(BothDetailsAndSummary, "full",319                      "Display each error as well as a summary. [default]")),320    cat(DwarfDumpCategory));321static opt<std::string> JsonErrSummaryFile(322    "verify-json", init(""),323    desc("Output JSON-formatted error summary to the specified file. "324         "(Implies --verify)"),325    value_desc("filename.json"), cat(DwarfDumpCategory));326static opt<bool> Quiet("quiet", desc("Use with -verify to not emit to STDOUT."),327                       cat(DwarfDumpCategory));328static opt<bool> DumpUUID("uuid", desc("Show the UUID for each architecture."),329                          cat(DwarfDumpCategory));330static alias DumpUUIDAlias("u", desc("Alias for --uuid."), aliasopt(DumpUUID),331                           cl::NotHidden);332static opt<bool> Verbose("verbose",333                         desc("Print more low-level encoding details."),334                         cat(DwarfDumpCategory));335static alias VerboseAlias("v", desc("Alias for --verbose."), aliasopt(Verbose),336                          cat(DwarfDumpCategory), cl::NotHidden);337static cl::extrahelp338    HelpResponse("\nPass @FILE as argument to read options from FILE.\n");339} // namespace340/// @}341//===----------------------------------------------------------------------===//342 343static llvm::SmallVector<unsigned>344makeTagVector(const list<std::string> &TagStrings) {345  return llvm::map_to_vector(TagStrings, [](const std::string &Tag) {346    return llvm::dwarf::getTag(Tag);347  });348}349 350static void error(Error Err) {351  if (!Err)352    return;353  WithColor::error() << toString(std::move(Err)) << "\n";354  exit(1);355}356 357static void error(StringRef Prefix, Error Err) {358  if (!Err)359    return;360  WithColor::error() << Prefix << ": " << toString(std::move(Err)) << "\n";361  exit(1);362}363 364static void error(StringRef Prefix, std::error_code EC) {365  error(Prefix, errorCodeToError(EC));366}367 368static DIDumpOptions getDumpOpts(DWARFContext &C) {369  DIDumpOptions DumpOpts;370  DumpOpts.DumpType = DumpType;371  DumpOpts.ChildRecurseDepth = ChildRecurseDepth;372  DumpOpts.ParentRecurseDepth = ParentRecurseDepth;373  DumpOpts.ShowAddresses = !Diff;374  DumpOpts.ShowChildren = ShowChildren;375  DumpOpts.ShowParents = ShowParents;376  DumpOpts.FilterChildTag = makeTagVector(FilterChildTag);377  DumpOpts.ShowForm = ShowForm;378  DumpOpts.SummarizeTypes = SummarizeTypes;379  DumpOpts.Verbose = Verbose;380  DumpOpts.DumpNonSkeleton = DumpNonSkeleton;381  DumpOpts.RecoverableErrorHandler = C.getRecoverableErrorHandler();382  // In -verify mode, print DIEs without children in error messages.383  if (Verify) {384    DumpOpts.Verbose = ErrorDetails != NoDetailsOnlySummary &&385                       ErrorDetails != NoDetailsOrSummary;386    DumpOpts.ShowAggregateErrors = ErrorDetails != OnlyDetailsNoSummary &&387                                   ErrorDetails != NoDetailsOnlySummary;388    DumpOpts.JsonErrSummaryFile = JsonErrSummaryFile;389    return DumpOpts.noImplicitRecursion();390  }391  return DumpOpts;392}393 394static uint32_t getCPUType(MachOObjectFile &MachO) {395  if (MachO.is64Bit())396    return MachO.getHeader64().cputype;397  else398    return MachO.getHeader().cputype;399}400 401/// Return true if the object file has not been filtered by an --arch option.402static bool filterArch(ObjectFile &Obj) {403  if (ArchFilters.empty())404    return true;405 406  if (auto *MachO = dyn_cast<MachOObjectFile>(&Obj)) {407    for (const StringRef Arch : ArchFilters) {408      // Match architecture number.409      unsigned Value;410      if (!Arch.getAsInteger(0, Value))411        if (Value == getCPUType(*MachO))412          return true;413 414      // Match as name.415      if (MachO->getArchTriple().getArchName() == Triple(Arch).getArchName())416        return true;417    }418  }419  return false;420}421 422using HandlerFn = std::function<bool(ObjectFile &, DWARFContext &DICtx,423                                     const Twine &, raw_ostream &)>;424 425/// Print only DIEs that have a certain name.426static bool filterByName(427    const StringSet<> &Names, DWARFDie Die, StringRef NameRef, raw_ostream &OS,428    std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {429  DIDumpOptions DumpOpts = getDumpOpts(Die.getDwarfUnit()->getContext());430  DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;431  std::string Name =432      (IgnoreCase && !UseRegex) ? NameRef.lower() : NameRef.str();433  if (UseRegex) {434    // Match regular expression.435    for (auto Pattern : Names.keys()) {436      Regex RE(Pattern, IgnoreCase ? Regex::IgnoreCase : Regex::NoFlags);437      std::string Error;438      if (!RE.isValid(Error)) {439        errs() << "error in regular expression: " << Error << "\n";440        exit(1);441      }442      if (RE.match(Name)) {443        Die.dump(OS, 0, DumpOpts);444        return true;445      }446    }447  } else if (Names.count(Name)) {448    // Match full text.449    Die.dump(OS, 0, DumpOpts);450    return true;451  }452  return false;453}454 455/// Print only DIEs that have a certain name.456static void filterByName(457    const StringSet<> &Names, DWARFContext::unit_iterator_range CUs,458    raw_ostream &OS,459    std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {460  auto filterDieNames = [&](DWARFUnit *Unit) {461    for (const auto &Entry : Unit->dies()) {462      DWARFDie Die = {Unit, &Entry};463      if (const char *Name = Die.getName(DINameKind::ShortName))464        if (filterByName(Names, Die, Name, OS, GetNameForDWARFReg))465          continue;466      if (const char *Name = Die.getName(DINameKind::LinkageName))467        filterByName(Names, Die, Name, OS, GetNameForDWARFReg);468    }469  };470  for (const auto &CU : CUs) {471    filterDieNames(CU.get());472    if (DumpNonSkeleton) {473      // If we have split DWARF, then recurse down into the .dwo files as well.474      DWARFDie CUDie = CU->getUnitDIE(false);475      DWARFDie CUNonSkeletonDie = CU->getNonSkeletonUnitDIE(false);476      // If we have a DWO file, we need to search it as well477      if (CUNonSkeletonDie && CUDie != CUNonSkeletonDie)478        filterDieNames(CUNonSkeletonDie.getDwarfUnit());479    }480  }481}482 483static void getDies(DWARFContext &DICtx, const AppleAcceleratorTable &Accel,484                    StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {485  for (const auto &Entry : Accel.equal_range(Name)) {486    if (std::optional<uint64_t> Off = Entry.getDIESectionOffset()) {487      if (DWARFDie Die = DICtx.getDIEForOffset(*Off))488        Dies.push_back(Die);489    }490  }491}492 493static DWARFDie toDie(const DWARFDebugNames::Entry &Entry,494                      DWARFContext &DICtx) {495  std::optional<uint64_t> CUOff = Entry.getCUOffset();496  std::optional<uint64_t> Off = Entry.getDIEUnitOffset();497  if (!CUOff || !Off)498    return DWARFDie();499 500  DWARFCompileUnit *CU = DICtx.getCompileUnitForOffset(*CUOff);501  if (!CU)502    return DWARFDie();503 504  if (std::optional<uint64_t> DWOId = CU->getDWOId()) {505    // This is a skeleton unit. Look up the DIE in the DWO unit.506    CU = DICtx.getDWOCompileUnitForHash(*DWOId);507    if (!CU)508      return DWARFDie();509  }510 511  return CU->getDIEForOffset(CU->getOffset() + *Off);512}513 514static void getDies(DWARFContext &DICtx, const DWARFDebugNames &Accel,515                    StringRef Name, SmallVectorImpl<DWARFDie> &Dies) {516  for (const auto &Entry : Accel.equal_range(Name)) {517    if (DWARFDie Die = toDie(Entry, DICtx))518      Dies.push_back(Die);519  }520}521 522/// Print only DIEs that have a certain name.523static void filterByAccelName(524    ArrayRef<std::string> Names, DWARFContext &DICtx, raw_ostream &OS,525    std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {526  SmallVector<DWARFDie, 4> Dies;527  for (const auto &Name : Names) {528    getDies(DICtx, DICtx.getAppleNames(), Name, Dies);529    getDies(DICtx, DICtx.getAppleTypes(), Name, Dies);530    getDies(DICtx, DICtx.getAppleNamespaces(), Name, Dies);531    getDies(DICtx, DICtx.getDebugNames(), Name, Dies);532  }533  llvm::sort(Dies);534  Dies.erase(llvm::unique(Dies), Dies.end());535 536  DIDumpOptions DumpOpts = getDumpOpts(DICtx);537  DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;538  for (DWARFDie Die : Dies)539    Die.dump(OS, 0, DumpOpts);540}541 542/// Print all DIEs in apple accelerator tables543static void findAllApple(544    DWARFContext &DICtx, raw_ostream &OS,545    std::function<StringRef(uint64_t RegNum, bool IsEH)> GetNameForDWARFReg) {546  MapVector<StringRef, llvm::SmallSet<DWARFDie, 2>> NameToDies;547 548  auto PushDIEs = [&](const AppleAcceleratorTable &Accel) {549    for (const auto &Entry : Accel.entries()) {550      if (std::optional<uint64_t> Off = Entry.BaseEntry.getDIESectionOffset()) {551        std::optional<StringRef> MaybeName = Entry.readName();552        DWARFDie Die = DICtx.getDIEForOffset(*Off);553        if (Die && MaybeName)554          NameToDies[*MaybeName].insert(Die);555      }556    }557  };558 559  PushDIEs(DICtx.getAppleNames());560  PushDIEs(DICtx.getAppleNamespaces());561  PushDIEs(DICtx.getAppleTypes());562 563  DIDumpOptions DumpOpts = getDumpOpts(DICtx);564  DumpOpts.GetNameForDWARFReg = GetNameForDWARFReg;565  for (const auto &[Name, Dies] : NameToDies) {566    OS << llvm::formatv("\nApple accelerator entries with name = \"{0}\":\n",567                        Name);568    for (DWARFDie Die : Dies)569      Die.dump(OS, 0, DumpOpts);570  }571}572 573/// Handle the --lookup option and dump the DIEs and line info for the given574/// address.575/// TODO: specified Address for --lookup option could relate for several576/// different sections(in case not-linked object file). llvm-dwarfdump577/// need to do something with this: extend lookup option with section578/// information or probably display all matched entries, or something else...579static bool lookup(ObjectFile &Obj, DWARFContext &DICtx, uint64_t Address,580                   raw_ostream &OS) {581  auto DIEsForAddr = DICtx.getDIEsForAddress(Lookup, DumpNonSkeleton);582 583  if (!DIEsForAddr)584    return false;585 586  DIDumpOptions DumpOpts = getDumpOpts(DICtx);587  DumpOpts.ChildRecurseDepth = 0;588  DIEsForAddr.CompileUnit->dump(OS, DumpOpts);589  if (DIEsForAddr.FunctionDIE) {590    DIEsForAddr.FunctionDIE.dump(OS, 2, DumpOpts);591    if (DIEsForAddr.BlockDIE)592      DIEsForAddr.BlockDIE.dump(OS, 4, DumpOpts);593  }594 595  // TODO: it is neccessary to set proper SectionIndex here.596  // object::SectionedAddress::UndefSection works for only absolute addresses.597  if (DILineInfo LineInfo =598          DICtx599              .getLineInfoForAddress(600                  {Lookup, object::SectionedAddress::UndefSection})601              .value_or(DILineInfo())) {602    LineInfo.dump(OS);603  }604 605  return true;606}607 608// Collect all sources referenced from the given line table, scoped to the given609// CU compilation directory.610static bool collectLineTableSources(const DWARFDebugLine::LineTable &LT,611                                    StringRef CompDir,612                                    std::vector<std::string> &Sources) {613  bool Result = true;614  std::optional<uint64_t> LastIndex = LT.getLastValidFileIndex();615  for (uint64_t I = LT.hasFileAtIndex(0) ? 0 : 1,616                E = LastIndex ? *LastIndex + 1 : 0;617       I < E; ++I) {618    std::string Path;619    Result &= LT.getFileNameByIndex(620        I, CompDir, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,621        Path);622    Sources.push_back(std::move(Path));623  }624  return Result;625}626 627static bool collectObjectSources(ObjectFile &Obj, DWARFContext &DICtx,628                                 const Twine &Filename, raw_ostream &OS) {629  bool Result = true;630  std::vector<std::string> Sources;631 632  bool HasCompileUnits = false;633  for (const auto &CU : DICtx.compile_units()) {634    HasCompileUnits = true;635    // Extract paths from the line table for this CU. This allows combining the636    // compilation directory with the line information, in case both the include637    // directory and file names in the line table are relative.638    const DWARFDebugLine::LineTable *LT = DICtx.getLineTableForUnit(CU.get());639    StringRef CompDir = CU->getCompilationDir();640    if (LT) {641      Result &= collectLineTableSources(*LT, CompDir, Sources);642    } else {643      // Since there's no line table for this CU, collect the name from the CU644      // itself.645      const char *Name = CU->getUnitDIE().getShortName();646      if (!Name) {647        WithColor::warning()648            << Filename << ": missing name for compilation unit\n";649        continue;650      }651      SmallString<64> AbsName;652      if (sys::path::is_relative(Name, sys::path::Style::posix) &&653          sys::path::is_relative(Name, sys::path::Style::windows))654        AbsName = CompDir;655      sys::path::append(AbsName, Name);656      Sources.push_back(std::string(AbsName));657    }658  }659 660  if (!HasCompileUnits) {661    // Since there's no compile units available, walk the line tables and662    // extract out any referenced paths.663    DWARFDataExtractor LineData(DICtx.getDWARFObj(),664                                DICtx.getDWARFObj().getLineSection(),665                                DICtx.isLittleEndian(), 0);666    DWARFDebugLine::SectionParser Parser(LineData, DICtx, DICtx.normal_units());667    while (!Parser.done()) {668      const auto RecoverableErrorHandler = [&](Error Err) {669        Result = false;670        WithColor::defaultErrorHandler(std::move(Err));671      };672      void (*UnrecoverableErrorHandler)(Error Err) = error;673 674      DWARFDebugLine::LineTable LT =675          Parser.parseNext(RecoverableErrorHandler, UnrecoverableErrorHandler);676      Result &= collectLineTableSources(LT, /*CompDir=*/"", Sources);677    }678  }679 680  // Dedup and order the sources.681  llvm::sort(Sources);682  Sources.erase(llvm::unique(Sources), Sources.end());683 684  for (StringRef Name : Sources)685    OS << Name << "\n";686  return Result;687}688 689static std::unique_ptr<MCRegisterInfo>690createRegInfo(const object::ObjectFile &Obj) {691  std::unique_ptr<MCRegisterInfo> MCRegInfo;692  Triple TT;693  TT.setArch(Triple::ArchType(Obj.getArch()));694  TT.setVendor(Triple::UnknownVendor);695  TT.setOS(Triple::UnknownOS);696  std::string TargetLookupError;697  const Target *TheTarget = TargetRegistry::lookupTarget(TT, TargetLookupError);698  if (!TargetLookupError.empty())699    return nullptr;700  MCRegInfo.reset(TheTarget->createMCRegInfo(TT));701  return MCRegInfo;702}703 704static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx,705                           const Twine &Filename, raw_ostream &OS) {706 707  auto MCRegInfo = createRegInfo(Obj);708  if (!MCRegInfo)709    logAllUnhandledErrors(createStringError(inconvertibleErrorCode(),710                                            "Error in creating MCRegInfo"),711                          errs(), Filename.str() + ": ");712 713  auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum, bool IsEH) -> StringRef {714    if (!MCRegInfo)715      return {};716    if (std::optional<MCRegister> LLVMRegNum =717            MCRegInfo->getLLVMRegNum(DwarfRegNum, IsEH))718      if (const char *RegName = MCRegInfo->getName(*LLVMRegNum))719        return StringRef(RegName);720    return {};721  };722 723  // The UUID dump already contains all the same information.724  if (!(DumpType & DIDT_UUID) || DumpType == DIDT_All)725    OS << Filename << ":\tfile format " << Obj.getFileFormatName() << '\n';726 727  // Handle the --lookup option.728  if (Lookup)729    return lookup(Obj, DICtx, Lookup, OS);730 731  // Handle the --name option.732  if (!Name.empty()) {733    StringSet<> Names;734    for (const auto &name : Name)735      Names.insert((IgnoreCase && !UseRegex) ? StringRef(name).lower() : name);736 737    filterByName(Names, DICtx.normal_units(), OS, GetRegName);738    filterByName(Names, DICtx.dwo_units(), OS, GetRegName);739    return true;740  }741 742  // Handle the --find option and lower it to --debug-info=<offset>.743  if (!Find.empty()) {744    filterByAccelName(Find, DICtx, OS, GetRegName);745    return true;746  }747 748  // Handle the --find-all-apple option and lower it to --debug-info=<offset>.749  if (FindAllApple) {750    findAllApple(DICtx, OS, GetRegName);751    return true;752  }753 754  // Dump the complete DWARF structure.755  auto DumpOpts = getDumpOpts(DICtx);756  DumpOpts.GetNameForDWARFReg = GetRegName;757  DICtx.dump(OS, DumpOpts, DumpOffsets);758  return true;759}760 761static bool verifyObjectFile(ObjectFile &Obj, DWARFContext &DICtx,762                             const Twine &Filename, raw_ostream &OS) {763  // Verify the DWARF and exit with non-zero exit status if verification764  // fails.765  raw_ostream &stream = Quiet ? nulls() : OS;766  stream << "Verifying " << Filename.str() << ":\tfile format "767         << Obj.getFileFormatName() << "\n";768  bool Result = DICtx.verify(stream, getDumpOpts(DICtx));769  if (Result)770    stream << "No errors.\n";771  else772    stream << "Errors detected.\n";773  return Result;774}775 776static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,777                         HandlerFn HandleObj, raw_ostream &OS);778 779static bool handleArchive(StringRef Filename, Archive &Arch,780                          HandlerFn HandleObj, raw_ostream &OS) {781  bool Result = true;782  Error Err = Error::success();783  for (const auto &Child : Arch.children(Err)) {784    auto BuffOrErr = Child.getMemoryBufferRef();785    error(Filename, BuffOrErr.takeError());786    auto NameOrErr = Child.getName();787    error(Filename, NameOrErr.takeError());788    std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();789    Result &= handleBuffer(Name, BuffOrErr.get(), HandleObj, OS);790  }791  error(Filename, std::move(Err));792 793  return Result;794}795 796static bool handleBuffer(StringRef Filename, MemoryBufferRef Buffer,797                         HandlerFn HandleObj, raw_ostream &OS) {798  Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);799  error(Filename, BinOrErr.takeError());800 801  bool Result = true;802  auto RecoverableErrorHandler = [&](Error E) {803    Result = false;804    WithColor::defaultErrorHandler(std::move(E));805  };806  if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {807    if (filterArch(*Obj)) {808      std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(809          *Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",810          RecoverableErrorHandler, WithColor::defaultWarningHandler,811          /*ThreadSafe=*/true);812      DICtx->setParseCUTUIndexManually(ManuallyGenerateUnitIndex);813      if (!HandleObj(*Obj, *DICtx, Filename, OS))814        Result = false;815    }816  } else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get()))817    for (auto &ObjForArch : Fat->objects()) {818      std::string ObjName =819          (Filename + "(" + ObjForArch.getArchFlagName() + ")").str();820      if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {821        auto &Obj = **MachOOrErr;822        if (filterArch(Obj)) {823          std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(824              Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",825              RecoverableErrorHandler);826          if (!HandleObj(Obj, *DICtx, ObjName, OS))827            Result = false;828        }829        continue;830      } else831        consumeError(MachOOrErr.takeError());832      if (auto ArchiveOrErr = ObjForArch.getAsArchive()) {833        error(ObjName, ArchiveOrErr.takeError());834        if (!handleArchive(ObjName, *ArchiveOrErr.get(), HandleObj, OS))835          Result = false;836        continue;837      } else838        consumeError(ArchiveOrErr.takeError());839    }840  else if (auto *Arch = dyn_cast<Archive>(BinOrErr->get()))841    Result = handleArchive(Filename, *Arch, HandleObj, OS);842  return Result;843}844 845static bool handleFile(StringRef Filename, HandlerFn HandleObj,846                       raw_ostream &OS) {847  ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =848      MemoryBuffer::getFileOrSTDIN(Filename);849  error(Filename, BuffOrErr.getError());850  std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());851  return handleBuffer(Filename, *Buffer, HandleObj, OS);852}853 854int main(int argc, char **argv) {855  InitLLVM X(argc, argv);856 857  // Flush outs() when printing to errs(). This avoids interleaving output858  // between the two.859  errs().tie(&outs());860 861  llvm::InitializeAllTargetInfos();862  llvm::InitializeAllTargetMCs();863 864  HideUnrelatedOptions(865      {&DwarfDumpCategory, &SectionCategory, &getColorCategory()});866  cl::ParseCommandLineOptions(867      argc, argv,868      "pretty-print DWARF debug information in object files"869      " and debug info archives.\n");870 871  // FIXME: Audit interactions between these two options and make them872  //        compatible.873  if (Diff && Verbose) {874    WithColor::error() << "incompatible arguments: specifying both -diff and "875                          "-verbose is currently not supported";876    return 1;877  }878  // -error-detail and -json-summary-file both imply -verify879  if (ErrorDetails != Unspecified || !JsonErrSummaryFile.empty()) {880    Verify = true;881  }882 883  std::error_code EC;884  ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_TextWithCRLF);885  error("unable to open output file " + OutputFilename, EC);886  // Don't remove output file if we exit with an error.887  OutputFile.keep();888 889  bool OffsetRequested = false;890 891  // Defaults to dumping only debug_info, unless: A) verbose mode is specified,892  // in which case all sections are dumped, or B) a specific section is893  // requested.894#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \895  if (Dump##ENUM_NAME.IsRequested) {                                           \896    DumpType |= DIDT_##ENUM_NAME;                                              \897    if (Dump##ENUM_NAME.HasValue) {                                            \898      DumpOffsets[DIDT_ID_##ENUM_NAME] = Dump##ENUM_NAME.Val;                  \899      OffsetRequested = true;                                                  \900    }                                                                          \901  }902#include "llvm/BinaryFormat/Dwarf.def"903#undef HANDLE_DWARF_SECTION904  if (DumpUUID)905    DumpType |= DIDT_UUID;906  if (DumpAll)907    DumpType = DIDT_All;908  if (DumpType == DIDT_Null) {909    if (Verbose || Verify)910      DumpType = DIDT_All;911    else912      DumpType = DIDT_DebugInfo;913  }914 915  // Unless dumping a specific DIE, default to --show-children.916  if (!ShowChildren && !Verify && !OffsetRequested && Name.empty() &&917      Find.empty() && !FindAllApple)918    ShowChildren = true;919 920  // Defaults to a.out if no filenames specified.921  if (InputFilenames.empty())922    InputFilenames.push_back("a.out");923 924  // Expand any .dSYM bundles to the individual object files contained therein.925  std::vector<std::string> Objects;926  for (const auto &F : InputFilenames) {927    if (auto DsymObjectsOrErr = MachOObjectFile::findDsymObjectMembers(F)) {928      if (DsymObjectsOrErr->empty())929        Objects.push_back(F);930      else931        llvm::append_range(Objects, *DsymObjectsOrErr);932    } else {933      error(DsymObjectsOrErr.takeError());934    }935  }936 937  bool Success = true;938  if (Verify) {939    if (!VerifyNumThreads)940      parallel::strategy =941          hardware_concurrency(hardware_concurrency().compute_thread_count());942    else943      parallel::strategy = hardware_concurrency(VerifyNumThreads);944    for (StringRef Object : Objects)945      Success &= handleFile(Object, verifyObjectFile, OutputFile.os());946  } else if (Statistics) {947    for (StringRef Object : Objects)948      Success &= handleFile(Object, collectStatsForObjectFile, OutputFile.os());949  } else if (ShowSectionSizes) {950    for (StringRef Object : Objects)951      Success &= handleFile(Object, collectObjectSectionSizes, OutputFile.os());952  } else if (ShowSources) {953    for (StringRef Object : Objects)954      Success &= handleFile(Object, collectObjectSources, OutputFile.os());955  } else {956    for (StringRef Object : Objects)957      Success &= handleFile(Object, dumpObjectFile, OutputFile.os());958  }959 960  return Success ? EXIT_SUCCESS : EXIT_FAILURE;961}962