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 Expected
<section_iterator
> ErrOrSec
= Section
.getRelocatedSection();
179 error(ErrOrSec
.takeError());
181 section_iterator Sec2
= *ErrOrSec
;
182 if (Sec2
!= Obj
->section_end())
183 SectionRelocMap
[*Sec2
].push_back(Section
);
186 uint8_t BytesInAddress
= Obj
->getBytesInAddress();
188 std::vector
<std::pair
<SymbolRef
, uint64_t>> SymAddr
=
189 object::computeSymbolSizes(*Obj
);
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())
203 const SectionRef
&Sec
= *SecI
;
204 // Skip virtual or BSS sections.
205 if (Sec
.isBSS() || Sec
.isVirtual())
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
);
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
);
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
;
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
);
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
);
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
);
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
);
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();
271 if (BytesInAddress
== 8)
272 TD
.AlwaysZero
= *reinterpret_cast<const little64_t
*>(DataPtr
);
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
);
280 // Throw descriptors in the MS-ABI start with '_TI'
281 else if (SymName
.startswith("_TI") || SymName
.startswith("__TI")) {
283 TI
.Flags
= *reinterpret_cast<const little32_t
*>(SymContents
.data());
284 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
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
;
292 *reinterpret_cast<const little32_t
*>(SymContents
.data());
293 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
294 SymName
, CTAEntries
);
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());
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
);
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
);
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'));
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
))
328 const char *DataPtr
=
329 SymContents
.substr(SymOffI
, BytesInAddress
).data();
331 if (BytesInAddress
== 8)
332 VData
= *reinterpret_cast<const little64_t
*>(DataPtr
);
334 VData
= *reinterpret_cast<const little32_t
*>(DataPtr
);
335 VTableDataEntries
[Key
] = VData
;
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!
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';
349 for (const auto &VBTable
: VBTables
) {
350 StringRef VBTableName
= VBTable
.first
;
352 for (little32_t Offset
: VBTable
.second
) {
353 outs() << VBTableName
<< '[' << Idx
<< "]: " << Offset
<< '\n';
354 Idx
+= sizeof(Offset
);
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]
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';
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';
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]
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)
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';
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';
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);
422 for (const auto &CTAPair
: CTAs
) {
423 StringRef CTAName
= CTAPair
.first
;
424 const CatchableTypeArray
&CTA
= CTAPair
.second
;
426 outs() << CTAName
<< "[NumEntries]: " << CTA
.NumEntries
<< '\n';
429 for (auto I
= CTAEntries
.lower_bound(std::make_pair(CTAName
, 0)),
430 E
= CTAEntries
.upper_bound(std::make_pair(CTAName
, UINT64_MAX
));
432 outs() << CTAName
<< '[' << Idx
++ << "]: " << I
->second
<< '\n';
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';
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';
448 << "[VirtualBasePointerOffset]: " << CT
.VirtualBasePointerOffset
450 outs() << CTName
<< "[VirtualBaseAdjustmentOffset]: "
451 << CT
.VirtualBaseAdjustmentOffset
<< '\n';
452 outs() << CTName
<< "[Size]: " << CT
.Size
<< '\n';
454 << "[CopyCtor]: " << (CT
.Symbols
[1].empty() ? "null" : CT
.Symbols
[1])
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';
463 for (const auto &TIPair
: TINames
) {
464 StringRef TIName
= TIPair
.first
;
465 outs() << TIName
<< ": " << TIPair
.second
<< '\n';
467 auto VTableSymI
= VTableSymEntries
.begin();
468 auto VTableSymE
= VTableSymEntries
.end();
469 auto VTableDataI
= VTableDataEntries
.begin();
470 auto VTableDataE
= VTableDataEntries
.end();
472 bool SymDone
= VTableSymI
== VTableSymE
;
473 bool DataDone
= VTableDataI
== VTableDataE
;
474 if (SymDone
&& DataDone
)
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
;
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
;
499 static 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();
504 // Ignore non-object files.
505 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError())) {
507 raw_string_ostream
OS(Buf
);
508 logAllUnhandledErrors(std::move(E
), OS
);
510 reportError(Arc
->getFileName(), Buf
);
512 consumeError(ChildOrErr
.takeError());
516 if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get()))
519 reportError(Arc
->getFileName(), cxxdump_error::unrecognized_file_format
);
522 error(std::move(Err
));
525 static void dumpInput(StringRef File
) {
526 // Attempt to open the binary.
527 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(File
);
529 auto EC
= errorToErrorCode(BinaryOrErr
.takeError());
530 reportError(File
, EC
);
533 Binary
&Binary
= *BinaryOrErr
.get().getBinary();
535 if (Archive
*Arc
= dyn_cast
<Archive
>(&Binary
))
537 else if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&Binary
))
540 reportError(File
, cxxdump_error::unrecognized_file_format
);
543 int main(int argc
, const char *argv
[]) {
544 InitLLVM
X(argc
, argv
);
546 // Initialize targets.
547 llvm::InitializeAllTargetInfos();
549 // Register the target printer for --version.
550 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion
);
552 cl::ParseCommandLineOptions(argc
, argv
, "LLVM C++ ABI Data Dumper\n");
554 // Default to stdin if no filename is specified.
555 if (opts::InputFilenames
.size() == 0)
556 opts::InputFilenames
.push_back("-");
558 llvm::for_each(opts::InputFilenames
, dumpInput
);