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