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/ScopedPrinter.h"
26#include "llvm/Support/Win64EH.h"
27#include "llvm/Support/WithColor.h"
28#include "llvm/Support/raw_ostream.h"
29
30using namespace llvm;
31using namespace llvm::objdump;
32using namespace llvm::object;
33using namespace llvm::Win64EH;
34
35namespace {
36class COFFDumper : public Dumper {
37public:
38 explicit COFFDumper(const llvm::object::COFFObjectFile &O)
39 : Dumper(O), Obj(O) {
40 Is64 = !Obj.getPE32Header();
41 }
42
43 template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
44 void printPrivateHeaders() override;
45
46private:
47 template <typename T> FormattedNumber formatAddr(T V) const {
48 return format_hex_no_prefix(V, Is64 ? 16 : 8);
49 }
50
51 uint32_t getBaseOfData(const void *Hdr) const {
52 return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;
53 }
54
55 const llvm::object::COFFObjectFile &Obj;
56 bool Is64;
57};
58} // namespace
59
60std::unique_ptr<Dumper>
61objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
62 return std::make_unique<COFFDumper>(args: Obj);
63}
64
65constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
66 {"PE32", uint16_t(COFF::PE32Header::PE32)},
67 {"PE32+", uint16_t(COFF::PE32Header::PE32_PLUS)},
68};
69
70constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
71 {"unspecified", COFF::IMAGE_SUBSYSTEM_UNKNOWN},
72 {"NT native", COFF::IMAGE_SUBSYSTEM_NATIVE},
73 {"Windows GUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI},
74 {"Windows CUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI},
75 {"POSIX CUI", COFF::IMAGE_SUBSYSTEM_POSIX_CUI},
76 {"Wince CUI", COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI},
77 {"EFI application", COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION},
78 {"EFI boot service driver", COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER},
79 {"EFI runtime driver", COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER},
80 {"SAL runtime driver", COFF::IMAGE_SUBSYSTEM_EFI_ROM},
81 {"XBOX", COFF::IMAGE_SUBSYSTEM_XBOX},
82};
83
84template <typename T, typename TEnum>
85static void printOptionalEnumName(T Value,
86 ArrayRef<EnumEntry<TEnum>> EnumValues) {
87 for (const EnumEntry<TEnum> &I : EnumValues)
88 if (I.Value == Value) {
89 outs() << "\t(" << I.Name << ')';
90 return;
91 }
92}
93
94template <class PEHeader>
95void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
96 auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {
97 outs() << format(Fmt: "%-23s ", Vals: K) << format(Fmt, V);
98 };
99 auto printU16 = [&](const char *K, support::ulittle16_t V,
100 const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); };
101 auto printU32 = [&](const char *K, support::ulittle32_t V,
102 const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); };
103 auto printAddr = [=](const char *K, uint64_t V) {
104 outs() << format(Fmt: "%-23s ", Vals: K) << formatAddr(V) << '\n';
105 };
106
107 printU16("Magic", Hdr.Magic, "%04x");
108 printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
109 outs() << '\n';
110 print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
111 print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
112 printAddr("SizeOfCode", Hdr.SizeOfCode);
113 printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData);
114 printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData);
115 printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint);
116 printAddr("BaseOfCode", Hdr.BaseOfCode);
117 if (!Is64)
118 printAddr("BaseOfData", getBaseOfData(Hdr: &Hdr));
119 printAddr("ImageBase", Hdr.ImageBase);
120 printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n");
121 printU32("FileAlignment", Hdr.FileAlignment, "%08x\n");
122 printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion);
123 printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion);
124 printU16("MajorImageVersion", Hdr.MajorImageVersion);
125 printU16("MinorImageVersion", Hdr.MinorImageVersion);
126 printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion);
127 printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion);
128 printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n");
129 printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n");
130 printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
131 printU32("CheckSum", Hdr.CheckSum, "%08x\n");
132 printU16("Subsystem", Hdr.Subsystem, "%08x");
133 printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
134 outs() << '\n';
135
136 printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
137#define FLAG(Name) \
138 if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \
139 outs() << "\t\t\t\t\t" << #Name << '\n';
140 FLAG(HIGH_ENTROPY_VA);
141 FLAG(DYNAMIC_BASE);
142 FLAG(FORCE_INTEGRITY);
143 FLAG(NX_COMPAT);
144 FLAG(NO_ISOLATION);
145 FLAG(NO_SEH);
146 FLAG(NO_BIND);
147 FLAG(APPCONTAINER);
148 FLAG(WDM_DRIVER);
149 FLAG(GUARD_CF);
150 FLAG(TERMINAL_SERVER_AWARE);
151#undef FLAG
152
153 printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve);
154 printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit);
155 printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve);
156 printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit);
157 printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n");
158 printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n");
159
160 static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = {
161 "Export Directory [.edata (or where ever we found it)]",
162 "Import Directory [parts of .idata]",
163 "Resource Directory [.rsrc]",
164 "Exception Directory [.pdata]",
165 "Security Directory",
166 "Base Relocation Directory [.reloc]",
167 "Debug Directory",
168 "Description Directory",
169 "Special Directory",
170 "Thread Storage Directory [.tls]",
171 "Load Configuration Directory",
172 "Bound Import Directory",
173 "Import Address Table Directory",
174 "Delay Import Directory",
175 "CLR Runtime Header",
176 "Reserved",
177 };
178 outs() << "\nThe Data Directory\n";
179 for (uint32_t I = 0; I != std::size(DirName); ++I) {
180 uint32_t Addr = 0, Size = 0;
181 if (const data_directory *Data = Obj.getDataDirectory(index: I)) {
182 Addr = Data->RelativeVirtualAddress;
183 Size = Data->Size;
184 }
185 outs() << format(Fmt: "Entry %x ", Vals: I) << formatAddr(V: Addr)
186 << format(Fmt: " %08x %s\n", Vals: Size, Vals: DirName[I]);
187 }
188}
189
190// Returns the name of the unwind code.
191static StringRef getUnwindCodeTypeName(uint8_t Code) {
192 switch(Code) {
193 default: llvm_unreachable("Invalid unwind code");
194 case UOP_PushNonVol: return "UOP_PushNonVol";
195 case UOP_AllocLarge: return "UOP_AllocLarge";
196 case UOP_AllocSmall: return "UOP_AllocSmall";
197 case UOP_SetFPReg: return "UOP_SetFPReg";
198 case UOP_SaveNonVol: return "UOP_SaveNonVol";
199 case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
200 case UOP_Epilog: return "UOP_Epilog";
201 case UOP_SpareCode: return "UOP_SpareCode";
202 case UOP_SaveXMM128: return "UOP_SaveXMM128";
203 case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
204 case UOP_PushMachFrame: return "UOP_PushMachFrame";
205 }
206}
207
208// Returns the name of a referenced register.
209static StringRef getUnwindRegisterName(uint8_t Reg) {
210 switch(Reg) {
211 default: llvm_unreachable("Invalid register");
212 case 0: return "RAX";
213 case 1: return "RCX";
214 case 2: return "RDX";
215 case 3: return "RBX";
216 case 4: return "RSP";
217 case 5: return "RBP";
218 case 6: return "RSI";
219 case 7: return "RDI";
220 case 8: return "R8";
221 case 9: return "R9";
222 case 10: return "R10";
223 case 11: return "R11";
224 case 12: return "R12";
225 case 13: return "R13";
226 case 14: return "R14";
227 case 15: return "R15";
228 }
229}
230
231// Calculates the number of array slots required for the unwind code.
232static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
233 switch (UnwindCode.getUnwindOp()) {
234 default: llvm_unreachable("Invalid unwind code");
235 case UOP_PushNonVol:
236 case UOP_AllocSmall:
237 case UOP_SetFPReg:
238 case UOP_PushMachFrame:
239 case UOP_Epilog:
240 return 1;
241 case UOP_SaveNonVol:
242 case UOP_SaveXMM128:
243 return 2;
244 case UOP_SaveNonVolBig:
245 case UOP_SaveXMM128Big:
246 case UOP_SpareCode:
247 return 3;
248 case UOP_AllocLarge:
249 return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
250 }
251}
252
253// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
254// the unwind codes array, this function requires that the correct number of
255// slots is provided.
256static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {
257 assert(UCs.size() >= getNumUsedSlots(UCs[0]));
258 outs() << format(Fmt: " 0x%02x: ", Vals: unsigned(UCs[0].u.CodeOffset))
259 << getUnwindCodeTypeName(Code: UCs[0].getUnwindOp());
260 switch (UCs[0].getUnwindOp()) {
261 case UOP_PushNonVol:
262 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo());
263 break;
264 case UOP_AllocLarge:
265 if (UCs[0].getOpInfo() == 0) {
266 outs() << " " << UCs[1].FrameOffset;
267 } else {
268 outs() << " " << UCs[1].FrameOffset
269 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
270 }
271 break;
272 case UOP_AllocSmall:
273 outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
274 break;
275 case UOP_SetFPReg:
276 outs() << " ";
277 break;
278 case UOP_SaveNonVol:
279 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo())
280 << format(Fmt: " [0x%04x]", Vals: 8 * UCs[1].FrameOffset);
281 break;
282 case UOP_SaveNonVolBig:
283 outs() << " " << getUnwindRegisterName(Reg: UCs[0].getOpInfo())
284 << format(Fmt: " [0x%08x]", Vals: UCs[1].FrameOffset
285 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
286 break;
287 case UOP_SaveXMM128:
288 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
289 << format(Fmt: " [0x%04x]", Vals: 16 * UCs[1].FrameOffset);
290 break;
291 case UOP_SaveXMM128Big:
292 outs() << " XMM" << UCs[0].getOpInfo()
293 << format(Fmt: " [0x%08x]", Vals: UCs[1].FrameOffset
294 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
295 break;
296 case UOP_PushMachFrame:
297 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
298 << " error code";
299 break;
300
301 case UOP_Epilog:
302 if (SeenFirstEpilog) {
303 uint32_t Offset = UCs[0].getEpilogOffset();
304 if (Offset == 0) {
305 outs() << " padding";
306 } else {
307 outs() << " offset=" << format(Fmt: "0x%X", Vals: Offset);
308 }
309 } else {
310 SeenFirstEpilog = true;
311 bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;
312 uint32_t Length = UCs[0].u.CodeOffset;
313 outs() << " atend=" << (AtEnd ? "yes" : "no")
314 << ", length=" << format(Fmt: "0x%X", Vals: Length);
315 }
316 break;
317 }
318 outs() << "\n";
319}
320
321static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
322 bool SeenFirstEpilog = false;
323 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
324 unsigned UsedSlots = getNumUsedSlots(UnwindCode: *I);
325 if (UsedSlots > UCs.size()) {
326 outs() << "Unwind data corrupted: Encountered unwind op "
327 << getUnwindCodeTypeName(Code: (*I).getUnwindOp())
328 << " which requires " << UsedSlots
329 << " slots, but only " << UCs.size()
330 << " remaining in buffer";
331 return ;
332 }
333 printUnwindCode(UCs: ArrayRef(I, E), SeenFirstEpilog);
334 I += UsedSlots;
335 }
336}
337
338// Given a symbol sym this functions returns the address and section of it.
339static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
340 const SymbolRef &Sym,
341 const coff_section *&ResolvedSection,
342 uint64_t &ResolvedAddr) {
343 Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
344 if (!ResolvedAddrOrErr)
345 return ResolvedAddrOrErr.takeError();
346 ResolvedAddr = *ResolvedAddrOrErr;
347 Expected<section_iterator> Iter = Sym.getSection();
348 if (!Iter)
349 return Iter.takeError();
350 ResolvedSection = Obj->getCOFFSection(Section: **Iter);
351 return Error::success();
352}
353
354// Given a vector of relocations for a section and an offset into this section
355// the function returns the symbol used for the relocation at the offset.
356static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
357 uint64_t Offset, SymbolRef &Sym) {
358 for (auto &R : Rels) {
359 uint64_t Ofs = R.getOffset();
360 if (Ofs == Offset) {
361 Sym = *R.getSymbol();
362 return Error::success();
363 }
364 }
365 return make_error<BinaryError>();
366}
367
368// Given a vector of relocations for a section and an offset into this section
369// the function resolves the symbol used for the relocation at the offset and
370// returns the section content and the address inside the content pointed to
371// by the symbol.
372static Error
373getSectionContents(const COFFObjectFile *Obj,
374 const std::vector<RelocationRef> &Rels, uint64_t Offset,
375 ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
376 SymbolRef Sym;
377 if (Error E = resolveSymbol(Rels, Offset, Sym))
378 return E;
379 const coff_section *Section;
380 if (Error E = resolveSectionAndAddress(Obj, Sym, ResolvedSection&: Section, ResolvedAddr&: Addr))
381 return E;
382 return Obj->getSectionContents(Sec: Section, Res&: Contents);
383}
384
385// Given a vector of relocations for a section and an offset into this section
386// the function returns the name of the symbol used for the relocation at the
387// offset.
388static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
389 uint64_t Offset, StringRef &Name) {
390 SymbolRef Sym;
391 if (Error EC = resolveSymbol(Rels, Offset, Sym))
392 return EC;
393 Expected<StringRef> NameOrErr = Sym.getName();
394 if (!NameOrErr)
395 return NameOrErr.takeError();
396 Name = *NameOrErr;
397 return Error::success();
398}
399
400static void printCOFFSymbolAddress(raw_ostream &Out,
401 const std::vector<RelocationRef> &Rels,
402 uint64_t Offset, uint32_t Disp) {
403 StringRef Sym;
404 if (!resolveSymbolName(Rels, Offset, Name&: Sym)) {
405 Out << Sym;
406 if (Disp > 0)
407 Out << format(Fmt: " + 0x%04x", Vals: Disp);
408 } else {
409 Out << format(Fmt: "0x%04x", Vals: Disp);
410 }
411}
412
413static void
414printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
415 if (Count == 0)
416 return;
417
418 uintptr_t IntPtr = 0;
419 if (Error E = Obj->getVaPtr(VA: TableVA, Res&: IntPtr))
420 reportError(E: std::move(E), FileName: Obj->getFileName());
421
422 const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
423 outs() << "SEH Table:";
424 for (int I = 0; I < Count; ++I)
425 outs() << format(Fmt: " 0x%x", Vals: P[I] + Obj->getPE32Header()->ImageBase);
426 outs() << "\n\n";
427}
428
429template <typename T>
430static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
431 size_t FormatWidth = sizeof(T) * 2;
432 outs() << "TLS directory:"
433 << "\n StartAddressOfRawData: "
434 << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
435 << "\n EndAddressOfRawData: "
436 << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
437 << "\n AddressOfIndex: "
438 << format_hex(TLSDir->AddressOfIndex, FormatWidth)
439 << "\n AddressOfCallBacks: "
440 << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
441 << "\n SizeOfZeroFill: "
442 << TLSDir->SizeOfZeroFill
443 << "\n Characteristics: "
444 << TLSDir->Characteristics
445 << "\n Alignment: "
446 << TLSDir->getAlignment()
447 << "\n\n";
448}
449
450static void printTLSDirectory(const COFFObjectFile *Obj) {
451 const pe32_header *PE32Header = Obj->getPE32Header();
452 const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
453
454 // Skip if it's not executable.
455 if (!PE32Header && !PE32PlusHeader)
456 return;
457
458 if (PE32Header) {
459 if (auto *TLSDir = Obj->getTLSDirectory32())
460 printTLSDirectoryT(TLSDir);
461 } else {
462 if (auto *TLSDir = Obj->getTLSDirectory64())
463 printTLSDirectoryT(TLSDir);
464 }
465
466 outs() << "\n";
467}
468
469static void printLoadConfiguration(const COFFObjectFile *Obj) {
470 // Skip if it's not executable.
471 if (!Obj->getPE32Header())
472 return;
473
474 // Currently only x86 is supported
475 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
476 return;
477
478 auto *LoadConf = Obj->getLoadConfig32();
479 if (!LoadConf)
480 return;
481
482 outs() << "Load configuration:"
483 << "\n Timestamp: " << LoadConf->TimeDateStamp
484 << "\n Major Version: " << LoadConf->MajorVersion
485 << "\n Minor Version: " << LoadConf->MinorVersion
486 << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
487 << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet
488 << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
489 << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
490 << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
491 << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable
492 << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
493 << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
494 << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask
495 << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags
496 << "\n CSD Version: " << LoadConf->CSDVersion
497 << "\n Security Cookie: " << LoadConf->SecurityCookie
498 << "\n SEH Table: " << LoadConf->SEHandlerTable
499 << "\n SEH Count: " << LoadConf->SEHandlerCount
500 << "\n\n";
501 printSEHTable(Obj, TableVA: LoadConf->SEHandlerTable, Count: LoadConf->SEHandlerCount);
502 outs() << "\n";
503}
504
505// Prints import tables. The import table is a table containing the list of
506// DLL name and symbol names which will be linked by the loader.
507static void printImportTables(const COFFObjectFile *Obj) {
508 import_directory_iterator I = Obj->import_directory_begin();
509 import_directory_iterator E = Obj->import_directory_end();
510 if (I == E)
511 return;
512 outs() << "The Import Tables:\n";
513 for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
514 const coff_import_directory_table_entry *Dir;
515 StringRef Name;
516 if (DirRef.getImportTableEntry(Result&: Dir)) return;
517 if (DirRef.getName(Result&: Name)) return;
518
519 outs() << format(Fmt: " lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
520 Vals: static_cast<uint32_t>(Dir->ImportLookupTableRVA),
521 Vals: static_cast<uint32_t>(Dir->TimeDateStamp),
522 Vals: static_cast<uint32_t>(Dir->ForwarderChain),
523 Vals: static_cast<uint32_t>(Dir->NameRVA),
524 Vals: static_cast<uint32_t>(Dir->ImportAddressTableRVA));
525 outs() << " DLL Name: " << Name << "\n";
526 outs() << " Hint/Ord Name\n";
527 for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
528 bool IsOrdinal;
529 if (Entry.isOrdinal(Result&: IsOrdinal))
530 return;
531 if (IsOrdinal) {
532 uint16_t Ordinal;
533 if (Entry.getOrdinal(Result&: Ordinal))
534 return;
535 outs() << format(Fmt: " % 6d\n", Vals: Ordinal);
536 continue;
537 }
538 uint32_t HintNameRVA;
539 if (Entry.getHintNameRVA(Result&: HintNameRVA))
540 return;
541 uint16_t Hint;
542 StringRef Name;
543 if (Obj->getHintName(Rva: HintNameRVA, Hint, Name))
544 return;
545 outs() << format(Fmt: " % 6d ", Vals: Hint) << Name << "\n";
546 }
547 outs() << "\n";
548 }
549}
550
551// Prints export tables. The export table is a table containing the list of
552// exported symbol from the DLL.
553static void printExportTable(const COFFObjectFile *Obj) {
554 export_directory_iterator I = Obj->export_directory_begin();
555 export_directory_iterator E = Obj->export_directory_end();
556 if (I == E)
557 return;
558 outs() << "Export Table:\n";
559 StringRef DllName;
560 uint32_t OrdinalBase;
561 if (I->getDllName(Result&: DllName))
562 return;
563 if (I->getOrdinalBase(Result&: OrdinalBase))
564 return;
565 outs() << " DLL name: " << DllName << "\n";
566 outs() << " Ordinal base: " << OrdinalBase << "\n";
567 outs() << " Ordinal RVA Name\n";
568 for (; I != E; I = ++I) {
569 uint32_t RVA;
570 if (I->getExportRVA(Result&: RVA))
571 return;
572 StringRef Name;
573 if (I->getSymbolName(Result&: Name))
574 continue;
575 if (!RVA && Name.empty())
576 continue;
577
578 uint32_t Ordinal;
579 if (I->getOrdinal(Result&: Ordinal))
580 return;
581 bool IsForwarder;
582 if (I->isForwarder(Result&: IsForwarder))
583 return;
584
585 if (IsForwarder) {
586 // Export table entries can be used to re-export symbols that
587 // this COFF file is imported from some DLLs. This is rare.
588 // In most cases IsForwarder is false.
589 outs() << format(Fmt: " %5d ", Vals: Ordinal);
590 } else {
591 outs() << format(Fmt: " %5d %# 8x", Vals: Ordinal, Vals: RVA);
592 }
593
594 if (!Name.empty())
595 outs() << " " << Name;
596 if (IsForwarder) {
597 StringRef S;
598 if (I->getForwardTo(Result&: S))
599 return;
600 outs() << " (forwarded to " << S << ")";
601 }
602 outs() << "\n";
603 }
604}
605
606// Given the COFF object file, this function returns the relocations for .pdata
607// and the pointer to "runtime function" structs.
608static bool getPDataSection(const COFFObjectFile *Obj,
609 std::vector<RelocationRef> &Rels,
610 const RuntimeFunction *&RFStart, int &NumRFs) {
611 for (const SectionRef &Section : Obj->sections()) {
612 StringRef Name = unwrapOrError(EO: Section.getName(), Args: Obj->getFileName());
613 if (Name != ".pdata")
614 continue;
615
616 const coff_section *Pdata = Obj->getCOFFSection(Section);
617 append_range(C&: Rels, R: Section.relocations());
618
619 // Sort relocations by address.
620 llvm::sort(C&: Rels, Comp: isRelocAddressLess);
621
622 ArrayRef<uint8_t> Contents;
623 if (Error E = Obj->getSectionContents(Sec: Pdata, Res&: Contents))
624 reportError(E: std::move(E), FileName: Obj->getFileName());
625
626 if (Contents.empty())
627 continue;
628
629 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
630 NumRFs = Contents.size() / sizeof(RuntimeFunction);
631 return true;
632 }
633 return false;
634}
635
636Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,
637 const RelocationRef &Rel,
638 SmallVectorImpl<char> &Result) {
639 symbol_iterator SymI = Rel.getSymbol();
640 Expected<StringRef> SymNameOrErr = SymI->getName();
641 if (!SymNameOrErr)
642 return SymNameOrErr.takeError();
643 StringRef SymName = *SymNameOrErr;
644 Result.append(in_start: SymName.begin(), in_end: SymName.end());
645 return Error::success();
646}
647
648static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
649 // The casts to int are required in order to output the value as number.
650 // Without the casts the value would be interpreted as char data (which
651 // results in garbage output).
652 outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n";
653 outs() << " Flags: " << static_cast<int>(UI->getFlags());
654 if (UI->getFlags()) {
655 if (UI->getFlags() & UNW_ExceptionHandler)
656 outs() << " UNW_ExceptionHandler";
657 if (UI->getFlags() & UNW_TerminateHandler)
658 outs() << " UNW_TerminateHandler";
659 if (UI->getFlags() & UNW_ChainInfo)
660 outs() << " UNW_ChainInfo";
661 }
662 outs() << "\n";
663 outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
664 outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
665 // Maybe this should move to output of UOP_SetFPReg?
666 if (UI->getFrameRegister()) {
667 outs() << " Frame register: "
668 << getUnwindRegisterName(Reg: UI->getFrameRegister()) << "\n";
669 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";
670 } else {
671 outs() << " No frame pointer used\n";
672 }
673 if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
674 // FIXME: Output exception handler data
675 } else if (UI->getFlags() & UNW_ChainInfo) {
676 // FIXME: Output chained unwind info
677 }
678
679 if (UI->NumCodes)
680 outs() << " Unwind Codes:\n";
681
682 printAllUnwindCodes(UCs: ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
683
684 outs() << "\n";
685 outs().flush();
686}
687
688/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
689/// pointing to an executable file.
690static void printRuntimeFunction(const COFFObjectFile *Obj,
691 const RuntimeFunction &RF) {
692 if (!RF.StartAddress)
693 return;
694 outs() << "Function Table:\n"
695 << format(Fmt: " Start Address: 0x%04x\n",
696 Vals: static_cast<uint32_t>(RF.StartAddress))
697 << format(Fmt: " End Address: 0x%04x\n",
698 Vals: static_cast<uint32_t>(RF.EndAddress))
699 << format(Fmt: " Unwind Info Address: 0x%04x\n",
700 Vals: static_cast<uint32_t>(RF.UnwindInfoOffset));
701 uintptr_t addr;
702 if (Obj->getRvaPtr(Rva: RF.UnwindInfoOffset, Res&: addr))
703 return;
704 printWin64EHUnwindInfo(UI: reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
705}
706
707/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
708/// pointing to an object file. Unlike executable, fields in RuntimeFunction
709/// struct are filled with zeros, but instead there are relocations pointing to
710/// them so that the linker will fill targets' RVAs to the fields at link
711/// time. This function interprets the relocations to find the data to be used
712/// in the resulting executable.
713static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
714 const RuntimeFunction &RF,
715 uint64_t SectionOffset,
716 const std::vector<RelocationRef> &Rels) {
717 outs() << "Function Table:\n";
718 outs() << " Start Address: ";
719 printCOFFSymbolAddress(Out&: outs(), Rels,
720 Offset: SectionOffset +
721 /*offsetof(RuntimeFunction, StartAddress)*/ 0,
722 Disp: RF.StartAddress);
723 outs() << "\n";
724
725 outs() << " End Address: ";
726 printCOFFSymbolAddress(Out&: outs(), Rels,
727 Offset: SectionOffset +
728 /*offsetof(RuntimeFunction, EndAddress)*/ 4,
729 Disp: RF.EndAddress);
730 outs() << "\n";
731
732 outs() << " Unwind Info Address: ";
733 printCOFFSymbolAddress(Out&: outs(), Rels,
734 Offset: SectionOffset +
735 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
736 Disp: RF.UnwindInfoOffset);
737 outs() << "\n";
738
739 ArrayRef<uint8_t> XContents;
740 uint64_t UnwindInfoOffset = 0;
741 if (Error E = getSectionContents(
742 Obj, Rels,
743 Offset: SectionOffset +
744 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
745 Contents&: XContents, Addr&: UnwindInfoOffset))
746 reportError(E: std::move(E), FileName: Obj->getFileName());
747 if (XContents.empty())
748 return;
749
750 UnwindInfoOffset += RF.UnwindInfoOffset;
751 if (UnwindInfoOffset > XContents.size())
752 return;
753
754 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
755 UnwindInfoOffset);
756 printWin64EHUnwindInfo(UI);
757}
758
759void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
760 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
761 WithColor::error(OS&: errs(), Prefix: "llvm-objdump")
762 << "unsupported image machine type "
763 "(currently only AMD64 is supported).\n";
764 return;
765 }
766
767 std::vector<RelocationRef> Rels;
768 const RuntimeFunction *RFStart;
769 int NumRFs;
770 if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
771 return;
772 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
773
774 bool IsExecutable = Rels.empty();
775 if (IsExecutable) {
776 for (const RuntimeFunction &RF : RFs)
777 printRuntimeFunction(Obj, RF);
778 return;
779 }
780
781 for (const RuntimeFunction &RF : RFs) {
782 uint64_t SectionOffset =
783 std::distance(first: RFs.begin(), last: &RF) * sizeof(RuntimeFunction);
784 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
785 }
786}
787
788void COFFDumper::printPrivateHeaders() {
789 COFFDumper CD(Obj);
790 const uint16_t Cha = Obj.getCharacteristics();
791 outs() << "Characteristics 0x" << Twine::utohexstr(Val: Cha) << '\n';
792#define FLAG(F, Name) \
793 if (Cha & F) \
794 outs() << '\t' << Name << '\n';
795 FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");
796 FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");
797 FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");
798 FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");
799 FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");
800 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");
801 FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");
802 FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");
803 FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,
804 "copy to swap file if on removable media");
805 FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,
806 "copy to swap file if on network media");
807 FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");
808 FLAG(COFF::IMAGE_FILE_DLL, "DLL");
809 FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");
810 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");
811#undef FLAG
812
813 // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.
814 // Since ctime(3) returns a 26 character string of the form:
815 // "Sun Sep 16 01:03:52 1973\n\0"
816 // just print 24 characters.
817 const time_t Timestamp = Obj.getTimeDateStamp();
818 outs() << format(Fmt: "\nTime/Date %.24s\n", Vals: ctime(timer: &Timestamp));
819
820 if (const pe32_header *Hdr = Obj.getPE32Header())
821 CD.printPEHeader<pe32_header>(Hdr: *Hdr);
822 else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())
823 CD.printPEHeader<pe32plus_header>(Hdr: *Hdr);
824
825 printTLSDirectory(Obj: &Obj);
826 printLoadConfiguration(Obj: &Obj);
827 printImportTables(Obj: &Obj);
828 printExportTable(Obj: &Obj);
829}
830
831void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {
832 unsigned Index = 0;
833 bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
834
835 for (const object::BasicSymbolRef &Sym : i.symbols()) {
836 std::string Name;
837 raw_string_ostream NS(Name);
838
839 cantFail(Err: Sym.printName(OS&: NS));
840
841 outs() << "[" << format(Fmt: "%2d", Vals: Index) << "]"
842 << "(sec " << format(Fmt: "%2d", Vals: 0) << ")"
843 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
844 << "(ty " << format(Fmt: "%3x", Vals: (IsCode && Index) ? 32 : 0) << ")"
845 << "(scl " << format(Fmt: "%3x", Vals: 0) << ") "
846 << "(nx " << 0 << ") "
847 << "0x" << format(Fmt: "%08x", Vals: 0) << " " << Name << '\n';
848
849 ++Index;
850 }
851}
852
853void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {
854 for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {
855 Expected<COFFSymbolRef> Symbol = coff.getSymbol(index: SI);
856 if (!Symbol)
857 reportError(E: Symbol.takeError(), FileName: coff.getFileName());
858
859 Expected<StringRef> NameOrErr = coff.getSymbolName(Symbol: *Symbol);
860 if (!NameOrErr)
861 reportError(E: NameOrErr.takeError(), FileName: coff.getFileName());
862 StringRef Name = *NameOrErr;
863
864 outs() << "[" << format(Fmt: "%2d", Vals: SI) << "]"
865 << "(sec " << format(Fmt: "%2d", Vals: int(Symbol->getSectionNumber())) << ")"
866 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
867 << "(ty " << format(Fmt: "%3x", Vals: unsigned(Symbol->getType())) << ")"
868 << "(scl " << format(Fmt: "%3x", Vals: unsigned(Symbol->getStorageClass()))
869 << ") "
870 << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
871 << "0x" << format(Fmt: "%08x", Vals: unsigned(Symbol->getValue())) << " "
872 << Name;
873 if (Demangle && Name.starts_with(Prefix: "?")) {
874 int Status = -1;
875 char *DemangledSymbol = microsoftDemangle(mangled_name: Name, n_read: nullptr, status: &Status);
876
877 if (Status == 0 && DemangledSymbol) {
878 outs() << " (" << StringRef(DemangledSymbol) << ")";
879 std::free(ptr: DemangledSymbol);
880 } else {
881 outs() << " (invalid mangled name)";
882 }
883 }
884 outs() << "\n";
885
886 for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
887 if (Symbol->isSectionDefinition()) {
888 const coff_aux_section_definition *asd;
889 if (Error E =
890 coff.getAuxSymbol<coff_aux_section_definition>(index: SI + 1, Res&: asd))
891 reportError(E: std::move(E), FileName: coff.getFileName());
892
893 int32_t AuxNumber = asd->getNumber(IsBigObj: Symbol->isBigObj());
894
895 outs() << "AUX "
896 << format(Fmt: "scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
897 , Vals: unsigned(asd->Length)
898 , Vals: unsigned(asd->NumberOfRelocations)
899 , Vals: unsigned(asd->NumberOfLinenumbers)
900 , Vals: unsigned(asd->CheckSum))
901 << format(Fmt: "assoc %d comdat %d\n"
902 , Vals: unsigned(AuxNumber)
903 , Vals: unsigned(asd->Selection));
904 } else if (Symbol->isFileRecord()) {
905 const char *FileName;
906 if (Error E = coff.getAuxSymbol<char>(index: SI + 1, Res&: FileName))
907 reportError(E: std::move(E), FileName: coff.getFileName());
908
909 StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
910 coff.getSymbolTableEntrySize());
911 outs() << "AUX " << Name.rtrim(Chars: StringRef("\0", 1)) << '\n';
912
913 SI = SI + Symbol->getNumberOfAuxSymbols();
914 break;
915 } else if (Symbol->isWeakExternal()) {
916 const coff_aux_weak_external *awe;
917 if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(index: SI + 1, Res&: awe))
918 reportError(E: std::move(E), FileName: coff.getFileName());
919
920 outs() << "AUX " << format(Fmt: "indx %d srch %d\n",
921 Vals: static_cast<uint32_t>(awe->TagIndex),
922 Vals: static_cast<uint32_t>(awe->Characteristics));
923 } else {
924 outs() << "AUX Unknown\n";
925 }
926 }
927 }
928}
929