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>(Obj);
67}
68
69constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
70    {uint16_t(COFF::PE32Header::PE32), "PE32"},
71    {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},
72};
73
74constexpr 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"},
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("%-23s ", 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("%-23s ", 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));
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(I)) {
186      Addr = Data->RelativeVirtualAddress;
187      Size = Data->Size;
188    }
189    outs() << format("Entry %x ", I) << formatAddr(Addr)
190           << format(" %08x %s\n", uint32_t(Size), 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("      0x%02x: ", unsigned(UCs[0].u.CodeOffset))
263         << getUnwindCodeTypeName(UCs[0].getUnwindOp());
264  switch (UCs[0].getUnwindOp()) {
265  case UOP_PushNonVol:
266    outs() << " " << getUnwindRegisterName(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(UCs[0].getOpInfo())
284           << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
285    break;
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));
290    break;
291  case UOP_SaveXMM128:
292    outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
293           << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
294    break;
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));
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(*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";
317      return ;
318    }
319    printUnwindCode(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(**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, Section, Addr))
367    return E;
368  return Obj->getSectionContents(Section, 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, Sym)) {
391    Out << Sym;
392    if (Disp > 0)
393      Out << format(" + 0x%04x", Disp);
394  } else {
395    Out << format("0x%04x", 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(TableVA, IntPtr))
406    reportError(std::move(E), 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(" 0x%x", 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, LoadConf->SEHandlerTable, 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(Dir)) return;
503    if (DirRef.getName(Name)) return;
504
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()) {
514      bool IsOrdinal;
515      if (Entry.isOrdinal(IsOrdinal))
516        return;
517      if (IsOrdinal) {
518        uint16_t Ordinal;
519        if (Entry.getOrdinal(Ordinal))
520          return;
521        outs() << format("      % 6d\n", Ordinal);
522        continue;
523      }
524      uint32_t HintNameRVA;
525      if (Entry.getHintNameRVA(HintNameRVA))
526        return;
527      uint16_t Hint;
528      StringRef Name;
529      if (Obj->getHintName(HintNameRVA, Hint, Name))
530        return;
531      outs() << format("      % 6d  ", 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(DllName))
548    return;
549  if (I->getOrdinalBase(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(RVA))
557      return;
558    StringRef Name;
559    if (I->getSymbolName(Name))
560      continue;
561    if (!RVA && Name.empty())
562      continue;
563
564    uint32_t Ordinal;
565    if (I->getOrdinal(Ordinal))
566      return;
567    bool IsForwarder;
568    if (I->isForwarder(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("   %5d         ", Ordinal);
576    } else {
577      outs() << format("   %5d %# 8x", Ordinal, RVA);
578    }
579
580    if (!Name.empty())
581      outs() << "  " << Name;
582    if (IsForwarder) {
583      StringRef S;
584      if (I->getForwardTo(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(Section.getName(), Obj->getFileName());
599    if (Name != ".pdata")
600      continue;
601
602    const coff_section *Pdata = Obj->getCOFFSection(Section);
603    append_range(Rels, Section.relocations());
604
605    // Sort relocations by address.
606    llvm::sort(Rels, isRelocAddressLess);
607
608    ArrayRef<uint8_t> Contents;
609    if (Error E = Obj->getSectionContents(Pdata, Contents))
610      reportError(std::move(E), 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(SymName.begin(), 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(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(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("  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));
687  uintptr_t addr;
688  if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
689    return;
690  printWin64EHUnwindInfo(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(outs(), Rels,
706                         SectionOffset +
707                             /*offsetof(RuntimeFunction, StartAddress)*/ 0,
708                         RF.StartAddress);
709  outs() << "\n";
710
711  outs() << "  End Address: ";
712  printCOFFSymbolAddress(outs(), Rels,
713                         SectionOffset +
714                             /*offsetof(RuntimeFunction, EndAddress)*/ 4,
715                         RF.EndAddress);
716  outs() << "\n";
717
718  outs() << "  Unwind Info Address: ";
719  printCOFFSymbolAddress(outs(), Rels,
720                         SectionOffset +
721                             /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
722                         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          SectionOffset +
730              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
731          XContents, UnwindInfoOffset))
732    reportError(std::move(E), 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(errs(), "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(RFs.begin(), &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(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("\nTime/Date               %.24s\n", ctime(&Timestamp));
805
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);
810
811  printTLSDirectory(&Obj);
812  printLoadConfiguration(&Obj);
813  printImportTables(&Obj);
814  printExportTable(&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(Sym.printName(NS));
826    NS.flush();
827
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';
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(SI);
843    if (!Symbol)
844      reportError(Symbol.takeError(), coff.getFileName());
845
846    Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);
847    if (!NameOrErr)
848      reportError(NameOrErr.takeError(), coff.getFileName());
849    StringRef Name = *NameOrErr;
850
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()))
856           << ") "
857           << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
858           << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
859           << Name;
860    if (Demangle && Name.starts_with("?")) {
861      int Status = -1;
862      char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);
863
864      if (Status == 0 && DemangledSymbol) {
865        outs() << " (" << StringRef(DemangledSymbol) << ")";
866        std::free(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>(SI + 1, asd))
878          reportError(std::move(E), coff.getFileName());
879
880        int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
881
882        outs() << "AUX "
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());
895
896        StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
897                                     coff.getSymbolTableEntrySize());
898        outs() << "AUX " << Name.rtrim(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>(SI + 1, awe))
905          reportError(std::move(E), coff.getFileName());
906
907        outs() << "AUX " << format("indx %d srch %d\n",
908                                   static_cast<uint32_t>(awe->TagIndex),
909                                   static_cast<uint32_t>(awe->Characteristics));
910      } else {
911        outs() << "AUX Unknown\n";
912      }
913    }
914  }
915}
916