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