1 //===- llvm-cxxdump.cpp - Dump C++ data in an Object File -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Dumps C++ data resident in object files and archives.
11 //===----------------------------------------------------------------------===//
13 #include "llvm-cxxdump.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"
29 #include <system_error>
32 using namespace llvm::object
;
33 using namespace llvm::support
;
36 cl::list
<std::string
> InputFilenames(cl::Positional
,
37 cl::desc("<input object files>"),
43 static void error(std::error_code EC
) {
46 WithColor::error(outs(), "") << "reading file: " << EC
.message() << ".\n";
51 static void error(Error Err
) {
54 logAllUnhandledErrors(std::move(Err
), WithColor::error(outs()),
62 static void reportError(StringRef Input
, StringRef Message
) {
65 WithColor::error(errs(), Input
) << Message
<< "\n";
70 static void reportError(StringRef Input
, std::error_code EC
) {
71 reportError(Input
, EC
.message());
74 static std::map
<SectionRef
, SmallVector
<SectionRef
, 1>> SectionRelocMap
;
76 static void collectRelocatedSymbols(const ObjectFile
*Obj
,
77 const SectionRef
&Sec
, uint64_t SecAddress
,
78 uint64_t SymAddress
, uint64_t SymSize
,
79 StringRef
*I
, StringRef
*E
) {
80 uint64_t SymOffset
= SymAddress
- SecAddress
;
81 uint64_t SymEnd
= SymOffset
+ SymSize
;
82 for (const SectionRef
&SR
: SectionRelocMap
[Sec
]) {
83 for (const object::RelocationRef
&Reloc
: SR
.relocations()) {
86 const object::symbol_iterator RelocSymI
= Reloc
.getSymbol();
87 if (RelocSymI
== Obj
->symbol_end())
89 Expected
<StringRef
> RelocSymName
= RelocSymI
->getName();
90 error(errorToErrorCode(RelocSymName
.takeError()));
91 uint64_t Offset
= Reloc
.getOffset();
92 if (Offset
>= SymOffset
&& Offset
< SymEnd
) {
100 static void collectRelocationOffsets(
101 const ObjectFile
*Obj
, const SectionRef
&Sec
, uint64_t SecAddress
,
102 uint64_t SymAddress
, uint64_t SymSize
, StringRef SymName
,
103 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> &Collection
) {
104 uint64_t SymOffset
= SymAddress
- SecAddress
;
105 uint64_t SymEnd
= SymOffset
+ SymSize
;
106 for (const SectionRef
&SR
: SectionRelocMap
[Sec
]) {
107 for (const object::RelocationRef
&Reloc
: SR
.relocations()) {
108 const object::symbol_iterator RelocSymI
= Reloc
.getSymbol();
109 if (RelocSymI
== Obj
->symbol_end())
111 Expected
<StringRef
> RelocSymName
= RelocSymI
->getName();
112 error(errorToErrorCode(RelocSymName
.takeError()));
113 uint64_t Offset
= Reloc
.getOffset();
114 if (Offset
>= SymOffset
&& Offset
< SymEnd
)
115 Collection
[std::make_pair(SymName
, Offset
- SymOffset
)] = *RelocSymName
;
120 static void dumpCXXData(const ObjectFile
*Obj
) {
121 struct CompleteObjectLocator
{
122 StringRef Symbols
[2];
123 ArrayRef
<little32_t
> Data
;
125 struct ClassHierarchyDescriptor
{
126 StringRef Symbols
[1];
127 ArrayRef
<little32_t
> Data
;
129 struct BaseClassDescriptor
{
130 StringRef Symbols
[2];
131 ArrayRef
<little32_t
> Data
;
133 struct TypeDescriptor
{
134 StringRef Symbols
[1];
136 StringRef MangledName
;
141 struct CatchableTypeArray
{
144 struct CatchableType
{
146 uint32_t NonVirtualBaseAdjustmentOffset
;
147 int32_t VirtualBasePointerOffset
;
148 uint32_t VirtualBaseAdjustmentOffset
;
150 StringRef Symbols
[2];
152 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VFTableEntries
;
153 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> TIEntries
;
154 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> CTAEntries
;
155 std::map
<StringRef
, ArrayRef
<little32_t
>> VBTables
;
156 std::map
<StringRef
, CompleteObjectLocator
> COLs
;
157 std::map
<StringRef
, ClassHierarchyDescriptor
> CHDs
;
158 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> BCAEntries
;
159 std::map
<StringRef
, BaseClassDescriptor
> BCDs
;
160 std::map
<StringRef
, TypeDescriptor
> TDs
;
161 std::map
<StringRef
, ThrowInfo
> TIs
;
162 std::map
<StringRef
, CatchableTypeArray
> CTAs
;
163 std::map
<StringRef
, CatchableType
> CTs
;
165 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VTableSymEntries
;
166 std::map
<std::pair
<StringRef
, uint64_t>, int64_t> VTableDataEntries
;
167 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VTTEntries
;
168 std::map
<StringRef
, StringRef
> TINames
;
170 SectionRelocMap
.clear();
171 for (const SectionRef
&Section
: Obj
->sections()) {
172 section_iterator Sec2
= Section
.getRelocatedSection();
173 if (Sec2
!= Obj
->section_end())
174 SectionRelocMap
[*Sec2
].push_back(Section
);
177 uint8_t BytesInAddress
= Obj
->getBytesInAddress();
179 std::vector
<std::pair
<SymbolRef
, uint64_t>> SymAddr
=
180 object::computeSymbolSizes(*Obj
);
182 for (auto &P
: SymAddr
) {
183 object::SymbolRef Sym
= P
.first
;
184 uint64_t SymSize
= P
.second
;
185 Expected
<StringRef
> SymNameOrErr
= Sym
.getName();
186 error(errorToErrorCode(SymNameOrErr
.takeError()));
187 StringRef SymName
= *SymNameOrErr
;
188 Expected
<object::section_iterator
> SecIOrErr
= Sym
.getSection();
189 error(errorToErrorCode(SecIOrErr
.takeError()));
190 object::section_iterator SecI
= *SecIOrErr
;
191 // Skip external symbols.
192 if (SecI
== Obj
->section_end())
194 const SectionRef
&Sec
= *SecI
;
195 // Skip virtual or BSS sections.
196 if (Sec
.isBSS() || Sec
.isVirtual())
198 StringRef SecContents
;
199 error(Sec
.getContents(SecContents
));
200 Expected
<uint64_t> SymAddressOrErr
= Sym
.getAddress();
201 error(errorToErrorCode(SymAddressOrErr
.takeError()));
202 uint64_t SymAddress
= *SymAddressOrErr
;
203 uint64_t SecAddress
= Sec
.getAddress();
204 uint64_t SecSize
= Sec
.getSize();
205 uint64_t SymOffset
= SymAddress
- SecAddress
;
206 StringRef SymContents
= SecContents
.substr(SymOffset
, SymSize
);
208 // VFTables in the MS-ABI start with '??_7' and are contained within their
209 // own COMDAT section. We then determine the contents of the VFTable by
210 // looking at each relocation in the section.
211 if (SymName
.startswith("??_7")) {
212 // Each relocation either names a virtual method or a thunk. We note the
213 // offset into the section and the symbol used for the relocation.
214 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SecAddress
, SecSize
,
215 SymName
, VFTableEntries
);
217 // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
218 // offsets of virtual bases.
219 else if (SymName
.startswith("??_8")) {
220 ArrayRef
<little32_t
> VBTableData(
221 reinterpret_cast<const little32_t
*>(SymContents
.data()),
222 SymContents
.size() / sizeof(little32_t
));
223 VBTables
[SymName
] = VBTableData
;
225 // Complete object locators in the MS-ABI start with '??_R4'
226 else if (SymName
.startswith("??_R4")) {
227 CompleteObjectLocator COL
;
228 COL
.Data
= makeArrayRef(
229 reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
230 StringRef
*I
= std::begin(COL
.Symbols
), *E
= std::end(COL
.Symbols
);
231 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
234 // Class hierarchy descriptors in the MS-ABI start with '??_R3'
235 else if (SymName
.startswith("??_R3")) {
236 ClassHierarchyDescriptor CHD
;
237 CHD
.Data
= makeArrayRef(
238 reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
239 StringRef
*I
= std::begin(CHD
.Symbols
), *E
= std::end(CHD
.Symbols
);
240 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
243 // Class hierarchy descriptors in the MS-ABI start with '??_R2'
244 else if (SymName
.startswith("??_R2")) {
245 // Each relocation names a base class descriptor. We note the offset into
246 // the section and the symbol used for the relocation.
247 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
248 SymName
, BCAEntries
);
250 // Base class descriptors in the MS-ABI start with '??_R1'
251 else if (SymName
.startswith("??_R1")) {
252 BaseClassDescriptor BCD
;
253 BCD
.Data
= makeArrayRef(
254 reinterpret_cast<const little32_t
*>(SymContents
.data()) + 1, 5);
255 StringRef
*I
= std::begin(BCD
.Symbols
), *E
= std::end(BCD
.Symbols
);
256 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
259 // Type descriptors in the MS-ABI start with '??_R0'
260 else if (SymName
.startswith("??_R0")) {
261 const char *DataPtr
= SymContents
.drop_front(BytesInAddress
).data();
263 if (BytesInAddress
== 8)
264 TD
.AlwaysZero
= *reinterpret_cast<const little64_t
*>(DataPtr
);
266 TD
.AlwaysZero
= *reinterpret_cast<const little32_t
*>(DataPtr
);
267 TD
.MangledName
= SymContents
.drop_front(BytesInAddress
* 2);
268 StringRef
*I
= std::begin(TD
.Symbols
), *E
= std::end(TD
.Symbols
);
269 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
272 // Throw descriptors in the MS-ABI start with '_TI'
273 else if (SymName
.startswith("_TI") || SymName
.startswith("__TI")) {
275 TI
.Flags
= *reinterpret_cast<const little32_t
*>(SymContents
.data());
276 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
280 // Catchable type arrays in the MS-ABI start with _CTA or __CTA.
281 else if (SymName
.startswith("_CTA") || SymName
.startswith("__CTA")) {
282 CatchableTypeArray CTA
;
284 *reinterpret_cast<const little32_t
*>(SymContents
.data());
285 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
286 SymName
, CTAEntries
);
289 // Catchable types in the MS-ABI start with _CT or __CT.
290 else if (SymName
.startswith("_CT") || SymName
.startswith("__CT")) {
291 const little32_t
*DataPtr
=
292 reinterpret_cast<const little32_t
*>(SymContents
.data());
294 CT
.Flags
= DataPtr
[0];
295 CT
.NonVirtualBaseAdjustmentOffset
= DataPtr
[2];
296 CT
.VirtualBasePointerOffset
= DataPtr
[3];
297 CT
.VirtualBaseAdjustmentOffset
= DataPtr
[4];
298 CT
.Size
= DataPtr
[5];
299 StringRef
*I
= std::begin(CT
.Symbols
), *E
= std::end(CT
.Symbols
);
300 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
303 // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
304 else if (SymName
.startswith("_ZTT") || SymName
.startswith("__ZTT")) {
305 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
306 SymName
, VTTEntries
);
308 // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
309 else if (SymName
.startswith("_ZTS") || SymName
.startswith("__ZTS")) {
310 TINames
[SymName
] = SymContents
.slice(0, SymContents
.find('\0'));
312 // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
313 else if (SymName
.startswith("_ZTV") || SymName
.startswith("__ZTV")) {
314 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
315 SymName
, VTableSymEntries
);
316 for (uint64_t SymOffI
= 0; SymOffI
< SymSize
; SymOffI
+= BytesInAddress
) {
317 auto Key
= std::make_pair(SymName
, SymOffI
);
318 if (VTableSymEntries
.count(Key
))
320 const char *DataPtr
=
321 SymContents
.substr(SymOffI
, BytesInAddress
).data();
323 if (BytesInAddress
== 8)
324 VData
= *reinterpret_cast<const little64_t
*>(DataPtr
);
326 VData
= *reinterpret_cast<const little32_t
*>(DataPtr
);
327 VTableDataEntries
[Key
] = VData
;
330 // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
331 else if (SymName
.startswith("_ZTI") || SymName
.startswith("__ZTI")) {
332 // FIXME: Do something with these!
335 for (const auto &VFTableEntry
: VFTableEntries
) {
336 StringRef VFTableName
= VFTableEntry
.first
.first
;
337 uint64_t Offset
= VFTableEntry
.first
.second
;
338 StringRef SymName
= VFTableEntry
.second
;
339 outs() << VFTableName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
341 for (const auto &VBTable
: VBTables
) {
342 StringRef VBTableName
= VBTable
.first
;
344 for (little32_t Offset
: VBTable
.second
) {
345 outs() << VBTableName
<< '[' << Idx
<< "]: " << Offset
<< '\n';
346 Idx
+= sizeof(Offset
);
349 for (const auto &COLPair
: COLs
) {
350 StringRef COLName
= COLPair
.first
;
351 const CompleteObjectLocator
&COL
= COLPair
.second
;
352 outs() << COLName
<< "[IsImageRelative]: " << COL
.Data
[0] << '\n';
353 outs() << COLName
<< "[OffsetToTop]: " << COL
.Data
[1] << '\n';
354 outs() << COLName
<< "[VFPtrOffset]: " << COL
.Data
[2] << '\n';
355 outs() << COLName
<< "[TypeDescriptor]: " << COL
.Symbols
[0] << '\n';
356 outs() << COLName
<< "[ClassHierarchyDescriptor]: " << COL
.Symbols
[1]
359 for (const auto &CHDPair
: CHDs
) {
360 StringRef CHDName
= CHDPair
.first
;
361 const ClassHierarchyDescriptor
&CHD
= CHDPair
.second
;
362 outs() << CHDName
<< "[AlwaysZero]: " << CHD
.Data
[0] << '\n';
363 outs() << CHDName
<< "[Flags]: " << CHD
.Data
[1] << '\n';
364 outs() << CHDName
<< "[NumClasses]: " << CHD
.Data
[2] << '\n';
365 outs() << CHDName
<< "[BaseClassArray]: " << CHD
.Symbols
[0] << '\n';
367 for (const auto &BCAEntry
: BCAEntries
) {
368 StringRef BCAName
= BCAEntry
.first
.first
;
369 uint64_t Offset
= BCAEntry
.first
.second
;
370 StringRef SymName
= BCAEntry
.second
;
371 outs() << BCAName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
373 for (const auto &BCDPair
: BCDs
) {
374 StringRef BCDName
= BCDPair
.first
;
375 const BaseClassDescriptor
&BCD
= BCDPair
.second
;
376 outs() << BCDName
<< "[TypeDescriptor]: " << BCD
.Symbols
[0] << '\n';
377 outs() << BCDName
<< "[NumBases]: " << BCD
.Data
[0] << '\n';
378 outs() << BCDName
<< "[OffsetInVBase]: " << BCD
.Data
[1] << '\n';
379 outs() << BCDName
<< "[VBPtrOffset]: " << BCD
.Data
[2] << '\n';
380 outs() << BCDName
<< "[OffsetInVBTable]: " << BCD
.Data
[3] << '\n';
381 outs() << BCDName
<< "[Flags]: " << BCD
.Data
[4] << '\n';
382 outs() << BCDName
<< "[ClassHierarchyDescriptor]: " << BCD
.Symbols
[1]
385 for (const auto &TDPair
: TDs
) {
386 StringRef TDName
= TDPair
.first
;
387 const TypeDescriptor
&TD
= TDPair
.second
;
388 outs() << TDName
<< "[VFPtr]: " << TD
.Symbols
[0] << '\n';
389 outs() << TDName
<< "[AlwaysZero]: " << TD
.AlwaysZero
<< '\n';
390 outs() << TDName
<< "[MangledName]: ";
391 outs().write_escaped(TD
.MangledName
.rtrim(StringRef("\0", 1)),
392 /*UseHexEscapes=*/true)
395 for (const auto &TIPair
: TIs
) {
396 StringRef TIName
= TIPair
.first
;
397 const ThrowInfo
&TI
= TIPair
.second
;
398 auto dumpThrowInfoFlag
= [&](const char *Name
, uint32_t Flag
) {
399 outs() << TIName
<< "[Flags." << Name
400 << "]: " << (TI
.Flags
& Flag
? "true" : "false") << '\n';
402 auto dumpThrowInfoSymbol
= [&](const char *Name
, int Offset
) {
403 outs() << TIName
<< '[' << Name
<< "]: ";
404 auto Entry
= TIEntries
.find(std::make_pair(TIName
, Offset
));
405 outs() << (Entry
== TIEntries
.end() ? "null" : Entry
->second
) << '\n';
407 outs() << TIName
<< "[Flags]: " << TI
.Flags
<< '\n';
408 dumpThrowInfoFlag("Const", 1);
409 dumpThrowInfoFlag("Volatile", 2);
410 dumpThrowInfoSymbol("CleanupFn", 4);
411 dumpThrowInfoSymbol("ForwardCompat", 8);
412 dumpThrowInfoSymbol("CatchableTypeArray", 12);
414 for (const auto &CTAPair
: CTAs
) {
415 StringRef CTAName
= CTAPair
.first
;
416 const CatchableTypeArray
&CTA
= CTAPair
.second
;
418 outs() << CTAName
<< "[NumEntries]: " << CTA
.NumEntries
<< '\n';
421 for (auto I
= CTAEntries
.lower_bound(std::make_pair(CTAName
, 0)),
422 E
= CTAEntries
.upper_bound(std::make_pair(CTAName
, UINT64_MAX
));
424 outs() << CTAName
<< '[' << Idx
++ << "]: " << I
->second
<< '\n';
426 for (const auto &CTPair
: CTs
) {
427 StringRef CTName
= CTPair
.first
;
428 const CatchableType
&CT
= CTPair
.second
;
429 auto dumpCatchableTypeFlag
= [&](const char *Name
, uint32_t Flag
) {
430 outs() << CTName
<< "[Flags." << Name
431 << "]: " << (CT
.Flags
& Flag
? "true" : "false") << '\n';
433 outs() << CTName
<< "[Flags]: " << CT
.Flags
<< '\n';
434 dumpCatchableTypeFlag("ScalarType", 1);
435 dumpCatchableTypeFlag("VirtualInheritance", 4);
436 outs() << CTName
<< "[TypeDescriptor]: " << CT
.Symbols
[0] << '\n';
437 outs() << CTName
<< "[NonVirtualBaseAdjustmentOffset]: "
438 << CT
.NonVirtualBaseAdjustmentOffset
<< '\n';
440 << "[VirtualBasePointerOffset]: " << CT
.VirtualBasePointerOffset
442 outs() << CTName
<< "[VirtualBaseAdjustmentOffset]: "
443 << CT
.VirtualBaseAdjustmentOffset
<< '\n';
444 outs() << CTName
<< "[Size]: " << CT
.Size
<< '\n';
446 << "[CopyCtor]: " << (CT
.Symbols
[1].empty() ? "null" : CT
.Symbols
[1])
449 for (const auto &VTTPair
: VTTEntries
) {
450 StringRef VTTName
= VTTPair
.first
.first
;
451 uint64_t VTTOffset
= VTTPair
.first
.second
;
452 StringRef VTTEntry
= VTTPair
.second
;
453 outs() << VTTName
<< '[' << VTTOffset
<< "]: " << VTTEntry
<< '\n';
455 for (const auto &TIPair
: TINames
) {
456 StringRef TIName
= TIPair
.first
;
457 outs() << TIName
<< ": " << TIPair
.second
<< '\n';
459 auto VTableSymI
= VTableSymEntries
.begin();
460 auto VTableSymE
= VTableSymEntries
.end();
461 auto VTableDataI
= VTableDataEntries
.begin();
462 auto VTableDataE
= VTableDataEntries
.end();
464 bool SymDone
= VTableSymI
== VTableSymE
;
465 bool DataDone
= VTableDataI
== VTableDataE
;
466 if (SymDone
&& DataDone
)
468 if (!SymDone
&& (DataDone
|| VTableSymI
->first
< VTableDataI
->first
)) {
469 StringRef VTableName
= VTableSymI
->first
.first
;
470 uint64_t Offset
= VTableSymI
->first
.second
;
471 StringRef VTableEntry
= VTableSymI
->second
;
472 outs() << VTableName
<< '[' << Offset
<< "]: ";
473 outs() << VTableEntry
;
478 if (!DataDone
&& (SymDone
|| VTableDataI
->first
< VTableSymI
->first
)) {
479 StringRef VTableName
= VTableDataI
->first
.first
;
480 uint64_t Offset
= VTableDataI
->first
.second
;
481 int64_t VTableEntry
= VTableDataI
->second
;
482 outs() << VTableName
<< '[' << Offset
<< "]: ";
483 outs() << VTableEntry
;
491 static void dumpArchive(const Archive
*Arc
) {
492 Error Err
= Error::success();
493 for (auto &ArcC
: Arc
->children(Err
)) {
494 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= ArcC
.getAsBinary();
496 // Ignore non-object files.
497 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError())) {
499 raw_string_ostream
OS(Buf
);
500 logAllUnhandledErrors(std::move(E
), OS
);
502 reportError(Arc
->getFileName(), Buf
);
504 consumeError(ChildOrErr
.takeError());
508 if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get()))
511 reportError(Arc
->getFileName(), cxxdump_error::unrecognized_file_format
);
513 error(std::move(Err
));
516 static void dumpInput(StringRef File
) {
517 // Attempt to open the binary.
518 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(File
);
520 auto EC
= errorToErrorCode(BinaryOrErr
.takeError());
521 reportError(File
, EC
);
524 Binary
&Binary
= *BinaryOrErr
.get().getBinary();
526 if (Archive
*Arc
= dyn_cast
<Archive
>(&Binary
))
528 else if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&Binary
))
531 reportError(File
, cxxdump_error::unrecognized_file_format
);
534 int main(int argc
, const char *argv
[]) {
535 InitLLVM
X(argc
, argv
);
537 // Initialize targets.
538 llvm::InitializeAllTargetInfos();
540 // Register the target printer for --version.
541 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion
);
543 cl::ParseCommandLineOptions(argc
, argv
, "LLVM C++ ABI Data Dumper\n");
545 // Default to stdin if no filename is specified.
546 if (opts::InputFilenames
.size() == 0)
547 opts::InputFilenames
.push_back("-");
549 llvm::for_each(opts::InputFilenames
, dumpInput
);