llvm-cxxdump.cpp 21 KB

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