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 LLVM_ATTRIBUTE_NORETURN
static void error(Error Err
) {
52 logAllUnhandledErrors(std::move(Err
), WithColor::error(outs()),
59 T
unwrapOrError(Expected
<T
> EO
) {
61 error(EO
.takeError());
62 return std::move(*EO
);
67 static void reportError(StringRef Input
, StringRef Message
) {
70 WithColor::error(errs(), Input
) << Message
<< "\n";
75 static void reportError(StringRef Input
, std::error_code EC
) {
76 reportError(Input
, EC
.message());
79 static std::map
<SectionRef
, SmallVector
<SectionRef
, 1>> SectionRelocMap
;
81 static 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()) {
91 const object::symbol_iterator RelocSymI
= Reloc
.getSymbol();
92 if (RelocSymI
== Obj
->symbol_end())
94 Expected
<StringRef
> RelocSymName
= RelocSymI
->getName();
95 error(errorToErrorCode(RelocSymName
.takeError()));
96 uint64_t Offset
= Reloc
.getOffset();
97 if (Offset
>= SymOffset
&& Offset
< SymEnd
) {
105 static 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())
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
;
125 static void dumpCXXData(const ObjectFile
*Obj
) {
126 struct CompleteObjectLocator
{
127 StringRef Symbols
[2];
128 ArrayRef
<little32_t
> Data
;
130 struct ClassHierarchyDescriptor
{
131 StringRef Symbols
[1];
132 ArrayRef
<little32_t
> Data
;
134 struct BaseClassDescriptor
{
135 StringRef Symbols
[2];
136 ArrayRef
<little32_t
> Data
;
138 struct TypeDescriptor
{
139 StringRef Symbols
[1];
141 StringRef MangledName
;
146 struct CatchableTypeArray
{
149 struct CatchableType
{
151 uint32_t NonVirtualBaseAdjustmentOffset
;
152 int32_t VirtualBasePointerOffset
;
153 uint32_t VirtualBaseAdjustmentOffset
;
155 StringRef Symbols
[2];
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
;
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
;
175 SectionRelocMap
.clear();
176 for (const SectionRef
&Section
: Obj
->sections()) {
177 section_iterator Sec2
= Section
.getRelocatedSection();
178 if (Sec2
!= Obj
->section_end())
179 SectionRelocMap
[*Sec2
].push_back(Section
);
182 uint8_t BytesInAddress
= Obj
->getBytesInAddress();
184 std::vector
<std::pair
<SymbolRef
, uint64_t>> SymAddr
=
185 object::computeSymbolSizes(*Obj
);
187 for (auto &P
: SymAddr
) {
188 object::SymbolRef Sym
= P
.first
;
189 uint64_t SymSize
= P
.second
;
190 Expected
<StringRef
> SymNameOrErr
= Sym
.getName();
191 error(errorToErrorCode(SymNameOrErr
.takeError()));
192 StringRef SymName
= *SymNameOrErr
;
193 Expected
<object::section_iterator
> SecIOrErr
= Sym
.getSection();
194 error(errorToErrorCode(SecIOrErr
.takeError()));
195 object::section_iterator SecI
= *SecIOrErr
;
196 // Skip external symbols.
197 if (SecI
== Obj
->section_end())
199 const SectionRef
&Sec
= *SecI
;
200 // Skip virtual or BSS sections.
201 if (Sec
.isBSS() || Sec
.isVirtual())
203 StringRef SecContents
= unwrapOrError(Sec
.getContents());
204 Expected
<uint64_t> SymAddressOrErr
= Sym
.getAddress();
205 error(errorToErrorCode(SymAddressOrErr
.takeError()));
206 uint64_t SymAddress
= *SymAddressOrErr
;
207 uint64_t SecAddress
= Sec
.getAddress();
208 uint64_t SecSize
= Sec
.getSize();
209 uint64_t SymOffset
= SymAddress
- SecAddress
;
210 StringRef SymContents
= SecContents
.substr(SymOffset
, SymSize
);
212 // VFTables in the MS-ABI start with '??_7' and are contained within their
213 // own COMDAT section. We then determine the contents of the VFTable by
214 // looking at each relocation in the section.
215 if (SymName
.startswith("??_7")) {
216 // Each relocation either names a virtual method or a thunk. We note the
217 // offset into the section and the symbol used for the relocation.
218 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SecAddress
, SecSize
,
219 SymName
, VFTableEntries
);
221 // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
222 // offsets of virtual bases.
223 else if (SymName
.startswith("??_8")) {
224 ArrayRef
<little32_t
> VBTableData(
225 reinterpret_cast<const little32_t
*>(SymContents
.data()),
226 SymContents
.size() / sizeof(little32_t
));
227 VBTables
[SymName
] = VBTableData
;
229 // Complete object locators in the MS-ABI start with '??_R4'
230 else if (SymName
.startswith("??_R4")) {
231 CompleteObjectLocator COL
;
232 COL
.Data
= makeArrayRef(
233 reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
234 StringRef
*I
= std::begin(COL
.Symbols
), *E
= std::end(COL
.Symbols
);
235 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
238 // Class hierarchy descriptors in the MS-ABI start with '??_R3'
239 else if (SymName
.startswith("??_R3")) {
240 ClassHierarchyDescriptor CHD
;
241 CHD
.Data
= makeArrayRef(
242 reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
243 StringRef
*I
= std::begin(CHD
.Symbols
), *E
= std::end(CHD
.Symbols
);
244 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
247 // Class hierarchy descriptors in the MS-ABI start with '??_R2'
248 else if (SymName
.startswith("??_R2")) {
249 // Each relocation names a base class descriptor. We note the offset into
250 // the section and the symbol used for the relocation.
251 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
252 SymName
, BCAEntries
);
254 // Base class descriptors in the MS-ABI start with '??_R1'
255 else if (SymName
.startswith("??_R1")) {
256 BaseClassDescriptor BCD
;
257 BCD
.Data
= makeArrayRef(
258 reinterpret_cast<const little32_t
*>(SymContents
.data()) + 1, 5);
259 StringRef
*I
= std::begin(BCD
.Symbols
), *E
= std::end(BCD
.Symbols
);
260 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
263 // Type descriptors in the MS-ABI start with '??_R0'
264 else if (SymName
.startswith("??_R0")) {
265 const char *DataPtr
= SymContents
.drop_front(BytesInAddress
).data();
267 if (BytesInAddress
== 8)
268 TD
.AlwaysZero
= *reinterpret_cast<const little64_t
*>(DataPtr
);
270 TD
.AlwaysZero
= *reinterpret_cast<const little32_t
*>(DataPtr
);
271 TD
.MangledName
= SymContents
.drop_front(BytesInAddress
* 2);
272 StringRef
*I
= std::begin(TD
.Symbols
), *E
= std::end(TD
.Symbols
);
273 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
276 // Throw descriptors in the MS-ABI start with '_TI'
277 else if (SymName
.startswith("_TI") || SymName
.startswith("__TI")) {
279 TI
.Flags
= *reinterpret_cast<const little32_t
*>(SymContents
.data());
280 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
284 // Catchable type arrays in the MS-ABI start with _CTA or __CTA.
285 else if (SymName
.startswith("_CTA") || SymName
.startswith("__CTA")) {
286 CatchableTypeArray CTA
;
288 *reinterpret_cast<const little32_t
*>(SymContents
.data());
289 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
290 SymName
, CTAEntries
);
293 // Catchable types in the MS-ABI start with _CT or __CT.
294 else if (SymName
.startswith("_CT") || SymName
.startswith("__CT")) {
295 const little32_t
*DataPtr
=
296 reinterpret_cast<const little32_t
*>(SymContents
.data());
298 CT
.Flags
= DataPtr
[0];
299 CT
.NonVirtualBaseAdjustmentOffset
= DataPtr
[2];
300 CT
.VirtualBasePointerOffset
= DataPtr
[3];
301 CT
.VirtualBaseAdjustmentOffset
= DataPtr
[4];
302 CT
.Size
= DataPtr
[5];
303 StringRef
*I
= std::begin(CT
.Symbols
), *E
= std::end(CT
.Symbols
);
304 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
307 // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
308 else if (SymName
.startswith("_ZTT") || SymName
.startswith("__ZTT")) {
309 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
310 SymName
, VTTEntries
);
312 // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
313 else if (SymName
.startswith("_ZTS") || SymName
.startswith("__ZTS")) {
314 TINames
[SymName
] = SymContents
.slice(0, SymContents
.find('\0'));
316 // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
317 else if (SymName
.startswith("_ZTV") || SymName
.startswith("__ZTV")) {
318 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
319 SymName
, VTableSymEntries
);
320 for (uint64_t SymOffI
= 0; SymOffI
< SymSize
; SymOffI
+= BytesInAddress
) {
321 auto Key
= std::make_pair(SymName
, SymOffI
);
322 if (VTableSymEntries
.count(Key
))
324 const char *DataPtr
=
325 SymContents
.substr(SymOffI
, BytesInAddress
).data();
327 if (BytesInAddress
== 8)
328 VData
= *reinterpret_cast<const little64_t
*>(DataPtr
);
330 VData
= *reinterpret_cast<const little32_t
*>(DataPtr
);
331 VTableDataEntries
[Key
] = VData
;
334 // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
335 else if (SymName
.startswith("_ZTI") || SymName
.startswith("__ZTI")) {
336 // FIXME: Do something with these!
339 for (const auto &VFTableEntry
: VFTableEntries
) {
340 StringRef VFTableName
= VFTableEntry
.first
.first
;
341 uint64_t Offset
= VFTableEntry
.first
.second
;
342 StringRef SymName
= VFTableEntry
.second
;
343 outs() << VFTableName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
345 for (const auto &VBTable
: VBTables
) {
346 StringRef VBTableName
= VBTable
.first
;
348 for (little32_t Offset
: VBTable
.second
) {
349 outs() << VBTableName
<< '[' << Idx
<< "]: " << Offset
<< '\n';
350 Idx
+= sizeof(Offset
);
353 for (const auto &COLPair
: COLs
) {
354 StringRef COLName
= COLPair
.first
;
355 const CompleteObjectLocator
&COL
= COLPair
.second
;
356 outs() << COLName
<< "[IsImageRelative]: " << COL
.Data
[0] << '\n';
357 outs() << COLName
<< "[OffsetToTop]: " << COL
.Data
[1] << '\n';
358 outs() << COLName
<< "[VFPtrOffset]: " << COL
.Data
[2] << '\n';
359 outs() << COLName
<< "[TypeDescriptor]: " << COL
.Symbols
[0] << '\n';
360 outs() << COLName
<< "[ClassHierarchyDescriptor]: " << COL
.Symbols
[1]
363 for (const auto &CHDPair
: CHDs
) {
364 StringRef CHDName
= CHDPair
.first
;
365 const ClassHierarchyDescriptor
&CHD
= CHDPair
.second
;
366 outs() << CHDName
<< "[AlwaysZero]: " << CHD
.Data
[0] << '\n';
367 outs() << CHDName
<< "[Flags]: " << CHD
.Data
[1] << '\n';
368 outs() << CHDName
<< "[NumClasses]: " << CHD
.Data
[2] << '\n';
369 outs() << CHDName
<< "[BaseClassArray]: " << CHD
.Symbols
[0] << '\n';
371 for (const auto &BCAEntry
: BCAEntries
) {
372 StringRef BCAName
= BCAEntry
.first
.first
;
373 uint64_t Offset
= BCAEntry
.first
.second
;
374 StringRef SymName
= BCAEntry
.second
;
375 outs() << BCAName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
377 for (const auto &BCDPair
: BCDs
) {
378 StringRef BCDName
= BCDPair
.first
;
379 const BaseClassDescriptor
&BCD
= BCDPair
.second
;
380 outs() << BCDName
<< "[TypeDescriptor]: " << BCD
.Symbols
[0] << '\n';
381 outs() << BCDName
<< "[NumBases]: " << BCD
.Data
[0] << '\n';
382 outs() << BCDName
<< "[OffsetInVBase]: " << BCD
.Data
[1] << '\n';
383 outs() << BCDName
<< "[VBPtrOffset]: " << BCD
.Data
[2] << '\n';
384 outs() << BCDName
<< "[OffsetInVBTable]: " << BCD
.Data
[3] << '\n';
385 outs() << BCDName
<< "[Flags]: " << BCD
.Data
[4] << '\n';
386 outs() << BCDName
<< "[ClassHierarchyDescriptor]: " << BCD
.Symbols
[1]
389 for (const auto &TDPair
: TDs
) {
390 StringRef TDName
= TDPair
.first
;
391 const TypeDescriptor
&TD
= TDPair
.second
;
392 outs() << TDName
<< "[VFPtr]: " << TD
.Symbols
[0] << '\n';
393 outs() << TDName
<< "[AlwaysZero]: " << TD
.AlwaysZero
<< '\n';
394 outs() << TDName
<< "[MangledName]: ";
395 outs().write_escaped(TD
.MangledName
.rtrim(StringRef("\0", 1)),
396 /*UseHexEscapes=*/true)
399 for (const auto &TIPair
: TIs
) {
400 StringRef TIName
= TIPair
.first
;
401 const ThrowInfo
&TI
= TIPair
.second
;
402 auto dumpThrowInfoFlag
= [&](const char *Name
, uint32_t Flag
) {
403 outs() << TIName
<< "[Flags." << Name
404 << "]: " << (TI
.Flags
& Flag
? "true" : "false") << '\n';
406 auto dumpThrowInfoSymbol
= [&](const char *Name
, int Offset
) {
407 outs() << TIName
<< '[' << Name
<< "]: ";
408 auto Entry
= TIEntries
.find(std::make_pair(TIName
, Offset
));
409 outs() << (Entry
== TIEntries
.end() ? "null" : Entry
->second
) << '\n';
411 outs() << TIName
<< "[Flags]: " << TI
.Flags
<< '\n';
412 dumpThrowInfoFlag("Const", 1);
413 dumpThrowInfoFlag("Volatile", 2);
414 dumpThrowInfoSymbol("CleanupFn", 4);
415 dumpThrowInfoSymbol("ForwardCompat", 8);
416 dumpThrowInfoSymbol("CatchableTypeArray", 12);
418 for (const auto &CTAPair
: CTAs
) {
419 StringRef CTAName
= CTAPair
.first
;
420 const CatchableTypeArray
&CTA
= CTAPair
.second
;
422 outs() << CTAName
<< "[NumEntries]: " << CTA
.NumEntries
<< '\n';
425 for (auto I
= CTAEntries
.lower_bound(std::make_pair(CTAName
, 0)),
426 E
= CTAEntries
.upper_bound(std::make_pair(CTAName
, UINT64_MAX
));
428 outs() << CTAName
<< '[' << Idx
++ << "]: " << I
->second
<< '\n';
430 for (const auto &CTPair
: CTs
) {
431 StringRef CTName
= CTPair
.first
;
432 const CatchableType
&CT
= CTPair
.second
;
433 auto dumpCatchableTypeFlag
= [&](const char *Name
, uint32_t Flag
) {
434 outs() << CTName
<< "[Flags." << Name
435 << "]: " << (CT
.Flags
& Flag
? "true" : "false") << '\n';
437 outs() << CTName
<< "[Flags]: " << CT
.Flags
<< '\n';
438 dumpCatchableTypeFlag("ScalarType", 1);
439 dumpCatchableTypeFlag("VirtualInheritance", 4);
440 outs() << CTName
<< "[TypeDescriptor]: " << CT
.Symbols
[0] << '\n';
441 outs() << CTName
<< "[NonVirtualBaseAdjustmentOffset]: "
442 << CT
.NonVirtualBaseAdjustmentOffset
<< '\n';
444 << "[VirtualBasePointerOffset]: " << CT
.VirtualBasePointerOffset
446 outs() << CTName
<< "[VirtualBaseAdjustmentOffset]: "
447 << CT
.VirtualBaseAdjustmentOffset
<< '\n';
448 outs() << CTName
<< "[Size]: " << CT
.Size
<< '\n';
450 << "[CopyCtor]: " << (CT
.Symbols
[1].empty() ? "null" : CT
.Symbols
[1])
453 for (const auto &VTTPair
: VTTEntries
) {
454 StringRef VTTName
= VTTPair
.first
.first
;
455 uint64_t VTTOffset
= VTTPair
.first
.second
;
456 StringRef VTTEntry
= VTTPair
.second
;
457 outs() << VTTName
<< '[' << VTTOffset
<< "]: " << VTTEntry
<< '\n';
459 for (const auto &TIPair
: TINames
) {
460 StringRef TIName
= TIPair
.first
;
461 outs() << TIName
<< ": " << TIPair
.second
<< '\n';
463 auto VTableSymI
= VTableSymEntries
.begin();
464 auto VTableSymE
= VTableSymEntries
.end();
465 auto VTableDataI
= VTableDataEntries
.begin();
466 auto VTableDataE
= VTableDataEntries
.end();
468 bool SymDone
= VTableSymI
== VTableSymE
;
469 bool DataDone
= VTableDataI
== VTableDataE
;
470 if (SymDone
&& DataDone
)
472 if (!SymDone
&& (DataDone
|| VTableSymI
->first
< VTableDataI
->first
)) {
473 StringRef VTableName
= VTableSymI
->first
.first
;
474 uint64_t Offset
= VTableSymI
->first
.second
;
475 StringRef VTableEntry
= VTableSymI
->second
;
476 outs() << VTableName
<< '[' << Offset
<< "]: ";
477 outs() << VTableEntry
;
482 if (!DataDone
&& (SymDone
|| VTableDataI
->first
< VTableSymI
->first
)) {
483 StringRef VTableName
= VTableDataI
->first
.first
;
484 uint64_t Offset
= VTableDataI
->first
.second
;
485 int64_t VTableEntry
= VTableDataI
->second
;
486 outs() << VTableName
<< '[' << Offset
<< "]: ";
487 outs() << VTableEntry
;
495 static void dumpArchive(const Archive
*Arc
) {
496 Error Err
= Error::success();
497 for (auto &ArcC
: Arc
->children(Err
)) {
498 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= ArcC
.getAsBinary();
500 // Ignore non-object files.
501 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError())) {
503 raw_string_ostream
OS(Buf
);
504 logAllUnhandledErrors(std::move(E
), OS
);
506 reportError(Arc
->getFileName(), Buf
);
508 consumeError(ChildOrErr
.takeError());
512 if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get()))
515 reportError(Arc
->getFileName(), cxxdump_error::unrecognized_file_format
);
518 error(std::move(Err
));
521 static void dumpInput(StringRef File
) {
522 // Attempt to open the binary.
523 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(File
);
525 auto EC
= errorToErrorCode(BinaryOrErr
.takeError());
526 reportError(File
, EC
);
529 Binary
&Binary
= *BinaryOrErr
.get().getBinary();
531 if (Archive
*Arc
= dyn_cast
<Archive
>(&Binary
))
533 else if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&Binary
))
536 reportError(File
, cxxdump_error::unrecognized_file_format
);
539 int main(int argc
, const char *argv
[]) {
540 InitLLVM
X(argc
, argv
);
542 // Initialize targets.
543 llvm::InitializeAllTargetInfos();
545 // Register the target printer for --version.
546 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion
);
548 cl::ParseCommandLineOptions(argc
, argv
, "LLVM C++ ABI Data Dumper\n");
550 // Default to stdin if no filename is specified.
551 if (opts::InputFilenames
.size() == 0)
552 opts::InputFilenames
.push_back("-");
554 llvm::for_each(opts::InputFilenames
, dumpInput
);