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