[RISCV] Eliminate dead li after emitting VSETVLIs (#65934)
[llvm-project.git] / llvm / tools / llvm-objdump / COFFDump.cpp
blob71697fa01e627d4cadeef6ea1418df9a62e785b5
1 //===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements the COFF-specific dumper for llvm-objdump.
11 /// It outputs the Win64 EH data structures as plain text.
12 /// The encoding of the unwind codes is described in MSDN:
13 /// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64
14 ///
15 //===----------------------------------------------------------------------===//
17 #include "COFFDump.h"
19 #include "llvm-objdump.h"
20 #include "llvm/Demangle/Demangle.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/COFFImportFile.h"
23 #include "llvm/Object/ObjectFile.h"
24 #include "llvm/Support/Format.h"
25 #include "llvm/Support/Win64EH.h"
26 #include "llvm/Support/WithColor.h"
27 #include "llvm/Support/raw_ostream.h"
29 using namespace llvm;
30 using namespace llvm::objdump;
31 using namespace llvm::object;
32 using namespace llvm::Win64EH;
34 namespace {
35 template <typename T> struct EnumEntry {
36 T Value;
37 StringRef Name;
40 class COFFDumper : public Dumper {
41 public:
42 explicit COFFDumper(const llvm::object::COFFObjectFile &O)
43 : Dumper(O), Obj(O) {
44 Is64 = !Obj.getPE32Header();
47 template <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
48 void printPrivateHeaders() override;
50 private:
51 template <typename T> FormattedNumber formatAddr(T V) const {
52 return format_hex_no_prefix(V, Is64 ? 16 : 8);
55 uint32_t getBaseOfData(const void *Hdr) const {
56 return Is64 ? 0 : static_cast<const pe32_header *>(Hdr)->BaseOfData;
59 const llvm::object::COFFObjectFile &Obj;
60 bool Is64;
62 } // namespace
64 std::unique_ptr<Dumper>
65 objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
66 return std::make_unique<COFFDumper>(Obj);
69 constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
70 {uint16_t(COFF::PE32Header::PE32), "PE32"},
71 {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},
74 constexpr EnumEntry<COFF::WindowsSubsystem> PEWindowsSubsystem[] = {
75 {COFF::IMAGE_SUBSYSTEM_UNKNOWN, "unspecified"},
76 {COFF::IMAGE_SUBSYSTEM_NATIVE, "NT native"},
77 {COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI, "Windows GUI"},
78 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI, "Windows CUI"},
79 {COFF::IMAGE_SUBSYSTEM_POSIX_CUI, "POSIX CUI"},
80 {COFF::IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, "Wince CUI"},
81 {COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION, "EFI application"},
82 {COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, "EFI boot service driver"},
83 {COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, "EFI runtime driver"},
84 {COFF::IMAGE_SUBSYSTEM_EFI_ROM, "SAL runtime driver"},
85 {COFF::IMAGE_SUBSYSTEM_XBOX, "XBOX"},
88 template <typename T, typename TEnum>
89 static void printOptionalEnumName(T Value,
90 ArrayRef<EnumEntry<TEnum>> EnumValues) {
91 for (const EnumEntry<TEnum> &I : EnumValues)
92 if (I.Value == Value) {
93 outs() << "\t(" << I.Name << ')';
94 return;
98 template <class PEHeader>
99 void COFFDumper::printPEHeader(const PEHeader &Hdr) const {
100 auto print = [](const char *K, auto V, const char *Fmt = "%d\n") {
101 outs() << format("%-23s ", K) << format(Fmt, V);
103 auto printU16 = [&](const char *K, support::ulittle16_t V,
104 const char *Fmt = "%d\n") { print(K, uint16_t(V), Fmt); };
105 auto printU32 = [&](const char *K, support::ulittle32_t V,
106 const char *Fmt = "%d\n") { print(K, uint32_t(V), Fmt); };
107 auto printAddr = [=](const char *K, uint64_t V) {
108 outs() << format("%-23s ", K) << formatAddr(V) << '\n';
111 printU16("Magic", Hdr.Magic, "%04x");
112 printOptionalEnumName(Hdr.Magic, ArrayRef(PEHeaderMagic));
113 outs() << '\n';
114 print("MajorLinkerVersion", Hdr.MajorLinkerVersion);
115 print("MinorLinkerVersion", Hdr.MinorLinkerVersion);
116 printAddr("SizeOfCode", Hdr.SizeOfCode);
117 printAddr("SizeOfInitializedData", Hdr.SizeOfInitializedData);
118 printAddr("SizeOfUninitializedData", Hdr.SizeOfUninitializedData);
119 printAddr("AddressOfEntryPoint", Hdr.AddressOfEntryPoint);
120 printAddr("BaseOfCode", Hdr.BaseOfCode);
121 if (!Is64)
122 printAddr("BaseOfData", getBaseOfData(&Hdr));
123 printAddr("ImageBase", Hdr.ImageBase);
124 printU32("SectionAlignment", Hdr.SectionAlignment, "%08x\n");
125 printU32("FileAlignment", Hdr.FileAlignment, "%08x\n");
126 printU16("MajorOSystemVersion", Hdr.MajorOperatingSystemVersion);
127 printU16("MinorOSystemVersion", Hdr.MinorOperatingSystemVersion);
128 printU16("MajorImageVersion", Hdr.MajorImageVersion);
129 printU16("MinorImageVersion", Hdr.MinorImageVersion);
130 printU16("MajorSubsystemVersion", Hdr.MajorSubsystemVersion);
131 printU16("MinorSubsystemVersion", Hdr.MinorSubsystemVersion);
132 printU32("Win32Version", Hdr.Win32VersionValue, "%08x\n");
133 printU32("SizeOfImage", Hdr.SizeOfImage, "%08x\n");
134 printU32("SizeOfHeaders", Hdr.SizeOfHeaders, "%08x\n");
135 printU32("CheckSum", Hdr.CheckSum, "%08x\n");
136 printU16("Subsystem", Hdr.Subsystem, "%08x");
137 printOptionalEnumName(Hdr.Subsystem, ArrayRef(PEWindowsSubsystem));
138 outs() << '\n';
140 printU16("DllCharacteristics", Hdr.DLLCharacteristics, "%08x\n");
141 #define FLAG(Name) \
142 if (Hdr.DLLCharacteristics & COFF::IMAGE_DLL_CHARACTERISTICS_##Name) \
143 outs() << "\t\t\t\t\t" << #Name << '\n';
144 FLAG(HIGH_ENTROPY_VA);
145 FLAG(DYNAMIC_BASE);
146 FLAG(FORCE_INTEGRITY);
147 FLAG(NX_COMPAT);
148 FLAG(NO_ISOLATION);
149 FLAG(NO_SEH);
150 FLAG(NO_BIND);
151 FLAG(APPCONTAINER);
152 FLAG(WDM_DRIVER);
153 FLAG(GUARD_CF);
154 FLAG(TERMINAL_SERVER_AWARE);
155 #undef FLAG
157 printAddr("SizeOfStackReserve", Hdr.SizeOfStackReserve);
158 printAddr("SizeOfStackCommit", Hdr.SizeOfStackCommit);
159 printAddr("SizeOfHeapReserve", Hdr.SizeOfHeapReserve);
160 printAddr("SizeOfHeapCommit", Hdr.SizeOfHeapCommit);
161 printU32("LoaderFlags", Hdr.LoaderFlags, "%08x\n");
162 printU32("NumberOfRvaAndSizes", Hdr.NumberOfRvaAndSize, "%08x\n");
164 static const char *DirName[COFF::NUM_DATA_DIRECTORIES + 1] = {
165 "Export Directory [.edata (or where ever we found it)]",
166 "Import Directory [parts of .idata]",
167 "Resource Directory [.rsrc]",
168 "Exception Directory [.pdata]",
169 "Security Directory",
170 "Base Relocation Directory [.reloc]",
171 "Debug Directory",
172 "Description Directory",
173 "Special Directory",
174 "Thread Storage Directory [.tls]",
175 "Load Configuration Directory",
176 "Bound Import Directory",
177 "Import Address Table Directory",
178 "Delay Import Directory",
179 "CLR Runtime Header",
180 "Reserved",
182 outs() << "\nThe Data Directory\n";
183 for (uint32_t I = 0; I != std::size(DirName); ++I) {
184 uint32_t Addr = 0, Size = 0;
185 if (const data_directory *Data = Obj.getDataDirectory(I)) {
186 Addr = Data->RelativeVirtualAddress;
187 Size = Data->Size;
189 outs() << format("Entry %x ", I) << formatAddr(Addr)
190 << format(" %08x %s\n", uint32_t(Size), DirName[I]);
194 // Returns the name of the unwind code.
195 static StringRef getUnwindCodeTypeName(uint8_t Code) {
196 switch(Code) {
197 default: llvm_unreachable("Invalid unwind code");
198 case UOP_PushNonVol: return "UOP_PushNonVol";
199 case UOP_AllocLarge: return "UOP_AllocLarge";
200 case UOP_AllocSmall: return "UOP_AllocSmall";
201 case UOP_SetFPReg: return "UOP_SetFPReg";
202 case UOP_SaveNonVol: return "UOP_SaveNonVol";
203 case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
204 case UOP_Epilog: return "UOP_Epilog";
205 case UOP_SpareCode: return "UOP_SpareCode";
206 case UOP_SaveXMM128: return "UOP_SaveXMM128";
207 case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
208 case UOP_PushMachFrame: return "UOP_PushMachFrame";
212 // Returns the name of a referenced register.
213 static StringRef getUnwindRegisterName(uint8_t Reg) {
214 switch(Reg) {
215 default: llvm_unreachable("Invalid register");
216 case 0: return "RAX";
217 case 1: return "RCX";
218 case 2: return "RDX";
219 case 3: return "RBX";
220 case 4: return "RSP";
221 case 5: return "RBP";
222 case 6: return "RSI";
223 case 7: return "RDI";
224 case 8: return "R8";
225 case 9: return "R9";
226 case 10: return "R10";
227 case 11: return "R11";
228 case 12: return "R12";
229 case 13: return "R13";
230 case 14: return "R14";
231 case 15: return "R15";
235 // Calculates the number of array slots required for the unwind code.
236 static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
237 switch (UnwindCode.getUnwindOp()) {
238 default: llvm_unreachable("Invalid unwind code");
239 case UOP_PushNonVol:
240 case UOP_AllocSmall:
241 case UOP_SetFPReg:
242 case UOP_PushMachFrame:
243 return 1;
244 case UOP_SaveNonVol:
245 case UOP_SaveXMM128:
246 case UOP_Epilog:
247 return 2;
248 case UOP_SaveNonVolBig:
249 case UOP_SaveXMM128Big:
250 case UOP_SpareCode:
251 return 3;
252 case UOP_AllocLarge:
253 return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
257 // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
258 // the unwind codes array, this function requires that the correct number of
259 // slots is provided.
260 static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
261 assert(UCs.size() >= getNumUsedSlots(UCs[0]));
262 outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))
263 << getUnwindCodeTypeName(UCs[0].getUnwindOp());
264 switch (UCs[0].getUnwindOp()) {
265 case UOP_PushNonVol:
266 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
267 break;
268 case UOP_AllocLarge:
269 if (UCs[0].getOpInfo() == 0) {
270 outs() << " " << UCs[1].FrameOffset;
271 } else {
272 outs() << " " << UCs[1].FrameOffset
273 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
275 break;
276 case UOP_AllocSmall:
277 outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
278 break;
279 case UOP_SetFPReg:
280 outs() << " ";
281 break;
282 case UOP_SaveNonVol:
283 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
284 << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
285 break;
286 case UOP_SaveNonVolBig:
287 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
288 << format(" [0x%08x]", UCs[1].FrameOffset
289 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
290 break;
291 case UOP_SaveXMM128:
292 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
293 << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
294 break;
295 case UOP_SaveXMM128Big:
296 outs() << " XMM" << UCs[0].getOpInfo()
297 << format(" [0x%08x]", UCs[1].FrameOffset
298 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
299 break;
300 case UOP_PushMachFrame:
301 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
302 << " error code";
303 break;
305 outs() << "\n";
308 static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
309 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
310 unsigned UsedSlots = getNumUsedSlots(*I);
311 if (UsedSlots > UCs.size()) {
312 outs() << "Unwind data corrupted: Encountered unwind op "
313 << getUnwindCodeTypeName((*I).getUnwindOp())
314 << " which requires " << UsedSlots
315 << " slots, but only " << UCs.size()
316 << " remaining in buffer";
317 return ;
319 printUnwindCode(ArrayRef(I, E));
320 I += UsedSlots;
324 // Given a symbol sym this functions returns the address and section of it.
325 static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
326 const SymbolRef &Sym,
327 const coff_section *&ResolvedSection,
328 uint64_t &ResolvedAddr) {
329 Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
330 if (!ResolvedAddrOrErr)
331 return ResolvedAddrOrErr.takeError();
332 ResolvedAddr = *ResolvedAddrOrErr;
333 Expected<section_iterator> Iter = Sym.getSection();
334 if (!Iter)
335 return Iter.takeError();
336 ResolvedSection = Obj->getCOFFSection(**Iter);
337 return Error::success();
340 // Given a vector of relocations for a section and an offset into this section
341 // the function returns the symbol used for the relocation at the offset.
342 static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
343 uint64_t Offset, SymbolRef &Sym) {
344 for (auto &R : Rels) {
345 uint64_t Ofs = R.getOffset();
346 if (Ofs == Offset) {
347 Sym = *R.getSymbol();
348 return Error::success();
351 return make_error<BinaryError>();
354 // Given a vector of relocations for a section and an offset into this section
355 // the function resolves the symbol used for the relocation at the offset and
356 // returns the section content and the address inside the content pointed to
357 // by the symbol.
358 static Error
359 getSectionContents(const COFFObjectFile *Obj,
360 const std::vector<RelocationRef> &Rels, uint64_t Offset,
361 ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
362 SymbolRef Sym;
363 if (Error E = resolveSymbol(Rels, Offset, Sym))
364 return E;
365 const coff_section *Section;
366 if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
367 return E;
368 return Obj->getSectionContents(Section, Contents);
371 // Given a vector of relocations for a section and an offset into this section
372 // the function returns the name of the symbol used for the relocation at the
373 // offset.
374 static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
375 uint64_t Offset, StringRef &Name) {
376 SymbolRef Sym;
377 if (Error EC = resolveSymbol(Rels, Offset, Sym))
378 return EC;
379 Expected<StringRef> NameOrErr = Sym.getName();
380 if (!NameOrErr)
381 return NameOrErr.takeError();
382 Name = *NameOrErr;
383 return Error::success();
386 static void printCOFFSymbolAddress(raw_ostream &Out,
387 const std::vector<RelocationRef> &Rels,
388 uint64_t Offset, uint32_t Disp) {
389 StringRef Sym;
390 if (!resolveSymbolName(Rels, Offset, Sym)) {
391 Out << Sym;
392 if (Disp > 0)
393 Out << format(" + 0x%04x", Disp);
394 } else {
395 Out << format("0x%04x", Disp);
399 static void
400 printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
401 if (Count == 0)
402 return;
404 uintptr_t IntPtr = 0;
405 if (Error E = Obj->getVaPtr(TableVA, IntPtr))
406 reportError(std::move(E), Obj->getFileName());
408 const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
409 outs() << "SEH Table:";
410 for (int I = 0; I < Count; ++I)
411 outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);
412 outs() << "\n\n";
415 template <typename T>
416 static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
417 size_t FormatWidth = sizeof(T) * 2;
418 outs() << "TLS directory:"
419 << "\n StartAddressOfRawData: "
420 << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
421 << "\n EndAddressOfRawData: "
422 << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
423 << "\n AddressOfIndex: "
424 << format_hex(TLSDir->AddressOfIndex, FormatWidth)
425 << "\n AddressOfCallBacks: "
426 << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
427 << "\n SizeOfZeroFill: "
428 << TLSDir->SizeOfZeroFill
429 << "\n Characteristics: "
430 << TLSDir->Characteristics
431 << "\n Alignment: "
432 << TLSDir->getAlignment()
433 << "\n\n";
436 static void printTLSDirectory(const COFFObjectFile *Obj) {
437 const pe32_header *PE32Header = Obj->getPE32Header();
438 const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
440 // Skip if it's not executable.
441 if (!PE32Header && !PE32PlusHeader)
442 return;
444 if (PE32Header) {
445 if (auto *TLSDir = Obj->getTLSDirectory32())
446 printTLSDirectoryT(TLSDir);
447 } else {
448 if (auto *TLSDir = Obj->getTLSDirectory64())
449 printTLSDirectoryT(TLSDir);
452 outs() << "\n";
455 static void printLoadConfiguration(const COFFObjectFile *Obj) {
456 // Skip if it's not executable.
457 if (!Obj->getPE32Header())
458 return;
460 // Currently only x86 is supported
461 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
462 return;
464 auto *LoadConf = Obj->getLoadConfig32();
465 if (!LoadConf)
466 return;
468 outs() << "Load configuration:"
469 << "\n Timestamp: " << LoadConf->TimeDateStamp
470 << "\n Major Version: " << LoadConf->MajorVersion
471 << "\n Minor Version: " << LoadConf->MinorVersion
472 << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
473 << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet
474 << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
475 << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
476 << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
477 << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable
478 << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
479 << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
480 << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask
481 << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags
482 << "\n CSD Version: " << LoadConf->CSDVersion
483 << "\n Security Cookie: " << LoadConf->SecurityCookie
484 << "\n SEH Table: " << LoadConf->SEHandlerTable
485 << "\n SEH Count: " << LoadConf->SEHandlerCount
486 << "\n\n";
487 printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);
488 outs() << "\n";
491 // Prints import tables. The import table is a table containing the list of
492 // DLL name and symbol names which will be linked by the loader.
493 static void printImportTables(const COFFObjectFile *Obj) {
494 import_directory_iterator I = Obj->import_directory_begin();
495 import_directory_iterator E = Obj->import_directory_end();
496 if (I == E)
497 return;
498 outs() << "The Import Tables:\n";
499 for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
500 const coff_import_directory_table_entry *Dir;
501 StringRef Name;
502 if (DirRef.getImportTableEntry(Dir)) return;
503 if (DirRef.getName(Name)) return;
505 outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
506 static_cast<uint32_t>(Dir->ImportLookupTableRVA),
507 static_cast<uint32_t>(Dir->TimeDateStamp),
508 static_cast<uint32_t>(Dir->ForwarderChain),
509 static_cast<uint32_t>(Dir->NameRVA),
510 static_cast<uint32_t>(Dir->ImportAddressTableRVA));
511 outs() << " DLL Name: " << Name << "\n";
512 outs() << " Hint/Ord Name\n";
513 for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
514 bool IsOrdinal;
515 if (Entry.isOrdinal(IsOrdinal))
516 return;
517 if (IsOrdinal) {
518 uint16_t Ordinal;
519 if (Entry.getOrdinal(Ordinal))
520 return;
521 outs() << format(" % 6d\n", Ordinal);
522 continue;
524 uint32_t HintNameRVA;
525 if (Entry.getHintNameRVA(HintNameRVA))
526 return;
527 uint16_t Hint;
528 StringRef Name;
529 if (Obj->getHintName(HintNameRVA, Hint, Name))
530 return;
531 outs() << format(" % 6d ", Hint) << Name << "\n";
533 outs() << "\n";
537 // Prints export tables. The export table is a table containing the list of
538 // exported symbol from the DLL.
539 static void printExportTable(const COFFObjectFile *Obj) {
540 export_directory_iterator I = Obj->export_directory_begin();
541 export_directory_iterator E = Obj->export_directory_end();
542 if (I == E)
543 return;
544 outs() << "Export Table:\n";
545 StringRef DllName;
546 uint32_t OrdinalBase;
547 if (I->getDllName(DllName))
548 return;
549 if (I->getOrdinalBase(OrdinalBase))
550 return;
551 outs() << " DLL name: " << DllName << "\n";
552 outs() << " Ordinal base: " << OrdinalBase << "\n";
553 outs() << " Ordinal RVA Name\n";
554 for (; I != E; I = ++I) {
555 uint32_t RVA;
556 if (I->getExportRVA(RVA))
557 return;
558 StringRef Name;
559 if (I->getSymbolName(Name))
560 continue;
561 if (!RVA && Name.empty())
562 continue;
564 uint32_t Ordinal;
565 if (I->getOrdinal(Ordinal))
566 return;
567 bool IsForwarder;
568 if (I->isForwarder(IsForwarder))
569 return;
571 if (IsForwarder) {
572 // Export table entries can be used to re-export symbols that
573 // this COFF file is imported from some DLLs. This is rare.
574 // In most cases IsForwarder is false.
575 outs() << format(" %5d ", Ordinal);
576 } else {
577 outs() << format(" %5d %# 8x", Ordinal, RVA);
580 if (!Name.empty())
581 outs() << " " << Name;
582 if (IsForwarder) {
583 StringRef S;
584 if (I->getForwardTo(S))
585 return;
586 outs() << " (forwarded to " << S << ")";
588 outs() << "\n";
592 // Given the COFF object file, this function returns the relocations for .pdata
593 // and the pointer to "runtime function" structs.
594 static bool getPDataSection(const COFFObjectFile *Obj,
595 std::vector<RelocationRef> &Rels,
596 const RuntimeFunction *&RFStart, int &NumRFs) {
597 for (const SectionRef &Section : Obj->sections()) {
598 StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
599 if (Name != ".pdata")
600 continue;
602 const coff_section *Pdata = Obj->getCOFFSection(Section);
603 append_range(Rels, Section.relocations());
605 // Sort relocations by address.
606 llvm::sort(Rels, isRelocAddressLess);
608 ArrayRef<uint8_t> Contents;
609 if (Error E = Obj->getSectionContents(Pdata, Contents))
610 reportError(std::move(E), Obj->getFileName());
612 if (Contents.empty())
613 continue;
615 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
616 NumRFs = Contents.size() / sizeof(RuntimeFunction);
617 return true;
619 return false;
622 Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,
623 const RelocationRef &Rel,
624 SmallVectorImpl<char> &Result) {
625 symbol_iterator SymI = Rel.getSymbol();
626 Expected<StringRef> SymNameOrErr = SymI->getName();
627 if (!SymNameOrErr)
628 return SymNameOrErr.takeError();
629 StringRef SymName = *SymNameOrErr;
630 Result.append(SymName.begin(), SymName.end());
631 return Error::success();
634 static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
635 // The casts to int are required in order to output the value as number.
636 // Without the casts the value would be interpreted as char data (which
637 // results in garbage output).
638 outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n";
639 outs() << " Flags: " << static_cast<int>(UI->getFlags());
640 if (UI->getFlags()) {
641 if (UI->getFlags() & UNW_ExceptionHandler)
642 outs() << " UNW_ExceptionHandler";
643 if (UI->getFlags() & UNW_TerminateHandler)
644 outs() << " UNW_TerminateHandler";
645 if (UI->getFlags() & UNW_ChainInfo)
646 outs() << " UNW_ChainInfo";
648 outs() << "\n";
649 outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
650 outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
651 // Maybe this should move to output of UOP_SetFPReg?
652 if (UI->getFrameRegister()) {
653 outs() << " Frame register: "
654 << getUnwindRegisterName(UI->getFrameRegister()) << "\n";
655 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n";
656 } else {
657 outs() << " No frame pointer used\n";
659 if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
660 // FIXME: Output exception handler data
661 } else if (UI->getFlags() & UNW_ChainInfo) {
662 // FIXME: Output chained unwind info
665 if (UI->NumCodes)
666 outs() << " Unwind Codes:\n";
668 printAllUnwindCodes(ArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
670 outs() << "\n";
671 outs().flush();
674 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
675 /// pointing to an executable file.
676 static void printRuntimeFunction(const COFFObjectFile *Obj,
677 const RuntimeFunction &RF) {
678 if (!RF.StartAddress)
679 return;
680 outs() << "Function Table:\n"
681 << format(" Start Address: 0x%04x\n",
682 static_cast<uint32_t>(RF.StartAddress))
683 << format(" End Address: 0x%04x\n",
684 static_cast<uint32_t>(RF.EndAddress))
685 << format(" Unwind Info Address: 0x%04x\n",
686 static_cast<uint32_t>(RF.UnwindInfoOffset));
687 uintptr_t addr;
688 if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
689 return;
690 printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
693 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
694 /// pointing to an object file. Unlike executable, fields in RuntimeFunction
695 /// struct are filled with zeros, but instead there are relocations pointing to
696 /// them so that the linker will fill targets' RVAs to the fields at link
697 /// time. This function interprets the relocations to find the data to be used
698 /// in the resulting executable.
699 static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
700 const RuntimeFunction &RF,
701 uint64_t SectionOffset,
702 const std::vector<RelocationRef> &Rels) {
703 outs() << "Function Table:\n";
704 outs() << " Start Address: ";
705 printCOFFSymbolAddress(outs(), Rels,
706 SectionOffset +
707 /*offsetof(RuntimeFunction, StartAddress)*/ 0,
708 RF.StartAddress);
709 outs() << "\n";
711 outs() << " End Address: ";
712 printCOFFSymbolAddress(outs(), Rels,
713 SectionOffset +
714 /*offsetof(RuntimeFunction, EndAddress)*/ 4,
715 RF.EndAddress);
716 outs() << "\n";
718 outs() << " Unwind Info Address: ";
719 printCOFFSymbolAddress(outs(), Rels,
720 SectionOffset +
721 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
722 RF.UnwindInfoOffset);
723 outs() << "\n";
725 ArrayRef<uint8_t> XContents;
726 uint64_t UnwindInfoOffset = 0;
727 if (Error E = getSectionContents(
728 Obj, Rels,
729 SectionOffset +
730 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
731 XContents, UnwindInfoOffset))
732 reportError(std::move(E), Obj->getFileName());
733 if (XContents.empty())
734 return;
736 UnwindInfoOffset += RF.UnwindInfoOffset;
737 if (UnwindInfoOffset > XContents.size())
738 return;
740 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
741 UnwindInfoOffset);
742 printWin64EHUnwindInfo(UI);
745 void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
746 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
747 WithColor::error(errs(), "llvm-objdump")
748 << "unsupported image machine type "
749 "(currently only AMD64 is supported).\n";
750 return;
753 std::vector<RelocationRef> Rels;
754 const RuntimeFunction *RFStart;
755 int NumRFs;
756 if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
757 return;
758 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
760 bool IsExecutable = Rels.empty();
761 if (IsExecutable) {
762 for (const RuntimeFunction &RF : RFs)
763 printRuntimeFunction(Obj, RF);
764 return;
767 for (const RuntimeFunction &RF : RFs) {
768 uint64_t SectionOffset =
769 std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
770 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
774 void COFFDumper::printPrivateHeaders() {
775 COFFDumper CD(Obj);
776 const uint16_t Cha = Obj.getCharacteristics();
777 outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n';
778 #define FLAG(F, Name) \
779 if (Cha & F) \
780 outs() << '\t' << Name << '\n';
781 FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped");
782 FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable");
783 FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped");
784 FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped");
785 FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware");
786 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian");
787 FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words");
788 FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed");
789 FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP,
790 "copy to swap file if on removable media");
791 FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP,
792 "copy to swap file if on network media");
793 FLAG(COFF::IMAGE_FILE_SYSTEM, "system file");
794 FLAG(COFF::IMAGE_FILE_DLL, "DLL");
795 FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine");
796 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian");
797 #undef FLAG
799 // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO.
800 // Since ctime(3) returns a 26 character string of the form:
801 // "Sun Sep 16 01:03:52 1973\n\0"
802 // just print 24 characters.
803 const time_t Timestamp = Obj.getTimeDateStamp();
804 outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp));
806 if (const pe32_header *Hdr = Obj.getPE32Header())
807 CD.printPEHeader<pe32_header>(*Hdr);
808 else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader())
809 CD.printPEHeader<pe32plus_header>(*Hdr);
811 printTLSDirectory(&Obj);
812 printLoadConfiguration(&Obj);
813 printImportTables(&Obj);
814 printExportTable(&Obj);
817 void objdump::printCOFFSymbolTable(const object::COFFImportFile &i) {
818 unsigned Index = 0;
819 bool IsCode = i.getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
821 for (const object::BasicSymbolRef &Sym : i.symbols()) {
822 std::string Name;
823 raw_string_ostream NS(Name);
825 cantFail(Sym.printName(NS));
826 NS.flush();
828 outs() << "[" << format("%2d", Index) << "]"
829 << "(sec " << format("%2d", 0) << ")"
830 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
831 << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"
832 << "(scl " << format("%3x", 0) << ") "
833 << "(nx " << 0 << ") "
834 << "0x" << format("%08x", 0) << " " << Name << '\n';
836 ++Index;
840 void objdump::printCOFFSymbolTable(const COFFObjectFile &coff) {
841 for (unsigned SI = 0, SE = coff.getNumberOfSymbols(); SI != SE; ++SI) {
842 Expected<COFFSymbolRef> Symbol = coff.getSymbol(SI);
843 if (!Symbol)
844 reportError(Symbol.takeError(), coff.getFileName());
846 Expected<StringRef> NameOrErr = coff.getSymbolName(*Symbol);
847 if (!NameOrErr)
848 reportError(NameOrErr.takeError(), coff.getFileName());
849 StringRef Name = *NameOrErr;
851 outs() << "[" << format("%2d", SI) << "]"
852 << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
853 << "(fl 0x00)" // Flag bits, which COFF doesn't have.
854 << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
855 << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))
856 << ") "
857 << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
858 << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
859 << Name;
860 if (Demangle && Name.starts_with("?")) {
861 int Status = -1;
862 char *DemangledSymbol = microsoftDemangle(Name, nullptr, &Status);
864 if (Status == 0 && DemangledSymbol) {
865 outs() << " (" << StringRef(DemangledSymbol) << ")";
866 std::free(DemangledSymbol);
867 } else {
868 outs() << " (invalid mangled name)";
871 outs() << "\n";
873 for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
874 if (Symbol->isSectionDefinition()) {
875 const coff_aux_section_definition *asd;
876 if (Error E =
877 coff.getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))
878 reportError(std::move(E), coff.getFileName());
880 int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
882 outs() << "AUX "
883 << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
884 , unsigned(asd->Length)
885 , unsigned(asd->NumberOfRelocations)
886 , unsigned(asd->NumberOfLinenumbers)
887 , unsigned(asd->CheckSum))
888 << format("assoc %d comdat %d\n"
889 , unsigned(AuxNumber)
890 , unsigned(asd->Selection));
891 } else if (Symbol->isFileRecord()) {
892 const char *FileName;
893 if (Error E = coff.getAuxSymbol<char>(SI + 1, FileName))
894 reportError(std::move(E), coff.getFileName());
896 StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
897 coff.getSymbolTableEntrySize());
898 outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';
900 SI = SI + Symbol->getNumberOfAuxSymbols();
901 break;
902 } else if (Symbol->isWeakExternal()) {
903 const coff_aux_weak_external *awe;
904 if (Error E = coff.getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))
905 reportError(std::move(E), coff.getFileName());
907 outs() << "AUX " << format("indx %d srch %d\n",
908 static_cast<uint32_t>(awe->TagIndex),
909 static_cast<uint32_t>(awe->Characteristics));
910 } else {
911 outs() << "AUX Unknown\n";