1//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
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
14///
15//===----------------------------------------------------------------------===//
16
17#include "COFFDump.h"
18
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"
28
29using namespace llvm;
30using namespace llvm::objdump;
31using namespace llvm::object;
32using namespace llvm::Win64EH;
33
34namespace {
35template <typename T> struct EnumEntry {
36 T Value;
37 StringRef Name;
38};
39
40class COFFDumper : public Dumper {
41public:
42 explicit COFFDumper(const llvm::object::COFFObjectFile &O)
43 : Dumper(O), Obj(O) {
44 Is64 = !Obj.getPE32Header();
45 }
46
47 template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
48 void printPrivateHeaders() override;
49
50private:
51 template <typename T> FormattedNumber formatAddr(T V) const {
52 return format_hex_no_prefix(V, Is64 ? 16 : 8);
53 }
54
55 uint32_t getBaseOfData(const void *Hdr) const {
56 return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;
57 }
58
59 const llvm::object::COFFObjectFile &Obj;
60 bool Is64;
61};
62} // namespace
63
64std::unique_ptr<Dumper>
65objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
66 return std::make_unique<COFFDumper>(args: Obj);
67}
68
69constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
70 {.Value: uint16_t(COFF::PE32Header::PE32), .Name: "PE32"},
71 {.Value: uint16_t(COFF::PE32Header::PE32_PLUS), .Name: "PE32+"},
72};
73
74constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
75 {.Value: COFF::IMAGE_SUBSYSTEM_UNKNOWN, .Name: "unspecified"},
76 {.Value: COFF::IMAGE_SUBSYSTEM_NATIVE, .Name: "NT native"},
77 {.Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, .Name: "Windows GUI"},
78 {.Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, .Name: "Windows CUI"},
79 {.Value: COFF::IMAGE_SUBSYSTEM_POSIX_CUI, .Name: "POSIX CUI"},
80 {.Value: COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, .Name: "Wince CUI"},
81 {.Value: COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, .Name: "EFI application"},
82 {.Value: COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, .Name: "EFI boot service driver"},
83 {.Value: COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, .Name: "EFI runtime driver"},
84 {.Value: COFF::IMAGE_SUBSYSTEM_EFI_ROM, .Name: "SAL runtime driver"},
85 {.Value: COFF::IMAGE_SUBSYSTEM_XBOX, .Name: "XBOX"},
86};
87
88template <typename T, typename TEnum>
89static 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 << ')';
94 return;
95 }
96}
97
98template <class PEHeader>
99void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
100 auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {
101 outs() << format(Fmt: "%-23s ", Vals: K) << format(Fmt, V);
102 };
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(Fmt: "%-23s ", Vals: K) << formatAddr(V) << '\n';
109 };
110
111 printU16("Magic", Hdr.Magic, "%04x");
112 printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
113 outs() << '\n';
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);
121 if (!Is64)
122 printAddr("BaseOfData", getBaseOfData(Hdr: &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));
138 outs() << '\n';
139
140 printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
141#define FLAG(Name) \
142 if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \
143 outs() << "\t\t\t\t\t" << #Name << '\n';
144 FLAG(HIGH_ENTROPY_VA);
145 FLAG(DYNAMIC_BASE);
146 FLAG(FORCE_INTEGRITY);
147 FLAG(NX_COMPAT);
148 FLAG(NO_ISOLATION);
149 FLAG(NO_SEH);
150 FLAG(NO_BIND);
151 FLAG(APPCONTAINER);
152 FLAG(WDM_DRIVER);
153 FLAG(GUARD_CF);
154 FLAG(TERMINAL_SERVER_AWARE);
155#undef FLAG
156
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");
163
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]",
171 "Debug Directory",
172 "Description Directory",
173 "Special 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",
180 "Reserved",
181 };
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(index: I)) {
186 Addr = Data->RelativeVirtualAddress;
187 Size = Data->Size;
188 }
189 outs() << format(Fmt: "Entry %x ", Vals: I) << formatAddr(V: Addr)
190 << format(Fmt: " %08x %s\n", Vals: uint32_t(Size), Vals: DirName[I]);
191 }
192}
193
194// Returns the name of the unwind code.
195static StringRef getUnwindCodeTypeName(uint8_t Code) {
196 switch(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";
209 }
210}
211
212// Returns the name of a referenced register.
213static StringRef getUnwindRegisterName(uint8_t Reg) {
214 switch(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";
224 case 8: return "R8";
225 case 9: return "R9";
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";
232 }
233}
234
235// Calculates the number of array slots required for the unwind code.
236static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
237 switch (UnwindCode.getUnwindOp()) {
238 default: llvm_unreachable("Invalid unwind code");
239 case UOP_PushNonVol:
240 case UOP_AllocSmall:
241 case UOP_SetFPReg:
242 case UOP_PushMachFrame:
243 return 1;
244 case UOP_SaveNonVol:
245 case UOP_SaveXMM128:
246 case UOP_Epilog:
247 return 2;
248 case UOP_SaveNonVolBig:
249 case UOP_SaveXMM128Big:
250 case UOP_SpareCode:
251 return 3;
252 case UOP_AllocLarge:
253 return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
254 }
255}
256
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.
260static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
261 assert(UCs.size() >= getNumUsedSlots(UCs[0]));
262 outs() << format(Fmt: " 0x%02x: ", Vals: unsigned(UCs[0].u.CodeOffset))
263 << getUnwindCodeTypeName(Code: UCs[0].getUnwindOp());
264 switch (UCs[0].getUnwindOp()) {
265 case UOP_PushNonVol:
266 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo());
267 break;
268 case UOP_AllocLarge:
269 if (UCs[0].getOpInfo() == 0) {
270 outs() << " " << UCs[1].FrameOffset;
271 } else {
272 outs() << " " << UCs[1].FrameOffset
273 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
274 }
275 break;
276 case UOP_AllocSmall:
277 outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
278 break;
279 case UOP_SetFPReg:
280 outs() << " ";
281 break;
282 case UOP_SaveNonVol:
283 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo())
284 << format(Fmt: " [0x%04x]", Vals: 8 * UCs[1].FrameOffset);
285 break;
286 case UOP_SaveNonVolBig:
287 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo())
288 << format(Fmt: " [0x%08x]", Vals: UCs[1].FrameOffset
289 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
290 break;
291 case UOP_SaveXMM128:
292 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
293 << format(Fmt: " [0x%04x]", Vals: 16 * UCs[1].FrameOffset);
294 break;
295 case UOP_SaveXMM128Big:
296 outs() << " XMM" << UCs[0].getOpInfo()
297 << format(Fmt: " [0x%08x]", Vals: UCs[1].FrameOffset
298 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
299 break;
300 case UOP_PushMachFrame:
301 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
302 << " error code";
303 break;
304 }
305 outs() << "\n";
306}
307
308static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
309 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
310 unsigned UsedSlots = getNumUsedSlots(UnwindCode: *I);
311 if (UsedSlots > UCs.size()) {
312 outs() << "Unwind data corrupted: Encountered unwind op "
313 << getUnwindCodeTypeName(Code: (*I).getUnwindOp())
314 << " which requires " << UsedSlots
315 << " slots, but only " << UCs.size()
316 << " remaining in buffer";
317 return ;
318 }
319 printUnwindCode(UCs: ArrayRef(I, E));
320 I += UsedSlots;
321 }
322}
323
324// Given a symbol sym this functions returns the address and section of it.
325static 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();
334 if (!Iter)
335 return Iter.takeError();
336 ResolvedSection = Obj->getCOFFSection(Section: **Iter);
337 return Error::success();
338}
339
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.
342static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
343 uint64_t Offset, SymbolRef &Sym) {
344 for (auto &R : Rels) {
345 uint64_t Ofs = R.getOffset();
346 if (Ofs == Offset) {
347 Sym = *R.getSymbol();
348 return Error::success();
349 }
350 }
351 return make_error<BinaryError>();
352}
353
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
357// by the symbol.
358static Error
359getSectionContents(const COFFObjectFile *Obj,
360 const std::vector<RelocationRef> &Rels, uint64_t Offset,
361 ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
362 SymbolRef Sym;
363 if (Error E = resolveSymbol(Rels, Offset, Sym))
364 return E;
365 const coff_section *Section;
366 if (Error E = resolveSectionAndAddress(Obj, Sym, ResolvedSection&: Section, ResolvedAddr&: Addr))
367 return E;
368 return Obj->getSectionContents(Sec: Section, Res&: Contents);
369}
370
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
373// offset.
374static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
375 uint64_t Offset, StringRef &Name) {
376 SymbolRef Sym;
377 if (Error EC = resolveSymbol(Rels, Offset, Sym))
378 return EC;
379 Expected<StringRef> NameOrErr = Sym.getName();
380 if (!NameOrErr)
381 return NameOrErr.takeError();
382 Name = *NameOrErr;
383 return Error::success();
384}
385
386static void printCOFFSymbolAddress(raw_ostream &Out,
387 const std::vector<RelocationRef> &Rels,
388 uint64_t Offset, uint32_t Disp) {
389 StringRef Sym;
390 if (!resolveSymbolName(Rels, Offset, Name&: Sym)) {
391 Out << Sym;
392 if (Disp > 0)
393 Out << format(Fmt: " + 0x%04x", Vals: Disp);
394 } else {
395 Out << format(Fmt: "0x%04x", Vals: Disp);
396 }
397}
398
399static void
400printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
401 if (Count == 0)
402 return;
403
404 uintptr_t IntPtr = 0;
405 if (Error E = Obj->getVaPtr(VA: TableVA, Res&: IntPtr))
406 reportError(E: std::move(E), FileName: Obj->getFileName());
407
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(Fmt: " 0x%x", Vals: P[I] + Obj->getPE32Header()->ImageBase);
412 outs() << "\n\n";
413}
414
415template <typename T>
416static 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
431 << "\n Alignment: "
432 << TLSDir->getAlignment()
433 << "\n\n";
434}
435
436static void printTLSDirectory(const COFFObjectFile *Obj) {
437 const pe32_header *PE32Header = Obj->getPE32Header();
438 const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
439
440 // Skip if it's not executable.
441 if (!PE32Header && !PE32PlusHeader)
442 return;
443
444 if (PE32Header) {
445 if (auto *TLSDir = Obj->getTLSDirectory32())
446 printTLSDirectoryT(TLSDir);
447 } else {
448 if (auto *TLSDir = Obj->getTLSDirectory64())
449 printTLSDirectoryT(TLSDir);
450 }
451
452 outs() << "\n";
453}
454
455static void printLoadConfiguration(const COFFObjectFile *Obj) {
456 // Skip if it's not executable.
457 if (!Obj->getPE32Header())
458 return;
459
460 // Currently only x86 is supported
461 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
462 return;
463
464 auto *LoadConf = Obj->getLoadConfig32();
465 if (!LoadConf)
466 return;
467
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
486 << "\n\n";
487 printSEHTable(Obj, TableVA: LoadConf->SEHandlerTable, Count: LoadConf->SEHandlerCount);
488 outs() << "\n";
489}
490
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.
493static void printImportTables(const COFFObjectFile *Obj) {
494 import_directory_iterator I = Obj->import_directory_begin();
495 import_directory_iterator E = Obj->import_directory_end();
496 if (I == E)
497 return;
498 outs() << "The Import Tables:\n";
499 for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
500 const coff_import_directory_table_entry *Dir;
501 StringRef Name;
502 if (DirRef.getImportTableEntry(Result&: Dir)) return;
503 if (DirRef.getName(Result&: Name)) return;
504
505 outs() << format(Fmt: " lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
506 Vals: static_cast<uint32_t>(Dir->ImportLookupTableRVA),
507 Vals: static_cast<uint32_t>(Dir->TimeDateStamp),
508 Vals: static_cast<uint32_t>(Dir->ForwarderChain),
509 Vals: static_cast<uint32_t>(Dir->NameRVA),
510 Vals: 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()) {
514 bool IsOrdinal;
515 if (Entry.isOrdinal(Result&: IsOrdinal))
516 return;
517 if (IsOrdinal) {
518 uint16_t Ordinal;
519 if (Entry.getOrdinal(Result&: Ordinal))
520 return;
521 outs() << format(Fmt: " % 6d\n", Vals: Ordinal);
522 continue;
523 }
524 uint32_t HintNameRVA;
525 if (Entry.getHintNameRVA(Result&: HintNameRVA))
526 return;
527 uint16_t Hint;
528 StringRef Name;
529 if (Obj->getHintName(Rva: HintNameRVA, Hint, Name))
530 return;
531 outs() << format(Fmt: " % 6d ", Vals: Hint) << Name << "\n";
532 }
533 outs() << "\n";
534 }
535}
536
537// Prints export tables. The export table is a table containing the list of
538// exported symbol from the DLL.
539static void printExportTable(const COFFObjectFile *Obj) {
540 export_directory_iterator I = Obj->export_directory_begin();
541 export_directory_iterator E = Obj->export_directory_end();
542 if (I == E)
543 return;
544 outs() << "Export Table:\n";
545 StringRef DllName;
546 uint32_t OrdinalBase;
547 if (I->getDllName(Result&: DllName))
548 return;
549 if (I->getOrdinalBase(Result&: OrdinalBase))
550 return;
551 outs() << " DLL name: " << DllName << "\n";
552 outs() << " Ordinal base: " << OrdinalBase << "\n";
553 outs() << " Ordinal RVA Name\n";
554 for (; I != E; I = ++I) {
555 uint32_t RVA;
556 if (I->getExportRVA(Result&: RVA))
557 return;
558 StringRef Name;
559 if (I->getSymbolName(Result&: Name))
560 continue;
561 if (!RVA && Name.empty())
562 continue;
563
564 uint32_t Ordinal;
565 if (I->getOrdinal(Result&: Ordinal))
566 return;
567 bool IsForwarder;
568 if (I->isForwarder(Result&: IsForwarder))
569 return;
570
571 if (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(Fmt: " %5d ", Vals: Ordinal);
576 } else {
577 outs() << format(Fmt: " %5d %# 8x", Vals: Ordinal, Vals: RVA);
578 }
579
580 if (!Name.empty())
581 outs() << " " << Name;
582 if (IsForwarder) {
583 StringRef S;
584 if (I->getForwardTo(Result&: S))
585 return;
586 outs() << " (forwarded to " << S << ")";
587 }
588 outs() << "\n";
589 }
590}
591
592// Given the COFF object file, this function returns the relocations for .pdata
593// and the pointer to "runtime function" structs.
594static 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(EO: Section.getName(), Args: Obj->getFileName());
599 if (Name != ".pdata")
600 continue;
601
602 const coff_section *Pdata = Obj->getCOFFSection(Section);
603 append_range(C&: Rels, R: Section.relocations());
604
605 // Sort relocations by address.
606 llvm::sort(C&: Rels, Comp: isRelocAddressLess);
607
608 ArrayRef<uint8_t> Contents;
609 if (Error E = Obj->getSectionContents(Sec: Pdata, Res&: Contents))
610 reportError(E: std::move(E), FileName: Obj->getFileName());
611
612 if (Contents.empty())
613 continue;
614
615 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
616 NumRFs = Contents.size() / sizeof(RuntimeFunction);
617 return true;
618 }
619 return false;
620}
621
622Error 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();
627 if (!SymNameOrErr)
628 return SymNameOrErr.takeError();
629 StringRef SymName = *SymNameOrErr;
630 Result.append(in_start: SymName.begin(), in_end: SymName.end());
631 return Error::success();
632}
633
634static 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";
647 }
648 outs() << "\n";
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(Reg: UI->getFrameRegister()) << "\n";
655 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";
656 } else {
657 outs() << " No frame pointer used\n";
658 }
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
663 }
664
665 if (UI->NumCodes)
666 outs() << " Unwind Codes:\n";
667
668 printAllUnwindCodes(UCs: ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
669
670 outs() << "\n";
671 outs().flush();
672}
673
674/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
675/// pointing to an executable file.
676static void printRuntimeFunction(const COFFObjectFile *Obj,
677 const RuntimeFunction &RF) {
678 if (!RF.StartAddress)
679 return;
680 outs() << "Function Table:\n"
681 << format(Fmt: " Start Address: 0x%04x\n",
682 Vals: static_cast<uint32_t>(RF.StartAddress))
683 << format(Fmt: " End Address: 0x%04x\n",
684 Vals: static_cast<uint32_t>(RF.EndAddress))
685 << format(Fmt: " Unwind Info Address: 0x%04x\n",
686 Vals: static_cast<uint32_t>(RF.UnwindInfoOffset));
687 uintptr_t addr;
688 if (Obj->getRvaPtr(Rva: RF.UnwindInfoOffset, Res&: addr))
689 return;
690 printWin64EHUnwindInfo(UI: reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
691}
692
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.
699static 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(Out&: outs(), Rels,
706 Offset: SectionOffset +
707 /*offsetof(RuntimeFunction, StartAddress)*/ 0,
708 Disp: RF.StartAddress);
709 outs() << "\n";
710
711 outs() << " End Address: ";
712 printCOFFSymbolAddress(Out&: outs(), Rels,
713 Offset: SectionOffset +
714 /*offsetof(RuntimeFunction, EndAddress)*/ 4,
715 Disp: RF.EndAddress);
716 outs() << "\n";
717
718 outs() << " Unwind Info Address: ";
719 printCOFFSymbolAddress(Out&: outs(), Rels,
720 Offset: SectionOffset +
721 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
722 Disp: RF.UnwindInfoOffset);
723 outs() << "\n";
724
725 ArrayRef<uint8_t> XContents;
726 uint64_t UnwindInfoOffset = 0;
727 if (Error E = getSectionContents(
728 Obj, Rels,
729 Offset: SectionOffset +
730 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
731 Contents&: XContents, Addr&: UnwindInfoOffset))
732 reportError(E: std::move(E), FileName: Obj->getFileName());
733 if (XContents.empty())
734 return;
735
736 UnwindInfoOffset += RF.UnwindInfoOffset;
737 if (UnwindInfoOffset > XContents.size())
738 return;
739
740 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
741 UnwindInfoOffset);
742 printWin64EHUnwindInfo(UI);
743}
744
745void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
746 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
747 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
748 << "unsupported image machine type "
749 "(currently only AMD64 is supported).\n";
750 return;
751 }
752
753 std::vector<RelocationRef> Rels;
754 const RuntimeFunction *RFStart;
755 int NumRFs;
756 if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
757 return;
758 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
759
760 bool IsExecutable = Rels.empty();
761 if (IsExecutable) {
762 for (const RuntimeFunction &RF : RFs)
763 printRuntimeFunction(Obj, RF);
764 return;
765 }
766
767 for (const RuntimeFunction &RF : RFs) {
768 uint64_t SectionOffset =
769 std::distance(first: RFs.begin(), last: &RF) * sizeof(RuntimeFunction);
770 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
771 }
772}
773
774void COFFDumper::printPrivateHeaders() {
775 COFFDumper CD(Obj);
776 const uint16_t Cha = Obj.getCharacteristics();
777 outs() << "Characteristics 0x" << Twine::utohexstr(Val: Cha) << '\n';
778#define FLAG(F, Name) \
779 if (Cha & F) \
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");
797#undef FLAG
798
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(Fmt: "\nTime/Date %.24s\n", Vals: ctime(timer: &Timestamp));
805
806 if (const pe32_header *Hdr = Obj.getPE32Header())
807 CD.printPEHeader<pe32_header>(Hdr: *Hdr);
808 else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())
809 CD.printPEHeader<pe32plus_header>(Hdr: *Hdr);
810
811 printTLSDirectory(Obj: &Obj);
812 printLoadConfiguration(Obj: &Obj);
813 printImportTables(Obj: &Obj);
814 printExportTable(Obj: &Obj);
815}
816
817void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {
818 unsigned Index = 0;
819 bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
820
821 for (const object::BasicSymbolRef &Sym : i.symbols()) {
822 std::string Name;
823 raw_string_ostream NS(Name);
824
825 cantFail(Err: Sym.printName(OS&: NS));
826 NS.flush();
827
828 outs() << "[" << format(Fmt: "%2d", Vals: Index) << "]"
829 << "(sec " << format(Fmt: "%2d", Vals: 0) << ")"
830 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
831 << "(ty " << format(Fmt: "%3x", Vals: (IsCode && Index) ? 32 : 0) << ")"
832 << "(scl " << format(Fmt: "%3x", Vals: 0) << ") "
833 << "(nx " << 0 << ") "
834 << "0x" << format(Fmt: "%08x", Vals: 0) << " " << Name << '\n';
835
836 ++Index;
837 }
838}
839
840void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {
841 for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {
842 Expected<COFFSymbolRef> Symbol = coff.getSymbol(index: SI);
843 if (!Symbol)
844 reportError(E: Symbol.takeError(), FileName: coff.getFileName());
845
846 Expected<StringRef> NameOrErr = coff.getSymbolName(Symbol: *Symbol);
847 if (!NameOrErr)
848 reportError(E: NameOrErr.takeError(), FileName: coff.getFileName());
849 StringRef Name = *NameOrErr;
850
851 outs() << "[" << format(Fmt: "%2d", Vals: SI) << "]"
852 << "(sec " << format(Fmt: "%2d", Vals: int(Symbol->getSectionNumber())) << ")"
853 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
854 << "(ty " << format(Fmt: "%3x", Vals: unsigned(Symbol->getType())) << ")"
855 << "(scl " << format(Fmt: "%3x", Vals: unsigned(Symbol->getStorageClass()))
856 << ") "
857 << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
858 << "0x" << format(Fmt: "%08x", Vals: unsigned(Symbol->getValue())) << " "
859 << Name;
860 if (Demangle && Name.starts_with(Prefix: "?")) {
861 int Status = -1;
862 char *DemangledSymbol = microsoftDemangle(mangled_name: Name, n_read: nullptr, status: &Status);
863
864 if (Status == 0 && DemangledSymbol) {
865 outs() << " (" << StringRef(DemangledSymbol) << ")";
866 std::free(ptr: DemangledSymbol);
867 } else {
868 outs() << " (invalid mangled name)";
869 }
870 }
871 outs() << "\n";
872
873 for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
874 if (Symbol->isSectionDefinition()) {
875 const coff_aux_section_definition *asd;
876 if (Error E =
877 coff.getAuxSymbol<coff_aux_section_definition>(index: SI + 1, Res&: asd))
878 reportError(E: std::move(E), FileName: coff.getFileName());
879
880 int32_t AuxNumber = asd->getNumber(IsBigObj: Symbol->isBigObj());
881
882 outs() << "AUX "
883 << format(Fmt: "scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
884 , Vals: unsigned(asd->Length)
885 , Vals: unsigned(asd->NumberOfRelocations)
886 , Vals: unsigned(asd->NumberOfLinenumbers)
887 , Vals: unsigned(asd->CheckSum))
888 << format(Fmt: "assoc %d comdat %d\n"
889 , Vals: unsigned(AuxNumber)
890 , Vals: unsigned(asd->Selection));
891 } else if (Symbol->isFileRecord()) {
892 const char *FileName;
893 if (Error E = coff.getAuxSymbol<char>(index: SI + 1, Res&: FileName))
894 reportError(E: std::move(E), FileName: coff.getFileName());
895
896 StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
897 coff.getSymbolTableEntrySize());
898 outs() << "AUX " << Name.rtrim(Chars: StringRef("\0", 1)) << '\n';
899
900 SI = SI + Symbol->getNumberOfAuxSymbols();
901 break;
902 } else if (Symbol->isWeakExternal()) {
903 const coff_aux_weak_external *awe;
904 if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(index: SI + 1, Res&: awe))
905 reportError(E: std::move(E), FileName: coff.getFileName());
906
907 outs() << "AUX " << format(Fmt: "indx %d srch %d\n",
908 Vals: static_cast<uint32_t>(awe->TagIndex),
909 Vals: static_cast<uint32_t>(awe->Characteristics));
910 } else {
911 outs() << "AUX Unknown\n";
912 }
913 }
914 }
915}
916

source code of llvm/tools/llvm-objdump/COFFDump.cpp