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