10b57cec5SDimitry Andric //===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements the COFF-specific dumper for llvm-objdump.
110b57cec5SDimitry Andric /// It outputs the Win64 EH data structures as plain text.
120b57cec5SDimitry Andric /// The encoding of the unwind codes is described in MSDN:
13bdd1243dSDimitry Andric /// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
140b57cec5SDimitry Andric ///
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric
175ffd83dbSDimitry Andric #include "COFFDump.h"
185ffd83dbSDimitry Andric
190b57cec5SDimitry Andric #include "llvm-objdump.h"
200b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h"
210b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
220b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h"
230b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
240b57cec5SDimitry Andric #include "llvm/Support/Format.h"
250b57cec5SDimitry Andric #include "llvm/Support/Win64EH.h"
260b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
270b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
280b57cec5SDimitry Andric
295ffd83dbSDimitry Andric using namespace llvm;
305ffd83dbSDimitry Andric using namespace llvm::objdump;
310b57cec5SDimitry Andric using namespace llvm::object;
320b57cec5SDimitry Andric using namespace llvm::Win64EH;
330b57cec5SDimitry Andric
34349cc55cSDimitry Andric namespace {
35349cc55cSDimitry Andric template <typename T> struct EnumEntry {
36349cc55cSDimitry Andric T Value;
37349cc55cSDimitry Andric StringRef Name;
38349cc55cSDimitry Andric };
39349cc55cSDimitry Andric
4006c3fb27SDimitry Andric class COFFDumper : public Dumper {
41349cc55cSDimitry Andric public:
COFFDumper(const llvm::object::COFFObjectFile & O)4206c3fb27SDimitry Andric explicit COFFDumper(const llvm::object::COFFObjectFile &O)
4306c3fb27SDimitry Andric : Dumper(O), Obj(O) {
44349cc55cSDimitry Andric Is64 = !Obj.getPE32Header();
45349cc55cSDimitry Andric }
46349cc55cSDimitry Andric
47349cc55cSDimitry Andric template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
48*5f757f3fSDimitry Andric void printPrivateHeaders() override;
49349cc55cSDimitry Andric
50349cc55cSDimitry Andric private:
formatAddr(T V) const51349cc55cSDimitry Andric template <typename T> FormattedNumber formatAddr(T V) const {
52349cc55cSDimitry Andric return format_hex_no_prefix(V, Is64 ? 16 : 8);
53349cc55cSDimitry Andric }
54349cc55cSDimitry Andric
getBaseOfData(const void * Hdr) const55349cc55cSDimitry Andric uint32_t getBaseOfData(const void *Hdr) const {
56349cc55cSDimitry Andric return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;
57349cc55cSDimitry Andric }
58349cc55cSDimitry Andric
59349cc55cSDimitry Andric const llvm::object::COFFObjectFile &Obj;
60349cc55cSDimitry Andric bool Is64;
61349cc55cSDimitry Andric };
62349cc55cSDimitry Andric } // namespace
63349cc55cSDimitry Andric
6406c3fb27SDimitry Andric std::unique_ptr<Dumper>
createCOFFDumper(const object::COFFObjectFile & Obj)6506c3fb27SDimitry Andric objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
6606c3fb27SDimitry Andric return std::make_unique<COFFDumper>(Obj);
6706c3fb27SDimitry Andric }
6806c3fb27SDimitry Andric
69349cc55cSDimitry Andric constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
70349cc55cSDimitry Andric {uint16_t(COFF::PE32Header::PE32), "PE32"},
71349cc55cSDimitry Andric {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},
72349cc55cSDimitry Andric };
73349cc55cSDimitry Andric
74349cc55cSDimitry Andric constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
75349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_UNKNOWN, "unspecified"},
76349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_NATIVE, "NT native"},
77349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, "Windows GUI"},
78349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, "Windows CUI"},
79349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_POSIX_CUI, "POSIX CUI"},
80349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, "Wince CUI"},
81349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application"},
82349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver"},
83349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver"},
84349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_EFI_ROM, "SAL runtime driver"},
85349cc55cSDimitry Andric {COFF::IMAGE_SUBSYSTEM_XBOX, "XBOX"},
86349cc55cSDimitry Andric };
87349cc55cSDimitry Andric
88349cc55cSDimitry Andric template <typename T, typename TEnum>
printOptionalEnumName(T Value,ArrayRef<EnumEntry<TEnum>> EnumValues)89349cc55cSDimitry Andric static void printOptionalEnumName(T Value,
90349cc55cSDimitry Andric ArrayRef<EnumEntry<TEnum>> EnumValues) {
91349cc55cSDimitry Andric for (const EnumEntry<TEnum> &I : EnumValues)
92349cc55cSDimitry Andric if (I.Value == Value) {
93349cc55cSDimitry Andric outs() << "\t(" << I.Name << ')';
94349cc55cSDimitry Andric return;
95349cc55cSDimitry Andric }
96349cc55cSDimitry Andric }
97349cc55cSDimitry Andric
98349cc55cSDimitry Andric template <class PEHeader>
printPEHeader(const PEHeader & Hdr) const99349cc55cSDimitry Andric void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
100349cc55cSDimitry Andric auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {
101349cc55cSDimitry Andric outs() << format("%-23s ", K) << format(Fmt, V);
102349cc55cSDimitry Andric };
103349cc55cSDimitry Andric auto printU16 = [&](const char *K, support::ulittle16_t V,
104349cc55cSDimitry Andric const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); };
105349cc55cSDimitry Andric auto printU32 = [&](const char *K, support::ulittle32_t V,
106349cc55cSDimitry Andric const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); };
107349cc55cSDimitry Andric auto printAddr = [=](const char *K, uint64_t V) {
108349cc55cSDimitry Andric outs() << format("%-23s ", K) << formatAddr(V) << '\n';
109349cc55cSDimitry Andric };
110349cc55cSDimitry Andric
111349cc55cSDimitry Andric printU16("Magic", Hdr.Magic, "%04x");
112bdd1243dSDimitry Andric printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
113349cc55cSDimitry Andric outs() << '\n';
114349cc55cSDimitry Andric print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
115349cc55cSDimitry Andric print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
116349cc55cSDimitry Andric printAddr("SizeOfCode", Hdr.SizeOfCode);
117349cc55cSDimitry Andric printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData);
118349cc55cSDimitry Andric printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData);
119349cc55cSDimitry Andric printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint);
120349cc55cSDimitry Andric printAddr("BaseOfCode", Hdr.BaseOfCode);
121349cc55cSDimitry Andric if (!Is64)
122349cc55cSDimitry Andric printAddr("BaseOfData", getBaseOfData(&Hdr));
123349cc55cSDimitry Andric printAddr("ImageBase", Hdr.ImageBase);
124349cc55cSDimitry Andric printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n");
125349cc55cSDimitry Andric printU32("FileAlignment", Hdr.FileAlignment, "%08x\n");
126349cc55cSDimitry Andric printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion);
127349cc55cSDimitry Andric printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion);
128349cc55cSDimitry Andric printU16("MajorImageVersion", Hdr.MajorImageVersion);
129349cc55cSDimitry Andric printU16("MinorImageVersion", Hdr.MinorImageVersion);
130349cc55cSDimitry Andric printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion);
131349cc55cSDimitry Andric printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion);
132349cc55cSDimitry Andric printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n");
133349cc55cSDimitry Andric printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n");
134349cc55cSDimitry Andric printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
135349cc55cSDimitry Andric printU32("CheckSum", Hdr.CheckSum, "%08x\n");
136349cc55cSDimitry Andric printU16("Subsystem", Hdr.Subsystem, "%08x");
137bdd1243dSDimitry Andric printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
138349cc55cSDimitry Andric outs() << '\n';
139349cc55cSDimitry Andric
140349cc55cSDimitry Andric printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
141349cc55cSDimitry Andric #define FLAG(Name) \
142349cc55cSDimitry Andric if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \
143349cc55cSDimitry Andric outs() << "\t\t\t\t\t" << #Name << '\n';
144349cc55cSDimitry Andric FLAG(HIGH_ENTROPY_VA);
145349cc55cSDimitry Andric FLAG(DYNAMIC_BASE);
146349cc55cSDimitry Andric FLAG(FORCE_INTEGRITY);
147349cc55cSDimitry Andric FLAG(NX_COMPAT);
148349cc55cSDimitry Andric FLAG(NO_ISOLATION);
149349cc55cSDimitry Andric FLAG(NO_SEH);
150349cc55cSDimitry Andric FLAG(NO_BIND);
151349cc55cSDimitry Andric FLAG(APPCONTAINER);
152349cc55cSDimitry Andric FLAG(WDM_DRIVER);
153349cc55cSDimitry Andric FLAG(GUARD_CF);
154349cc55cSDimitry Andric FLAG(TERMINAL_SERVER_AWARE);
155349cc55cSDimitry Andric #undef FLAG
156349cc55cSDimitry Andric
157349cc55cSDimitry Andric printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve);
158349cc55cSDimitry Andric printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit);
159349cc55cSDimitry Andric printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve);
160349cc55cSDimitry Andric printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit);
161349cc55cSDimitry Andric printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n");
162349cc55cSDimitry Andric printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n");
163349cc55cSDimitry Andric
164349cc55cSDimitry Andric static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = {
165349cc55cSDimitry Andric "Export Directory [.edata (or where ever we found it)]",
166349cc55cSDimitry Andric "Import Directory [parts of .idata]",
167349cc55cSDimitry Andric "Resource Directory [.rsrc]",
168349cc55cSDimitry Andric "Exception Directory [.pdata]",
169349cc55cSDimitry Andric "Security Directory",
170349cc55cSDimitry Andric "Base Relocation Directory [.reloc]",
171349cc55cSDimitry Andric "Debug Directory",
172349cc55cSDimitry Andric "Description Directory",
173349cc55cSDimitry Andric "Special Directory",
174349cc55cSDimitry Andric "Thread Storage Directory [.tls]",
175349cc55cSDimitry Andric "Load Configuration Directory",
176349cc55cSDimitry Andric "Bound Import Directory",
177349cc55cSDimitry Andric "Import Address Table Directory",
178349cc55cSDimitry Andric "Delay Import Directory",
179349cc55cSDimitry Andric "CLR Runtime Header",
180349cc55cSDimitry Andric "Reserved",
181349cc55cSDimitry Andric };
182349cc55cSDimitry Andric outs() << "\nThe Data Directory\n";
183bdd1243dSDimitry Andric for (uint32_t I = 0; I != std::size(DirName); ++I) {
184349cc55cSDimitry Andric uint32_t Addr = 0, Size = 0;
185349cc55cSDimitry Andric if (const data_directory *Data = Obj.getDataDirectory(I)) {
186349cc55cSDimitry Andric Addr = Data->RelativeVirtualAddress;
187349cc55cSDimitry Andric Size = Data->Size;
188349cc55cSDimitry Andric }
189349cc55cSDimitry Andric outs() << format("Entry %x ", I) << formatAddr(Addr)
190349cc55cSDimitry Andric << format(" %08x %s\n", uint32_t(Size), DirName[I]);
191349cc55cSDimitry Andric }
192349cc55cSDimitry Andric }
193349cc55cSDimitry Andric
1940b57cec5SDimitry Andric // Returns the name of the unwind code.
getUnwindCodeTypeName(uint8_t Code)1950b57cec5SDimitry Andric static StringRef getUnwindCodeTypeName(uint8_t Code) {
1960b57cec5SDimitry Andric switch(Code) {
1970b57cec5SDimitry Andric default: llvm_unreachable("Invalid unwind code");
1980b57cec5SDimitry Andric case UOP_PushNonVol: return "UOP_PushNonVol";
1990b57cec5SDimitry Andric case UOP_AllocLarge: return "UOP_AllocLarge";
2000b57cec5SDimitry Andric case UOP_AllocSmall: return "UOP_AllocSmall";
2010b57cec5SDimitry Andric case UOP_SetFPReg: return "UOP_SetFPReg";
2020b57cec5SDimitry Andric case UOP_SaveNonVol: return "UOP_SaveNonVol";
2030b57cec5SDimitry Andric case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
204bdd1243dSDimitry Andric case UOP_Epilog: return "UOP_Epilog";
205bdd1243dSDimitry Andric case UOP_SpareCode: return "UOP_SpareCode";
2060b57cec5SDimitry Andric case UOP_SaveXMM128: return "UOP_SaveXMM128";
2070b57cec5SDimitry Andric case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
2080b57cec5SDimitry Andric case UOP_PushMachFrame: return "UOP_PushMachFrame";
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric // Returns the name of a referenced register.
getUnwindRegisterName(uint8_t Reg)2130b57cec5SDimitry Andric static StringRef getUnwindRegisterName(uint8_t Reg) {
2140b57cec5SDimitry Andric switch(Reg) {
2150b57cec5SDimitry Andric default: llvm_unreachable("Invalid register");
2160b57cec5SDimitry Andric case 0: return "RAX";
2170b57cec5SDimitry Andric case 1: return "RCX";
2180b57cec5SDimitry Andric case 2: return "RDX";
2190b57cec5SDimitry Andric case 3: return "RBX";
2200b57cec5SDimitry Andric case 4: return "RSP";
2210b57cec5SDimitry Andric case 5: return "RBP";
2220b57cec5SDimitry Andric case 6: return "RSI";
2230b57cec5SDimitry Andric case 7: return "RDI";
2240b57cec5SDimitry Andric case 8: return "R8";
2250b57cec5SDimitry Andric case 9: return "R9";
2260b57cec5SDimitry Andric case 10: return "R10";
2270b57cec5SDimitry Andric case 11: return "R11";
2280b57cec5SDimitry Andric case 12: return "R12";
2290b57cec5SDimitry Andric case 13: return "R13";
2300b57cec5SDimitry Andric case 14: return "R14";
2310b57cec5SDimitry Andric case 15: return "R15";
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric // Calculates the number of array slots required for the unwind code.
getNumUsedSlots(const UnwindCode & UnwindCode)2360b57cec5SDimitry Andric static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
2370b57cec5SDimitry Andric switch (UnwindCode.getUnwindOp()) {
2380b57cec5SDimitry Andric default: llvm_unreachable("Invalid unwind code");
2390b57cec5SDimitry Andric case UOP_PushNonVol:
2400b57cec5SDimitry Andric case UOP_AllocSmall:
2410b57cec5SDimitry Andric case UOP_SetFPReg:
2420b57cec5SDimitry Andric case UOP_PushMachFrame:
2430b57cec5SDimitry Andric return 1;
2440b57cec5SDimitry Andric case UOP_SaveNonVol:
2450b57cec5SDimitry Andric case UOP_SaveXMM128:
246bdd1243dSDimitry Andric case UOP_Epilog:
2470b57cec5SDimitry Andric return 2;
2480b57cec5SDimitry Andric case UOP_SaveNonVolBig:
2490b57cec5SDimitry Andric case UOP_SaveXMM128Big:
250bdd1243dSDimitry Andric case UOP_SpareCode:
2510b57cec5SDimitry Andric return 3;
2520b57cec5SDimitry Andric case UOP_AllocLarge:
2530b57cec5SDimitry Andric return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
2580b57cec5SDimitry Andric // the unwind codes array, this function requires that the correct number of
2590b57cec5SDimitry Andric // slots is provided.
printUnwindCode(ArrayRef<UnwindCode> UCs)2600b57cec5SDimitry Andric static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
2610b57cec5SDimitry Andric assert(UCs.size() >= getNumUsedSlots(UCs[0]));
2620b57cec5SDimitry Andric outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))
2630b57cec5SDimitry Andric << getUnwindCodeTypeName(UCs[0].getUnwindOp());
2640b57cec5SDimitry Andric switch (UCs[0].getUnwindOp()) {
2650b57cec5SDimitry Andric case UOP_PushNonVol:
2660b57cec5SDimitry Andric outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
2670b57cec5SDimitry Andric break;
2680b57cec5SDimitry Andric case UOP_AllocLarge:
2690b57cec5SDimitry Andric if (UCs[0].getOpInfo() == 0) {
2700b57cec5SDimitry Andric outs() << " " << UCs[1].FrameOffset;
2710b57cec5SDimitry Andric } else {
2720b57cec5SDimitry Andric outs() << " " << UCs[1].FrameOffset
2730b57cec5SDimitry Andric + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric break;
2760b57cec5SDimitry Andric case UOP_AllocSmall:
2770b57cec5SDimitry Andric outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
2780b57cec5SDimitry Andric break;
2790b57cec5SDimitry Andric case UOP_SetFPReg:
2800b57cec5SDimitry Andric outs() << " ";
2810b57cec5SDimitry Andric break;
2820b57cec5SDimitry Andric case UOP_SaveNonVol:
2830b57cec5SDimitry Andric outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
2840b57cec5SDimitry Andric << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
2850b57cec5SDimitry Andric break;
2860b57cec5SDimitry Andric case UOP_SaveNonVolBig:
2870b57cec5SDimitry Andric outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
2880b57cec5SDimitry Andric << format(" [0x%08x]", UCs[1].FrameOffset
2890b57cec5SDimitry Andric + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
2900b57cec5SDimitry Andric break;
2910b57cec5SDimitry Andric case UOP_SaveXMM128:
2920b57cec5SDimitry Andric outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
2930b57cec5SDimitry Andric << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
2940b57cec5SDimitry Andric break;
2950b57cec5SDimitry Andric case UOP_SaveXMM128Big:
2960b57cec5SDimitry Andric outs() << " XMM" << UCs[0].getOpInfo()
2970b57cec5SDimitry Andric << format(" [0x%08x]", UCs[1].FrameOffset
2980b57cec5SDimitry Andric + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
2990b57cec5SDimitry Andric break;
3000b57cec5SDimitry Andric case UOP_PushMachFrame:
3010b57cec5SDimitry Andric outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
3020b57cec5SDimitry Andric << " error code";
3030b57cec5SDimitry Andric break;
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric outs() << "\n";
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric
printAllUnwindCodes(ArrayRef<UnwindCode> UCs)3080b57cec5SDimitry Andric static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
3090b57cec5SDimitry Andric for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
3100b57cec5SDimitry Andric unsigned UsedSlots = getNumUsedSlots(*I);
3110b57cec5SDimitry Andric if (UsedSlots > UCs.size()) {
3120b57cec5SDimitry Andric outs() << "Unwind data corrupted: Encountered unwind op "
3130b57cec5SDimitry Andric << getUnwindCodeTypeName((*I).getUnwindOp())
3140b57cec5SDimitry Andric << " which requires " << UsedSlots
3150b57cec5SDimitry Andric << " slots, but only " << UCs.size()
3160b57cec5SDimitry Andric << " remaining in buffer";
3170b57cec5SDimitry Andric return ;
3180b57cec5SDimitry Andric }
319bdd1243dSDimitry Andric printUnwindCode(ArrayRef(I, E));
3200b57cec5SDimitry Andric I += UsedSlots;
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric // Given a symbol sym this functions returns the address and section of it.
resolveSectionAndAddress(const COFFObjectFile * Obj,const SymbolRef & Sym,const coff_section * & ResolvedSection,uint64_t & ResolvedAddr)3250b57cec5SDimitry Andric static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
3260b57cec5SDimitry Andric const SymbolRef &Sym,
3270b57cec5SDimitry Andric const coff_section *&ResolvedSection,
3280b57cec5SDimitry Andric uint64_t &ResolvedAddr) {
3290b57cec5SDimitry Andric Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
3300b57cec5SDimitry Andric if (!ResolvedAddrOrErr)
3310b57cec5SDimitry Andric return ResolvedAddrOrErr.takeError();
3320b57cec5SDimitry Andric ResolvedAddr = *ResolvedAddrOrErr;
3330b57cec5SDimitry Andric Expected<section_iterator> Iter = Sym.getSection();
3340b57cec5SDimitry Andric if (!Iter)
3350b57cec5SDimitry Andric return Iter.takeError();
3360b57cec5SDimitry Andric ResolvedSection = Obj->getCOFFSection(**Iter);
3370b57cec5SDimitry Andric return Error::success();
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andric // Given a vector of relocations for a section and an offset into this section
3410b57cec5SDimitry Andric // the function returns the symbol used for the relocation at the offset.
resolveSymbol(const std::vector<RelocationRef> & Rels,uint64_t Offset,SymbolRef & Sym)3420b57cec5SDimitry Andric static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
3430b57cec5SDimitry Andric uint64_t Offset, SymbolRef &Sym) {
3440b57cec5SDimitry Andric for (auto &R : Rels) {
3450b57cec5SDimitry Andric uint64_t Ofs = R.getOffset();
3460b57cec5SDimitry Andric if (Ofs == Offset) {
3470b57cec5SDimitry Andric Sym = *R.getSymbol();
3480b57cec5SDimitry Andric return Error::success();
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric return make_error<BinaryError>();
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric
3540b57cec5SDimitry Andric // Given a vector of relocations for a section and an offset into this section
3550b57cec5SDimitry Andric // the function resolves the symbol used for the relocation at the offset and
3560b57cec5SDimitry Andric // returns the section content and the address inside the content pointed to
3570b57cec5SDimitry Andric // by the symbol.
3580b57cec5SDimitry Andric static Error
getSectionContents(const COFFObjectFile * Obj,const std::vector<RelocationRef> & Rels,uint64_t Offset,ArrayRef<uint8_t> & Contents,uint64_t & Addr)3590b57cec5SDimitry Andric getSectionContents(const COFFObjectFile *Obj,
3600b57cec5SDimitry Andric const std::vector<RelocationRef> &Rels, uint64_t Offset,
3610b57cec5SDimitry Andric ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
3620b57cec5SDimitry Andric SymbolRef Sym;
3630b57cec5SDimitry Andric if (Error E = resolveSymbol(Rels, Offset, Sym))
3640b57cec5SDimitry Andric return E;
3650b57cec5SDimitry Andric const coff_section *Section;
3660b57cec5SDimitry Andric if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
3670b57cec5SDimitry Andric return E;
3680b57cec5SDimitry Andric return Obj->getSectionContents(Section, Contents);
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric
3710b57cec5SDimitry Andric // Given a vector of relocations for a section and an offset into this section
3720b57cec5SDimitry Andric // the function returns the name of the symbol used for the relocation at the
3730b57cec5SDimitry Andric // offset.
resolveSymbolName(const std::vector<RelocationRef> & Rels,uint64_t Offset,StringRef & Name)3740b57cec5SDimitry Andric static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
3750b57cec5SDimitry Andric uint64_t Offset, StringRef &Name) {
3760b57cec5SDimitry Andric SymbolRef Sym;
3770b57cec5SDimitry Andric if (Error EC = resolveSymbol(Rels, Offset, Sym))
3780b57cec5SDimitry Andric return EC;
3790b57cec5SDimitry Andric Expected<StringRef> NameOrErr = Sym.getName();
3800b57cec5SDimitry Andric if (!NameOrErr)
3810b57cec5SDimitry Andric return NameOrErr.takeError();
3820b57cec5SDimitry Andric Name = *NameOrErr;
3830b57cec5SDimitry Andric return Error::success();
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric
printCOFFSymbolAddress(raw_ostream & Out,const std::vector<RelocationRef> & Rels,uint64_t Offset,uint32_t Disp)3860b57cec5SDimitry Andric static void printCOFFSymbolAddress(raw_ostream &Out,
3870b57cec5SDimitry Andric const std::vector<RelocationRef> &Rels,
3880b57cec5SDimitry Andric uint64_t Offset, uint32_t Disp) {
3890b57cec5SDimitry Andric StringRef Sym;
3900b57cec5SDimitry Andric if (!resolveSymbolName(Rels, Offset, Sym)) {
3910b57cec5SDimitry Andric Out << Sym;
3920b57cec5SDimitry Andric if (Disp > 0)
3930b57cec5SDimitry Andric Out << format(" + 0x%04x", Disp);
3940b57cec5SDimitry Andric } else {
3950b57cec5SDimitry Andric Out << format("0x%04x", Disp);
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric
3990b57cec5SDimitry Andric static void
printSEHTable(const COFFObjectFile * Obj,uint32_t TableVA,int Count)4000b57cec5SDimitry Andric printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
4010b57cec5SDimitry Andric if (Count == 0)
4020b57cec5SDimitry Andric return;
4030b57cec5SDimitry Andric
4040b57cec5SDimitry Andric uintptr_t IntPtr = 0;
4055ffd83dbSDimitry Andric if (Error E = Obj->getVaPtr(TableVA, IntPtr))
4065ffd83dbSDimitry Andric reportError(std::move(E), Obj->getFileName());
4078bcb0991SDimitry Andric
4080b57cec5SDimitry Andric const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
4090b57cec5SDimitry Andric outs() << "SEH Table:";
4100b57cec5SDimitry Andric for (int I = 0; I < Count; ++I)
4118bcb0991SDimitry Andric outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);
4120b57cec5SDimitry Andric outs() << "\n\n";
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric template <typename T>
printTLSDirectoryT(const coff_tls_directory<T> * TLSDir)4160b57cec5SDimitry Andric static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
4170b57cec5SDimitry Andric size_t FormatWidth = sizeof(T) * 2;
4180b57cec5SDimitry Andric outs() << "TLS directory:"
4190b57cec5SDimitry Andric << "\n StartAddressOfRawData: "
4200b57cec5SDimitry Andric << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
4210b57cec5SDimitry Andric << "\n EndAddressOfRawData: "
4220b57cec5SDimitry Andric << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
4230b57cec5SDimitry Andric << "\n AddressOfIndex: "
4240b57cec5SDimitry Andric << format_hex(TLSDir->AddressOfIndex, FormatWidth)
4250b57cec5SDimitry Andric << "\n AddressOfCallBacks: "
4260b57cec5SDimitry Andric << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
4270b57cec5SDimitry Andric << "\n SizeOfZeroFill: "
4280b57cec5SDimitry Andric << TLSDir->SizeOfZeroFill
4290b57cec5SDimitry Andric << "\n Characteristics: "
4300b57cec5SDimitry Andric << TLSDir->Characteristics
4310b57cec5SDimitry Andric << "\n Alignment: "
4320b57cec5SDimitry Andric << TLSDir->getAlignment()
4330b57cec5SDimitry Andric << "\n\n";
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric
printTLSDirectory(const COFFObjectFile * Obj)4360b57cec5SDimitry Andric static void printTLSDirectory(const COFFObjectFile *Obj) {
4378bcb0991SDimitry Andric const pe32_header *PE32Header = Obj->getPE32Header();
4388bcb0991SDimitry Andric const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
4390b57cec5SDimitry Andric
4400b57cec5SDimitry Andric // Skip if it's not executable.
4410b57cec5SDimitry Andric if (!PE32Header && !PE32PlusHeader)
4420b57cec5SDimitry Andric return;
4430b57cec5SDimitry Andric
4440b57cec5SDimitry Andric if (PE32Header) {
44581ad6265SDimitry Andric if (auto *TLSDir = Obj->getTLSDirectory32())
4460b57cec5SDimitry Andric printTLSDirectoryT(TLSDir);
4470b57cec5SDimitry Andric } else {
44881ad6265SDimitry Andric if (auto *TLSDir = Obj->getTLSDirectory64())
4490b57cec5SDimitry Andric printTLSDirectoryT(TLSDir);
4500b57cec5SDimitry Andric }
4510b57cec5SDimitry Andric
4520b57cec5SDimitry Andric outs() << "\n";
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric
printLoadConfiguration(const COFFObjectFile * Obj)4550b57cec5SDimitry Andric static void printLoadConfiguration(const COFFObjectFile *Obj) {
4560b57cec5SDimitry Andric // Skip if it's not executable.
4578bcb0991SDimitry Andric if (!Obj->getPE32Header())
4580b57cec5SDimitry Andric return;
4590b57cec5SDimitry Andric
4600b57cec5SDimitry Andric // Currently only x86 is supported
4610b57cec5SDimitry Andric if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
4620b57cec5SDimitry Andric return;
4630b57cec5SDimitry Andric
46481ad6265SDimitry Andric auto *LoadConf = Obj->getLoadConfig32();
46581ad6265SDimitry Andric if (!LoadConf)
4660b57cec5SDimitry Andric return;
4678bcb0991SDimitry Andric
4680b57cec5SDimitry Andric outs() << "Load configuration:"
4690b57cec5SDimitry Andric << "\n Timestamp: " << LoadConf->TimeDateStamp
4700b57cec5SDimitry Andric << "\n Major Version: " << LoadConf->MajorVersion
4710b57cec5SDimitry Andric << "\n Minor Version: " << LoadConf->MinorVersion
4720b57cec5SDimitry Andric << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
4730b57cec5SDimitry Andric << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet
4740b57cec5SDimitry Andric << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
4750b57cec5SDimitry Andric << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
4760b57cec5SDimitry Andric << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
4770b57cec5SDimitry Andric << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable
4780b57cec5SDimitry Andric << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
4790b57cec5SDimitry Andric << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
4800b57cec5SDimitry Andric << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask
4810b57cec5SDimitry Andric << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags
4820b57cec5SDimitry Andric << "\n CSD Version: " << LoadConf->CSDVersion
4830b57cec5SDimitry Andric << "\n Security Cookie: " << LoadConf->SecurityCookie
4840b57cec5SDimitry Andric << "\n SEH Table: " << LoadConf->SEHandlerTable
4850b57cec5SDimitry Andric << "\n SEH Count: " << LoadConf->SEHandlerCount
4860b57cec5SDimitry Andric << "\n\n";
4870b57cec5SDimitry Andric printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);
4880b57cec5SDimitry Andric outs() << "\n";
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric
4910b57cec5SDimitry Andric // Prints import tables. The import table is a table containing the list of
4920b57cec5SDimitry Andric // DLL name and symbol names which will be linked by the loader.
printImportTables(const COFFObjectFile * Obj)4930b57cec5SDimitry Andric static void printImportTables(const COFFObjectFile *Obj) {
4940b57cec5SDimitry Andric import_directory_iterator I = Obj->import_directory_begin();
4950b57cec5SDimitry Andric import_directory_iterator E = Obj->import_directory_end();
4960b57cec5SDimitry Andric if (I == E)
4970b57cec5SDimitry Andric return;
4980b57cec5SDimitry Andric outs() << "The Import Tables:\n";
4990b57cec5SDimitry Andric for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
5000b57cec5SDimitry Andric const coff_import_directory_table_entry *Dir;
5010b57cec5SDimitry Andric StringRef Name;
5020b57cec5SDimitry Andric if (DirRef.getImportTableEntry(Dir)) return;
5030b57cec5SDimitry Andric if (DirRef.getName(Name)) return;
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
5060b57cec5SDimitry Andric static_cast<uint32_t>(Dir->ImportLookupTableRVA),
5070b57cec5SDimitry Andric static_cast<uint32_t>(Dir->TimeDateStamp),
5080b57cec5SDimitry Andric static_cast<uint32_t>(Dir->ForwarderChain),
5090b57cec5SDimitry Andric static_cast<uint32_t>(Dir->NameRVA),
5100b57cec5SDimitry Andric static_cast<uint32_t>(Dir->ImportAddressTableRVA));
5110b57cec5SDimitry Andric outs() << " DLL Name: " << Name << "\n";
5120b57cec5SDimitry Andric outs() << " Hint/Ord Name\n";
5130b57cec5SDimitry Andric for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
5140b57cec5SDimitry Andric bool IsOrdinal;
5150b57cec5SDimitry Andric if (Entry.isOrdinal(IsOrdinal))
5160b57cec5SDimitry Andric return;
5170b57cec5SDimitry Andric if (IsOrdinal) {
5180b57cec5SDimitry Andric uint16_t Ordinal;
5190b57cec5SDimitry Andric if (Entry.getOrdinal(Ordinal))
5200b57cec5SDimitry Andric return;
5210b57cec5SDimitry Andric outs() << format(" % 6d\n", Ordinal);
5220b57cec5SDimitry Andric continue;
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric uint32_t HintNameRVA;
5250b57cec5SDimitry Andric if (Entry.getHintNameRVA(HintNameRVA))
5260b57cec5SDimitry Andric return;
5270b57cec5SDimitry Andric uint16_t Hint;
5280b57cec5SDimitry Andric StringRef Name;
5290b57cec5SDimitry Andric if (Obj->getHintName(HintNameRVA, Hint, Name))
5300b57cec5SDimitry Andric return;
5310b57cec5SDimitry Andric outs() << format(" % 6d ", Hint) << Name << "\n";
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric outs() << "\n";
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric
5370b57cec5SDimitry Andric // Prints export tables. The export table is a table containing the list of
5380b57cec5SDimitry Andric // exported symbol from the DLL.
printExportTable(const COFFObjectFile * Obj)5390b57cec5SDimitry Andric static void printExportTable(const COFFObjectFile *Obj) {
5400b57cec5SDimitry Andric export_directory_iterator I = Obj->export_directory_begin();
5410b57cec5SDimitry Andric export_directory_iterator E = Obj->export_directory_end();
5420b57cec5SDimitry Andric if (I == E)
5430b57cec5SDimitry Andric return;
54481ad6265SDimitry Andric outs() << "Export Table:\n";
5450b57cec5SDimitry Andric StringRef DllName;
5460b57cec5SDimitry Andric uint32_t OrdinalBase;
5470b57cec5SDimitry Andric if (I->getDllName(DllName))
5480b57cec5SDimitry Andric return;
5490b57cec5SDimitry Andric if (I->getOrdinalBase(OrdinalBase))
5500b57cec5SDimitry Andric return;
5510b57cec5SDimitry Andric outs() << " DLL name: " << DllName << "\n";
5520b57cec5SDimitry Andric outs() << " Ordinal base: " << OrdinalBase << "\n";
5530b57cec5SDimitry Andric outs() << " Ordinal RVA Name\n";
5540b57cec5SDimitry Andric for (; I != E; I = ++I) {
5550b57cec5SDimitry Andric uint32_t RVA;
5560b57cec5SDimitry Andric if (I->getExportRVA(RVA))
5570b57cec5SDimitry Andric return;
55806c3fb27SDimitry Andric StringRef Name;
55906c3fb27SDimitry Andric if (I->getSymbolName(Name))
56006c3fb27SDimitry Andric continue;
56106c3fb27SDimitry Andric if (!RVA && Name.empty())
56206c3fb27SDimitry Andric continue;
56306c3fb27SDimitry Andric
56406c3fb27SDimitry Andric uint32_t Ordinal;
56506c3fb27SDimitry Andric if (I->getOrdinal(Ordinal))
56606c3fb27SDimitry Andric return;
5670b57cec5SDimitry Andric bool IsForwarder;
5680b57cec5SDimitry Andric if (I->isForwarder(IsForwarder))
5690b57cec5SDimitry Andric return;
5700b57cec5SDimitry Andric
5710b57cec5SDimitry Andric if (IsForwarder) {
5720b57cec5SDimitry Andric // Export table entries can be used to re-export symbols that
5730b57cec5SDimitry Andric // this COFF file is imported from some DLLs. This is rare.
5740b57cec5SDimitry Andric // In most cases IsForwarder is false.
57506c3fb27SDimitry Andric outs() << format(" %5d ", Ordinal);
5760b57cec5SDimitry Andric } else {
57706c3fb27SDimitry Andric outs() << format(" %5d %# 8x", Ordinal, RVA);
5780b57cec5SDimitry Andric }
5790b57cec5SDimitry Andric
5800b57cec5SDimitry Andric if (!Name.empty())
5810b57cec5SDimitry Andric outs() << " " << Name;
5820b57cec5SDimitry Andric if (IsForwarder) {
5830b57cec5SDimitry Andric StringRef S;
5840b57cec5SDimitry Andric if (I->getForwardTo(S))
5850b57cec5SDimitry Andric return;
5860b57cec5SDimitry Andric outs() << " (forwarded to " << S << ")";
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric outs() << "\n";
5890b57cec5SDimitry Andric }
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric
5920b57cec5SDimitry Andric // Given the COFF object file, this function returns the relocations for .pdata
5930b57cec5SDimitry Andric // and the pointer to "runtime function" structs.
getPDataSection(const COFFObjectFile * Obj,std::vector<RelocationRef> & Rels,const RuntimeFunction * & RFStart,int & NumRFs)5940b57cec5SDimitry Andric static bool getPDataSection(const COFFObjectFile *Obj,
5950b57cec5SDimitry Andric std::vector<RelocationRef> &Rels,
5960b57cec5SDimitry Andric const RuntimeFunction *&RFStart, int &NumRFs) {
5970b57cec5SDimitry Andric for (const SectionRef &Section : Obj->sections()) {
5988bcb0991SDimitry Andric StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
5990b57cec5SDimitry Andric if (Name != ".pdata")
6000b57cec5SDimitry Andric continue;
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric const coff_section *Pdata = Obj->getCOFFSection(Section);
603fe6060f1SDimitry Andric append_range(Rels, Section.relocations());
6040b57cec5SDimitry Andric
6050b57cec5SDimitry Andric // Sort relocations by address.
6060b57cec5SDimitry Andric llvm::sort(Rels, isRelocAddressLess);
6070b57cec5SDimitry Andric
6080b57cec5SDimitry Andric ArrayRef<uint8_t> Contents;
6098bcb0991SDimitry Andric if (Error E = Obj->getSectionContents(Pdata, Contents))
6108bcb0991SDimitry Andric reportError(std::move(E), Obj->getFileName());
6118bcb0991SDimitry Andric
6120b57cec5SDimitry Andric if (Contents.empty())
6130b57cec5SDimitry Andric continue;
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
6160b57cec5SDimitry Andric NumRFs = Contents.size() / sizeof(RuntimeFunction);
6170b57cec5SDimitry Andric return true;
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric return false;
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric
getCOFFRelocationValueString(const COFFObjectFile * Obj,const RelocationRef & Rel,SmallVectorImpl<char> & Result)6225ffd83dbSDimitry Andric Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,
6230b57cec5SDimitry Andric const RelocationRef &Rel,
6240b57cec5SDimitry Andric SmallVectorImpl<char> &Result) {
6250b57cec5SDimitry Andric symbol_iterator SymI = Rel.getSymbol();
6260b57cec5SDimitry Andric Expected<StringRef> SymNameOrErr = SymI->getName();
6270b57cec5SDimitry Andric if (!SymNameOrErr)
6280b57cec5SDimitry Andric return SymNameOrErr.takeError();
6290b57cec5SDimitry Andric StringRef SymName = *SymNameOrErr;
6300b57cec5SDimitry Andric Result.append(SymName.begin(), SymName.end());
6310b57cec5SDimitry Andric return Error::success();
6320b57cec5SDimitry Andric }
6330b57cec5SDimitry Andric
printWin64EHUnwindInfo(const Win64EH::UnwindInfo * UI)6340b57cec5SDimitry Andric static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
6350b57cec5SDimitry Andric // The casts to int are required in order to output the value as number.
6360b57cec5SDimitry Andric // Without the casts the value would be interpreted as char data (which
6370b57cec5SDimitry Andric // results in garbage output).
6380b57cec5SDimitry Andric outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n";
6390b57cec5SDimitry Andric outs() << " Flags: " << static_cast<int>(UI->getFlags());
6400b57cec5SDimitry Andric if (UI->getFlags()) {
6410b57cec5SDimitry Andric if (UI->getFlags() & UNW_ExceptionHandler)
6420b57cec5SDimitry Andric outs() << " UNW_ExceptionHandler";
6430b57cec5SDimitry Andric if (UI->getFlags() & UNW_TerminateHandler)
6440b57cec5SDimitry Andric outs() << " UNW_TerminateHandler";
6450b57cec5SDimitry Andric if (UI->getFlags() & UNW_ChainInfo)
6460b57cec5SDimitry Andric outs() << " UNW_ChainInfo";
6470b57cec5SDimitry Andric }
6480b57cec5SDimitry Andric outs() << "\n";
6490b57cec5SDimitry Andric outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
6500b57cec5SDimitry Andric outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
6510b57cec5SDimitry Andric // Maybe this should move to output of UOP_SetFPReg?
6520b57cec5SDimitry Andric if (UI->getFrameRegister()) {
6530b57cec5SDimitry Andric outs() << " Frame register: "
6540b57cec5SDimitry Andric << getUnwindRegisterName(UI->getFrameRegister()) << "\n";
6550b57cec5SDimitry Andric outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";
6560b57cec5SDimitry Andric } else {
6570b57cec5SDimitry Andric outs() << " No frame pointer used\n";
6580b57cec5SDimitry Andric }
6590b57cec5SDimitry Andric if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
6600b57cec5SDimitry Andric // FIXME: Output exception handler data
6610b57cec5SDimitry Andric } else if (UI->getFlags() & UNW_ChainInfo) {
6620b57cec5SDimitry Andric // FIXME: Output chained unwind info
6630b57cec5SDimitry Andric }
6640b57cec5SDimitry Andric
6650b57cec5SDimitry Andric if (UI->NumCodes)
6660b57cec5SDimitry Andric outs() << " Unwind Codes:\n";
6670b57cec5SDimitry Andric
668bdd1243dSDimitry Andric printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
6690b57cec5SDimitry Andric
6700b57cec5SDimitry Andric outs() << "\n";
6710b57cec5SDimitry Andric outs().flush();
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric
6740b57cec5SDimitry Andric /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
6750b57cec5SDimitry Andric /// pointing to an executable file.
printRuntimeFunction(const COFFObjectFile * Obj,const RuntimeFunction & RF)6760b57cec5SDimitry Andric static void printRuntimeFunction(const COFFObjectFile *Obj,
6770b57cec5SDimitry Andric const RuntimeFunction &RF) {
6780b57cec5SDimitry Andric if (!RF.StartAddress)
6790b57cec5SDimitry Andric return;
6800b57cec5SDimitry Andric outs() << "Function Table:\n"
6810b57cec5SDimitry Andric << format(" Start Address: 0x%04x\n",
6820b57cec5SDimitry Andric static_cast<uint32_t>(RF.StartAddress))
6830b57cec5SDimitry Andric << format(" End Address: 0x%04x\n",
6840b57cec5SDimitry Andric static_cast<uint32_t>(RF.EndAddress))
6850b57cec5SDimitry Andric << format(" Unwind Info Address: 0x%04x\n",
6860b57cec5SDimitry Andric static_cast<uint32_t>(RF.UnwindInfoOffset));
6870b57cec5SDimitry Andric uintptr_t addr;
6880b57cec5SDimitry Andric if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
6890b57cec5SDimitry Andric return;
6900b57cec5SDimitry Andric printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
6910b57cec5SDimitry Andric }
6920b57cec5SDimitry Andric
6930b57cec5SDimitry Andric /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
6940b57cec5SDimitry Andric /// pointing to an object file. Unlike executable, fields in RuntimeFunction
6950b57cec5SDimitry Andric /// struct are filled with zeros, but instead there are relocations pointing to
6960b57cec5SDimitry Andric /// them so that the linker will fill targets' RVAs to the fields at link
6970b57cec5SDimitry Andric /// time. This function interprets the relocations to find the data to be used
6980b57cec5SDimitry Andric /// in the resulting executable.
printRuntimeFunctionRels(const COFFObjectFile * Obj,const RuntimeFunction & RF,uint64_t SectionOffset,const std::vector<RelocationRef> & Rels)6990b57cec5SDimitry Andric static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
7000b57cec5SDimitry Andric const RuntimeFunction &RF,
7010b57cec5SDimitry Andric uint64_t SectionOffset,
7020b57cec5SDimitry Andric const std::vector<RelocationRef> &Rels) {
7030b57cec5SDimitry Andric outs() << "Function Table:\n";
7040b57cec5SDimitry Andric outs() << " Start Address: ";
7050b57cec5SDimitry Andric printCOFFSymbolAddress(outs(), Rels,
7060b57cec5SDimitry Andric SectionOffset +
7070b57cec5SDimitry Andric /*offsetof(RuntimeFunction, StartAddress)*/ 0,
7080b57cec5SDimitry Andric RF.StartAddress);
7090b57cec5SDimitry Andric outs() << "\n";
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric outs() << " End Address: ";
7120b57cec5SDimitry Andric printCOFFSymbolAddress(outs(), Rels,
7130b57cec5SDimitry Andric SectionOffset +
7140b57cec5SDimitry Andric /*offsetof(RuntimeFunction, EndAddress)*/ 4,
7150b57cec5SDimitry Andric RF.EndAddress);
7160b57cec5SDimitry Andric outs() << "\n";
7170b57cec5SDimitry Andric
7180b57cec5SDimitry Andric outs() << " Unwind Info Address: ";
7190b57cec5SDimitry Andric printCOFFSymbolAddress(outs(), Rels,
7200b57cec5SDimitry Andric SectionOffset +
7210b57cec5SDimitry Andric /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
7220b57cec5SDimitry Andric RF.UnwindInfoOffset);
7230b57cec5SDimitry Andric outs() << "\n";
7240b57cec5SDimitry Andric
7250b57cec5SDimitry Andric ArrayRef<uint8_t> XContents;
7260b57cec5SDimitry Andric uint64_t UnwindInfoOffset = 0;
7278bcb0991SDimitry Andric if (Error E = getSectionContents(
7288bcb0991SDimitry Andric Obj, Rels,
7298bcb0991SDimitry Andric SectionOffset +
7300b57cec5SDimitry Andric /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
7318bcb0991SDimitry Andric XContents, UnwindInfoOffset))
7328bcb0991SDimitry Andric reportError(std::move(E), Obj->getFileName());
7330b57cec5SDimitry Andric if (XContents.empty())
7340b57cec5SDimitry Andric return;
7350b57cec5SDimitry Andric
7360b57cec5SDimitry Andric UnwindInfoOffset += RF.UnwindInfoOffset;
7370b57cec5SDimitry Andric if (UnwindInfoOffset > XContents.size())
7380b57cec5SDimitry Andric return;
7390b57cec5SDimitry Andric
7400b57cec5SDimitry Andric auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
7410b57cec5SDimitry Andric UnwindInfoOffset);
7420b57cec5SDimitry Andric printWin64EHUnwindInfo(UI);
7430b57cec5SDimitry Andric }
7440b57cec5SDimitry Andric
printCOFFUnwindInfo(const COFFObjectFile * Obj)7455ffd83dbSDimitry Andric void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
7460b57cec5SDimitry Andric if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
7470b57cec5SDimitry Andric WithColor::error(errs(), "llvm-objdump")
7480b57cec5SDimitry Andric << "unsupported image machine type "
7490b57cec5SDimitry Andric "(currently only AMD64 is supported).\n";
7500b57cec5SDimitry Andric return;
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric
7530b57cec5SDimitry Andric std::vector<RelocationRef> Rels;
7540b57cec5SDimitry Andric const RuntimeFunction *RFStart;
7550b57cec5SDimitry Andric int NumRFs;
7560b57cec5SDimitry Andric if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
7570b57cec5SDimitry Andric return;
7580b57cec5SDimitry Andric ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
7590b57cec5SDimitry Andric
7600b57cec5SDimitry Andric bool IsExecutable = Rels.empty();
7610b57cec5SDimitry Andric if (IsExecutable) {
7620b57cec5SDimitry Andric for (const RuntimeFunction &RF : RFs)
7630b57cec5SDimitry Andric printRuntimeFunction(Obj, RF);
7640b57cec5SDimitry Andric return;
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric
7670b57cec5SDimitry Andric for (const RuntimeFunction &RF : RFs) {
7680b57cec5SDimitry Andric uint64_t SectionOffset =
7690b57cec5SDimitry Andric std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
7700b57cec5SDimitry Andric printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric }
7730b57cec5SDimitry Andric
printPrivateHeaders()774*5f757f3fSDimitry Andric void COFFDumper::printPrivateHeaders() {
775349cc55cSDimitry Andric COFFDumper CD(Obj);
776349cc55cSDimitry Andric const uint16_t Cha = Obj.getCharacteristics();
777349cc55cSDimitry Andric outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';
778349cc55cSDimitry Andric #define FLAG(F, Name) \
779349cc55cSDimitry Andric if (Cha & F) \
780349cc55cSDimitry Andric outs() << '\t' << Name << '\n';
781349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");
782349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");
783349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");
784349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");
785349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");
786349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");
787349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");
788349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");
789349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,
790349cc55cSDimitry Andric "copy to swap file if on removable media");
791349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,
792349cc55cSDimitry Andric "copy to swap file if on network media");
793349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");
794349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_DLL, "DLL");
795349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");
796349cc55cSDimitry Andric FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");
797349cc55cSDimitry Andric #undef FLAG
798349cc55cSDimitry Andric
799349cc55cSDimitry Andric // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.
800349cc55cSDimitry Andric // Since ctime(3) returns a 26 character string of the form:
801349cc55cSDimitry Andric // "Sun Sep 16 01:03:52 1973\n\0"
802349cc55cSDimitry Andric // just print 24 characters.
803349cc55cSDimitry Andric const time_t Timestamp = Obj.getTimeDateStamp();
804349cc55cSDimitry Andric outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp));
805349cc55cSDimitry Andric
806349cc55cSDimitry Andric if (const pe32_header *Hdr = Obj.getPE32Header())
807349cc55cSDimitry Andric CD.printPEHeader<pe32_header>(*Hdr);
808349cc55cSDimitry Andric else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())
809349cc55cSDimitry Andric CD.printPEHeader<pe32plus_header>(*Hdr);
810349cc55cSDimitry Andric
811349cc55cSDimitry Andric printTLSDirectory(&Obj);
812349cc55cSDimitry Andric printLoadConfiguration(&Obj);
813349cc55cSDimitry Andric printImportTables(&Obj);
814349cc55cSDimitry Andric printExportTable(&Obj);
8150b57cec5SDimitry Andric }
8160b57cec5SDimitry Andric
printCOFFSymbolTable(const object::COFFImportFile & i)817753f127fSDimitry Andric void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {
8180b57cec5SDimitry Andric unsigned Index = 0;
819753f127fSDimitry Andric bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
8200b57cec5SDimitry Andric
821753f127fSDimitry Andric for (const object::BasicSymbolRef &Sym : i.symbols()) {
8220b57cec5SDimitry Andric std::string Name;
8230b57cec5SDimitry Andric raw_string_ostream NS(Name);
8240b57cec5SDimitry Andric
8250b57cec5SDimitry Andric cantFail(Sym.printName(NS));
8260b57cec5SDimitry Andric NS.flush();
8270b57cec5SDimitry Andric
8280b57cec5SDimitry Andric outs() << "[" << format("%2d", Index) << "]"
8290b57cec5SDimitry Andric << "(sec " << format("%2d", 0) << ")"
8300b57cec5SDimitry Andric << "(fl 0x00)" // Flag bits, which COFF doesn't have.
8310b57cec5SDimitry Andric << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"
8320b57cec5SDimitry Andric << "(scl " << format("%3x", 0) << ") "
8330b57cec5SDimitry Andric << "(nx " << 0 << ") "
8340b57cec5SDimitry Andric << "0x" << format("%08x", 0) << " " << Name << '\n';
8350b57cec5SDimitry Andric
8360b57cec5SDimitry Andric ++Index;
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric
printCOFFSymbolTable(const COFFObjectFile & coff)840753f127fSDimitry Andric void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {
841753f127fSDimitry Andric for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {
842753f127fSDimitry Andric Expected<COFFSymbolRef> Symbol = coff.getSymbol(SI);
8438bcb0991SDimitry Andric if (!Symbol)
844753f127fSDimitry Andric reportError(Symbol.takeError(), coff.getFileName());
8458bcb0991SDimitry Andric
846753f127fSDimitry Andric Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);
8475ffd83dbSDimitry Andric if (!NameOrErr)
848753f127fSDimitry Andric reportError(NameOrErr.takeError(), coff.getFileName());
8495ffd83dbSDimitry Andric StringRef Name = *NameOrErr;
8500b57cec5SDimitry Andric
8510b57cec5SDimitry Andric outs() << "[" << format("%2d", SI) << "]"
8520b57cec5SDimitry Andric << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
8530b57cec5SDimitry Andric << "(fl 0x00)" // Flag bits, which COFF doesn't have.
8540b57cec5SDimitry Andric << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
8550b57cec5SDimitry Andric << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))
8560b57cec5SDimitry Andric << ") "
8570b57cec5SDimitry Andric << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
8580b57cec5SDimitry Andric << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
8590b57cec5SDimitry Andric << Name;
860*5f757f3fSDimitry Andric if (Demangle && Name.starts_with("?")) {
8610b57cec5SDimitry Andric int Status = -1;
86206c3fb27SDimitry Andric char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);
8630b57cec5SDimitry Andric
8640b57cec5SDimitry Andric if (Status == 0 && DemangledSymbol) {
8650b57cec5SDimitry Andric outs() << " (" << StringRef(DemangledSymbol) << ")";
8660b57cec5SDimitry Andric std::free(DemangledSymbol);
8670b57cec5SDimitry Andric } else {
8680b57cec5SDimitry Andric outs() << " (invalid mangled name)";
8690b57cec5SDimitry Andric }
8700b57cec5SDimitry Andric }
8710b57cec5SDimitry Andric outs() << "\n";
8720b57cec5SDimitry Andric
8730b57cec5SDimitry Andric for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
8740b57cec5SDimitry Andric if (Symbol->isSectionDefinition()) {
8750b57cec5SDimitry Andric const coff_aux_section_definition *asd;
8765ffd83dbSDimitry Andric if (Error E =
877753f127fSDimitry Andric coff.getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))
878753f127fSDimitry Andric reportError(std::move(E), coff.getFileName());
8790b57cec5SDimitry Andric
8800b57cec5SDimitry Andric int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
8810b57cec5SDimitry Andric
8820b57cec5SDimitry Andric outs() << "AUX "
8830b57cec5SDimitry Andric << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
8840b57cec5SDimitry Andric , unsigned(asd->Length)
8850b57cec5SDimitry Andric , unsigned(asd->NumberOfRelocations)
8860b57cec5SDimitry Andric , unsigned(asd->NumberOfLinenumbers)
8870b57cec5SDimitry Andric , unsigned(asd->CheckSum))
8880b57cec5SDimitry Andric << format("assoc %d comdat %d\n"
8890b57cec5SDimitry Andric , unsigned(AuxNumber)
8900b57cec5SDimitry Andric , unsigned(asd->Selection));
8910b57cec5SDimitry Andric } else if (Symbol->isFileRecord()) {
8920b57cec5SDimitry Andric const char *FileName;
893753f127fSDimitry Andric if (Error E = coff.getAuxSymbol<char>(SI + 1, FileName))
894753f127fSDimitry Andric reportError(std::move(E), coff.getFileName());
8950b57cec5SDimitry Andric
8960b57cec5SDimitry Andric StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
897753f127fSDimitry Andric coff.getSymbolTableEntrySize());
8980b57cec5SDimitry Andric outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';
8990b57cec5SDimitry Andric
9000b57cec5SDimitry Andric SI = SI + Symbol->getNumberOfAuxSymbols();
9010b57cec5SDimitry Andric break;
9020b57cec5SDimitry Andric } else if (Symbol->isWeakExternal()) {
9030b57cec5SDimitry Andric const coff_aux_weak_external *awe;
904753f127fSDimitry Andric if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))
905753f127fSDimitry Andric reportError(std::move(E), coff.getFileName());
9060b57cec5SDimitry Andric
9070b57cec5SDimitry Andric outs() << "AUX " << format("indx %d srch %d\n",
9080b57cec5SDimitry Andric static_cast<uint32_t>(awe->TagIndex),
9090b57cec5SDimitry Andric static_cast<uint32_t>(awe->Characteristics));
9100b57cec5SDimitry Andric } else {
9110b57cec5SDimitry Andric outs() << "AUX Unknown\n";
9120b57cec5SDimitry Andric }
9130b57cec5SDimitry Andric }
9140b57cec5SDimitry Andric }
9150b57cec5SDimitry Andric }
916