1 //===-- COFFDump.cpp - COFF-specific dumper ---------------------*- 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 //===----------------------------------------------------------------------===//
10 /// This file implements the COFF-specific dumper for llvm-objdump.
11 /// It outputs the Win64 EH data structures as plain text.
12 /// The encoding of the unwind codes is described in MSDN:
13 /// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
15 //===----------------------------------------------------------------------===//
19 #include "llvm-objdump.h"
20 #include "llvm/Demangle/Demangle.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/COFFImportFile.h"
23 #include "llvm/Object/ObjectFile.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/Win64EH.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
30 using namespace llvm::objdump
;
31 using namespace llvm::object
;
32 using namespace llvm::Win64EH
;
35 template <typename T
> struct EnumEntry
{
40 class COFFDumper
: public Dumper
{
42 explicit COFFDumper(const llvm::object::COFFObjectFile
&O
)
44 Is64
= !Obj
.getPE32Header();
47 template <class PEHeader
> void printPEHeader(const PEHeader
&Hdr
) const;
48 void printPrivateHeaders() override
;
51 template <typename T
> FormattedNumber
formatAddr(T V
) const {
52 return format_hex_no_prefix(V
, Is64
? 16 : 8);
55 uint32_t getBaseOfData(const void *Hdr
) const {
56 return Is64
? 0 : static_cast<const pe32_header
*>(Hdr
)->BaseOfData
;
59 const llvm::object::COFFObjectFile
&Obj
;
64 std::unique_ptr
<Dumper
>
65 objdump::createCOFFDumper(const object::COFFObjectFile
&Obj
) {
66 return std::make_unique
<COFFDumper
>(Obj
);
69 constexpr EnumEntry
<uint16_t> PEHeaderMagic
[] = {
70 {uint16_t(COFF::PE32Header::PE32
), "PE32"},
71 {uint16_t(COFF::PE32Header::PE32_PLUS
), "PE32+"},
74 constexpr EnumEntry
<COFF::WindowsSubsystem
> PEWindowsSubsystem
[] = {
75 {COFF::IMAGE_SUBSYSTEM_UNKNOWN
, "unspecified"},
76 {COFF::IMAGE_SUBSYSTEM_NATIVE
, "NT native"},
77 {COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI
, "Windows GUI"},
78 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI
, "Windows CUI"},
79 {COFF::IMAGE_SUBSYSTEM_POSIX_CUI
, "POSIX CUI"},
80 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
, "Wince CUI"},
81 {COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION
, "EFI application"},
82 {COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
, "EFI boot service driver"},
83 {COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
, "EFI runtime driver"},
84 {COFF::IMAGE_SUBSYSTEM_EFI_ROM
, "SAL runtime driver"},
85 {COFF::IMAGE_SUBSYSTEM_XBOX
, "XBOX"},
88 template <typename T
, typename TEnum
>
89 static void printOptionalEnumName(T Value
,
90 ArrayRef
<EnumEntry
<TEnum
>> EnumValues
) {
91 for (const EnumEntry
<TEnum
> &I
: EnumValues
)
92 if (I
.Value
== Value
) {
93 outs() << "\t(" << I
.Name
<< ')';
98 template <class PEHeader
>
99 void COFFDumper::printPEHeader(const PEHeader
&Hdr
) const {
100 auto print
= [](const char *K
, auto V
, const char *Fmt
= "%d\n") {
101 outs() << format("%-23s ", K
) << format(Fmt
, V
);
103 auto printU16
= [&](const char *K
, support::ulittle16_t V
,
104 const char *Fmt
= "%d\n") { print(K
, uint16_t(V
), Fmt
); };
105 auto printU32
= [&](const char *K
, support::ulittle32_t V
,
106 const char *Fmt
= "%d\n") { print(K
, uint32_t(V
), Fmt
); };
107 auto printAddr
= [=](const char *K
, uint64_t V
) {
108 outs() << format("%-23s ", K
) << formatAddr(V
) << '\n';
111 printU16("Magic", Hdr
.Magic
, "%04x");
112 printOptionalEnumName(Hdr
.Magic
, ArrayRef(PEHeaderMagic
));
114 print("MajorLinkerVersion", Hdr
.MajorLinkerVersion
);
115 print("MinorLinkerVersion", Hdr
.MinorLinkerVersion
);
116 printAddr("SizeOfCode", Hdr
.SizeOfCode
);
117 printAddr("SizeOfInitializedData", Hdr
.SizeOfInitializedData
);
118 printAddr("SizeOfUninitializedData", Hdr
.SizeOfUninitializedData
);
119 printAddr("AddressOfEntryPoint", Hdr
.AddressOfEntryPoint
);
120 printAddr("BaseOfCode", Hdr
.BaseOfCode
);
122 printAddr("BaseOfData", getBaseOfData(&Hdr
));
123 printAddr("ImageBase", Hdr
.ImageBase
);
124 printU32("SectionAlignment", Hdr
.SectionAlignment
, "%08x\n");
125 printU32("FileAlignment", Hdr
.FileAlignment
, "%08x\n");
126 printU16("MajorOSystemVersion", Hdr
.MajorOperatingSystemVersion
);
127 printU16("MinorOSystemVersion", Hdr
.MinorOperatingSystemVersion
);
128 printU16("MajorImageVersion", Hdr
.MajorImageVersion
);
129 printU16("MinorImageVersion", Hdr
.MinorImageVersion
);
130 printU16("MajorSubsystemVersion", Hdr
.MajorSubsystemVersion
);
131 printU16("MinorSubsystemVersion", Hdr
.MinorSubsystemVersion
);
132 printU32("Win32Version", Hdr
.Win32VersionValue
, "%08x\n");
133 printU32("SizeOfImage", Hdr
.SizeOfImage
, "%08x\n");
134 printU32("SizeOfHeaders", Hdr
.SizeOfHeaders
, "%08x\n");
135 printU32("CheckSum", Hdr
.CheckSum
, "%08x\n");
136 printU16("Subsystem", Hdr
.Subsystem
, "%08x");
137 printOptionalEnumName(Hdr
.Subsystem
, ArrayRef(PEWindowsSubsystem
));
140 printU16("DllCharacteristics", Hdr
.DLLCharacteristics
, "%08x\n");
142 if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \
143 outs() << "\t\t\t\t\t" << #Name << '\n';
144 FLAG(HIGH_ENTROPY_VA
);
146 FLAG(FORCE_INTEGRITY
);
154 FLAG(TERMINAL_SERVER_AWARE
);
157 printAddr("SizeOfStackReserve", Hdr
.SizeOfStackReserve
);
158 printAddr("SizeOfStackCommit", Hdr
.SizeOfStackCommit
);
159 printAddr("SizeOfHeapReserve", Hdr
.SizeOfHeapReserve
);
160 printAddr("SizeOfHeapCommit", Hdr
.SizeOfHeapCommit
);
161 printU32("LoaderFlags", Hdr
.LoaderFlags
, "%08x\n");
162 printU32("NumberOfRvaAndSizes", Hdr
.NumberOfRvaAndSize
, "%08x\n");
164 static const char *DirName
[COFF::NUM_DATA_DIRECTORIES
+ 1] = {
165 "Export Directory [.edata (or where ever we found it)]",
166 "Import Directory [parts of .idata]",
167 "Resource Directory [.rsrc]",
168 "Exception Directory [.pdata]",
169 "Security Directory",
170 "Base Relocation Directory [.reloc]",
172 "Description Directory",
174 "Thread Storage Directory [.tls]",
175 "Load Configuration Directory",
176 "Bound Import Directory",
177 "Import Address Table Directory",
178 "Delay Import Directory",
179 "CLR Runtime Header",
182 outs() << "\nThe Data Directory\n";
183 for (uint32_t I
= 0; I
!= std::size(DirName
); ++I
) {
184 uint32_t Addr
= 0, Size
= 0;
185 if (const data_directory
*Data
= Obj
.getDataDirectory(I
)) {
186 Addr
= Data
->RelativeVirtualAddress
;
189 outs() << format("Entry %x ", I
) << formatAddr(Addr
)
190 << format(" %08x %s\n", uint32_t(Size
), DirName
[I
]);
194 // Returns the name of the unwind code.
195 static StringRef
getUnwindCodeTypeName(uint8_t Code
) {
197 default: llvm_unreachable("Invalid unwind code");
198 case UOP_PushNonVol
: return "UOP_PushNonVol";
199 case UOP_AllocLarge
: return "UOP_AllocLarge";
200 case UOP_AllocSmall
: return "UOP_AllocSmall";
201 case UOP_SetFPReg
: return "UOP_SetFPReg";
202 case UOP_SaveNonVol
: return "UOP_SaveNonVol";
203 case UOP_SaveNonVolBig
: return "UOP_SaveNonVolBig";
204 case UOP_Epilog
: return "UOP_Epilog";
205 case UOP_SpareCode
: return "UOP_SpareCode";
206 case UOP_SaveXMM128
: return "UOP_SaveXMM128";
207 case UOP_SaveXMM128Big
: return "UOP_SaveXMM128Big";
208 case UOP_PushMachFrame
: return "UOP_PushMachFrame";
212 // Returns the name of a referenced register.
213 static StringRef
getUnwindRegisterName(uint8_t Reg
) {
215 default: llvm_unreachable("Invalid register");
216 case 0: return "RAX";
217 case 1: return "RCX";
218 case 2: return "RDX";
219 case 3: return "RBX";
220 case 4: return "RSP";
221 case 5: return "RBP";
222 case 6: return "RSI";
223 case 7: return "RDI";
226 case 10: return "R10";
227 case 11: return "R11";
228 case 12: return "R12";
229 case 13: return "R13";
230 case 14: return "R14";
231 case 15: return "R15";
235 // Calculates the number of array slots required for the unwind code.
236 static unsigned getNumUsedSlots(const UnwindCode
&UnwindCode
) {
237 switch (UnwindCode
.getUnwindOp()) {
238 default: llvm_unreachable("Invalid unwind code");
242 case UOP_PushMachFrame
:
248 case UOP_SaveNonVolBig
:
249 case UOP_SaveXMM128Big
:
253 return (UnwindCode
.getOpInfo() == 0) ? 2 : 3;
257 // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
258 // the unwind codes array, this function requires that the correct number of
259 // slots is provided.
260 static void printUnwindCode(ArrayRef
<UnwindCode
> UCs
) {
261 assert(UCs
.size() >= getNumUsedSlots(UCs
[0]));
262 outs() << format(" 0x%02x: ", unsigned(UCs
[0].u
.CodeOffset
))
263 << getUnwindCodeTypeName(UCs
[0].getUnwindOp());
264 switch (UCs
[0].getUnwindOp()) {
266 outs() << " " << getUnwindRegisterName(UCs
[0].getOpInfo());
269 if (UCs
[0].getOpInfo() == 0) {
270 outs() << " " << UCs
[1].FrameOffset
;
272 outs() << " " << UCs
[1].FrameOffset
273 + (static_cast<uint32_t>(UCs
[2].FrameOffset
) << 16);
277 outs() << " " << ((UCs
[0].getOpInfo() + 1) * 8);
283 outs() << " " << getUnwindRegisterName(UCs
[0].getOpInfo())
284 << format(" [0x%04x]", 8 * UCs
[1].FrameOffset
);
286 case UOP_SaveNonVolBig
:
287 outs() << " " << getUnwindRegisterName(UCs
[0].getOpInfo())
288 << format(" [0x%08x]", UCs
[1].FrameOffset
289 + (static_cast<uint32_t>(UCs
[2].FrameOffset
) << 16));
292 outs() << " XMM" << static_cast<uint32_t>(UCs
[0].getOpInfo())
293 << format(" [0x%04x]", 16 * UCs
[1].FrameOffset
);
295 case UOP_SaveXMM128Big
:
296 outs() << " XMM" << UCs
[0].getOpInfo()
297 << format(" [0x%08x]", UCs
[1].FrameOffset
298 + (static_cast<uint32_t>(UCs
[2].FrameOffset
) << 16));
300 case UOP_PushMachFrame
:
301 outs() << " " << (UCs
[0].getOpInfo() ? "w/o" : "w")
308 static void printAllUnwindCodes(ArrayRef
<UnwindCode
> UCs
) {
309 for (const UnwindCode
*I
= UCs
.begin(), *E
= UCs
.end(); I
< E
; ) {
310 unsigned UsedSlots
= getNumUsedSlots(*I
);
311 if (UsedSlots
> UCs
.size()) {
312 outs() << "Unwind data corrupted: Encountered unwind op "
313 << getUnwindCodeTypeName((*I
).getUnwindOp())
314 << " which requires " << UsedSlots
315 << " slots, but only " << UCs
.size()
316 << " remaining in buffer";
319 printUnwindCode(ArrayRef(I
, E
));
324 // Given a symbol sym this functions returns the address and section of it.
325 static Error
resolveSectionAndAddress(const COFFObjectFile
*Obj
,
326 const SymbolRef
&Sym
,
327 const coff_section
*&ResolvedSection
,
328 uint64_t &ResolvedAddr
) {
329 Expected
<uint64_t> ResolvedAddrOrErr
= Sym
.getAddress();
330 if (!ResolvedAddrOrErr
)
331 return ResolvedAddrOrErr
.takeError();
332 ResolvedAddr
= *ResolvedAddrOrErr
;
333 Expected
<section_iterator
> Iter
= Sym
.getSection();
335 return Iter
.takeError();
336 ResolvedSection
= Obj
->getCOFFSection(**Iter
);
337 return Error::success();
340 // Given a vector of relocations for a section and an offset into this section
341 // the function returns the symbol used for the relocation at the offset.
342 static Error
resolveSymbol(const std::vector
<RelocationRef
> &Rels
,
343 uint64_t Offset
, SymbolRef
&Sym
) {
344 for (auto &R
: Rels
) {
345 uint64_t Ofs
= R
.getOffset();
347 Sym
= *R
.getSymbol();
348 return Error::success();
351 return make_error
<BinaryError
>();
354 // Given a vector of relocations for a section and an offset into this section
355 // the function resolves the symbol used for the relocation at the offset and
356 // returns the section content and the address inside the content pointed to
359 getSectionContents(const COFFObjectFile
*Obj
,
360 const std::vector
<RelocationRef
> &Rels
, uint64_t Offset
,
361 ArrayRef
<uint8_t> &Contents
, uint64_t &Addr
) {
363 if (Error E
= resolveSymbol(Rels
, Offset
, Sym
))
365 const coff_section
*Section
;
366 if (Error E
= resolveSectionAndAddress(Obj
, Sym
, Section
, Addr
))
368 return Obj
->getSectionContents(Section
, Contents
);
371 // Given a vector of relocations for a section and an offset into this section
372 // the function returns the name of the symbol used for the relocation at the
374 static Error
resolveSymbolName(const std::vector
<RelocationRef
> &Rels
,
375 uint64_t Offset
, StringRef
&Name
) {
377 if (Error EC
= resolveSymbol(Rels
, Offset
, Sym
))
379 Expected
<StringRef
> NameOrErr
= Sym
.getName();
381 return NameOrErr
.takeError();
383 return Error::success();
386 static void printCOFFSymbolAddress(raw_ostream
&Out
,
387 const std::vector
<RelocationRef
> &Rels
,
388 uint64_t Offset
, uint32_t Disp
) {
390 if (!resolveSymbolName(Rels
, Offset
, Sym
)) {
393 Out
<< format(" + 0x%04x", Disp
);
395 Out
<< format("0x%04x", Disp
);
400 printSEHTable(const COFFObjectFile
*Obj
, uint32_t TableVA
, int Count
) {
404 uintptr_t IntPtr
= 0;
405 if (Error E
= Obj
->getVaPtr(TableVA
, IntPtr
))
406 reportError(std::move(E
), Obj
->getFileName());
408 const support::ulittle32_t
*P
= (const support::ulittle32_t
*)IntPtr
;
409 outs() << "SEH Table:";
410 for (int I
= 0; I
< Count
; ++I
)
411 outs() << format(" 0x%x", P
[I
] + Obj
->getPE32Header()->ImageBase
);
415 template <typename T
>
416 static void printTLSDirectoryT(const coff_tls_directory
<T
> *TLSDir
) {
417 size_t FormatWidth
= sizeof(T
) * 2;
418 outs() << "TLS directory:"
419 << "\n StartAddressOfRawData: "
420 << format_hex(TLSDir
->StartAddressOfRawData
, FormatWidth
)
421 << "\n EndAddressOfRawData: "
422 << format_hex(TLSDir
->EndAddressOfRawData
, FormatWidth
)
423 << "\n AddressOfIndex: "
424 << format_hex(TLSDir
->AddressOfIndex
, FormatWidth
)
425 << "\n AddressOfCallBacks: "
426 << format_hex(TLSDir
->AddressOfCallBacks
, FormatWidth
)
427 << "\n SizeOfZeroFill: "
428 << TLSDir
->SizeOfZeroFill
429 << "\n Characteristics: "
430 << TLSDir
->Characteristics
432 << TLSDir
->getAlignment()
436 static void printTLSDirectory(const COFFObjectFile
*Obj
) {
437 const pe32_header
*PE32Header
= Obj
->getPE32Header();
438 const pe32plus_header
*PE32PlusHeader
= Obj
->getPE32PlusHeader();
440 // Skip if it's not executable.
441 if (!PE32Header
&& !PE32PlusHeader
)
445 if (auto *TLSDir
= Obj
->getTLSDirectory32())
446 printTLSDirectoryT(TLSDir
);
448 if (auto *TLSDir
= Obj
->getTLSDirectory64())
449 printTLSDirectoryT(TLSDir
);
455 static void printLoadConfiguration(const COFFObjectFile
*Obj
) {
456 // Skip if it's not executable.
457 if (!Obj
->getPE32Header())
460 // Currently only x86 is supported
461 if (Obj
->getMachine() != COFF::IMAGE_FILE_MACHINE_I386
)
464 auto *LoadConf
= Obj
->getLoadConfig32();
468 outs() << "Load configuration:"
469 << "\n Timestamp: " << LoadConf
->TimeDateStamp
470 << "\n Major Version: " << LoadConf
->MajorVersion
471 << "\n Minor Version: " << LoadConf
->MinorVersion
472 << "\n GlobalFlags Clear: " << LoadConf
->GlobalFlagsClear
473 << "\n GlobalFlags Set: " << LoadConf
->GlobalFlagsSet
474 << "\n Critical Section Default Timeout: " << LoadConf
->CriticalSectionDefaultTimeout
475 << "\n Decommit Free Block Threshold: " << LoadConf
->DeCommitFreeBlockThreshold
476 << "\n Decommit Total Free Threshold: " << LoadConf
->DeCommitTotalFreeThreshold
477 << "\n Lock Prefix Table: " << LoadConf
->LockPrefixTable
478 << "\n Maximum Allocation Size: " << LoadConf
->MaximumAllocationSize
479 << "\n Virtual Memory Threshold: " << LoadConf
->VirtualMemoryThreshold
480 << "\n Process Affinity Mask: " << LoadConf
->ProcessAffinityMask
481 << "\n Process Heap Flags: " << LoadConf
->ProcessHeapFlags
482 << "\n CSD Version: " << LoadConf
->CSDVersion
483 << "\n Security Cookie: " << LoadConf
->SecurityCookie
484 << "\n SEH Table: " << LoadConf
->SEHandlerTable
485 << "\n SEH Count: " << LoadConf
->SEHandlerCount
487 printSEHTable(Obj
, LoadConf
->SEHandlerTable
, LoadConf
->SEHandlerCount
);
491 // Prints import tables. The import table is a table containing the list of
492 // DLL name and symbol names which will be linked by the loader.
493 static void printImportTables(const COFFObjectFile
*Obj
) {
494 import_directory_iterator I
= Obj
->import_directory_begin();
495 import_directory_iterator E
= Obj
->import_directory_end();
498 outs() << "The Import Tables:\n";
499 for (const ImportDirectoryEntryRef
&DirRef
: Obj
->import_directories()) {
500 const coff_import_directory_table_entry
*Dir
;
502 if (DirRef
.getImportTableEntry(Dir
)) return;
503 if (DirRef
.getName(Name
)) return;
505 outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
506 static_cast<uint32_t>(Dir
->ImportLookupTableRVA
),
507 static_cast<uint32_t>(Dir
->TimeDateStamp
),
508 static_cast<uint32_t>(Dir
->ForwarderChain
),
509 static_cast<uint32_t>(Dir
->NameRVA
),
510 static_cast<uint32_t>(Dir
->ImportAddressTableRVA
));
511 outs() << " DLL Name: " << Name
<< "\n";
512 outs() << " Hint/Ord Name\n";
513 for (const ImportedSymbolRef
&Entry
: DirRef
.imported_symbols()) {
515 if (Entry
.isOrdinal(IsOrdinal
))
519 if (Entry
.getOrdinal(Ordinal
))
521 outs() << format(" % 6d\n", Ordinal
);
524 uint32_t HintNameRVA
;
525 if (Entry
.getHintNameRVA(HintNameRVA
))
529 if (Obj
->getHintName(HintNameRVA
, Hint
, Name
))
531 outs() << format(" % 6d ", Hint
) << Name
<< "\n";
537 // Prints export tables. The export table is a table containing the list of
538 // exported symbol from the DLL.
539 static void printExportTable(const COFFObjectFile
*Obj
) {
540 export_directory_iterator I
= Obj
->export_directory_begin();
541 export_directory_iterator E
= Obj
->export_directory_end();
544 outs() << "Export Table:\n";
546 uint32_t OrdinalBase
;
547 if (I
->getDllName(DllName
))
549 if (I
->getOrdinalBase(OrdinalBase
))
551 outs() << " DLL name: " << DllName
<< "\n";
552 outs() << " Ordinal base: " << OrdinalBase
<< "\n";
553 outs() << " Ordinal RVA Name\n";
554 for (; I
!= E
; I
= ++I
) {
556 if (I
->getExportRVA(RVA
))
559 if (I
->getSymbolName(Name
))
561 if (!RVA
&& Name
.empty())
565 if (I
->getOrdinal(Ordinal
))
568 if (I
->isForwarder(IsForwarder
))
572 // Export table entries can be used to re-export symbols that
573 // this COFF file is imported from some DLLs. This is rare.
574 // In most cases IsForwarder is false.
575 outs() << format(" %5d ", Ordinal
);
577 outs() << format(" %5d %# 8x", Ordinal
, RVA
);
581 outs() << " " << Name
;
584 if (I
->getForwardTo(S
))
586 outs() << " (forwarded to " << S
<< ")";
592 // Given the COFF object file, this function returns the relocations for .pdata
593 // and the pointer to "runtime function" structs.
594 static bool getPDataSection(const COFFObjectFile
*Obj
,
595 std::vector
<RelocationRef
> &Rels
,
596 const RuntimeFunction
*&RFStart
, int &NumRFs
) {
597 for (const SectionRef
&Section
: Obj
->sections()) {
598 StringRef Name
= unwrapOrError(Section
.getName(), Obj
->getFileName());
599 if (Name
!= ".pdata")
602 const coff_section
*Pdata
= Obj
->getCOFFSection(Section
);
603 append_range(Rels
, Section
.relocations());
605 // Sort relocations by address.
606 llvm::sort(Rels
, isRelocAddressLess
);
608 ArrayRef
<uint8_t> Contents
;
609 if (Error E
= Obj
->getSectionContents(Pdata
, Contents
))
610 reportError(std::move(E
), Obj
->getFileName());
612 if (Contents
.empty())
615 RFStart
= reinterpret_cast<const RuntimeFunction
*>(Contents
.data());
616 NumRFs
= Contents
.size() / sizeof(RuntimeFunction
);
622 Error
objdump::getCOFFRelocationValueString(const COFFObjectFile
*Obj
,
623 const RelocationRef
&Rel
,
624 SmallVectorImpl
<char> &Result
) {
625 symbol_iterator SymI
= Rel
.getSymbol();
626 Expected
<StringRef
> SymNameOrErr
= SymI
->getName();
628 return SymNameOrErr
.takeError();
629 StringRef SymName
= *SymNameOrErr
;
630 Result
.append(SymName
.begin(), SymName
.end());
631 return Error::success();
634 static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo
*UI
) {
635 // The casts to int are required in order to output the value as number.
636 // Without the casts the value would be interpreted as char data (which
637 // results in garbage output).
638 outs() << " Version: " << static_cast<int>(UI
->getVersion()) << "\n";
639 outs() << " Flags: " << static_cast<int>(UI
->getFlags());
640 if (UI
->getFlags()) {
641 if (UI
->getFlags() & UNW_ExceptionHandler
)
642 outs() << " UNW_ExceptionHandler";
643 if (UI
->getFlags() & UNW_TerminateHandler
)
644 outs() << " UNW_TerminateHandler";
645 if (UI
->getFlags() & UNW_ChainInfo
)
646 outs() << " UNW_ChainInfo";
649 outs() << " Size of prolog: " << static_cast<int>(UI
->PrologSize
) << "\n";
650 outs() << " Number of Codes: " << static_cast<int>(UI
->NumCodes
) << "\n";
651 // Maybe this should move to output of UOP_SetFPReg?
652 if (UI
->getFrameRegister()) {
653 outs() << " Frame register: "
654 << getUnwindRegisterName(UI
->getFrameRegister()) << "\n";
655 outs() << " Frame offset: " << 16 * UI
->getFrameOffset() << "\n";
657 outs() << " No frame pointer used\n";
659 if (UI
->getFlags() & (UNW_ExceptionHandler
| UNW_TerminateHandler
)) {
660 // FIXME: Output exception handler data
661 } else if (UI
->getFlags() & UNW_ChainInfo
) {
662 // FIXME: Output chained unwind info
666 outs() << " Unwind Codes:\n";
668 printAllUnwindCodes(ArrayRef(&UI
->UnwindCodes
[0], UI
->NumCodes
));
674 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
675 /// pointing to an executable file.
676 static void printRuntimeFunction(const COFFObjectFile
*Obj
,
677 const RuntimeFunction
&RF
) {
678 if (!RF
.StartAddress
)
680 outs() << "Function Table:\n"
681 << format(" Start Address: 0x%04x\n",
682 static_cast<uint32_t>(RF
.StartAddress
))
683 << format(" End Address: 0x%04x\n",
684 static_cast<uint32_t>(RF
.EndAddress
))
685 << format(" Unwind Info Address: 0x%04x\n",
686 static_cast<uint32_t>(RF
.UnwindInfoOffset
));
688 if (Obj
->getRvaPtr(RF
.UnwindInfoOffset
, addr
))
690 printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo
*>(addr
));
693 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
694 /// pointing to an object file. Unlike executable, fields in RuntimeFunction
695 /// struct are filled with zeros, but instead there are relocations pointing to
696 /// them so that the linker will fill targets' RVAs to the fields at link
697 /// time. This function interprets the relocations to find the data to be used
698 /// in the resulting executable.
699 static void printRuntimeFunctionRels(const COFFObjectFile
*Obj
,
700 const RuntimeFunction
&RF
,
701 uint64_t SectionOffset
,
702 const std::vector
<RelocationRef
> &Rels
) {
703 outs() << "Function Table:\n";
704 outs() << " Start Address: ";
705 printCOFFSymbolAddress(outs(), Rels
,
707 /*offsetof(RuntimeFunction, StartAddress)*/ 0,
711 outs() << " End Address: ";
712 printCOFFSymbolAddress(outs(), Rels
,
714 /*offsetof(RuntimeFunction, EndAddress)*/ 4,
718 outs() << " Unwind Info Address: ";
719 printCOFFSymbolAddress(outs(), Rels
,
721 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
722 RF
.UnwindInfoOffset
);
725 ArrayRef
<uint8_t> XContents
;
726 uint64_t UnwindInfoOffset
= 0;
727 if (Error E
= getSectionContents(
730 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
731 XContents
, UnwindInfoOffset
))
732 reportError(std::move(E
), Obj
->getFileName());
733 if (XContents
.empty())
736 UnwindInfoOffset
+= RF
.UnwindInfoOffset
;
737 if (UnwindInfoOffset
> XContents
.size())
740 auto *UI
= reinterpret_cast<const Win64EH::UnwindInfo
*>(XContents
.data() +
742 printWin64EHUnwindInfo(UI
);
745 void objdump::printCOFFUnwindInfo(const COFFObjectFile
*Obj
) {
746 if (Obj
->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64
) {
747 WithColor::error(errs(), "llvm-objdump")
748 << "unsupported image machine type "
749 "(currently only AMD64 is supported).\n";
753 std::vector
<RelocationRef
> Rels
;
754 const RuntimeFunction
*RFStart
;
756 if (!getPDataSection(Obj
, Rels
, RFStart
, NumRFs
))
758 ArrayRef
<RuntimeFunction
> RFs(RFStart
, NumRFs
);
760 bool IsExecutable
= Rels
.empty();
762 for (const RuntimeFunction
&RF
: RFs
)
763 printRuntimeFunction(Obj
, RF
);
767 for (const RuntimeFunction
&RF
: RFs
) {
768 uint64_t SectionOffset
=
769 std::distance(RFs
.begin(), &RF
) * sizeof(RuntimeFunction
);
770 printRuntimeFunctionRels(Obj
, RF
, SectionOffset
, Rels
);
774 void COFFDumper::printPrivateHeaders() {
776 const uint16_t Cha
= Obj
.getCharacteristics();
777 outs() << "Characteristics 0x" << Twine::utohexstr(Cha
) << '\n';
778 #define FLAG(F, Name) \
780 outs() << '\t' << Name << '\n';
781 FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED
, "relocations stripped");
782 FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE
, "executable");
783 FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED
, "line numbers stripped");
784 FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED
, "symbols stripped");
785 FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE
, "large address aware");
786 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO
, "little endian");
787 FLAG(COFF::IMAGE_FILE_32BIT_MACHINE
, "32 bit words");
788 FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED
, "debugging information removed");
789 FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
,
790 "copy to swap file if on removable media");
791 FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP
,
792 "copy to swap file if on network media");
793 FLAG(COFF::IMAGE_FILE_SYSTEM
, "system file");
794 FLAG(COFF::IMAGE_FILE_DLL
, "DLL");
795 FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY
, "run only on uniprocessor machine");
796 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI
, "big endian");
799 // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.
800 // Since ctime(3) returns a 26 character string of the form:
801 // "Sun Sep 16 01:03:52 1973\n\0"
802 // just print 24 characters.
803 const time_t Timestamp
= Obj
.getTimeDateStamp();
804 outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp
));
806 if (const pe32_header
*Hdr
= Obj
.getPE32Header())
807 CD
.printPEHeader
<pe32_header
>(*Hdr
);
808 else if (const pe32plus_header
*Hdr
= Obj
.getPE32PlusHeader())
809 CD
.printPEHeader
<pe32plus_header
>(*Hdr
);
811 printTLSDirectory(&Obj
);
812 printLoadConfiguration(&Obj
);
813 printImportTables(&Obj
);
814 printExportTable(&Obj
);
817 void objdump::printCOFFSymbolTable(const object::COFFImportFile
&i
) {
819 bool IsCode
= i
.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE
;
821 for (const object::BasicSymbolRef
&Sym
: i
.symbols()) {
823 raw_string_ostream
NS(Name
);
825 cantFail(Sym
.printName(NS
));
828 outs() << "[" << format("%2d", Index
) << "]"
829 << "(sec " << format("%2d", 0) << ")"
830 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
831 << "(ty " << format("%3x", (IsCode
&& Index
) ? 32 : 0) << ")"
832 << "(scl " << format("%3x", 0) << ") "
833 << "(nx " << 0 << ") "
834 << "0x" << format("%08x", 0) << " " << Name
<< '\n';
840 void objdump::printCOFFSymbolTable(const COFFObjectFile
&coff
) {
841 for (unsigned SI
= 0, SE
= coff
.getNumberOfSymbols(); SI
!= SE
; ++SI
) {
842 Expected
<COFFSymbolRef
> Symbol
= coff
.getSymbol(SI
);
844 reportError(Symbol
.takeError(), coff
.getFileName());
846 Expected
<StringRef
> NameOrErr
= coff
.getSymbolName(*Symbol
);
848 reportError(NameOrErr
.takeError(), coff
.getFileName());
849 StringRef Name
= *NameOrErr
;
851 outs() << "[" << format("%2d", SI
) << "]"
852 << "(sec " << format("%2d", int(Symbol
->getSectionNumber())) << ")"
853 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
854 << "(ty " << format("%3x", unsigned(Symbol
->getType())) << ")"
855 << "(scl " << format("%3x", unsigned(Symbol
->getStorageClass()))
857 << "(nx " << unsigned(Symbol
->getNumberOfAuxSymbols()) << ") "
858 << "0x" << format("%08x", unsigned(Symbol
->getValue())) << " "
860 if (Demangle
&& Name
.starts_with("?")) {
862 char *DemangledSymbol
= microsoftDemangle(Name
, nullptr, &Status
);
864 if (Status
== 0 && DemangledSymbol
) {
865 outs() << " (" << StringRef(DemangledSymbol
) << ")";
866 std::free(DemangledSymbol
);
868 outs() << " (invalid mangled name)";
873 for (unsigned AI
= 0, AE
= Symbol
->getNumberOfAuxSymbols(); AI
< AE
; ++AI
, ++SI
) {
874 if (Symbol
->isSectionDefinition()) {
875 const coff_aux_section_definition
*asd
;
877 coff
.getAuxSymbol
<coff_aux_section_definition
>(SI
+ 1, asd
))
878 reportError(std::move(E
), coff
.getFileName());
880 int32_t AuxNumber
= asd
->getNumber(Symbol
->isBigObj());
883 << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
884 , unsigned(asd
->Length
)
885 , unsigned(asd
->NumberOfRelocations
)
886 , unsigned(asd
->NumberOfLinenumbers
)
887 , unsigned(asd
->CheckSum
))
888 << format("assoc %d comdat %d\n"
889 , unsigned(AuxNumber
)
890 , unsigned(asd
->Selection
));
891 } else if (Symbol
->isFileRecord()) {
892 const char *FileName
;
893 if (Error E
= coff
.getAuxSymbol
<char>(SI
+ 1, FileName
))
894 reportError(std::move(E
), coff
.getFileName());
896 StringRef
Name(FileName
, Symbol
->getNumberOfAuxSymbols() *
897 coff
.getSymbolTableEntrySize());
898 outs() << "AUX " << Name
.rtrim(StringRef("\0", 1)) << '\n';
900 SI
= SI
+ Symbol
->getNumberOfAuxSymbols();
902 } else if (Symbol
->isWeakExternal()) {
903 const coff_aux_weak_external
*awe
;
904 if (Error E
= coff
.getAuxSymbol
<coff_aux_weak_external
>(SI
+ 1, awe
))
905 reportError(std::move(E
), coff
.getFileName());
907 outs() << "AUX " << format("indx %d srch %d\n",
908 static_cast<uint32_t>(awe
->TagIndex
),
909 static_cast<uint32_t>(awe
->Characteristics
));
911 outs() << "AUX Unknown\n";