109467b48Spatrick //===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick ///
909467b48Spatrick /// \file
1009467b48Spatrick /// This file implements the COFF-specific dumper for llvm-objdump.
1109467b48Spatrick /// It outputs the Win64 EH data structures as plain text.
1209467b48Spatrick /// The encoding of the unwind codes is described in MSDN:
1309467b48Spatrick /// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
1409467b48Spatrick ///
1509467b48Spatrick //===----------------------------------------------------------------------===//
1609467b48Spatrick 
17097a140dSpatrick #include "COFFDump.h"
18097a140dSpatrick 
1909467b48Spatrick #include "llvm-objdump.h"
2009467b48Spatrick #include "llvm/Demangle/Demangle.h"
2109467b48Spatrick #include "llvm/Object/COFF.h"
2209467b48Spatrick #include "llvm/Object/COFFImportFile.h"
2309467b48Spatrick #include "llvm/Object/ObjectFile.h"
2409467b48Spatrick #include "llvm/Support/Format.h"
2509467b48Spatrick #include "llvm/Support/Win64EH.h"
2609467b48Spatrick #include "llvm/Support/WithColor.h"
2709467b48Spatrick #include "llvm/Support/raw_ostream.h"
2809467b48Spatrick 
29097a140dSpatrick using namespace llvm;
30097a140dSpatrick using namespace llvm::objdump;
3109467b48Spatrick using namespace llvm::object;
3209467b48Spatrick using namespace llvm::Win64EH;
3309467b48Spatrick 
3409467b48Spatrick // Returns the name of the unwind code.
3509467b48Spatrick static StringRef getUnwindCodeTypeName(uint8_t Code) {
3609467b48Spatrick   switch(Code) {
3709467b48Spatrick   default: llvm_unreachable("Invalid unwind code");
3809467b48Spatrick   case UOP_PushNonVol: return "UOP_PushNonVol";
3909467b48Spatrick   case UOP_AllocLarge: return "UOP_AllocLarge";
4009467b48Spatrick   case UOP_AllocSmall: return "UOP_AllocSmall";
4109467b48Spatrick   case UOP_SetFPReg: return "UOP_SetFPReg";
4209467b48Spatrick   case UOP_SaveNonVol: return "UOP_SaveNonVol";
4309467b48Spatrick   case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
4409467b48Spatrick   case UOP_SaveXMM128: return "UOP_SaveXMM128";
4509467b48Spatrick   case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
4609467b48Spatrick   case UOP_PushMachFrame: return "UOP_PushMachFrame";
4709467b48Spatrick   }
4809467b48Spatrick }
4909467b48Spatrick 
5009467b48Spatrick // Returns the name of a referenced register.
5109467b48Spatrick static StringRef getUnwindRegisterName(uint8_t Reg) {
5209467b48Spatrick   switch(Reg) {
5309467b48Spatrick   default: llvm_unreachable("Invalid register");
5409467b48Spatrick   case 0: return "RAX";
5509467b48Spatrick   case 1: return "RCX";
5609467b48Spatrick   case 2: return "RDX";
5709467b48Spatrick   case 3: return "RBX";
5809467b48Spatrick   case 4: return "RSP";
5909467b48Spatrick   case 5: return "RBP";
6009467b48Spatrick   case 6: return "RSI";
6109467b48Spatrick   case 7: return "RDI";
6209467b48Spatrick   case 8: return "R8";
6309467b48Spatrick   case 9: return "R9";
6409467b48Spatrick   case 10: return "R10";
6509467b48Spatrick   case 11: return "R11";
6609467b48Spatrick   case 12: return "R12";
6709467b48Spatrick   case 13: return "R13";
6809467b48Spatrick   case 14: return "R14";
6909467b48Spatrick   case 15: return "R15";
7009467b48Spatrick   }
7109467b48Spatrick }
7209467b48Spatrick 
7309467b48Spatrick // Calculates the number of array slots required for the unwind code.
7409467b48Spatrick static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
7509467b48Spatrick   switch (UnwindCode.getUnwindOp()) {
7609467b48Spatrick   default: llvm_unreachable("Invalid unwind code");
7709467b48Spatrick   case UOP_PushNonVol:
7809467b48Spatrick   case UOP_AllocSmall:
7909467b48Spatrick   case UOP_SetFPReg:
8009467b48Spatrick   case UOP_PushMachFrame:
8109467b48Spatrick     return 1;
8209467b48Spatrick   case UOP_SaveNonVol:
8309467b48Spatrick   case UOP_SaveXMM128:
8409467b48Spatrick     return 2;
8509467b48Spatrick   case UOP_SaveNonVolBig:
8609467b48Spatrick   case UOP_SaveXMM128Big:
8709467b48Spatrick     return 3;
8809467b48Spatrick   case UOP_AllocLarge:
8909467b48Spatrick     return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
9009467b48Spatrick   }
9109467b48Spatrick }
9209467b48Spatrick 
9309467b48Spatrick // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
9409467b48Spatrick // the unwind codes array, this function requires that the correct number of
9509467b48Spatrick // slots is provided.
9609467b48Spatrick static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
9709467b48Spatrick   assert(UCs.size() >= getNumUsedSlots(UCs[0]));
9809467b48Spatrick   outs() <<  format("      0x%02x: ", unsigned(UCs[0].u.CodeOffset))
9909467b48Spatrick          << getUnwindCodeTypeName(UCs[0].getUnwindOp());
10009467b48Spatrick   switch (UCs[0].getUnwindOp()) {
10109467b48Spatrick   case UOP_PushNonVol:
10209467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
10309467b48Spatrick     break;
10409467b48Spatrick   case UOP_AllocLarge:
10509467b48Spatrick     if (UCs[0].getOpInfo() == 0) {
10609467b48Spatrick       outs() << " " << UCs[1].FrameOffset;
10709467b48Spatrick     } else {
10809467b48Spatrick       outs() << " " << UCs[1].FrameOffset
10909467b48Spatrick                        + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
11009467b48Spatrick     }
11109467b48Spatrick     break;
11209467b48Spatrick   case UOP_AllocSmall:
11309467b48Spatrick     outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
11409467b48Spatrick     break;
11509467b48Spatrick   case UOP_SetFPReg:
11609467b48Spatrick     outs() << " ";
11709467b48Spatrick     break;
11809467b48Spatrick   case UOP_SaveNonVol:
11909467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
12009467b48Spatrick            << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
12109467b48Spatrick     break;
12209467b48Spatrick   case UOP_SaveNonVolBig:
12309467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
12409467b48Spatrick            << format(" [0x%08x]", UCs[1].FrameOffset
12509467b48Spatrick                     + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
12609467b48Spatrick     break;
12709467b48Spatrick   case UOP_SaveXMM128:
12809467b48Spatrick     outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
12909467b48Spatrick            << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
13009467b48Spatrick     break;
13109467b48Spatrick   case UOP_SaveXMM128Big:
13209467b48Spatrick     outs() << " XMM" << UCs[0].getOpInfo()
13309467b48Spatrick            << format(" [0x%08x]", UCs[1].FrameOffset
13409467b48Spatrick                            + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
13509467b48Spatrick     break;
13609467b48Spatrick   case UOP_PushMachFrame:
13709467b48Spatrick     outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
13809467b48Spatrick            << " error code";
13909467b48Spatrick     break;
14009467b48Spatrick   }
14109467b48Spatrick   outs() << "\n";
14209467b48Spatrick }
14309467b48Spatrick 
14409467b48Spatrick static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
14509467b48Spatrick   for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
14609467b48Spatrick     unsigned UsedSlots = getNumUsedSlots(*I);
14709467b48Spatrick     if (UsedSlots > UCs.size()) {
14809467b48Spatrick       outs() << "Unwind data corrupted: Encountered unwind op "
14909467b48Spatrick              << getUnwindCodeTypeName((*I).getUnwindOp())
15009467b48Spatrick              << " which requires " << UsedSlots
15109467b48Spatrick              << " slots, but only " << UCs.size()
15209467b48Spatrick              << " remaining in buffer";
15309467b48Spatrick       return ;
15409467b48Spatrick     }
15509467b48Spatrick     printUnwindCode(makeArrayRef(I, E));
15609467b48Spatrick     I += UsedSlots;
15709467b48Spatrick   }
15809467b48Spatrick }
15909467b48Spatrick 
16009467b48Spatrick // Given a symbol sym this functions returns the address and section of it.
16109467b48Spatrick static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
16209467b48Spatrick                                       const SymbolRef &Sym,
16309467b48Spatrick                                       const coff_section *&ResolvedSection,
16409467b48Spatrick                                       uint64_t &ResolvedAddr) {
16509467b48Spatrick   Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
16609467b48Spatrick   if (!ResolvedAddrOrErr)
16709467b48Spatrick     return ResolvedAddrOrErr.takeError();
16809467b48Spatrick   ResolvedAddr = *ResolvedAddrOrErr;
16909467b48Spatrick   Expected<section_iterator> Iter = Sym.getSection();
17009467b48Spatrick   if (!Iter)
17109467b48Spatrick     return Iter.takeError();
17209467b48Spatrick   ResolvedSection = Obj->getCOFFSection(**Iter);
17309467b48Spatrick   return Error::success();
17409467b48Spatrick }
17509467b48Spatrick 
17609467b48Spatrick // Given a vector of relocations for a section and an offset into this section
17709467b48Spatrick // the function returns the symbol used for the relocation at the offset.
17809467b48Spatrick static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
17909467b48Spatrick                                      uint64_t Offset, SymbolRef &Sym) {
18009467b48Spatrick   for (auto &R : Rels) {
18109467b48Spatrick     uint64_t Ofs = R.getOffset();
18209467b48Spatrick     if (Ofs == Offset) {
18309467b48Spatrick       Sym = *R.getSymbol();
18409467b48Spatrick       return Error::success();
18509467b48Spatrick     }
18609467b48Spatrick   }
18709467b48Spatrick   return make_error<BinaryError>();
18809467b48Spatrick }
18909467b48Spatrick 
19009467b48Spatrick // Given a vector of relocations for a section and an offset into this section
19109467b48Spatrick // the function resolves the symbol used for the relocation at the offset and
19209467b48Spatrick // returns the section content and the address inside the content pointed to
19309467b48Spatrick // by the symbol.
19409467b48Spatrick static Error
19509467b48Spatrick getSectionContents(const COFFObjectFile *Obj,
19609467b48Spatrick                    const std::vector<RelocationRef> &Rels, uint64_t Offset,
19709467b48Spatrick                    ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
19809467b48Spatrick   SymbolRef Sym;
19909467b48Spatrick   if (Error E = resolveSymbol(Rels, Offset, Sym))
20009467b48Spatrick     return E;
20109467b48Spatrick   const coff_section *Section;
20209467b48Spatrick   if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
20309467b48Spatrick     return E;
20409467b48Spatrick   return Obj->getSectionContents(Section, Contents);
20509467b48Spatrick }
20609467b48Spatrick 
20709467b48Spatrick // Given a vector of relocations for a section and an offset into this section
20809467b48Spatrick // the function returns the name of the symbol used for the relocation at the
20909467b48Spatrick // offset.
21009467b48Spatrick static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
21109467b48Spatrick                                uint64_t Offset, StringRef &Name) {
21209467b48Spatrick   SymbolRef Sym;
21309467b48Spatrick   if (Error EC = resolveSymbol(Rels, Offset, Sym))
21409467b48Spatrick     return EC;
21509467b48Spatrick   Expected<StringRef> NameOrErr = Sym.getName();
21609467b48Spatrick   if (!NameOrErr)
21709467b48Spatrick     return NameOrErr.takeError();
21809467b48Spatrick   Name = *NameOrErr;
21909467b48Spatrick   return Error::success();
22009467b48Spatrick }
22109467b48Spatrick 
22209467b48Spatrick static void printCOFFSymbolAddress(raw_ostream &Out,
22309467b48Spatrick                                    const std::vector<RelocationRef> &Rels,
22409467b48Spatrick                                    uint64_t Offset, uint32_t Disp) {
22509467b48Spatrick   StringRef Sym;
22609467b48Spatrick   if (!resolveSymbolName(Rels, Offset, Sym)) {
22709467b48Spatrick     Out << Sym;
22809467b48Spatrick     if (Disp > 0)
22909467b48Spatrick       Out << format(" + 0x%04x", Disp);
23009467b48Spatrick   } else {
23109467b48Spatrick     Out << format("0x%04x", Disp);
23209467b48Spatrick   }
23309467b48Spatrick }
23409467b48Spatrick 
23509467b48Spatrick static void
23609467b48Spatrick printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
23709467b48Spatrick   if (Count == 0)
23809467b48Spatrick     return;
23909467b48Spatrick 
24009467b48Spatrick   uintptr_t IntPtr = 0;
241097a140dSpatrick   if (Error E = Obj->getVaPtr(TableVA, IntPtr))
242097a140dSpatrick     reportError(std::move(E), Obj->getFileName());
24309467b48Spatrick 
24409467b48Spatrick   const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
24509467b48Spatrick   outs() << "SEH Table:";
24609467b48Spatrick   for (int I = 0; I < Count; ++I)
24709467b48Spatrick     outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);
24809467b48Spatrick   outs() << "\n\n";
24909467b48Spatrick }
25009467b48Spatrick 
25109467b48Spatrick template <typename T>
25209467b48Spatrick static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
25309467b48Spatrick   size_t FormatWidth = sizeof(T) * 2;
25409467b48Spatrick   outs() << "TLS directory:"
25509467b48Spatrick          << "\n  StartAddressOfRawData: "
25609467b48Spatrick          << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
25709467b48Spatrick          << "\n  EndAddressOfRawData: "
25809467b48Spatrick          << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
25909467b48Spatrick          << "\n  AddressOfIndex: "
26009467b48Spatrick          << format_hex(TLSDir->AddressOfIndex, FormatWidth)
26109467b48Spatrick          << "\n  AddressOfCallBacks: "
26209467b48Spatrick          << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
26309467b48Spatrick          << "\n  SizeOfZeroFill: "
26409467b48Spatrick          << TLSDir->SizeOfZeroFill
26509467b48Spatrick          << "\n  Characteristics: "
26609467b48Spatrick          << TLSDir->Characteristics
26709467b48Spatrick          << "\n  Alignment: "
26809467b48Spatrick          << TLSDir->getAlignment()
26909467b48Spatrick          << "\n\n";
27009467b48Spatrick }
27109467b48Spatrick 
27209467b48Spatrick static void printTLSDirectory(const COFFObjectFile *Obj) {
27309467b48Spatrick   const pe32_header *PE32Header = Obj->getPE32Header();
27409467b48Spatrick   const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
27509467b48Spatrick 
27609467b48Spatrick   // Skip if it's not executable.
27709467b48Spatrick   if (!PE32Header && !PE32PlusHeader)
27809467b48Spatrick     return;
27909467b48Spatrick 
280097a140dSpatrick   const data_directory *DataDir = Obj->getDataDirectory(COFF::TLS_TABLE);
281097a140dSpatrick   if (!DataDir)
282097a140dSpatrick     reportError("missing data dir for TLS table", Obj->getFileName());
28309467b48Spatrick 
28409467b48Spatrick   if (DataDir->RelativeVirtualAddress == 0)
28509467b48Spatrick     return;
28609467b48Spatrick 
28709467b48Spatrick   uintptr_t IntPtr = 0;
288097a140dSpatrick   if (Error E =
28909467b48Spatrick           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
290097a140dSpatrick     reportError(std::move(E), Obj->getFileName());
29109467b48Spatrick 
29209467b48Spatrick   if (PE32Header) {
29309467b48Spatrick     auto *TLSDir = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
29409467b48Spatrick     printTLSDirectoryT(TLSDir);
29509467b48Spatrick   } else {
29609467b48Spatrick     auto *TLSDir = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
29709467b48Spatrick     printTLSDirectoryT(TLSDir);
29809467b48Spatrick   }
29909467b48Spatrick 
30009467b48Spatrick   outs() << "\n";
30109467b48Spatrick }
30209467b48Spatrick 
30309467b48Spatrick static void printLoadConfiguration(const COFFObjectFile *Obj) {
30409467b48Spatrick   // Skip if it's not executable.
30509467b48Spatrick   if (!Obj->getPE32Header())
30609467b48Spatrick     return;
30709467b48Spatrick 
30809467b48Spatrick   // Currently only x86 is supported
30909467b48Spatrick   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
31009467b48Spatrick     return;
31109467b48Spatrick 
312097a140dSpatrick   const data_directory *DataDir = Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE);
313097a140dSpatrick   if (!DataDir)
314097a140dSpatrick     reportError("no load config data dir", Obj->getFileName());
31509467b48Spatrick 
31609467b48Spatrick   uintptr_t IntPtr = 0;
31709467b48Spatrick   if (DataDir->RelativeVirtualAddress == 0)
31809467b48Spatrick     return;
31909467b48Spatrick 
320097a140dSpatrick   if (Error E =
32109467b48Spatrick           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
322097a140dSpatrick     reportError(std::move(E), Obj->getFileName());
32309467b48Spatrick 
32409467b48Spatrick   auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr);
32509467b48Spatrick   outs() << "Load configuration:"
32609467b48Spatrick          << "\n  Timestamp: " << LoadConf->TimeDateStamp
32709467b48Spatrick          << "\n  Major Version: " << LoadConf->MajorVersion
32809467b48Spatrick          << "\n  Minor Version: " << LoadConf->MinorVersion
32909467b48Spatrick          << "\n  GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
33009467b48Spatrick          << "\n  GlobalFlags Set: " << LoadConf->GlobalFlagsSet
33109467b48Spatrick          << "\n  Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
33209467b48Spatrick          << "\n  Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
33309467b48Spatrick          << "\n  Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
33409467b48Spatrick          << "\n  Lock Prefix Table: " << LoadConf->LockPrefixTable
33509467b48Spatrick          << "\n  Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
33609467b48Spatrick          << "\n  Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
33709467b48Spatrick          << "\n  Process Affinity Mask: " << LoadConf->ProcessAffinityMask
33809467b48Spatrick          << "\n  Process Heap Flags: " << LoadConf->ProcessHeapFlags
33909467b48Spatrick          << "\n  CSD Version: " << LoadConf->CSDVersion
34009467b48Spatrick          << "\n  Security Cookie: " << LoadConf->SecurityCookie
34109467b48Spatrick          << "\n  SEH Table: " << LoadConf->SEHandlerTable
34209467b48Spatrick          << "\n  SEH Count: " << LoadConf->SEHandlerCount
34309467b48Spatrick          << "\n\n";
34409467b48Spatrick   printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);
34509467b48Spatrick   outs() << "\n";
34609467b48Spatrick }
34709467b48Spatrick 
34809467b48Spatrick // Prints import tables. The import table is a table containing the list of
34909467b48Spatrick // DLL name and symbol names which will be linked by the loader.
35009467b48Spatrick static void printImportTables(const COFFObjectFile *Obj) {
35109467b48Spatrick   import_directory_iterator I = Obj->import_directory_begin();
35209467b48Spatrick   import_directory_iterator E = Obj->import_directory_end();
35309467b48Spatrick   if (I == E)
35409467b48Spatrick     return;
35509467b48Spatrick   outs() << "The Import Tables:\n";
35609467b48Spatrick   for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
35709467b48Spatrick     const coff_import_directory_table_entry *Dir;
35809467b48Spatrick     StringRef Name;
35909467b48Spatrick     if (DirRef.getImportTableEntry(Dir)) return;
36009467b48Spatrick     if (DirRef.getName(Name)) return;
36109467b48Spatrick 
36209467b48Spatrick     outs() << format("  lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
36309467b48Spatrick                      static_cast<uint32_t>(Dir->ImportLookupTableRVA),
36409467b48Spatrick                      static_cast<uint32_t>(Dir->TimeDateStamp),
36509467b48Spatrick                      static_cast<uint32_t>(Dir->ForwarderChain),
36609467b48Spatrick                      static_cast<uint32_t>(Dir->NameRVA),
36709467b48Spatrick                      static_cast<uint32_t>(Dir->ImportAddressTableRVA));
36809467b48Spatrick     outs() << "    DLL Name: " << Name << "\n";
36909467b48Spatrick     outs() << "    Hint/Ord  Name\n";
37009467b48Spatrick     for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
37109467b48Spatrick       bool IsOrdinal;
37209467b48Spatrick       if (Entry.isOrdinal(IsOrdinal))
37309467b48Spatrick         return;
37409467b48Spatrick       if (IsOrdinal) {
37509467b48Spatrick         uint16_t Ordinal;
37609467b48Spatrick         if (Entry.getOrdinal(Ordinal))
37709467b48Spatrick           return;
37809467b48Spatrick         outs() << format("      % 6d\n", Ordinal);
37909467b48Spatrick         continue;
38009467b48Spatrick       }
38109467b48Spatrick       uint32_t HintNameRVA;
38209467b48Spatrick       if (Entry.getHintNameRVA(HintNameRVA))
38309467b48Spatrick         return;
38409467b48Spatrick       uint16_t Hint;
38509467b48Spatrick       StringRef Name;
38609467b48Spatrick       if (Obj->getHintName(HintNameRVA, Hint, Name))
38709467b48Spatrick         return;
38809467b48Spatrick       outs() << format("      % 6d  ", Hint) << Name << "\n";
38909467b48Spatrick     }
39009467b48Spatrick     outs() << "\n";
39109467b48Spatrick   }
39209467b48Spatrick }
39309467b48Spatrick 
39409467b48Spatrick // Prints export tables. The export table is a table containing the list of
39509467b48Spatrick // exported symbol from the DLL.
39609467b48Spatrick static void printExportTable(const COFFObjectFile *Obj) {
39709467b48Spatrick   outs() << "Export Table:\n";
39809467b48Spatrick   export_directory_iterator I = Obj->export_directory_begin();
39909467b48Spatrick   export_directory_iterator E = Obj->export_directory_end();
40009467b48Spatrick   if (I == E)
40109467b48Spatrick     return;
40209467b48Spatrick   StringRef DllName;
40309467b48Spatrick   uint32_t OrdinalBase;
40409467b48Spatrick   if (I->getDllName(DllName))
40509467b48Spatrick     return;
40609467b48Spatrick   if (I->getOrdinalBase(OrdinalBase))
40709467b48Spatrick     return;
40809467b48Spatrick   outs() << " DLL name: " << DllName << "\n";
40909467b48Spatrick   outs() << " Ordinal base: " << OrdinalBase << "\n";
41009467b48Spatrick   outs() << " Ordinal      RVA  Name\n";
41109467b48Spatrick   for (; I != E; I = ++I) {
41209467b48Spatrick     uint32_t Ordinal;
41309467b48Spatrick     if (I->getOrdinal(Ordinal))
41409467b48Spatrick       return;
41509467b48Spatrick     uint32_t RVA;
41609467b48Spatrick     if (I->getExportRVA(RVA))
41709467b48Spatrick       return;
41809467b48Spatrick     bool IsForwarder;
41909467b48Spatrick     if (I->isForwarder(IsForwarder))
42009467b48Spatrick       return;
42109467b48Spatrick 
42209467b48Spatrick     if (IsForwarder) {
42309467b48Spatrick       // Export table entries can be used to re-export symbols that
42409467b48Spatrick       // this COFF file is imported from some DLLs. This is rare.
42509467b48Spatrick       // In most cases IsForwarder is false.
42609467b48Spatrick       outs() << format("    % 4d         ", Ordinal);
42709467b48Spatrick     } else {
42809467b48Spatrick       outs() << format("    % 4d %# 8x", Ordinal, RVA);
42909467b48Spatrick     }
43009467b48Spatrick 
43109467b48Spatrick     StringRef Name;
43209467b48Spatrick     if (I->getSymbolName(Name))
43309467b48Spatrick       continue;
43409467b48Spatrick     if (!Name.empty())
43509467b48Spatrick       outs() << "  " << Name;
43609467b48Spatrick     if (IsForwarder) {
43709467b48Spatrick       StringRef S;
43809467b48Spatrick       if (I->getForwardTo(S))
43909467b48Spatrick         return;
44009467b48Spatrick       outs() << " (forwarded to " << S << ")";
44109467b48Spatrick     }
44209467b48Spatrick     outs() << "\n";
44309467b48Spatrick   }
44409467b48Spatrick }
44509467b48Spatrick 
44609467b48Spatrick // Given the COFF object file, this function returns the relocations for .pdata
44709467b48Spatrick // and the pointer to "runtime function" structs.
44809467b48Spatrick static bool getPDataSection(const COFFObjectFile *Obj,
44909467b48Spatrick                             std::vector<RelocationRef> &Rels,
45009467b48Spatrick                             const RuntimeFunction *&RFStart, int &NumRFs) {
45109467b48Spatrick   for (const SectionRef &Section : Obj->sections()) {
45209467b48Spatrick     StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
45309467b48Spatrick     if (Name != ".pdata")
45409467b48Spatrick       continue;
45509467b48Spatrick 
45609467b48Spatrick     const coff_section *Pdata = Obj->getCOFFSection(Section);
457*73471bf0Spatrick     append_range(Rels, Section.relocations());
45809467b48Spatrick 
45909467b48Spatrick     // Sort relocations by address.
46009467b48Spatrick     llvm::sort(Rels, isRelocAddressLess);
46109467b48Spatrick 
46209467b48Spatrick     ArrayRef<uint8_t> Contents;
46309467b48Spatrick     if (Error E = Obj->getSectionContents(Pdata, Contents))
46409467b48Spatrick       reportError(std::move(E), Obj->getFileName());
46509467b48Spatrick 
46609467b48Spatrick     if (Contents.empty())
46709467b48Spatrick       continue;
46809467b48Spatrick 
46909467b48Spatrick     RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
47009467b48Spatrick     NumRFs = Contents.size() / sizeof(RuntimeFunction);
47109467b48Spatrick     return true;
47209467b48Spatrick   }
47309467b48Spatrick   return false;
47409467b48Spatrick }
47509467b48Spatrick 
476097a140dSpatrick Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,
47709467b48Spatrick                                             const RelocationRef &Rel,
47809467b48Spatrick                                             SmallVectorImpl<char> &Result) {
47909467b48Spatrick   symbol_iterator SymI = Rel.getSymbol();
48009467b48Spatrick   Expected<StringRef> SymNameOrErr = SymI->getName();
48109467b48Spatrick   if (!SymNameOrErr)
48209467b48Spatrick     return SymNameOrErr.takeError();
48309467b48Spatrick   StringRef SymName = *SymNameOrErr;
48409467b48Spatrick   Result.append(SymName.begin(), SymName.end());
48509467b48Spatrick   return Error::success();
48609467b48Spatrick }
48709467b48Spatrick 
48809467b48Spatrick static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
48909467b48Spatrick   // The casts to int are required in order to output the value as number.
49009467b48Spatrick   // Without the casts the value would be interpreted as char data (which
49109467b48Spatrick   // results in garbage output).
49209467b48Spatrick   outs() << "    Version: " << static_cast<int>(UI->getVersion()) << "\n";
49309467b48Spatrick   outs() << "    Flags: " << static_cast<int>(UI->getFlags());
49409467b48Spatrick   if (UI->getFlags()) {
49509467b48Spatrick     if (UI->getFlags() & UNW_ExceptionHandler)
49609467b48Spatrick       outs() << " UNW_ExceptionHandler";
49709467b48Spatrick     if (UI->getFlags() & UNW_TerminateHandler)
49809467b48Spatrick       outs() << " UNW_TerminateHandler";
49909467b48Spatrick     if (UI->getFlags() & UNW_ChainInfo)
50009467b48Spatrick       outs() << " UNW_ChainInfo";
50109467b48Spatrick   }
50209467b48Spatrick   outs() << "\n";
50309467b48Spatrick   outs() << "    Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
50409467b48Spatrick   outs() << "    Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
50509467b48Spatrick   // Maybe this should move to output of UOP_SetFPReg?
50609467b48Spatrick   if (UI->getFrameRegister()) {
50709467b48Spatrick     outs() << "    Frame register: "
50809467b48Spatrick            << getUnwindRegisterName(UI->getFrameRegister()) << "\n";
50909467b48Spatrick     outs() << "    Frame offset: " << 16 * UI->getFrameOffset() << "\n";
51009467b48Spatrick   } else {
51109467b48Spatrick     outs() << "    No frame pointer used\n";
51209467b48Spatrick   }
51309467b48Spatrick   if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
51409467b48Spatrick     // FIXME: Output exception handler data
51509467b48Spatrick   } else if (UI->getFlags() & UNW_ChainInfo) {
51609467b48Spatrick     // FIXME: Output chained unwind info
51709467b48Spatrick   }
51809467b48Spatrick 
51909467b48Spatrick   if (UI->NumCodes)
52009467b48Spatrick     outs() << "    Unwind Codes:\n";
52109467b48Spatrick 
52209467b48Spatrick   printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
52309467b48Spatrick 
52409467b48Spatrick   outs() << "\n";
52509467b48Spatrick   outs().flush();
52609467b48Spatrick }
52709467b48Spatrick 
52809467b48Spatrick /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
52909467b48Spatrick /// pointing to an executable file.
53009467b48Spatrick static void printRuntimeFunction(const COFFObjectFile *Obj,
53109467b48Spatrick                                  const RuntimeFunction &RF) {
53209467b48Spatrick   if (!RF.StartAddress)
53309467b48Spatrick     return;
53409467b48Spatrick   outs() << "Function Table:\n"
53509467b48Spatrick          << format("  Start Address: 0x%04x\n",
53609467b48Spatrick                    static_cast<uint32_t>(RF.StartAddress))
53709467b48Spatrick          << format("  End Address: 0x%04x\n",
53809467b48Spatrick                    static_cast<uint32_t>(RF.EndAddress))
53909467b48Spatrick          << format("  Unwind Info Address: 0x%04x\n",
54009467b48Spatrick                    static_cast<uint32_t>(RF.UnwindInfoOffset));
54109467b48Spatrick   uintptr_t addr;
54209467b48Spatrick   if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
54309467b48Spatrick     return;
54409467b48Spatrick   printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
54509467b48Spatrick }
54609467b48Spatrick 
54709467b48Spatrick /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
54809467b48Spatrick /// pointing to an object file. Unlike executable, fields in RuntimeFunction
54909467b48Spatrick /// struct are filled with zeros, but instead there are relocations pointing to
55009467b48Spatrick /// them so that the linker will fill targets' RVAs to the fields at link
55109467b48Spatrick /// time. This function interprets the relocations to find the data to be used
55209467b48Spatrick /// in the resulting executable.
55309467b48Spatrick static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
55409467b48Spatrick                                      const RuntimeFunction &RF,
55509467b48Spatrick                                      uint64_t SectionOffset,
55609467b48Spatrick                                      const std::vector<RelocationRef> &Rels) {
55709467b48Spatrick   outs() << "Function Table:\n";
55809467b48Spatrick   outs() << "  Start Address: ";
55909467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
56009467b48Spatrick                          SectionOffset +
56109467b48Spatrick                              /*offsetof(RuntimeFunction, StartAddress)*/ 0,
56209467b48Spatrick                          RF.StartAddress);
56309467b48Spatrick   outs() << "\n";
56409467b48Spatrick 
56509467b48Spatrick   outs() << "  End Address: ";
56609467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
56709467b48Spatrick                          SectionOffset +
56809467b48Spatrick                              /*offsetof(RuntimeFunction, EndAddress)*/ 4,
56909467b48Spatrick                          RF.EndAddress);
57009467b48Spatrick   outs() << "\n";
57109467b48Spatrick 
57209467b48Spatrick   outs() << "  Unwind Info Address: ";
57309467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
57409467b48Spatrick                          SectionOffset +
57509467b48Spatrick                              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
57609467b48Spatrick                          RF.UnwindInfoOffset);
57709467b48Spatrick   outs() << "\n";
57809467b48Spatrick 
57909467b48Spatrick   ArrayRef<uint8_t> XContents;
58009467b48Spatrick   uint64_t UnwindInfoOffset = 0;
58109467b48Spatrick   if (Error E = getSectionContents(
58209467b48Spatrick           Obj, Rels,
58309467b48Spatrick           SectionOffset +
58409467b48Spatrick               /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
58509467b48Spatrick           XContents, UnwindInfoOffset))
58609467b48Spatrick     reportError(std::move(E), Obj->getFileName());
58709467b48Spatrick   if (XContents.empty())
58809467b48Spatrick     return;
58909467b48Spatrick 
59009467b48Spatrick   UnwindInfoOffset += RF.UnwindInfoOffset;
59109467b48Spatrick   if (UnwindInfoOffset > XContents.size())
59209467b48Spatrick     return;
59309467b48Spatrick 
59409467b48Spatrick   auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
59509467b48Spatrick                                                            UnwindInfoOffset);
59609467b48Spatrick   printWin64EHUnwindInfo(UI);
59709467b48Spatrick }
59809467b48Spatrick 
599097a140dSpatrick void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
60009467b48Spatrick   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
60109467b48Spatrick     WithColor::error(errs(), "llvm-objdump")
60209467b48Spatrick         << "unsupported image machine type "
60309467b48Spatrick            "(currently only AMD64 is supported).\n";
60409467b48Spatrick     return;
60509467b48Spatrick   }
60609467b48Spatrick 
60709467b48Spatrick   std::vector<RelocationRef> Rels;
60809467b48Spatrick   const RuntimeFunction *RFStart;
60909467b48Spatrick   int NumRFs;
61009467b48Spatrick   if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
61109467b48Spatrick     return;
61209467b48Spatrick   ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
61309467b48Spatrick 
61409467b48Spatrick   bool IsExecutable = Rels.empty();
61509467b48Spatrick   if (IsExecutable) {
61609467b48Spatrick     for (const RuntimeFunction &RF : RFs)
61709467b48Spatrick       printRuntimeFunction(Obj, RF);
61809467b48Spatrick     return;
61909467b48Spatrick   }
62009467b48Spatrick 
62109467b48Spatrick   for (const RuntimeFunction &RF : RFs) {
62209467b48Spatrick     uint64_t SectionOffset =
62309467b48Spatrick         std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
62409467b48Spatrick     printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
62509467b48Spatrick   }
62609467b48Spatrick }
62709467b48Spatrick 
628097a140dSpatrick void objdump::printCOFFFileHeader(const object::ObjectFile *Obj) {
62909467b48Spatrick   const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
63009467b48Spatrick   printTLSDirectory(file);
63109467b48Spatrick   printLoadConfiguration(file);
63209467b48Spatrick   printImportTables(file);
63309467b48Spatrick   printExportTable(file);
63409467b48Spatrick }
63509467b48Spatrick 
636097a140dSpatrick void objdump::printCOFFSymbolTable(const object::COFFImportFile *i) {
63709467b48Spatrick   unsigned Index = 0;
63809467b48Spatrick   bool IsCode = i->getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
63909467b48Spatrick 
64009467b48Spatrick   for (const object::BasicSymbolRef &Sym : i->symbols()) {
64109467b48Spatrick     std::string Name;
64209467b48Spatrick     raw_string_ostream NS(Name);
64309467b48Spatrick 
64409467b48Spatrick     cantFail(Sym.printName(NS));
64509467b48Spatrick     NS.flush();
64609467b48Spatrick 
64709467b48Spatrick     outs() << "[" << format("%2d", Index) << "]"
64809467b48Spatrick            << "(sec " << format("%2d", 0) << ")"
64909467b48Spatrick            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
65009467b48Spatrick            << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"
65109467b48Spatrick            << "(scl " << format("%3x", 0) << ") "
65209467b48Spatrick            << "(nx " << 0 << ") "
65309467b48Spatrick            << "0x" << format("%08x", 0) << " " << Name << '\n';
65409467b48Spatrick 
65509467b48Spatrick     ++Index;
65609467b48Spatrick   }
65709467b48Spatrick }
65809467b48Spatrick 
659097a140dSpatrick void objdump::printCOFFSymbolTable(const COFFObjectFile *coff) {
66009467b48Spatrick   for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
66109467b48Spatrick     Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI);
66209467b48Spatrick     if (!Symbol)
66309467b48Spatrick       reportError(Symbol.takeError(), coff->getFileName());
66409467b48Spatrick 
665097a140dSpatrick     Expected<StringRef> NameOrErr = coff->getSymbolName(*Symbol);
666097a140dSpatrick     if (!NameOrErr)
667097a140dSpatrick       reportError(NameOrErr.takeError(), coff->getFileName());
668097a140dSpatrick     StringRef Name = *NameOrErr;
66909467b48Spatrick 
67009467b48Spatrick     outs() << "[" << format("%2d", SI) << "]"
67109467b48Spatrick            << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
67209467b48Spatrick            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
67309467b48Spatrick            << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
67409467b48Spatrick            << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))
67509467b48Spatrick            << ") "
67609467b48Spatrick            << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
67709467b48Spatrick            << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
67809467b48Spatrick            << Name;
67909467b48Spatrick     if (Demangle && Name.startswith("?")) {
68009467b48Spatrick       int Status = -1;
681097a140dSpatrick       char *DemangledSymbol =
682097a140dSpatrick           microsoftDemangle(Name.data(), nullptr, nullptr, nullptr, &Status);
68309467b48Spatrick 
68409467b48Spatrick       if (Status == 0 && DemangledSymbol) {
68509467b48Spatrick         outs() << " (" << StringRef(DemangledSymbol) << ")";
68609467b48Spatrick         std::free(DemangledSymbol);
68709467b48Spatrick       } else {
68809467b48Spatrick         outs() << " (invalid mangled name)";
68909467b48Spatrick       }
69009467b48Spatrick     }
69109467b48Spatrick     outs() << "\n";
69209467b48Spatrick 
69309467b48Spatrick     for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
69409467b48Spatrick       if (Symbol->isSectionDefinition()) {
69509467b48Spatrick         const coff_aux_section_definition *asd;
696097a140dSpatrick         if (Error E =
69709467b48Spatrick                 coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))
698097a140dSpatrick           reportError(std::move(E), coff->getFileName());
69909467b48Spatrick 
70009467b48Spatrick         int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
70109467b48Spatrick 
70209467b48Spatrick         outs() << "AUX "
70309467b48Spatrick                << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
70409467b48Spatrick                          , unsigned(asd->Length)
70509467b48Spatrick                          , unsigned(asd->NumberOfRelocations)
70609467b48Spatrick                          , unsigned(asd->NumberOfLinenumbers)
70709467b48Spatrick                          , unsigned(asd->CheckSum))
70809467b48Spatrick                << format("assoc %d comdat %d\n"
70909467b48Spatrick                          , unsigned(AuxNumber)
71009467b48Spatrick                          , unsigned(asd->Selection));
71109467b48Spatrick       } else if (Symbol->isFileRecord()) {
71209467b48Spatrick         const char *FileName;
713097a140dSpatrick         if (Error E = coff->getAuxSymbol<char>(SI + 1, FileName))
714097a140dSpatrick           reportError(std::move(E), coff->getFileName());
71509467b48Spatrick 
71609467b48Spatrick         StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
71709467b48Spatrick                                      coff->getSymbolTableEntrySize());
71809467b48Spatrick         outs() << "AUX " << Name.rtrim(StringRef("\0", 1))  << '\n';
71909467b48Spatrick 
72009467b48Spatrick         SI = SI + Symbol->getNumberOfAuxSymbols();
72109467b48Spatrick         break;
72209467b48Spatrick       } else if (Symbol->isWeakExternal()) {
72309467b48Spatrick         const coff_aux_weak_external *awe;
724097a140dSpatrick         if (Error E = coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))
725097a140dSpatrick           reportError(std::move(E), coff->getFileName());
72609467b48Spatrick 
72709467b48Spatrick         outs() << "AUX " << format("indx %d srch %d\n",
72809467b48Spatrick                                    static_cast<uint32_t>(awe->TagIndex),
72909467b48Spatrick                                    static_cast<uint32_t>(awe->Characteristics));
73009467b48Spatrick       } else {
73109467b48Spatrick         outs() << "AUX Unknown\n";
73209467b48Spatrick       }
73309467b48Spatrick     }
73409467b48Spatrick   }
73509467b48Spatrick }
736