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/MC/TargetRegistry.h"
17 #include "llvm/Object/Archive.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Object/SymbolSize.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/Endian.h"
22 #include "llvm/Support/FileSystem.h"
23 #include "llvm/Support/InitLLVM.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::OptionCategory
CXXDumpCategory("CXX Dump Options");
37 cl::list
<std::string
> InputFilenames(cl::Positional
,
38 cl::desc("<input object files>"),
39 cl::cat(CXXDumpCategory
));
44 static void error(std::error_code EC
) {
47 WithColor::error(outs(), "") << "reading file: " << EC
.message() << ".\n";
52 [[noreturn
]] static void error(Error Err
) {
53 logAllUnhandledErrors(std::move(Err
), WithColor::error(outs()),
60 T
unwrapOrError(Expected
<T
> EO
) {
62 error(EO
.takeError());
63 return std::move(*EO
);
68 static void reportError(StringRef Input
, StringRef Message
) {
71 WithColor::error(errs(), Input
) << Message
<< "\n";
76 static void reportError(StringRef Input
, std::error_code EC
) {
77 reportError(Input
, EC
.message());
80 static std::map
<SectionRef
, SmallVector
<SectionRef
, 1>> SectionRelocMap
;
82 static void collectRelocatedSymbols(const ObjectFile
*Obj
,
83 const SectionRef
&Sec
, uint64_t SecAddress
,
84 uint64_t SymAddress
, uint64_t SymSize
,
85 StringRef
*I
, StringRef
*E
) {
86 uint64_t SymOffset
= SymAddress
- SecAddress
;
87 uint64_t SymEnd
= SymOffset
+ SymSize
;
88 for (const SectionRef
&SR
: SectionRelocMap
[Sec
]) {
89 for (const object::RelocationRef
&Reloc
: SR
.relocations()) {
92 const object::symbol_iterator RelocSymI
= Reloc
.getSymbol();
93 if (RelocSymI
== Obj
->symbol_end())
95 Expected
<StringRef
> RelocSymName
= RelocSymI
->getName();
96 error(errorToErrorCode(RelocSymName
.takeError()));
97 uint64_t Offset
= Reloc
.getOffset();
98 if (Offset
>= SymOffset
&& Offset
< SymEnd
) {
106 static void collectRelocationOffsets(
107 const ObjectFile
*Obj
, const SectionRef
&Sec
, uint64_t SecAddress
,
108 uint64_t SymAddress
, uint64_t SymSize
, StringRef SymName
,
109 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> &Collection
) {
110 uint64_t SymOffset
= SymAddress
- SecAddress
;
111 uint64_t SymEnd
= SymOffset
+ SymSize
;
112 for (const SectionRef
&SR
: SectionRelocMap
[Sec
]) {
113 for (const object::RelocationRef
&Reloc
: SR
.relocations()) {
114 const object::symbol_iterator RelocSymI
= Reloc
.getSymbol();
115 if (RelocSymI
== Obj
->symbol_end())
117 Expected
<StringRef
> RelocSymName
= RelocSymI
->getName();
118 error(errorToErrorCode(RelocSymName
.takeError()));
119 uint64_t Offset
= Reloc
.getOffset();
120 if (Offset
>= SymOffset
&& Offset
< SymEnd
)
121 Collection
[std::make_pair(SymName
, Offset
- SymOffset
)] = *RelocSymName
;
126 static void dumpCXXData(const ObjectFile
*Obj
) {
127 struct CompleteObjectLocator
{
128 StringRef Symbols
[2];
129 ArrayRef
<little32_t
> Data
;
131 struct ClassHierarchyDescriptor
{
132 StringRef Symbols
[1];
133 ArrayRef
<little32_t
> Data
;
135 struct BaseClassDescriptor
{
136 StringRef Symbols
[2];
137 ArrayRef
<little32_t
> Data
;
139 struct TypeDescriptor
{
140 StringRef Symbols
[1];
142 StringRef MangledName
;
147 struct CatchableTypeArray
{
150 struct CatchableType
{
152 uint32_t NonVirtualBaseAdjustmentOffset
;
153 int32_t VirtualBasePointerOffset
;
154 uint32_t VirtualBaseAdjustmentOffset
;
156 StringRef Symbols
[2];
158 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VFTableEntries
;
159 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> TIEntries
;
160 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> CTAEntries
;
161 std::map
<StringRef
, ArrayRef
<little32_t
>> VBTables
;
162 std::map
<StringRef
, CompleteObjectLocator
> COLs
;
163 std::map
<StringRef
, ClassHierarchyDescriptor
> CHDs
;
164 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> BCAEntries
;
165 std::map
<StringRef
, BaseClassDescriptor
> BCDs
;
166 std::map
<StringRef
, TypeDescriptor
> TDs
;
167 std::map
<StringRef
, ThrowInfo
> TIs
;
168 std::map
<StringRef
, CatchableTypeArray
> CTAs
;
169 std::map
<StringRef
, CatchableType
> CTs
;
171 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VTableSymEntries
;
172 std::map
<std::pair
<StringRef
, uint64_t>, int64_t> VTableDataEntries
;
173 std::map
<std::pair
<StringRef
, uint64_t>, StringRef
> VTTEntries
;
174 std::map
<StringRef
, StringRef
> TINames
;
176 SectionRelocMap
.clear();
177 for (const SectionRef
&Section
: Obj
->sections()) {
178 Expected
<section_iterator
> ErrOrSec
= Section
.getRelocatedSection();
180 error(ErrOrSec
.takeError());
182 section_iterator Sec2
= *ErrOrSec
;
183 if (Sec2
!= Obj
->section_end())
184 SectionRelocMap
[*Sec2
].push_back(Section
);
187 uint8_t BytesInAddress
= Obj
->getBytesInAddress();
189 std::vector
<std::pair
<SymbolRef
, uint64_t>> SymAddr
=
190 object::computeSymbolSizes(*Obj
);
192 for (auto &P
: SymAddr
) {
193 object::SymbolRef Sym
= P
.first
;
194 uint64_t SymSize
= P
.second
;
195 Expected
<StringRef
> SymNameOrErr
= Sym
.getName();
196 error(errorToErrorCode(SymNameOrErr
.takeError()));
197 StringRef SymName
= *SymNameOrErr
;
198 Expected
<object::section_iterator
> SecIOrErr
= Sym
.getSection();
199 error(errorToErrorCode(SecIOrErr
.takeError()));
200 object::section_iterator SecI
= *SecIOrErr
;
201 // Skip external symbols.
202 if (SecI
== Obj
->section_end())
204 const SectionRef
&Sec
= *SecI
;
205 // Skip virtual or BSS sections.
206 if (Sec
.isBSS() || Sec
.isVirtual())
208 StringRef SecContents
= unwrapOrError(Sec
.getContents());
209 Expected
<uint64_t> SymAddressOrErr
= Sym
.getAddress();
210 error(errorToErrorCode(SymAddressOrErr
.takeError()));
211 uint64_t SymAddress
= *SymAddressOrErr
;
212 uint64_t SecAddress
= Sec
.getAddress();
213 uint64_t SecSize
= Sec
.getSize();
214 uint64_t SymOffset
= SymAddress
- SecAddress
;
215 StringRef SymContents
= SecContents
.substr(SymOffset
, SymSize
);
217 // VFTables in the MS-ABI start with '??_7' and are contained within their
218 // own COMDAT section. We then determine the contents of the VFTable by
219 // looking at each relocation in the section.
220 if (SymName
.starts_with("??_7")) {
221 // Each relocation either names a virtual method or a thunk. We note the
222 // offset into the section and the symbol used for the relocation.
223 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SecAddress
, SecSize
,
224 SymName
, VFTableEntries
);
226 // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
227 // offsets of virtual bases.
228 else if (SymName
.starts_with("??_8")) {
229 ArrayRef
<little32_t
> VBTableData(
230 reinterpret_cast<const little32_t
*>(SymContents
.data()),
231 SymContents
.size() / sizeof(little32_t
));
232 VBTables
[SymName
] = VBTableData
;
234 // Complete object locators in the MS-ABI start with '??_R4'
235 else if (SymName
.starts_with("??_R4")) {
236 CompleteObjectLocator COL
;
238 ArrayRef(reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
239 StringRef
*I
= std::begin(COL
.Symbols
), *E
= std::end(COL
.Symbols
);
240 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
243 // Class hierarchy descriptors in the MS-ABI start with '??_R3'
244 else if (SymName
.starts_with("??_R3")) {
245 ClassHierarchyDescriptor CHD
;
247 ArrayRef(reinterpret_cast<const little32_t
*>(SymContents
.data()), 3);
248 StringRef
*I
= std::begin(CHD
.Symbols
), *E
= std::end(CHD
.Symbols
);
249 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
252 // Class hierarchy descriptors in the MS-ABI start with '??_R2'
253 else if (SymName
.starts_with("??_R2")) {
254 // Each relocation names a base class descriptor. We note the offset into
255 // the section and the symbol used for the relocation.
256 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
257 SymName
, BCAEntries
);
259 // Base class descriptors in the MS-ABI start with '??_R1'
260 else if (SymName
.starts_with("??_R1")) {
261 BaseClassDescriptor BCD
;
263 reinterpret_cast<const little32_t
*>(SymContents
.data()) + 1, 5);
264 StringRef
*I
= std::begin(BCD
.Symbols
), *E
= std::end(BCD
.Symbols
);
265 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
268 // Type descriptors in the MS-ABI start with '??_R0'
269 else if (SymName
.starts_with("??_R0")) {
270 const char *DataPtr
= SymContents
.drop_front(BytesInAddress
).data();
272 if (BytesInAddress
== 8)
273 TD
.AlwaysZero
= *reinterpret_cast<const little64_t
*>(DataPtr
);
275 TD
.AlwaysZero
= *reinterpret_cast<const little32_t
*>(DataPtr
);
276 TD
.MangledName
= SymContents
.drop_front(BytesInAddress
* 2);
277 StringRef
*I
= std::begin(TD
.Symbols
), *E
= std::end(TD
.Symbols
);
278 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
281 // Throw descriptors in the MS-ABI start with '_TI'
282 else if (SymName
.starts_with("_TI") || SymName
.starts_with("__TI")) {
284 TI
.Flags
= *reinterpret_cast<const little32_t
*>(SymContents
.data());
285 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
289 // Catchable type arrays in the MS-ABI start with _CTA or __CTA.
290 else if (SymName
.starts_with("_CTA") || SymName
.starts_with("__CTA")) {
291 CatchableTypeArray CTA
;
293 *reinterpret_cast<const little32_t
*>(SymContents
.data());
294 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
295 SymName
, CTAEntries
);
298 // Catchable types in the MS-ABI start with _CT or __CT.
299 else if (SymName
.starts_with("_CT") || SymName
.starts_with("__CT")) {
300 const little32_t
*DataPtr
=
301 reinterpret_cast<const little32_t
*>(SymContents
.data());
303 CT
.Flags
= DataPtr
[0];
304 CT
.NonVirtualBaseAdjustmentOffset
= DataPtr
[2];
305 CT
.VirtualBasePointerOffset
= DataPtr
[3];
306 CT
.VirtualBaseAdjustmentOffset
= DataPtr
[4];
307 CT
.Size
= DataPtr
[5];
308 StringRef
*I
= std::begin(CT
.Symbols
), *E
= std::end(CT
.Symbols
);
309 collectRelocatedSymbols(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
, I
, E
);
312 // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
313 else if (SymName
.starts_with("_ZTT") || SymName
.starts_with("__ZTT")) {
314 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
315 SymName
, VTTEntries
);
317 // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
318 else if (SymName
.starts_with("_ZTS") || SymName
.starts_with("__ZTS")) {
319 TINames
[SymName
] = SymContents
.slice(0, SymContents
.find('\0'));
321 // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
322 else if (SymName
.starts_with("_ZTV") || SymName
.starts_with("__ZTV")) {
323 collectRelocationOffsets(Obj
, Sec
, SecAddress
, SymAddress
, SymSize
,
324 SymName
, VTableSymEntries
);
325 for (uint64_t SymOffI
= 0; SymOffI
< SymSize
; SymOffI
+= BytesInAddress
) {
326 auto Key
= std::make_pair(SymName
, SymOffI
);
327 if (VTableSymEntries
.count(Key
))
329 const char *DataPtr
=
330 SymContents
.substr(SymOffI
, BytesInAddress
).data();
332 if (BytesInAddress
== 8)
333 VData
= *reinterpret_cast<const little64_t
*>(DataPtr
);
335 VData
= *reinterpret_cast<const little32_t
*>(DataPtr
);
336 VTableDataEntries
[Key
] = VData
;
339 // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
340 else if (SymName
.starts_with("_ZTI") || SymName
.starts_with("__ZTI")) {
341 // FIXME: Do something with these!
344 for (const auto &VFTableEntry
: VFTableEntries
) {
345 StringRef VFTableName
= VFTableEntry
.first
.first
;
346 uint64_t Offset
= VFTableEntry
.first
.second
;
347 StringRef SymName
= VFTableEntry
.second
;
348 outs() << VFTableName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
350 for (const auto &VBTable
: VBTables
) {
351 StringRef VBTableName
= VBTable
.first
;
353 for (little32_t Offset
: VBTable
.second
) {
354 outs() << VBTableName
<< '[' << Idx
<< "]: " << Offset
<< '\n';
355 Idx
+= sizeof(Offset
);
358 for (const auto &COLPair
: COLs
) {
359 StringRef COLName
= COLPair
.first
;
360 const CompleteObjectLocator
&COL
= COLPair
.second
;
361 outs() << COLName
<< "[IsImageRelative]: " << COL
.Data
[0] << '\n';
362 outs() << COLName
<< "[OffsetToTop]: " << COL
.Data
[1] << '\n';
363 outs() << COLName
<< "[VFPtrOffset]: " << COL
.Data
[2] << '\n';
364 outs() << COLName
<< "[TypeDescriptor]: " << COL
.Symbols
[0] << '\n';
365 outs() << COLName
<< "[ClassHierarchyDescriptor]: " << COL
.Symbols
[1]
368 for (const auto &CHDPair
: CHDs
) {
369 StringRef CHDName
= CHDPair
.first
;
370 const ClassHierarchyDescriptor
&CHD
= CHDPair
.second
;
371 outs() << CHDName
<< "[AlwaysZero]: " << CHD
.Data
[0] << '\n';
372 outs() << CHDName
<< "[Flags]: " << CHD
.Data
[1] << '\n';
373 outs() << CHDName
<< "[NumClasses]: " << CHD
.Data
[2] << '\n';
374 outs() << CHDName
<< "[BaseClassArray]: " << CHD
.Symbols
[0] << '\n';
376 for (const auto &BCAEntry
: BCAEntries
) {
377 StringRef BCAName
= BCAEntry
.first
.first
;
378 uint64_t Offset
= BCAEntry
.first
.second
;
379 StringRef SymName
= BCAEntry
.second
;
380 outs() << BCAName
<< '[' << Offset
<< "]: " << SymName
<< '\n';
382 for (const auto &BCDPair
: BCDs
) {
383 StringRef BCDName
= BCDPair
.first
;
384 const BaseClassDescriptor
&BCD
= BCDPair
.second
;
385 outs() << BCDName
<< "[TypeDescriptor]: " << BCD
.Symbols
[0] << '\n';
386 outs() << BCDName
<< "[NumBases]: " << BCD
.Data
[0] << '\n';
387 outs() << BCDName
<< "[OffsetInVBase]: " << BCD
.Data
[1] << '\n';
388 outs() << BCDName
<< "[VBPtrOffset]: " << BCD
.Data
[2] << '\n';
389 outs() << BCDName
<< "[OffsetInVBTable]: " << BCD
.Data
[3] << '\n';
390 outs() << BCDName
<< "[Flags]: " << BCD
.Data
[4] << '\n';
391 outs() << BCDName
<< "[ClassHierarchyDescriptor]: " << BCD
.Symbols
[1]
394 for (const auto &TDPair
: TDs
) {
395 StringRef TDName
= TDPair
.first
;
396 const TypeDescriptor
&TD
= TDPair
.second
;
397 outs() << TDName
<< "[VFPtr]: " << TD
.Symbols
[0] << '\n';
398 outs() << TDName
<< "[AlwaysZero]: " << TD
.AlwaysZero
<< '\n';
399 outs() << TDName
<< "[MangledName]: ";
400 outs().write_escaped(TD
.MangledName
.rtrim(StringRef("\0", 1)),
401 /*UseHexEscapes=*/true)
404 for (const auto &TIPair
: TIs
) {
405 StringRef TIName
= TIPair
.first
;
406 const ThrowInfo
&TI
= TIPair
.second
;
407 auto dumpThrowInfoFlag
= [&](const char *Name
, uint32_t Flag
) {
408 outs() << TIName
<< "[Flags." << Name
409 << "]: " << (TI
.Flags
& Flag
? "true" : "false") << '\n';
411 auto dumpThrowInfoSymbol
= [&](const char *Name
, int Offset
) {
412 outs() << TIName
<< '[' << Name
<< "]: ";
413 auto Entry
= TIEntries
.find(std::make_pair(TIName
, Offset
));
414 outs() << (Entry
== TIEntries
.end() ? "null" : Entry
->second
) << '\n';
416 outs() << TIName
<< "[Flags]: " << TI
.Flags
<< '\n';
417 dumpThrowInfoFlag("Const", 1);
418 dumpThrowInfoFlag("Volatile", 2);
419 dumpThrowInfoSymbol("CleanupFn", 4);
420 dumpThrowInfoSymbol("ForwardCompat", 8);
421 dumpThrowInfoSymbol("CatchableTypeArray", 12);
423 for (const auto &CTAPair
: CTAs
) {
424 StringRef CTAName
= CTAPair
.first
;
425 const CatchableTypeArray
&CTA
= CTAPair
.second
;
427 outs() << CTAName
<< "[NumEntries]: " << CTA
.NumEntries
<< '\n';
430 for (auto I
= CTAEntries
.lower_bound(std::make_pair(CTAName
, 0)),
431 E
= CTAEntries
.upper_bound(std::make_pair(CTAName
, UINT64_MAX
));
433 outs() << CTAName
<< '[' << Idx
++ << "]: " << I
->second
<< '\n';
435 for (const auto &CTPair
: CTs
) {
436 StringRef CTName
= CTPair
.first
;
437 const CatchableType
&CT
= CTPair
.second
;
438 auto dumpCatchableTypeFlag
= [&](const char *Name
, uint32_t Flag
) {
439 outs() << CTName
<< "[Flags." << Name
440 << "]: " << (CT
.Flags
& Flag
? "true" : "false") << '\n';
442 outs() << CTName
<< "[Flags]: " << CT
.Flags
<< '\n';
443 dumpCatchableTypeFlag("ScalarType", 1);
444 dumpCatchableTypeFlag("VirtualInheritance", 4);
445 outs() << CTName
<< "[TypeDescriptor]: " << CT
.Symbols
[0] << '\n';
446 outs() << CTName
<< "[NonVirtualBaseAdjustmentOffset]: "
447 << CT
.NonVirtualBaseAdjustmentOffset
<< '\n';
449 << "[VirtualBasePointerOffset]: " << CT
.VirtualBasePointerOffset
451 outs() << CTName
<< "[VirtualBaseAdjustmentOffset]: "
452 << CT
.VirtualBaseAdjustmentOffset
<< '\n';
453 outs() << CTName
<< "[Size]: " << CT
.Size
<< '\n';
455 << "[CopyCtor]: " << (CT
.Symbols
[1].empty() ? "null" : CT
.Symbols
[1])
458 for (const auto &VTTPair
: VTTEntries
) {
459 StringRef VTTName
= VTTPair
.first
.first
;
460 uint64_t VTTOffset
= VTTPair
.first
.second
;
461 StringRef VTTEntry
= VTTPair
.second
;
462 outs() << VTTName
<< '[' << VTTOffset
<< "]: " << VTTEntry
<< '\n';
464 for (const auto &TIPair
: TINames
) {
465 StringRef TIName
= TIPair
.first
;
466 outs() << TIName
<< ": " << TIPair
.second
<< '\n';
468 auto VTableSymI
= VTableSymEntries
.begin();
469 auto VTableSymE
= VTableSymEntries
.end();
470 auto VTableDataI
= VTableDataEntries
.begin();
471 auto VTableDataE
= VTableDataEntries
.end();
473 bool SymDone
= VTableSymI
== VTableSymE
;
474 bool DataDone
= VTableDataI
== VTableDataE
;
475 if (SymDone
&& DataDone
)
477 if (!SymDone
&& (DataDone
|| VTableSymI
->first
< VTableDataI
->first
)) {
478 StringRef VTableName
= VTableSymI
->first
.first
;
479 uint64_t Offset
= VTableSymI
->first
.second
;
480 StringRef VTableEntry
= VTableSymI
->second
;
481 outs() << VTableName
<< '[' << Offset
<< "]: ";
482 outs() << VTableEntry
;
487 if (!DataDone
&& (SymDone
|| VTableDataI
->first
< VTableSymI
->first
)) {
488 StringRef VTableName
= VTableDataI
->first
.first
;
489 uint64_t Offset
= VTableDataI
->first
.second
;
490 int64_t VTableEntry
= VTableDataI
->second
;
491 outs() << VTableName
<< '[' << Offset
<< "]: ";
492 outs() << VTableEntry
;
500 static void dumpArchive(const Archive
*Arc
) {
501 Error Err
= Error::success();
502 for (const auto &ArcC
: Arc
->children(Err
)) {
503 Expected
<std::unique_ptr
<Binary
>> ChildOrErr
= ArcC
.getAsBinary();
505 // Ignore non-object files.
506 if (auto E
= isNotObjectErrorInvalidFileType(ChildOrErr
.takeError())) {
508 raw_string_ostream
OS(Buf
);
509 logAllUnhandledErrors(std::move(E
), OS
);
511 reportError(Arc
->getFileName(), Buf
);
513 consumeError(ChildOrErr
.takeError());
517 if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&*ChildOrErr
.get()))
520 reportError(Arc
->getFileName(), cxxdump_error::unrecognized_file_format
);
523 error(std::move(Err
));
526 static void dumpInput(StringRef File
) {
527 // Attempt to open the binary.
528 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(File
);
530 auto EC
= errorToErrorCode(BinaryOrErr
.takeError());
531 reportError(File
, EC
);
534 Binary
&Binary
= *BinaryOrErr
.get().getBinary();
536 if (Archive
*Arc
= dyn_cast
<Archive
>(&Binary
))
538 else if (ObjectFile
*Obj
= dyn_cast
<ObjectFile
>(&Binary
))
541 reportError(File
, cxxdump_error::unrecognized_file_format
);
544 int main(int argc
, const char *argv
[]) {
545 InitLLVM
X(argc
, argv
);
547 // Initialize targets.
548 llvm::InitializeAllTargetInfos();
550 // Register the target printer for --version.
551 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion
);
553 cl::HideUnrelatedOptions({&opts::CXXDumpCategory
, &getColorCategory()});
554 cl::ParseCommandLineOptions(argc
, argv
, "LLVM C++ ABI Data Dumper\n");
556 // Default to stdin if no filename is specified.
557 if (opts::InputFilenames
.size() == 0)
558 opts::InputFilenames
.push_back("-");
560 llvm::for_each(opts::InputFilenames
, dumpInput
);