1*09467b48Spatrick //===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
2*09467b48Spatrick //
3*09467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*09467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*09467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*09467b48Spatrick //
7*09467b48Spatrick //===----------------------------------------------------------------------===//
8*09467b48Spatrick ///
9*09467b48Spatrick /// \file
10*09467b48Spatrick /// This file implements the COFF-specific dumper for llvm-objdump.
11*09467b48Spatrick /// It outputs the Win64 EH data structures as plain text.
12*09467b48Spatrick /// The encoding of the unwind codes is described in MSDN:
13*09467b48Spatrick /// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
14*09467b48Spatrick ///
15*09467b48Spatrick //===----------------------------------------------------------------------===//
16*09467b48Spatrick 
17*09467b48Spatrick #include "llvm-objdump.h"
18*09467b48Spatrick #include "llvm/Demangle/Demangle.h"
19*09467b48Spatrick #include "llvm/Object/COFF.h"
20*09467b48Spatrick #include "llvm/Object/COFFImportFile.h"
21*09467b48Spatrick #include "llvm/Object/ObjectFile.h"
22*09467b48Spatrick #include "llvm/Support/Format.h"
23*09467b48Spatrick #include "llvm/Support/Win64EH.h"
24*09467b48Spatrick #include "llvm/Support/WithColor.h"
25*09467b48Spatrick #include "llvm/Support/raw_ostream.h"
26*09467b48Spatrick 
27*09467b48Spatrick using namespace llvm::object;
28*09467b48Spatrick using namespace llvm::Win64EH;
29*09467b48Spatrick 
30*09467b48Spatrick namespace llvm {
31*09467b48Spatrick // Returns the name of the unwind code.
32*09467b48Spatrick static StringRef getUnwindCodeTypeName(uint8_t Code) {
33*09467b48Spatrick   switch(Code) {
34*09467b48Spatrick   default: llvm_unreachable("Invalid unwind code");
35*09467b48Spatrick   case UOP_PushNonVol: return "UOP_PushNonVol";
36*09467b48Spatrick   case UOP_AllocLarge: return "UOP_AllocLarge";
37*09467b48Spatrick   case UOP_AllocSmall: return "UOP_AllocSmall";
38*09467b48Spatrick   case UOP_SetFPReg: return "UOP_SetFPReg";
39*09467b48Spatrick   case UOP_SaveNonVol: return "UOP_SaveNonVol";
40*09467b48Spatrick   case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
41*09467b48Spatrick   case UOP_SaveXMM128: return "UOP_SaveXMM128";
42*09467b48Spatrick   case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
43*09467b48Spatrick   case UOP_PushMachFrame: return "UOP_PushMachFrame";
44*09467b48Spatrick   }
45*09467b48Spatrick }
46*09467b48Spatrick 
47*09467b48Spatrick // Returns the name of a referenced register.
48*09467b48Spatrick static StringRef getUnwindRegisterName(uint8_t Reg) {
49*09467b48Spatrick   switch(Reg) {
50*09467b48Spatrick   default: llvm_unreachable("Invalid register");
51*09467b48Spatrick   case 0: return "RAX";
52*09467b48Spatrick   case 1: return "RCX";
53*09467b48Spatrick   case 2: return "RDX";
54*09467b48Spatrick   case 3: return "RBX";
55*09467b48Spatrick   case 4: return "RSP";
56*09467b48Spatrick   case 5: return "RBP";
57*09467b48Spatrick   case 6: return "RSI";
58*09467b48Spatrick   case 7: return "RDI";
59*09467b48Spatrick   case 8: return "R8";
60*09467b48Spatrick   case 9: return "R9";
61*09467b48Spatrick   case 10: return "R10";
62*09467b48Spatrick   case 11: return "R11";
63*09467b48Spatrick   case 12: return "R12";
64*09467b48Spatrick   case 13: return "R13";
65*09467b48Spatrick   case 14: return "R14";
66*09467b48Spatrick   case 15: return "R15";
67*09467b48Spatrick   }
68*09467b48Spatrick }
69*09467b48Spatrick 
70*09467b48Spatrick // Calculates the number of array slots required for the unwind code.
71*09467b48Spatrick static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
72*09467b48Spatrick   switch (UnwindCode.getUnwindOp()) {
73*09467b48Spatrick   default: llvm_unreachable("Invalid unwind code");
74*09467b48Spatrick   case UOP_PushNonVol:
75*09467b48Spatrick   case UOP_AllocSmall:
76*09467b48Spatrick   case UOP_SetFPReg:
77*09467b48Spatrick   case UOP_PushMachFrame:
78*09467b48Spatrick     return 1;
79*09467b48Spatrick   case UOP_SaveNonVol:
80*09467b48Spatrick   case UOP_SaveXMM128:
81*09467b48Spatrick     return 2;
82*09467b48Spatrick   case UOP_SaveNonVolBig:
83*09467b48Spatrick   case UOP_SaveXMM128Big:
84*09467b48Spatrick     return 3;
85*09467b48Spatrick   case UOP_AllocLarge:
86*09467b48Spatrick     return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
87*09467b48Spatrick   }
88*09467b48Spatrick }
89*09467b48Spatrick 
90*09467b48Spatrick // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
91*09467b48Spatrick // the unwind codes array, this function requires that the correct number of
92*09467b48Spatrick // slots is provided.
93*09467b48Spatrick static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
94*09467b48Spatrick   assert(UCs.size() >= getNumUsedSlots(UCs[0]));
95*09467b48Spatrick   outs() <<  format("      0x%02x: ", unsigned(UCs[0].u.CodeOffset))
96*09467b48Spatrick          << getUnwindCodeTypeName(UCs[0].getUnwindOp());
97*09467b48Spatrick   switch (UCs[0].getUnwindOp()) {
98*09467b48Spatrick   case UOP_PushNonVol:
99*09467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
100*09467b48Spatrick     break;
101*09467b48Spatrick   case UOP_AllocLarge:
102*09467b48Spatrick     if (UCs[0].getOpInfo() == 0) {
103*09467b48Spatrick       outs() << " " << UCs[1].FrameOffset;
104*09467b48Spatrick     } else {
105*09467b48Spatrick       outs() << " " << UCs[1].FrameOffset
106*09467b48Spatrick                        + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
107*09467b48Spatrick     }
108*09467b48Spatrick     break;
109*09467b48Spatrick   case UOP_AllocSmall:
110*09467b48Spatrick     outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
111*09467b48Spatrick     break;
112*09467b48Spatrick   case UOP_SetFPReg:
113*09467b48Spatrick     outs() << " ";
114*09467b48Spatrick     break;
115*09467b48Spatrick   case UOP_SaveNonVol:
116*09467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
117*09467b48Spatrick            << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
118*09467b48Spatrick     break;
119*09467b48Spatrick   case UOP_SaveNonVolBig:
120*09467b48Spatrick     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
121*09467b48Spatrick            << format(" [0x%08x]", UCs[1].FrameOffset
122*09467b48Spatrick                     + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
123*09467b48Spatrick     break;
124*09467b48Spatrick   case UOP_SaveXMM128:
125*09467b48Spatrick     outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
126*09467b48Spatrick            << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
127*09467b48Spatrick     break;
128*09467b48Spatrick   case UOP_SaveXMM128Big:
129*09467b48Spatrick     outs() << " XMM" << UCs[0].getOpInfo()
130*09467b48Spatrick            << format(" [0x%08x]", UCs[1].FrameOffset
131*09467b48Spatrick                            + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
132*09467b48Spatrick     break;
133*09467b48Spatrick   case UOP_PushMachFrame:
134*09467b48Spatrick     outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
135*09467b48Spatrick            << " error code";
136*09467b48Spatrick     break;
137*09467b48Spatrick   }
138*09467b48Spatrick   outs() << "\n";
139*09467b48Spatrick }
140*09467b48Spatrick 
141*09467b48Spatrick static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
142*09467b48Spatrick   for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
143*09467b48Spatrick     unsigned UsedSlots = getNumUsedSlots(*I);
144*09467b48Spatrick     if (UsedSlots > UCs.size()) {
145*09467b48Spatrick       outs() << "Unwind data corrupted: Encountered unwind op "
146*09467b48Spatrick              << getUnwindCodeTypeName((*I).getUnwindOp())
147*09467b48Spatrick              << " which requires " << UsedSlots
148*09467b48Spatrick              << " slots, but only " << UCs.size()
149*09467b48Spatrick              << " remaining in buffer";
150*09467b48Spatrick       return ;
151*09467b48Spatrick     }
152*09467b48Spatrick     printUnwindCode(makeArrayRef(I, E));
153*09467b48Spatrick     I += UsedSlots;
154*09467b48Spatrick   }
155*09467b48Spatrick }
156*09467b48Spatrick 
157*09467b48Spatrick // Given a symbol sym this functions returns the address and section of it.
158*09467b48Spatrick static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
159*09467b48Spatrick                                       const SymbolRef &Sym,
160*09467b48Spatrick                                       const coff_section *&ResolvedSection,
161*09467b48Spatrick                                       uint64_t &ResolvedAddr) {
162*09467b48Spatrick   Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
163*09467b48Spatrick   if (!ResolvedAddrOrErr)
164*09467b48Spatrick     return ResolvedAddrOrErr.takeError();
165*09467b48Spatrick   ResolvedAddr = *ResolvedAddrOrErr;
166*09467b48Spatrick   Expected<section_iterator> Iter = Sym.getSection();
167*09467b48Spatrick   if (!Iter)
168*09467b48Spatrick     return Iter.takeError();
169*09467b48Spatrick   ResolvedSection = Obj->getCOFFSection(**Iter);
170*09467b48Spatrick   return Error::success();
171*09467b48Spatrick }
172*09467b48Spatrick 
173*09467b48Spatrick // Given a vector of relocations for a section and an offset into this section
174*09467b48Spatrick // the function returns the symbol used for the relocation at the offset.
175*09467b48Spatrick static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
176*09467b48Spatrick                                      uint64_t Offset, SymbolRef &Sym) {
177*09467b48Spatrick   for (auto &R : Rels) {
178*09467b48Spatrick     uint64_t Ofs = R.getOffset();
179*09467b48Spatrick     if (Ofs == Offset) {
180*09467b48Spatrick       Sym = *R.getSymbol();
181*09467b48Spatrick       return Error::success();
182*09467b48Spatrick     }
183*09467b48Spatrick   }
184*09467b48Spatrick   return make_error<BinaryError>();
185*09467b48Spatrick }
186*09467b48Spatrick 
187*09467b48Spatrick // Given a vector of relocations for a section and an offset into this section
188*09467b48Spatrick // the function resolves the symbol used for the relocation at the offset and
189*09467b48Spatrick // returns the section content and the address inside the content pointed to
190*09467b48Spatrick // by the symbol.
191*09467b48Spatrick static Error
192*09467b48Spatrick getSectionContents(const COFFObjectFile *Obj,
193*09467b48Spatrick                    const std::vector<RelocationRef> &Rels, uint64_t Offset,
194*09467b48Spatrick                    ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
195*09467b48Spatrick   SymbolRef Sym;
196*09467b48Spatrick   if (Error E = resolveSymbol(Rels, Offset, Sym))
197*09467b48Spatrick     return E;
198*09467b48Spatrick   const coff_section *Section;
199*09467b48Spatrick   if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
200*09467b48Spatrick     return E;
201*09467b48Spatrick   return Obj->getSectionContents(Section, Contents);
202*09467b48Spatrick }
203*09467b48Spatrick 
204*09467b48Spatrick // Given a vector of relocations for a section and an offset into this section
205*09467b48Spatrick // the function returns the name of the symbol used for the relocation at the
206*09467b48Spatrick // offset.
207*09467b48Spatrick static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
208*09467b48Spatrick                                uint64_t Offset, StringRef &Name) {
209*09467b48Spatrick   SymbolRef Sym;
210*09467b48Spatrick   if (Error EC = resolveSymbol(Rels, Offset, Sym))
211*09467b48Spatrick     return EC;
212*09467b48Spatrick   Expected<StringRef> NameOrErr = Sym.getName();
213*09467b48Spatrick   if (!NameOrErr)
214*09467b48Spatrick     return NameOrErr.takeError();
215*09467b48Spatrick   Name = *NameOrErr;
216*09467b48Spatrick   return Error::success();
217*09467b48Spatrick }
218*09467b48Spatrick 
219*09467b48Spatrick static void printCOFFSymbolAddress(raw_ostream &Out,
220*09467b48Spatrick                                    const std::vector<RelocationRef> &Rels,
221*09467b48Spatrick                                    uint64_t Offset, uint32_t Disp) {
222*09467b48Spatrick   StringRef Sym;
223*09467b48Spatrick   if (!resolveSymbolName(Rels, Offset, Sym)) {
224*09467b48Spatrick     Out << Sym;
225*09467b48Spatrick     if (Disp > 0)
226*09467b48Spatrick       Out << format(" + 0x%04x", Disp);
227*09467b48Spatrick   } else {
228*09467b48Spatrick     Out << format("0x%04x", Disp);
229*09467b48Spatrick   }
230*09467b48Spatrick }
231*09467b48Spatrick 
232*09467b48Spatrick static void
233*09467b48Spatrick printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
234*09467b48Spatrick   if (Count == 0)
235*09467b48Spatrick     return;
236*09467b48Spatrick 
237*09467b48Spatrick   uintptr_t IntPtr = 0;
238*09467b48Spatrick   if (std::error_code EC = Obj->getVaPtr(TableVA, IntPtr))
239*09467b48Spatrick     reportError(errorCodeToError(EC), Obj->getFileName());
240*09467b48Spatrick 
241*09467b48Spatrick   const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
242*09467b48Spatrick   outs() << "SEH Table:";
243*09467b48Spatrick   for (int I = 0; I < Count; ++I)
244*09467b48Spatrick     outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);
245*09467b48Spatrick   outs() << "\n\n";
246*09467b48Spatrick }
247*09467b48Spatrick 
248*09467b48Spatrick template <typename T>
249*09467b48Spatrick static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
250*09467b48Spatrick   size_t FormatWidth = sizeof(T) * 2;
251*09467b48Spatrick   outs() << "TLS directory:"
252*09467b48Spatrick          << "\n  StartAddressOfRawData: "
253*09467b48Spatrick          << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
254*09467b48Spatrick          << "\n  EndAddressOfRawData: "
255*09467b48Spatrick          << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
256*09467b48Spatrick          << "\n  AddressOfIndex: "
257*09467b48Spatrick          << format_hex(TLSDir->AddressOfIndex, FormatWidth)
258*09467b48Spatrick          << "\n  AddressOfCallBacks: "
259*09467b48Spatrick          << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
260*09467b48Spatrick          << "\n  SizeOfZeroFill: "
261*09467b48Spatrick          << TLSDir->SizeOfZeroFill
262*09467b48Spatrick          << "\n  Characteristics: "
263*09467b48Spatrick          << TLSDir->Characteristics
264*09467b48Spatrick          << "\n  Alignment: "
265*09467b48Spatrick          << TLSDir->getAlignment()
266*09467b48Spatrick          << "\n\n";
267*09467b48Spatrick }
268*09467b48Spatrick 
269*09467b48Spatrick static void printTLSDirectory(const COFFObjectFile *Obj) {
270*09467b48Spatrick   const pe32_header *PE32Header = Obj->getPE32Header();
271*09467b48Spatrick   const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
272*09467b48Spatrick 
273*09467b48Spatrick   // Skip if it's not executable.
274*09467b48Spatrick   if (!PE32Header && !PE32PlusHeader)
275*09467b48Spatrick     return;
276*09467b48Spatrick 
277*09467b48Spatrick   const data_directory *DataDir;
278*09467b48Spatrick   if (std::error_code EC = Obj->getDataDirectory(COFF::TLS_TABLE, DataDir))
279*09467b48Spatrick     reportError(errorCodeToError(EC), Obj->getFileName());
280*09467b48Spatrick 
281*09467b48Spatrick   if (DataDir->RelativeVirtualAddress == 0)
282*09467b48Spatrick     return;
283*09467b48Spatrick 
284*09467b48Spatrick   uintptr_t IntPtr = 0;
285*09467b48Spatrick   if (std::error_code EC =
286*09467b48Spatrick           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
287*09467b48Spatrick     reportError(errorCodeToError(EC), Obj->getFileName());
288*09467b48Spatrick 
289*09467b48Spatrick   if (PE32Header) {
290*09467b48Spatrick     auto *TLSDir = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
291*09467b48Spatrick     printTLSDirectoryT(TLSDir);
292*09467b48Spatrick   } else {
293*09467b48Spatrick     auto *TLSDir = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
294*09467b48Spatrick     printTLSDirectoryT(TLSDir);
295*09467b48Spatrick   }
296*09467b48Spatrick 
297*09467b48Spatrick   outs() << "\n";
298*09467b48Spatrick }
299*09467b48Spatrick 
300*09467b48Spatrick static void printLoadConfiguration(const COFFObjectFile *Obj) {
301*09467b48Spatrick   // Skip if it's not executable.
302*09467b48Spatrick   if (!Obj->getPE32Header())
303*09467b48Spatrick     return;
304*09467b48Spatrick 
305*09467b48Spatrick   // Currently only x86 is supported
306*09467b48Spatrick   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
307*09467b48Spatrick     return;
308*09467b48Spatrick 
309*09467b48Spatrick   const data_directory *DataDir;
310*09467b48Spatrick 
311*09467b48Spatrick   if (std::error_code EC =
312*09467b48Spatrick           Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))
313*09467b48Spatrick     reportError(errorCodeToError(EC), Obj->getFileName());
314*09467b48Spatrick 
315*09467b48Spatrick   uintptr_t IntPtr = 0;
316*09467b48Spatrick   if (DataDir->RelativeVirtualAddress == 0)
317*09467b48Spatrick     return;
318*09467b48Spatrick 
319*09467b48Spatrick   if (std::error_code EC =
320*09467b48Spatrick           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
321*09467b48Spatrick     reportError(errorCodeToError(EC), Obj->getFileName());
322*09467b48Spatrick 
323*09467b48Spatrick   auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr);
324*09467b48Spatrick   outs() << "Load configuration:"
325*09467b48Spatrick          << "\n  Timestamp: " << LoadConf->TimeDateStamp
326*09467b48Spatrick          << "\n  Major Version: " << LoadConf->MajorVersion
327*09467b48Spatrick          << "\n  Minor Version: " << LoadConf->MinorVersion
328*09467b48Spatrick          << "\n  GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
329*09467b48Spatrick          << "\n  GlobalFlags Set: " << LoadConf->GlobalFlagsSet
330*09467b48Spatrick          << "\n  Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
331*09467b48Spatrick          << "\n  Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
332*09467b48Spatrick          << "\n  Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
333*09467b48Spatrick          << "\n  Lock Prefix Table: " << LoadConf->LockPrefixTable
334*09467b48Spatrick          << "\n  Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
335*09467b48Spatrick          << "\n  Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
336*09467b48Spatrick          << "\n  Process Affinity Mask: " << LoadConf->ProcessAffinityMask
337*09467b48Spatrick          << "\n  Process Heap Flags: " << LoadConf->ProcessHeapFlags
338*09467b48Spatrick          << "\n  CSD Version: " << LoadConf->CSDVersion
339*09467b48Spatrick          << "\n  Security Cookie: " << LoadConf->SecurityCookie
340*09467b48Spatrick          << "\n  SEH Table: " << LoadConf->SEHandlerTable
341*09467b48Spatrick          << "\n  SEH Count: " << LoadConf->SEHandlerCount
342*09467b48Spatrick          << "\n\n";
343*09467b48Spatrick   printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);
344*09467b48Spatrick   outs() << "\n";
345*09467b48Spatrick }
346*09467b48Spatrick 
347*09467b48Spatrick // Prints import tables. The import table is a table containing the list of
348*09467b48Spatrick // DLL name and symbol names which will be linked by the loader.
349*09467b48Spatrick static void printImportTables(const COFFObjectFile *Obj) {
350*09467b48Spatrick   import_directory_iterator I = Obj->import_directory_begin();
351*09467b48Spatrick   import_directory_iterator E = Obj->import_directory_end();
352*09467b48Spatrick   if (I == E)
353*09467b48Spatrick     return;
354*09467b48Spatrick   outs() << "The Import Tables:\n";
355*09467b48Spatrick   for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
356*09467b48Spatrick     const coff_import_directory_table_entry *Dir;
357*09467b48Spatrick     StringRef Name;
358*09467b48Spatrick     if (DirRef.getImportTableEntry(Dir)) return;
359*09467b48Spatrick     if (DirRef.getName(Name)) return;
360*09467b48Spatrick 
361*09467b48Spatrick     outs() << format("  lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
362*09467b48Spatrick                      static_cast<uint32_t>(Dir->ImportLookupTableRVA),
363*09467b48Spatrick                      static_cast<uint32_t>(Dir->TimeDateStamp),
364*09467b48Spatrick                      static_cast<uint32_t>(Dir->ForwarderChain),
365*09467b48Spatrick                      static_cast<uint32_t>(Dir->NameRVA),
366*09467b48Spatrick                      static_cast<uint32_t>(Dir->ImportAddressTableRVA));
367*09467b48Spatrick     outs() << "    DLL Name: " << Name << "\n";
368*09467b48Spatrick     outs() << "    Hint/Ord  Name\n";
369*09467b48Spatrick     for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
370*09467b48Spatrick       bool IsOrdinal;
371*09467b48Spatrick       if (Entry.isOrdinal(IsOrdinal))
372*09467b48Spatrick         return;
373*09467b48Spatrick       if (IsOrdinal) {
374*09467b48Spatrick         uint16_t Ordinal;
375*09467b48Spatrick         if (Entry.getOrdinal(Ordinal))
376*09467b48Spatrick           return;
377*09467b48Spatrick         outs() << format("      % 6d\n", Ordinal);
378*09467b48Spatrick         continue;
379*09467b48Spatrick       }
380*09467b48Spatrick       uint32_t HintNameRVA;
381*09467b48Spatrick       if (Entry.getHintNameRVA(HintNameRVA))
382*09467b48Spatrick         return;
383*09467b48Spatrick       uint16_t Hint;
384*09467b48Spatrick       StringRef Name;
385*09467b48Spatrick       if (Obj->getHintName(HintNameRVA, Hint, Name))
386*09467b48Spatrick         return;
387*09467b48Spatrick       outs() << format("      % 6d  ", Hint) << Name << "\n";
388*09467b48Spatrick     }
389*09467b48Spatrick     outs() << "\n";
390*09467b48Spatrick   }
391*09467b48Spatrick }
392*09467b48Spatrick 
393*09467b48Spatrick // Prints export tables. The export table is a table containing the list of
394*09467b48Spatrick // exported symbol from the DLL.
395*09467b48Spatrick static void printExportTable(const COFFObjectFile *Obj) {
396*09467b48Spatrick   outs() << "Export Table:\n";
397*09467b48Spatrick   export_directory_iterator I = Obj->export_directory_begin();
398*09467b48Spatrick   export_directory_iterator E = Obj->export_directory_end();
399*09467b48Spatrick   if (I == E)
400*09467b48Spatrick     return;
401*09467b48Spatrick   StringRef DllName;
402*09467b48Spatrick   uint32_t OrdinalBase;
403*09467b48Spatrick   if (I->getDllName(DllName))
404*09467b48Spatrick     return;
405*09467b48Spatrick   if (I->getOrdinalBase(OrdinalBase))
406*09467b48Spatrick     return;
407*09467b48Spatrick   outs() << " DLL name: " << DllName << "\n";
408*09467b48Spatrick   outs() << " Ordinal base: " << OrdinalBase << "\n";
409*09467b48Spatrick   outs() << " Ordinal      RVA  Name\n";
410*09467b48Spatrick   for (; I != E; I = ++I) {
411*09467b48Spatrick     uint32_t Ordinal;
412*09467b48Spatrick     if (I->getOrdinal(Ordinal))
413*09467b48Spatrick       return;
414*09467b48Spatrick     uint32_t RVA;
415*09467b48Spatrick     if (I->getExportRVA(RVA))
416*09467b48Spatrick       return;
417*09467b48Spatrick     bool IsForwarder;
418*09467b48Spatrick     if (I->isForwarder(IsForwarder))
419*09467b48Spatrick       return;
420*09467b48Spatrick 
421*09467b48Spatrick     if (IsForwarder) {
422*09467b48Spatrick       // Export table entries can be used to re-export symbols that
423*09467b48Spatrick       // this COFF file is imported from some DLLs. This is rare.
424*09467b48Spatrick       // In most cases IsForwarder is false.
425*09467b48Spatrick       outs() << format("    % 4d         ", Ordinal);
426*09467b48Spatrick     } else {
427*09467b48Spatrick       outs() << format("    % 4d %# 8x", Ordinal, RVA);
428*09467b48Spatrick     }
429*09467b48Spatrick 
430*09467b48Spatrick     StringRef Name;
431*09467b48Spatrick     if (I->getSymbolName(Name))
432*09467b48Spatrick       continue;
433*09467b48Spatrick     if (!Name.empty())
434*09467b48Spatrick       outs() << "  " << Name;
435*09467b48Spatrick     if (IsForwarder) {
436*09467b48Spatrick       StringRef S;
437*09467b48Spatrick       if (I->getForwardTo(S))
438*09467b48Spatrick         return;
439*09467b48Spatrick       outs() << " (forwarded to " << S << ")";
440*09467b48Spatrick     }
441*09467b48Spatrick     outs() << "\n";
442*09467b48Spatrick   }
443*09467b48Spatrick }
444*09467b48Spatrick 
445*09467b48Spatrick // Given the COFF object file, this function returns the relocations for .pdata
446*09467b48Spatrick // and the pointer to "runtime function" structs.
447*09467b48Spatrick static bool getPDataSection(const COFFObjectFile *Obj,
448*09467b48Spatrick                             std::vector<RelocationRef> &Rels,
449*09467b48Spatrick                             const RuntimeFunction *&RFStart, int &NumRFs) {
450*09467b48Spatrick   for (const SectionRef &Section : Obj->sections()) {
451*09467b48Spatrick     StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
452*09467b48Spatrick     if (Name != ".pdata")
453*09467b48Spatrick       continue;
454*09467b48Spatrick 
455*09467b48Spatrick     const coff_section *Pdata = Obj->getCOFFSection(Section);
456*09467b48Spatrick     for (const RelocationRef &Reloc : Section.relocations())
457*09467b48Spatrick       Rels.push_back(Reloc);
458*09467b48Spatrick 
459*09467b48Spatrick     // Sort relocations by address.
460*09467b48Spatrick     llvm::sort(Rels, isRelocAddressLess);
461*09467b48Spatrick 
462*09467b48Spatrick     ArrayRef<uint8_t> Contents;
463*09467b48Spatrick     if (Error E = Obj->getSectionContents(Pdata, Contents))
464*09467b48Spatrick       reportError(std::move(E), Obj->getFileName());
465*09467b48Spatrick 
466*09467b48Spatrick     if (Contents.empty())
467*09467b48Spatrick       continue;
468*09467b48Spatrick 
469*09467b48Spatrick     RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
470*09467b48Spatrick     NumRFs = Contents.size() / sizeof(RuntimeFunction);
471*09467b48Spatrick     return true;
472*09467b48Spatrick   }
473*09467b48Spatrick   return false;
474*09467b48Spatrick }
475*09467b48Spatrick 
476*09467b48Spatrick Error getCOFFRelocationValueString(const COFFObjectFile *Obj,
477*09467b48Spatrick                                          const RelocationRef &Rel,
478*09467b48Spatrick                                          SmallVectorImpl<char> &Result) {
479*09467b48Spatrick   symbol_iterator SymI = Rel.getSymbol();
480*09467b48Spatrick   Expected<StringRef> SymNameOrErr = SymI->getName();
481*09467b48Spatrick   if (!SymNameOrErr)
482*09467b48Spatrick     return SymNameOrErr.takeError();
483*09467b48Spatrick   StringRef SymName = *SymNameOrErr;
484*09467b48Spatrick   Result.append(SymName.begin(), SymName.end());
485*09467b48Spatrick   return Error::success();
486*09467b48Spatrick }
487*09467b48Spatrick 
488*09467b48Spatrick static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
489*09467b48Spatrick   // The casts to int are required in order to output the value as number.
490*09467b48Spatrick   // Without the casts the value would be interpreted as char data (which
491*09467b48Spatrick   // results in garbage output).
492*09467b48Spatrick   outs() << "    Version: " << static_cast<int>(UI->getVersion()) << "\n";
493*09467b48Spatrick   outs() << "    Flags: " << static_cast<int>(UI->getFlags());
494*09467b48Spatrick   if (UI->getFlags()) {
495*09467b48Spatrick     if (UI->getFlags() & UNW_ExceptionHandler)
496*09467b48Spatrick       outs() << " UNW_ExceptionHandler";
497*09467b48Spatrick     if (UI->getFlags() & UNW_TerminateHandler)
498*09467b48Spatrick       outs() << " UNW_TerminateHandler";
499*09467b48Spatrick     if (UI->getFlags() & UNW_ChainInfo)
500*09467b48Spatrick       outs() << " UNW_ChainInfo";
501*09467b48Spatrick   }
502*09467b48Spatrick   outs() << "\n";
503*09467b48Spatrick   outs() << "    Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
504*09467b48Spatrick   outs() << "    Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
505*09467b48Spatrick   // Maybe this should move to output of UOP_SetFPReg?
506*09467b48Spatrick   if (UI->getFrameRegister()) {
507*09467b48Spatrick     outs() << "    Frame register: "
508*09467b48Spatrick            << getUnwindRegisterName(UI->getFrameRegister()) << "\n";
509*09467b48Spatrick     outs() << "    Frame offset: " << 16 * UI->getFrameOffset() << "\n";
510*09467b48Spatrick   } else {
511*09467b48Spatrick     outs() << "    No frame pointer used\n";
512*09467b48Spatrick   }
513*09467b48Spatrick   if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
514*09467b48Spatrick     // FIXME: Output exception handler data
515*09467b48Spatrick   } else if (UI->getFlags() & UNW_ChainInfo) {
516*09467b48Spatrick     // FIXME: Output chained unwind info
517*09467b48Spatrick   }
518*09467b48Spatrick 
519*09467b48Spatrick   if (UI->NumCodes)
520*09467b48Spatrick     outs() << "    Unwind Codes:\n";
521*09467b48Spatrick 
522*09467b48Spatrick   printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
523*09467b48Spatrick 
524*09467b48Spatrick   outs() << "\n";
525*09467b48Spatrick   outs().flush();
526*09467b48Spatrick }
527*09467b48Spatrick 
528*09467b48Spatrick /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
529*09467b48Spatrick /// pointing to an executable file.
530*09467b48Spatrick static void printRuntimeFunction(const COFFObjectFile *Obj,
531*09467b48Spatrick                                  const RuntimeFunction &RF) {
532*09467b48Spatrick   if (!RF.StartAddress)
533*09467b48Spatrick     return;
534*09467b48Spatrick   outs() << "Function Table:\n"
535*09467b48Spatrick          << format("  Start Address: 0x%04x\n",
536*09467b48Spatrick                    static_cast<uint32_t>(RF.StartAddress))
537*09467b48Spatrick          << format("  End Address: 0x%04x\n",
538*09467b48Spatrick                    static_cast<uint32_t>(RF.EndAddress))
539*09467b48Spatrick          << format("  Unwind Info Address: 0x%04x\n",
540*09467b48Spatrick                    static_cast<uint32_t>(RF.UnwindInfoOffset));
541*09467b48Spatrick   uintptr_t addr;
542*09467b48Spatrick   if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
543*09467b48Spatrick     return;
544*09467b48Spatrick   printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
545*09467b48Spatrick }
546*09467b48Spatrick 
547*09467b48Spatrick /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
548*09467b48Spatrick /// pointing to an object file. Unlike executable, fields in RuntimeFunction
549*09467b48Spatrick /// struct are filled with zeros, but instead there are relocations pointing to
550*09467b48Spatrick /// them so that the linker will fill targets' RVAs to the fields at link
551*09467b48Spatrick /// time. This function interprets the relocations to find the data to be used
552*09467b48Spatrick /// in the resulting executable.
553*09467b48Spatrick static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
554*09467b48Spatrick                                      const RuntimeFunction &RF,
555*09467b48Spatrick                                      uint64_t SectionOffset,
556*09467b48Spatrick                                      const std::vector<RelocationRef> &Rels) {
557*09467b48Spatrick   outs() << "Function Table:\n";
558*09467b48Spatrick   outs() << "  Start Address: ";
559*09467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
560*09467b48Spatrick                          SectionOffset +
561*09467b48Spatrick                              /*offsetof(RuntimeFunction, StartAddress)*/ 0,
562*09467b48Spatrick                          RF.StartAddress);
563*09467b48Spatrick   outs() << "\n";
564*09467b48Spatrick 
565*09467b48Spatrick   outs() << "  End Address: ";
566*09467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
567*09467b48Spatrick                          SectionOffset +
568*09467b48Spatrick                              /*offsetof(RuntimeFunction, EndAddress)*/ 4,
569*09467b48Spatrick                          RF.EndAddress);
570*09467b48Spatrick   outs() << "\n";
571*09467b48Spatrick 
572*09467b48Spatrick   outs() << "  Unwind Info Address: ";
573*09467b48Spatrick   printCOFFSymbolAddress(outs(), Rels,
574*09467b48Spatrick                          SectionOffset +
575*09467b48Spatrick                              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
576*09467b48Spatrick                          RF.UnwindInfoOffset);
577*09467b48Spatrick   outs() << "\n";
578*09467b48Spatrick 
579*09467b48Spatrick   ArrayRef<uint8_t> XContents;
580*09467b48Spatrick   uint64_t UnwindInfoOffset = 0;
581*09467b48Spatrick   if (Error E = getSectionContents(
582*09467b48Spatrick           Obj, Rels,
583*09467b48Spatrick           SectionOffset +
584*09467b48Spatrick               /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
585*09467b48Spatrick           XContents, UnwindInfoOffset))
586*09467b48Spatrick     reportError(std::move(E), Obj->getFileName());
587*09467b48Spatrick   if (XContents.empty())
588*09467b48Spatrick     return;
589*09467b48Spatrick 
590*09467b48Spatrick   UnwindInfoOffset += RF.UnwindInfoOffset;
591*09467b48Spatrick   if (UnwindInfoOffset > XContents.size())
592*09467b48Spatrick     return;
593*09467b48Spatrick 
594*09467b48Spatrick   auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
595*09467b48Spatrick                                                            UnwindInfoOffset);
596*09467b48Spatrick   printWin64EHUnwindInfo(UI);
597*09467b48Spatrick }
598*09467b48Spatrick 
599*09467b48Spatrick void printCOFFUnwindInfo(const COFFObjectFile *Obj) {
600*09467b48Spatrick   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
601*09467b48Spatrick     WithColor::error(errs(), "llvm-objdump")
602*09467b48Spatrick         << "unsupported image machine type "
603*09467b48Spatrick            "(currently only AMD64 is supported).\n";
604*09467b48Spatrick     return;
605*09467b48Spatrick   }
606*09467b48Spatrick 
607*09467b48Spatrick   std::vector<RelocationRef> Rels;
608*09467b48Spatrick   const RuntimeFunction *RFStart;
609*09467b48Spatrick   int NumRFs;
610*09467b48Spatrick   if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
611*09467b48Spatrick     return;
612*09467b48Spatrick   ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
613*09467b48Spatrick 
614*09467b48Spatrick   bool IsExecutable = Rels.empty();
615*09467b48Spatrick   if (IsExecutable) {
616*09467b48Spatrick     for (const RuntimeFunction &RF : RFs)
617*09467b48Spatrick       printRuntimeFunction(Obj, RF);
618*09467b48Spatrick     return;
619*09467b48Spatrick   }
620*09467b48Spatrick 
621*09467b48Spatrick   for (const RuntimeFunction &RF : RFs) {
622*09467b48Spatrick     uint64_t SectionOffset =
623*09467b48Spatrick         std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
624*09467b48Spatrick     printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
625*09467b48Spatrick   }
626*09467b48Spatrick }
627*09467b48Spatrick 
628*09467b48Spatrick void printCOFFFileHeader(const object::ObjectFile *Obj) {
629*09467b48Spatrick   const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
630*09467b48Spatrick   printTLSDirectory(file);
631*09467b48Spatrick   printLoadConfiguration(file);
632*09467b48Spatrick   printImportTables(file);
633*09467b48Spatrick   printExportTable(file);
634*09467b48Spatrick }
635*09467b48Spatrick 
636*09467b48Spatrick void printCOFFSymbolTable(const object::COFFImportFile *i) {
637*09467b48Spatrick   unsigned Index = 0;
638*09467b48Spatrick   bool IsCode = i->getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
639*09467b48Spatrick 
640*09467b48Spatrick   for (const object::BasicSymbolRef &Sym : i->symbols()) {
641*09467b48Spatrick     std::string Name;
642*09467b48Spatrick     raw_string_ostream NS(Name);
643*09467b48Spatrick 
644*09467b48Spatrick     cantFail(Sym.printName(NS));
645*09467b48Spatrick     NS.flush();
646*09467b48Spatrick 
647*09467b48Spatrick     outs() << "[" << format("%2d", Index) << "]"
648*09467b48Spatrick            << "(sec " << format("%2d", 0) << ")"
649*09467b48Spatrick            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
650*09467b48Spatrick            << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"
651*09467b48Spatrick            << "(scl " << format("%3x", 0) << ") "
652*09467b48Spatrick            << "(nx " << 0 << ") "
653*09467b48Spatrick            << "0x" << format("%08x", 0) << " " << Name << '\n';
654*09467b48Spatrick 
655*09467b48Spatrick     ++Index;
656*09467b48Spatrick   }
657*09467b48Spatrick }
658*09467b48Spatrick 
659*09467b48Spatrick void printCOFFSymbolTable(const COFFObjectFile *coff) {
660*09467b48Spatrick   for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
661*09467b48Spatrick     Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI);
662*09467b48Spatrick     if (!Symbol)
663*09467b48Spatrick       reportError(Symbol.takeError(), coff->getFileName());
664*09467b48Spatrick 
665*09467b48Spatrick     StringRef Name;
666*09467b48Spatrick     if (std::error_code EC = coff->getSymbolName(*Symbol, Name))
667*09467b48Spatrick       reportError(errorCodeToError(EC), coff->getFileName());
668*09467b48Spatrick 
669*09467b48Spatrick     outs() << "[" << format("%2d", SI) << "]"
670*09467b48Spatrick            << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
671*09467b48Spatrick            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
672*09467b48Spatrick            << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
673*09467b48Spatrick            << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))
674*09467b48Spatrick            << ") "
675*09467b48Spatrick            << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
676*09467b48Spatrick            << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
677*09467b48Spatrick            << Name;
678*09467b48Spatrick     if (Demangle && Name.startswith("?")) {
679*09467b48Spatrick       char *DemangledSymbol = nullptr;
680*09467b48Spatrick       size_t Size = 0;
681*09467b48Spatrick       int Status = -1;
682*09467b48Spatrick       DemangledSymbol =
683*09467b48Spatrick           microsoftDemangle(Name.data(), DemangledSymbol, &Size, &Status);
684*09467b48Spatrick 
685*09467b48Spatrick       if (Status == 0 && DemangledSymbol) {
686*09467b48Spatrick         outs() << " (" << StringRef(DemangledSymbol) << ")";
687*09467b48Spatrick         std::free(DemangledSymbol);
688*09467b48Spatrick       } else {
689*09467b48Spatrick         outs() << " (invalid mangled name)";
690*09467b48Spatrick       }
691*09467b48Spatrick     }
692*09467b48Spatrick     outs() << "\n";
693*09467b48Spatrick 
694*09467b48Spatrick     for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
695*09467b48Spatrick       if (Symbol->isSectionDefinition()) {
696*09467b48Spatrick         const coff_aux_section_definition *asd;
697*09467b48Spatrick         if (std::error_code EC =
698*09467b48Spatrick                 coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))
699*09467b48Spatrick           reportError(errorCodeToError(EC), coff->getFileName());
700*09467b48Spatrick 
701*09467b48Spatrick         int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
702*09467b48Spatrick 
703*09467b48Spatrick         outs() << "AUX "
704*09467b48Spatrick                << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
705*09467b48Spatrick                          , unsigned(asd->Length)
706*09467b48Spatrick                          , unsigned(asd->NumberOfRelocations)
707*09467b48Spatrick                          , unsigned(asd->NumberOfLinenumbers)
708*09467b48Spatrick                          , unsigned(asd->CheckSum))
709*09467b48Spatrick                << format("assoc %d comdat %d\n"
710*09467b48Spatrick                          , unsigned(AuxNumber)
711*09467b48Spatrick                          , unsigned(asd->Selection));
712*09467b48Spatrick       } else if (Symbol->isFileRecord()) {
713*09467b48Spatrick         const char *FileName;
714*09467b48Spatrick         if (std::error_code EC = coff->getAuxSymbol<char>(SI + 1, FileName))
715*09467b48Spatrick           reportError(errorCodeToError(EC), coff->getFileName());
716*09467b48Spatrick 
717*09467b48Spatrick         StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
718*09467b48Spatrick                                      coff->getSymbolTableEntrySize());
719*09467b48Spatrick         outs() << "AUX " << Name.rtrim(StringRef("\0", 1))  << '\n';
720*09467b48Spatrick 
721*09467b48Spatrick         SI = SI + Symbol->getNumberOfAuxSymbols();
722*09467b48Spatrick         break;
723*09467b48Spatrick       } else if (Symbol->isWeakExternal()) {
724*09467b48Spatrick         const coff_aux_weak_external *awe;
725*09467b48Spatrick         if (std::error_code EC =
726*09467b48Spatrick                 coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))
727*09467b48Spatrick           reportError(errorCodeToError(EC), coff->getFileName());
728*09467b48Spatrick 
729*09467b48Spatrick         outs() << "AUX " << format("indx %d srch %d\n",
730*09467b48Spatrick                                    static_cast<uint32_t>(awe->TagIndex),
731*09467b48Spatrick                                    static_cast<uint32_t>(awe->Characteristics));
732*09467b48Spatrick       } else {
733*09467b48Spatrick         outs() << "AUX Unknown\n";
734*09467b48Spatrick       }
735*09467b48Spatrick     }
736*09467b48Spatrick   }
737*09467b48Spatrick }
738*09467b48Spatrick } // namespace llvm
739