brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.6 KiB · 2022444 Raw
564 lines · cpp
1//===- llvm-cxxdump.cpp - Dump C++ data in an Object File -------*- C++ -*-===//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// Dumps C++ data resident in object files and archives.10//11//===----------------------------------------------------------------------===//12 13#include "llvm-cxxdump.h"14#include "Error.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/MC/TargetRegistry.h"17#include "llvm/Object/Archive.h"18#include "llvm/Object/ObjectFile.h"19#include "llvm/Object/SymbolSize.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/Endian.h"22#include "llvm/Support/FileSystem.h"23#include "llvm/Support/InitLLVM.h"24#include "llvm/Support/TargetSelect.h"25#include "llvm/Support/WithColor.h"26#include "llvm/Support/raw_ostream.h"27#include <map>28#include <string>29#include <system_error>30 31using namespace llvm;32using namespace llvm::object;33using namespace llvm::support;34 35namespace opts {36static cl::OptionCategory CXXDumpCategory("CXX Dump Options");37cl::list<std::string> InputFilenames(cl::Positional,38                                     cl::desc("<input object files>"),39                                     cl::cat(CXXDumpCategory));40} // namespace opts41 42namespace llvm {43 44static void error(std::error_code EC) {45  if (!EC)46    return;47  WithColor::error(outs(), "") << "reading file: " << EC.message() << ".\n";48  outs().flush();49  exit(1);50}51 52[[noreturn]] static void error(Error Err) {53  logAllUnhandledErrors(std::move(Err), WithColor::error(outs()),54                        "reading file: ");55  outs().flush();56  exit(1);57}58 59template <typename T>60T unwrapOrError(Expected<T> EO) {61  if (!EO)62    error(EO.takeError());63  return std::move(*EO);64}65 66} // namespace llvm67 68static void reportError(StringRef Input, StringRef Message) {69  if (Input == "-")70    Input = "<stdin>";71  WithColor::error(errs(), Input) << Message << "\n";72  errs().flush();73  exit(1);74}75 76static void reportError(StringRef Input, std::error_code EC) {77  reportError(Input, EC.message());78}79 80static std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;81 82static void collectRelocatedSymbols(const ObjectFile *Obj,83                                    const SectionRef &Sec, uint64_t SecAddress,84                                    uint64_t SymAddress, uint64_t SymSize,85                                    StringRef *I, StringRef *E) {86  uint64_t SymOffset = SymAddress - SecAddress;87  uint64_t SymEnd = SymOffset + SymSize;88  for (const SectionRef &SR : SectionRelocMap[Sec]) {89    for (const object::RelocationRef &Reloc : SR.relocations()) {90      if (I == E)91        break;92      const object::symbol_iterator RelocSymI = Reloc.getSymbol();93      if (RelocSymI == Obj->symbol_end())94        continue;95      Expected<StringRef> RelocSymName = RelocSymI->getName();96      error(errorToErrorCode(RelocSymName.takeError()));97      uint64_t Offset = Reloc.getOffset();98      if (Offset >= SymOffset && Offset < SymEnd) {99        *I = *RelocSymName;100        ++I;101      }102    }103  }104}105 106static void collectRelocationOffsets(107    const ObjectFile *Obj, const SectionRef &Sec, uint64_t SecAddress,108    uint64_t SymAddress, uint64_t SymSize, StringRef SymName,109    std::map<std::pair<StringRef, uint64_t>, StringRef> &Collection) {110  uint64_t SymOffset = SymAddress - SecAddress;111  uint64_t SymEnd = SymOffset + SymSize;112  for (const SectionRef &SR : SectionRelocMap[Sec]) {113    for (const object::RelocationRef &Reloc : SR.relocations()) {114      const object::symbol_iterator RelocSymI = Reloc.getSymbol();115      if (RelocSymI == Obj->symbol_end())116        continue;117      Expected<StringRef> RelocSymName = RelocSymI->getName();118      error(errorToErrorCode(RelocSymName.takeError()));119      uint64_t Offset = Reloc.getOffset();120      if (Offset >= SymOffset && Offset < SymEnd)121        Collection[std::make_pair(SymName, Offset - SymOffset)] = *RelocSymName;122    }123  }124}125 126static void dumpCXXData(const ObjectFile *Obj) {127  struct CompleteObjectLocator {128    StringRef Symbols[2];129    ArrayRef<little32_t> Data;130  };131  struct ClassHierarchyDescriptor {132    StringRef Symbols[1];133    ArrayRef<little32_t> Data;134  };135  struct BaseClassDescriptor {136    StringRef Symbols[2];137    ArrayRef<little32_t> Data;138  };139  struct TypeDescriptor {140    StringRef Symbols[1];141    uint64_t AlwaysZero;142    StringRef MangledName;143  };144  struct ThrowInfo {145    uint32_t Flags;146  };147  struct CatchableTypeArray {148    uint32_t NumEntries;149  };150  struct CatchableType {151    uint32_t Flags;152    uint32_t NonVirtualBaseAdjustmentOffset;153    int32_t VirtualBasePointerOffset;154    uint32_t VirtualBaseAdjustmentOffset;155    uint32_t Size;156    StringRef Symbols[2];157  };158  std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries;159  std::map<std::pair<StringRef, uint64_t>, StringRef> TIEntries;160  std::map<std::pair<StringRef, uint64_t>, StringRef> CTAEntries;161  std::map<StringRef, ArrayRef<little32_t>> VBTables;162  std::map<StringRef, CompleteObjectLocator> COLs;163  std::map<StringRef, ClassHierarchyDescriptor> CHDs;164  std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries;165  std::map<StringRef, BaseClassDescriptor> BCDs;166  std::map<StringRef, TypeDescriptor> TDs;167  std::map<StringRef, ThrowInfo> TIs;168  std::map<StringRef, CatchableTypeArray> CTAs;169  std::map<StringRef, CatchableType> CTs;170 171  std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries;172  std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries;173  std::map<std::pair<StringRef, uint64_t>, StringRef> VTTEntries;174  std::map<StringRef, StringRef> TINames;175 176  SectionRelocMap.clear();177  for (const SectionRef &Section : Obj->sections()) {178    Expected<section_iterator> ErrOrSec = Section.getRelocatedSection();179    if (!ErrOrSec)180      error(ErrOrSec.takeError());181 182    section_iterator Sec2 = *ErrOrSec;183    if (Sec2 != Obj->section_end())184      SectionRelocMap[*Sec2].push_back(Section);185  }186 187  uint8_t BytesInAddress = Obj->getBytesInAddress();188 189  std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =190      object::computeSymbolSizes(*Obj);191 192  for (auto &P : SymAddr) {193    object::SymbolRef Sym = P.first;194    uint64_t SymSize = P.second;195    Expected<StringRef> SymNameOrErr = Sym.getName();196    error(errorToErrorCode(SymNameOrErr.takeError()));197    StringRef SymName = *SymNameOrErr;198    Expected<object::section_iterator> SecIOrErr = Sym.getSection();199    error(errorToErrorCode(SecIOrErr.takeError()));200    object::section_iterator SecI = *SecIOrErr;201    // Skip external symbols.202    if (SecI == Obj->section_end())203      continue;204    const SectionRef &Sec = *SecI;205    // Skip virtual or BSS sections.206    if (Sec.isBSS() || Sec.isVirtual())207      continue;208    StringRef SecContents = unwrapOrError(Sec.getContents());209    Expected<uint64_t> SymAddressOrErr = Sym.getAddress();210    error(errorToErrorCode(SymAddressOrErr.takeError()));211    uint64_t SymAddress = *SymAddressOrErr;212    uint64_t SecAddress = Sec.getAddress();213    uint64_t SecSize = Sec.getSize();214    uint64_t SymOffset = SymAddress - SecAddress;215    StringRef SymContents = SecContents.substr(SymOffset, SymSize);216 217    // VFTables in the MS-ABI start with '??_7' and are contained within their218    // own COMDAT section.  We then determine the contents of the VFTable by219    // looking at each relocation in the section.220    if (SymName.starts_with("??_7")) {221      // Each relocation either names a virtual method or a thunk.  We note the222      // offset into the section and the symbol used for the relocation.223      collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize,224                               SymName, VFTableEntries);225    }226    // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit227    // offsets of virtual bases.228    else if (SymName.starts_with("??_8")) {229      ArrayRef<little32_t> VBTableData(230          reinterpret_cast<const little32_t *>(SymContents.data()),231          SymContents.size() / sizeof(little32_t));232      VBTables[SymName] = VBTableData;233    }234    // Complete object locators in the MS-ABI start with '??_R4'235    else if (SymName.starts_with("??_R4")) {236      CompleteObjectLocator COL;237      COL.Data =238          ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);239      StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols);240      collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);241      COLs[SymName] = COL;242    }243    // Class hierarchy descriptors in the MS-ABI start with '??_R3'244    else if (SymName.starts_with("??_R3")) {245      ClassHierarchyDescriptor CHD;246      CHD.Data =247          ArrayRef(reinterpret_cast<const little32_t *>(SymContents.data()), 3);248      StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols);249      collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);250      CHDs[SymName] = CHD;251    }252    // Class hierarchy descriptors in the MS-ABI start with '??_R2'253    else if (SymName.starts_with("??_R2")) {254      // Each relocation names a base class descriptor.  We note the offset into255      // the section and the symbol used for the relocation.256      collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,257                               SymName, BCAEntries);258    }259    // Base class descriptors in the MS-ABI start with '??_R1'260    else if (SymName.starts_with("??_R1")) {261      BaseClassDescriptor BCD;262      BCD.Data = ArrayRef(263          reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5);264      StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols);265      collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);266      BCDs[SymName] = BCD;267    }268    // Type descriptors in the MS-ABI start with '??_R0'269    else if (SymName.starts_with("??_R0")) {270      const char *DataPtr = SymContents.drop_front(BytesInAddress).data();271      TypeDescriptor TD;272      if (BytesInAddress == 8)273        TD.AlwaysZero = *reinterpret_cast<const little64_t *>(DataPtr);274      else275        TD.AlwaysZero = *reinterpret_cast<const little32_t *>(DataPtr);276      TD.MangledName = SymContents.drop_front(BytesInAddress * 2);277      StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols);278      collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);279      TDs[SymName] = TD;280    }281    // Throw descriptors in the MS-ABI start with '_TI'282    else if (SymName.starts_with("_TI") || SymName.starts_with("__TI")) {283      ThrowInfo TI;284      TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data());285      collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,286                               SymName, TIEntries);287      TIs[SymName] = TI;288    }289    // Catchable type arrays in the MS-ABI start with _CTA or __CTA.290    else if (SymName.starts_with("_CTA") || SymName.starts_with("__CTA")) {291      CatchableTypeArray CTA;292      CTA.NumEntries =293          *reinterpret_cast<const little32_t *>(SymContents.data());294      collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,295                               SymName, CTAEntries);296      CTAs[SymName] = CTA;297    }298    // Catchable types in the MS-ABI start with _CT or __CT.299    else if (SymName.starts_with("_CT") || SymName.starts_with("__CT")) {300      const little32_t *DataPtr =301          reinterpret_cast<const little32_t *>(SymContents.data());302      CatchableType CT;303      CT.Flags = DataPtr[0];304      CT.NonVirtualBaseAdjustmentOffset = DataPtr[2];305      CT.VirtualBasePointerOffset = DataPtr[3];306      CT.VirtualBaseAdjustmentOffset = DataPtr[4];307      CT.Size = DataPtr[5];308      StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols);309      collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E);310      CTs[SymName] = CT;311    }312    // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.313    else if (SymName.starts_with("_ZTT") || SymName.starts_with("__ZTT")) {314      collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,315                               SymName, VTTEntries);316    }317    // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.318    else if (SymName.starts_with("_ZTS") || SymName.starts_with("__ZTS")) {319      TINames[SymName] = SymContents.slice(0, SymContents.find('\0'));320    }321    // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.322    else if (SymName.starts_with("_ZTV") || SymName.starts_with("__ZTV")) {323      collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,324                               SymName, VTableSymEntries);325      for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) {326        auto Key = std::make_pair(SymName, SymOffI);327        if (VTableSymEntries.count(Key))328          continue;329        const char *DataPtr =330            SymContents.substr(SymOffI, BytesInAddress).data();331        int64_t VData;332        if (BytesInAddress == 8)333          VData = *reinterpret_cast<const little64_t *>(DataPtr);334        else335          VData = *reinterpret_cast<const little32_t *>(DataPtr);336        VTableDataEntries[Key] = VData;337      }338    }339    // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.340    else if (SymName.starts_with("_ZTI") || SymName.starts_with("__ZTI")) {341      // FIXME: Do something with these!342    }343  }344  for (const auto &VFTableEntry : VFTableEntries) {345    StringRef VFTableName = VFTableEntry.first.first;346    uint64_t Offset = VFTableEntry.first.second;347    StringRef SymName = VFTableEntry.second;348    outs() << VFTableName << '[' << Offset << "]: " << SymName << '\n';349  }350  for (const auto &VBTable : VBTables) {351    StringRef VBTableName = VBTable.first;352    uint32_t Idx = 0;353    for (little32_t Offset : VBTable.second) {354      outs() << VBTableName << '[' << Idx << "]: " << Offset << '\n';355      Idx += sizeof(Offset);356    }357  }358  for (const auto &COLPair : COLs) {359    StringRef COLName = COLPair.first;360    const CompleteObjectLocator &COL = COLPair.second;361    outs() << COLName << "[IsImageRelative]: " << COL.Data[0] << '\n';362    outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n';363    outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n';364    outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n';365    outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1]366           << '\n';367  }368  for (const auto &CHDPair : CHDs) {369    StringRef CHDName = CHDPair.first;370    const ClassHierarchyDescriptor &CHD = CHDPair.second;371    outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n';372    outs() << CHDName << "[Flags]: " << CHD.Data[1] << '\n';373    outs() << CHDName << "[NumClasses]: " << CHD.Data[2] << '\n';374    outs() << CHDName << "[BaseClassArray]: " << CHD.Symbols[0] << '\n';375  }376  for (const auto &BCAEntry : BCAEntries) {377    StringRef BCAName = BCAEntry.first.first;378    uint64_t Offset = BCAEntry.first.second;379    StringRef SymName = BCAEntry.second;380    outs() << BCAName << '[' << Offset << "]: " << SymName << '\n';381  }382  for (const auto &BCDPair : BCDs) {383    StringRef BCDName = BCDPair.first;384    const BaseClassDescriptor &BCD = BCDPair.second;385    outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n';386    outs() << BCDName << "[NumBases]: " << BCD.Data[0] << '\n';387    outs() << BCDName << "[OffsetInVBase]: " << BCD.Data[1] << '\n';388    outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n';389    outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n';390    outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n';391    outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1]392           << '\n';393  }394  for (const auto &TDPair : TDs) {395    StringRef TDName = TDPair.first;396    const TypeDescriptor &TD = TDPair.second;397    outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n';398    outs() << TDName << "[AlwaysZero]: " << TD.AlwaysZero << '\n';399    outs() << TDName << "[MangledName]: ";400    outs().write_escaped(TD.MangledName.rtrim(StringRef("\0", 1)),401                         /*UseHexEscapes=*/true)402        << '\n';403  }404  for (const auto &TIPair : TIs) {405    StringRef TIName = TIPair.first;406    const ThrowInfo &TI = TIPair.second;407    auto dumpThrowInfoFlag = [&](const char *Name, uint32_t Flag) {408      outs() << TIName << "[Flags." << Name409             << "]: " << (TI.Flags & Flag ? "true" : "false") << '\n';410    };411    auto dumpThrowInfoSymbol = [&](const char *Name, int Offset) {412      outs() << TIName << '[' << Name << "]: ";413      auto Entry = TIEntries.find(std::make_pair(TIName, Offset));414      outs() << (Entry == TIEntries.end() ? "null" : Entry->second) << '\n';415    };416    outs() << TIName << "[Flags]: " << TI.Flags << '\n';417    dumpThrowInfoFlag("Const", 1);418    dumpThrowInfoFlag("Volatile", 2);419    dumpThrowInfoSymbol("CleanupFn", 4);420    dumpThrowInfoSymbol("ForwardCompat", 8);421    dumpThrowInfoSymbol("CatchableTypeArray", 12);422  }423  for (const auto &CTAPair : CTAs) {424    StringRef CTAName = CTAPair.first;425    const CatchableTypeArray &CTA = CTAPair.second;426 427    outs() << CTAName << "[NumEntries]: " << CTA.NumEntries << '\n';428 429    unsigned Idx = 0;430    for (auto I = CTAEntries.lower_bound(std::make_pair(CTAName, 0)),431              E = CTAEntries.upper_bound(std::make_pair(CTAName, UINT64_MAX));432         I != E; ++I)433      outs() << CTAName << '[' << Idx++ << "]: " << I->second << '\n';434  }435  for (const auto &CTPair : CTs) {436    StringRef CTName = CTPair.first;437    const CatchableType &CT = CTPair.second;438    auto dumpCatchableTypeFlag = [&](const char *Name, uint32_t Flag) {439      outs() << CTName << "[Flags." << Name440             << "]: " << (CT.Flags & Flag ? "true" : "false") << '\n';441    };442    outs() << CTName << "[Flags]: " << CT.Flags << '\n';443    dumpCatchableTypeFlag("ScalarType", 1);444    dumpCatchableTypeFlag("VirtualInheritance", 4);445    outs() << CTName << "[TypeDescriptor]: " << CT.Symbols[0] << '\n';446    outs() << CTName << "[NonVirtualBaseAdjustmentOffset]: "447           << CT.NonVirtualBaseAdjustmentOffset << '\n';448    outs() << CTName449           << "[VirtualBasePointerOffset]: " << CT.VirtualBasePointerOffset450           << '\n';451    outs() << CTName << "[VirtualBaseAdjustmentOffset]: "452           << CT.VirtualBaseAdjustmentOffset << '\n';453    outs() << CTName << "[Size]: " << CT.Size << '\n';454    outs() << CTName455           << "[CopyCtor]: " << (CT.Symbols[1].empty() ? "null" : CT.Symbols[1])456           << '\n';457  }458  for (const auto &VTTPair : VTTEntries) {459    StringRef VTTName = VTTPair.first.first;460    uint64_t VTTOffset = VTTPair.first.second;461    StringRef VTTEntry = VTTPair.second;462    outs() << VTTName << '[' << VTTOffset << "]: " << VTTEntry << '\n';463  }464  for (const auto &TIPair : TINames) {465    StringRef TIName = TIPair.first;466    outs() << TIName << ": " << TIPair.second << '\n';467  }468  auto VTableSymI = VTableSymEntries.begin();469  auto VTableSymE = VTableSymEntries.end();470  auto VTableDataI = VTableDataEntries.begin();471  auto VTableDataE = VTableDataEntries.end();472  for (;;) {473    bool SymDone = VTableSymI == VTableSymE;474    bool DataDone = VTableDataI == VTableDataE;475    if (SymDone && DataDone)476      break;477    if (!SymDone && (DataDone || VTableSymI->first < VTableDataI->first)) {478      StringRef VTableName = VTableSymI->first.first;479      uint64_t Offset = VTableSymI->first.second;480      StringRef VTableEntry = VTableSymI->second;481      outs() << VTableName << '[' << Offset << "]: ";482      outs() << VTableEntry;483      outs() << '\n';484      ++VTableSymI;485      continue;486    }487    if (!DataDone && (SymDone || VTableDataI->first < VTableSymI->first)) {488      StringRef VTableName = VTableDataI->first.first;489      uint64_t Offset = VTableDataI->first.second;490      int64_t VTableEntry = VTableDataI->second;491      outs() << VTableName << '[' << Offset << "]: ";492      outs() << VTableEntry;493      outs() << '\n';494      ++VTableDataI;495      continue;496    }497  }498}499 500static void dumpArchive(const Archive *Arc) {501  Error Err = Error::success();502  for (const auto &ArcC : Arc->children(Err)) {503    Expected<std::unique_ptr<Binary>> ChildOrErr = ArcC.getAsBinary();504    if (!ChildOrErr) {505      // Ignore non-object files.506      if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {507        std::string Buf;508        raw_string_ostream OS(Buf);509        logAllUnhandledErrors(std::move(E), OS);510        OS.flush();511        reportError(Arc->getFileName(), Buf);512      }513      consumeError(ChildOrErr.takeError());514      continue;515    }516 517    if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))518      dumpCXXData(Obj);519    else520      reportError(Arc->getFileName(), cxxdump_error::unrecognized_file_format);521  }522  if (Err)523    error(std::move(Err));524}525 526static void dumpInput(StringRef File) {527  // Attempt to open the binary.528  Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);529  if (!BinaryOrErr) {530    auto EC = errorToErrorCode(BinaryOrErr.takeError());531    reportError(File, EC);532    return;533  }534  Binary &Binary = *BinaryOrErr.get().getBinary();535 536  if (Archive *Arc = dyn_cast<Archive>(&Binary))537    dumpArchive(Arc);538  else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))539    dumpCXXData(Obj);540  else541    reportError(File, cxxdump_error::unrecognized_file_format);542}543 544int main(int argc, const char *argv[]) {545  InitLLVM X(argc, argv);546 547  // Initialize targets.548  llvm::InitializeAllTargetInfos();549 550  // Register the target printer for --version.551  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);552 553  cl::HideUnrelatedOptions({&opts::CXXDumpCategory, &getColorCategory()});554  cl::ParseCommandLineOptions(argc, argv, "LLVM C++ ABI Data Dumper\n");555 556  // Default to stdin if no filename is specified.557  if (opts::InputFilenames.size() == 0)558    opts::InputFilenames.push_back("-");559 560  llvm::for_each(opts::InputFilenames, dumpInput);561 562  return EXIT_SUCCESS;563}564