brintos

brintos / llvm-project-archived public Read only

0
0
Text · 33.3 KiB · de82561 Raw
934 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// 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-x6414///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} // namespace63 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 FLAG156 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", 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  case UOP_Epilog:244    return 1;245  case UOP_SaveNonVol:246  case UOP_SaveXMM128: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 in258// the unwind codes array, this function requires that the correct number of259// slots is provided.260static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {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].FrameOffset273                       + (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].FrameOffset289                    + (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].FrameOffset298                           + (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  case UOP_Epilog:306    if (SeenFirstEpilog) {307      uint32_t Offset = UCs[0].getEpilogOffset();308      if (Offset == 0) {309        outs() << " padding";310      } else {311        outs() << " offset=" << format("0x%X", Offset);312      }313    } else {314      SeenFirstEpilog = true;315      bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;316      uint32_t Length = UCs[0].u.CodeOffset;317      outs() << " atend=" << (AtEnd ? "yes" : "no")318             << ", length=" << format("0x%X", Length);319    }320    break;321  }322  outs() << "\n";323}324 325static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {326  bool SeenFirstEpilog = false;327  for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {328    unsigned UsedSlots = getNumUsedSlots(*I);329    if (UsedSlots > UCs.size()) {330      outs() << "Unwind data corrupted: Encountered unwind op "331             << getUnwindCodeTypeName((*I).getUnwindOp())332             << " which requires " << UsedSlots333             << " slots, but only " << UCs.size()334             << " remaining in buffer";335      return ;336    }337    printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);338    I += UsedSlots;339  }340}341 342// Given a symbol sym this functions returns the address and section of it.343static Error resolveSectionAndAddress(const COFFObjectFile *Obj,344                                      const SymbolRef &Sym,345                                      const coff_section *&ResolvedSection,346                                      uint64_t &ResolvedAddr) {347  Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();348  if (!ResolvedAddrOrErr)349    return ResolvedAddrOrErr.takeError();350  ResolvedAddr = *ResolvedAddrOrErr;351  Expected<section_iterator> Iter = Sym.getSection();352  if (!Iter)353    return Iter.takeError();354  ResolvedSection = Obj->getCOFFSection(**Iter);355  return Error::success();356}357 358// Given a vector of relocations for a section and an offset into this section359// the function returns the symbol used for the relocation at the offset.360static Error resolveSymbol(const std::vector<RelocationRef> &Rels,361                                     uint64_t Offset, SymbolRef &Sym) {362  for (auto &R : Rels) {363    uint64_t Ofs = R.getOffset();364    if (Ofs == Offset) {365      Sym = *R.getSymbol();366      return Error::success();367    }368  }369  return make_error<BinaryError>();370}371 372// Given a vector of relocations for a section and an offset into this section373// the function resolves the symbol used for the relocation at the offset and374// returns the section content and the address inside the content pointed to375// by the symbol.376static Error377getSectionContents(const COFFObjectFile *Obj,378                   const std::vector<RelocationRef> &Rels, uint64_t Offset,379                   ArrayRef<uint8_t> &Contents, uint64_t &Addr) {380  SymbolRef Sym;381  if (Error E = resolveSymbol(Rels, Offset, Sym))382    return E;383  const coff_section *Section;384  if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))385    return E;386  return Obj->getSectionContents(Section, Contents);387}388 389// Given a vector of relocations for a section and an offset into this section390// the function returns the name of the symbol used for the relocation at the391// offset.392static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,393                               uint64_t Offset, StringRef &Name) {394  SymbolRef Sym;395  if (Error EC = resolveSymbol(Rels, Offset, Sym))396    return EC;397  Expected<StringRef> NameOrErr = Sym.getName();398  if (!NameOrErr)399    return NameOrErr.takeError();400  Name = *NameOrErr;401  return Error::success();402}403 404static void printCOFFSymbolAddress(raw_ostream &Out,405                                   const std::vector<RelocationRef> &Rels,406                                   uint64_t Offset, uint32_t Disp) {407  StringRef Sym;408  if (!resolveSymbolName(Rels, Offset, Sym)) {409    Out << Sym;410    if (Disp > 0)411      Out << format(" + 0x%04x", Disp);412  } else {413    Out << format("0x%04x", Disp);414  }415}416 417static void418printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {419  if (Count == 0)420    return;421 422  uintptr_t IntPtr = 0;423  if (Error E = Obj->getVaPtr(TableVA, IntPtr))424    reportError(std::move(E), Obj->getFileName());425 426  const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;427  outs() << "SEH Table:";428  for (int I = 0; I < Count; ++I)429    outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);430  outs() << "\n\n";431}432 433template <typename T>434static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {435  size_t FormatWidth = sizeof(T) * 2;436  outs() << "TLS directory:"437         << "\n  StartAddressOfRawData: "438         << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)439         << "\n  EndAddressOfRawData: "440         << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)441         << "\n  AddressOfIndex: "442         << format_hex(TLSDir->AddressOfIndex, FormatWidth)443         << "\n  AddressOfCallBacks: "444         << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)445         << "\n  SizeOfZeroFill: "446         << TLSDir->SizeOfZeroFill447         << "\n  Characteristics: "448         << TLSDir->Characteristics449         << "\n  Alignment: "450         << TLSDir->getAlignment()451         << "\n\n";452}453 454static void printTLSDirectory(const COFFObjectFile *Obj) {455  const pe32_header *PE32Header = Obj->getPE32Header();456  const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();457 458  // Skip if it's not executable.459  if (!PE32Header && !PE32PlusHeader)460    return;461 462  if (PE32Header) {463    if (auto *TLSDir = Obj->getTLSDirectory32())464      printTLSDirectoryT(TLSDir);465  } else {466    if (auto *TLSDir = Obj->getTLSDirectory64())467      printTLSDirectoryT(TLSDir);468  }469 470  outs() << "\n";471}472 473static void printLoadConfiguration(const COFFObjectFile *Obj) {474  // Skip if it's not executable.475  if (!Obj->getPE32Header())476    return;477 478  // Currently only x86 is supported479  if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)480    return;481 482  auto *LoadConf = Obj->getLoadConfig32();483  if (!LoadConf)484    return;485 486  outs() << "Load configuration:"487         << "\n  Timestamp: " << LoadConf->TimeDateStamp488         << "\n  Major Version: " << LoadConf->MajorVersion489         << "\n  Minor Version: " << LoadConf->MinorVersion490         << "\n  GlobalFlags Clear: " << LoadConf->GlobalFlagsClear491         << "\n  GlobalFlags Set: " << LoadConf->GlobalFlagsSet492         << "\n  Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout493         << "\n  Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold494         << "\n  Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold495         << "\n  Lock Prefix Table: " << LoadConf->LockPrefixTable496         << "\n  Maximum Allocation Size: " << LoadConf->MaximumAllocationSize497         << "\n  Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold498         << "\n  Process Affinity Mask: " << LoadConf->ProcessAffinityMask499         << "\n  Process Heap Flags: " << LoadConf->ProcessHeapFlags500         << "\n  CSD Version: " << LoadConf->CSDVersion501         << "\n  Security Cookie: " << LoadConf->SecurityCookie502         << "\n  SEH Table: " << LoadConf->SEHandlerTable503         << "\n  SEH Count: " << LoadConf->SEHandlerCount504         << "\n\n";505  printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);506  outs() << "\n";507}508 509// Prints import tables. The import table is a table containing the list of510// DLL name and symbol names which will be linked by the loader.511static void printImportTables(const COFFObjectFile *Obj) {512  import_directory_iterator I = Obj->import_directory_begin();513  import_directory_iterator E = Obj->import_directory_end();514  if (I == E)515    return;516  outs() << "The Import Tables:\n";517  for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {518    const coff_import_directory_table_entry *Dir;519    StringRef Name;520    if (DirRef.getImportTableEntry(Dir)) return;521    if (DirRef.getName(Name)) return;522 523    outs() << format("  lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",524                     static_cast<uint32_t>(Dir->ImportLookupTableRVA),525                     static_cast<uint32_t>(Dir->TimeDateStamp),526                     static_cast<uint32_t>(Dir->ForwarderChain),527                     static_cast<uint32_t>(Dir->NameRVA),528                     static_cast<uint32_t>(Dir->ImportAddressTableRVA));529    outs() << "    DLL Name: " << Name << "\n";530    outs() << "    Hint/Ord  Name\n";531    for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {532      bool IsOrdinal;533      if (Entry.isOrdinal(IsOrdinal))534        return;535      if (IsOrdinal) {536        uint16_t Ordinal;537        if (Entry.getOrdinal(Ordinal))538          return;539        outs() << format("      % 6d\n", Ordinal);540        continue;541      }542      uint32_t HintNameRVA;543      if (Entry.getHintNameRVA(HintNameRVA))544        return;545      uint16_t Hint;546      StringRef Name;547      if (Obj->getHintName(HintNameRVA, Hint, Name))548        return;549      outs() << format("      % 6d  ", Hint) << Name << "\n";550    }551    outs() << "\n";552  }553}554 555// Prints export tables. The export table is a table containing the list of556// exported symbol from the DLL.557static void printExportTable(const COFFObjectFile *Obj) {558  export_directory_iterator I = Obj->export_directory_begin();559  export_directory_iterator E = Obj->export_directory_end();560  if (I == E)561    return;562  outs() << "Export Table:\n";563  StringRef DllName;564  uint32_t OrdinalBase;565  if (I->getDllName(DllName))566    return;567  if (I->getOrdinalBase(OrdinalBase))568    return;569  outs() << " DLL name: " << DllName << "\n";570  outs() << " Ordinal base: " << OrdinalBase << "\n";571  outs() << " Ordinal      RVA  Name\n";572  for (; I != E; I = ++I) {573    uint32_t RVA;574    if (I->getExportRVA(RVA))575      return;576    StringRef Name;577    if (I->getSymbolName(Name))578      continue;579    if (!RVA && Name.empty())580      continue;581 582    uint32_t Ordinal;583    if (I->getOrdinal(Ordinal))584      return;585    bool IsForwarder;586    if (I->isForwarder(IsForwarder))587      return;588 589    if (IsForwarder) {590      // Export table entries can be used to re-export symbols that591      // this COFF file is imported from some DLLs. This is rare.592      // In most cases IsForwarder is false.593      outs() << format("   %5d         ", Ordinal);594    } else {595      outs() << format("   %5d %# 8x", Ordinal, RVA);596    }597 598    if (!Name.empty())599      outs() << "  " << Name;600    if (IsForwarder) {601      StringRef S;602      if (I->getForwardTo(S))603        return;604      outs() << " (forwarded to " << S << ")";605    }606    outs() << "\n";607  }608}609 610// Given the COFF object file, this function returns the relocations for .pdata611// and the pointer to "runtime function" structs.612static bool getPDataSection(const COFFObjectFile *Obj,613                            std::vector<RelocationRef> &Rels,614                            const RuntimeFunction *&RFStart, int &NumRFs) {615  for (const SectionRef &Section : Obj->sections()) {616    StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());617    if (Name != ".pdata")618      continue;619 620    const coff_section *Pdata = Obj->getCOFFSection(Section);621    append_range(Rels, Section.relocations());622 623    // Sort relocations by address.624    llvm::sort(Rels, isRelocAddressLess);625 626    ArrayRef<uint8_t> Contents;627    if (Error E = Obj->getSectionContents(Pdata, Contents))628      reportError(std::move(E), Obj->getFileName());629 630    if (Contents.empty())631      continue;632 633    RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());634    NumRFs = Contents.size() / sizeof(RuntimeFunction);635    return true;636  }637  return false;638}639 640Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,641                                            const RelocationRef &Rel,642                                            SmallVectorImpl<char> &Result) {643  symbol_iterator SymI = Rel.getSymbol();644  Expected<StringRef> SymNameOrErr = SymI->getName();645  if (!SymNameOrErr)646    return SymNameOrErr.takeError();647  StringRef SymName = *SymNameOrErr;648  Result.append(SymName.begin(), SymName.end());649  return Error::success();650}651 652static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {653  // The casts to int are required in order to output the value as number.654  // Without the casts the value would be interpreted as char data (which655  // results in garbage output).656  outs() << "    Version: " << static_cast<int>(UI->getVersion()) << "\n";657  outs() << "    Flags: " << static_cast<int>(UI->getFlags());658  if (UI->getFlags()) {659    if (UI->getFlags() & UNW_ExceptionHandler)660      outs() << " UNW_ExceptionHandler";661    if (UI->getFlags() & UNW_TerminateHandler)662      outs() << " UNW_TerminateHandler";663    if (UI->getFlags() & UNW_ChainInfo)664      outs() << " UNW_ChainInfo";665  }666  outs() << "\n";667  outs() << "    Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";668  outs() << "    Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";669  // Maybe this should move to output of UOP_SetFPReg?670  if (UI->getFrameRegister()) {671    outs() << "    Frame register: "672           << getUnwindRegisterName(UI->getFrameRegister()) << "\n";673    outs() << "    Frame offset: " << 16 * UI->getFrameOffset() << "\n";674  } else {675    outs() << "    No frame pointer used\n";676  }677  if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {678    // FIXME: Output exception handler data679  } else if (UI->getFlags() & UNW_ChainInfo) {680    // FIXME: Output chained unwind info681  }682 683  if (UI->NumCodes)684    outs() << "    Unwind Codes:\n";685 686  printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));687 688  outs() << "\n";689  outs().flush();690}691 692/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is693/// pointing to an executable file.694static void printRuntimeFunction(const COFFObjectFile *Obj,695                                 const RuntimeFunction &RF) {696  if (!RF.StartAddress)697    return;698  outs() << "Function Table:\n"699         << format("  Start Address: 0x%04x\n",700                   static_cast<uint32_t>(RF.StartAddress))701         << format("  End Address: 0x%04x\n",702                   static_cast<uint32_t>(RF.EndAddress))703         << format("  Unwind Info Address: 0x%04x\n",704                   static_cast<uint32_t>(RF.UnwindInfoOffset));705  uintptr_t addr;706  if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))707    return;708  printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));709}710 711/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is712/// pointing to an object file. Unlike executable, fields in RuntimeFunction713/// struct are filled with zeros, but instead there are relocations pointing to714/// them so that the linker will fill targets' RVAs to the fields at link715/// time. This function interprets the relocations to find the data to be used716/// in the resulting executable.717static void printRuntimeFunctionRels(const COFFObjectFile *Obj,718                                     const RuntimeFunction &RF,719                                     uint64_t SectionOffset,720                                     const std::vector<RelocationRef> &Rels) {721  outs() << "Function Table:\n";722  outs() << "  Start Address: ";723  printCOFFSymbolAddress(outs(), Rels,724                         SectionOffset +725                             /*offsetof(RuntimeFunction, StartAddress)*/ 0,726                         RF.StartAddress);727  outs() << "\n";728 729  outs() << "  End Address: ";730  printCOFFSymbolAddress(outs(), Rels,731                         SectionOffset +732                             /*offsetof(RuntimeFunction, EndAddress)*/ 4,733                         RF.EndAddress);734  outs() << "\n";735 736  outs() << "  Unwind Info Address: ";737  printCOFFSymbolAddress(outs(), Rels,738                         SectionOffset +739                             /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,740                         RF.UnwindInfoOffset);741  outs() << "\n";742 743  ArrayRef<uint8_t> XContents;744  uint64_t UnwindInfoOffset = 0;745  if (Error E = getSectionContents(746          Obj, Rels,747          SectionOffset +748              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,749          XContents, UnwindInfoOffset))750    reportError(std::move(E), Obj->getFileName());751  if (XContents.empty())752    return;753 754  UnwindInfoOffset += RF.UnwindInfoOffset;755  if (UnwindInfoOffset > XContents.size())756    return;757 758  auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +759                                                           UnwindInfoOffset);760  printWin64EHUnwindInfo(UI);761}762 763void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {764  if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {765    WithColor::error(errs(), "llvm-objdump")766        << "unsupported image machine type "767           "(currently only AMD64 is supported).\n";768    return;769  }770 771  std::vector<RelocationRef> Rels;772  const RuntimeFunction *RFStart;773  int NumRFs;774  if (!getPDataSection(Obj, Rels, RFStart, NumRFs))775    return;776  ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);777 778  bool IsExecutable = Rels.empty();779  if (IsExecutable) {780    for (const RuntimeFunction &RF : RFs)781      printRuntimeFunction(Obj, RF);782    return;783  }784 785  for (const RuntimeFunction &RF : RFs) {786    uint64_t SectionOffset =787        std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);788    printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);789  }790}791 792void COFFDumper::printPrivateHeaders() {793  COFFDumper CD(Obj);794  const uint16_t Cha = Obj.getCharacteristics();795  outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';796#define FLAG(F, Name)                                                          \797  if (Cha & F)                                                                 \798    outs() << '\t' << Name << '\n';799  FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");800  FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");801  FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");802  FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");803  FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");804  FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");805  FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");806  FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");807  FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,808       "copy to swap file if on removable media");809  FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,810       "copy to swap file if on network media");811  FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");812  FLAG(COFF::IMAGE_FILE_DLL, "DLL");813  FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");814  FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");815#undef FLAG816 817  // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.818  // Since ctime(3) returns a 26 character string of the form:819  // "Sun Sep 16 01:03:52 1973\n\0"820  // just print 24 characters.821  const time_t Timestamp = Obj.getTimeDateStamp();822  outs() << format("\nTime/Date               %.24s\n", ctime(&Timestamp));823 824  if (const pe32_header *Hdr = Obj.getPE32Header())825    CD.printPEHeader<pe32_header>(*Hdr);826  else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())827    CD.printPEHeader<pe32plus_header>(*Hdr);828 829  printTLSDirectory(&Obj);830  printLoadConfiguration(&Obj);831  printImportTables(&Obj);832  printExportTable(&Obj);833}834 835void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {836  unsigned Index = 0;837  bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;838 839  for (const object::BasicSymbolRef &Sym : i.symbols()) {840    std::string Name;841    raw_string_ostream NS(Name);842 843    cantFail(Sym.printName(NS));844    NS.flush();845 846    outs() << "[" << format("%2d", Index) << "]"847           << "(sec " << format("%2d", 0) << ")"848           << "(fl 0x00)" // Flag bits, which COFF doesn't have.849           << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"850           << "(scl " << format("%3x", 0) << ") "851           << "(nx " << 0 << ") "852           << "0x" << format("%08x", 0) << " " << Name << '\n';853 854    ++Index;855  }856}857 858void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {859  for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {860    Expected<COFFSymbolRef> Symbol = coff.getSymbol(SI);861    if (!Symbol)862      reportError(Symbol.takeError(), coff.getFileName());863 864    Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);865    if (!NameOrErr)866      reportError(NameOrErr.takeError(), coff.getFileName());867    StringRef Name = *NameOrErr;868 869    outs() << "[" << format("%2d", SI) << "]"870           << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"871           << "(fl 0x00)" // Flag bits, which COFF doesn't have.872           << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"873           << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))874           << ") "875           << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "876           << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "877           << Name;878    if (Demangle && Name.starts_with("?")) {879      int Status = -1;880      char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);881 882      if (Status == 0 && DemangledSymbol) {883        outs() << " (" << StringRef(DemangledSymbol) << ")";884        std::free(DemangledSymbol);885      } else {886        outs() << " (invalid mangled name)";887      }888    }889    outs() << "\n";890 891    for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {892      if (Symbol->isSectionDefinition()) {893        const coff_aux_section_definition *asd;894        if (Error E =895                coff.getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))896          reportError(std::move(E), coff.getFileName());897 898        int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());899 900        outs() << "AUX "901               << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "902                         , unsigned(asd->Length)903                         , unsigned(asd->NumberOfRelocations)904                         , unsigned(asd->NumberOfLinenumbers)905                         , unsigned(asd->CheckSum))906               << format("assoc %d comdat %d\n"907                         , unsigned(AuxNumber)908                         , unsigned(asd->Selection));909      } else if (Symbol->isFileRecord()) {910        const char *FileName;911        if (Error E = coff.getAuxSymbol<char>(SI + 1, FileName))912          reportError(std::move(E), coff.getFileName());913 914        StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *915                                     coff.getSymbolTableEntrySize());916        outs() << "AUX " << Name.rtrim(StringRef("\0", 1))  << '\n';917 918        SI = SI + Symbol->getNumberOfAuxSymbols();919        break;920      } else if (Symbol->isWeakExternal()) {921        const coff_aux_weak_external *awe;922        if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))923          reportError(std::move(E), coff.getFileName());924 925        outs() << "AUX " << format("indx %d srch %d\n",926                                   static_cast<uint32_t>(awe->TagIndex),927                                   static_cast<uint32_t>(awe->Characteristics));928      } else {929        outs() << "AUX Unknown\n";930      }931    }932  }933}934