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 /// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx 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, makeArrayRef(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, makeArrayRef(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 != array_lengthof(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_SaveXMM128: return "UOP_SaveXMM128"; 198 case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big"; 199 case UOP_PushMachFrame: return "UOP_PushMachFrame"; 200 } 201 } 202 203 // Returns the name of a referenced register. 204 static StringRef getUnwindRegisterName(uint8_t Reg) { 205 switch(Reg) { 206 default: llvm_unreachable("Invalid register"); 207 case 0: return "RAX"; 208 case 1: return "RCX"; 209 case 2: return "RDX"; 210 case 3: return "RBX"; 211 case 4: return "RSP"; 212 case 5: return "RBP"; 213 case 6: return "RSI"; 214 case 7: return "RDI"; 215 case 8: return "R8"; 216 case 9: return "R9"; 217 case 10: return "R10"; 218 case 11: return "R11"; 219 case 12: return "R12"; 220 case 13: return "R13"; 221 case 14: return "R14"; 222 case 15: return "R15"; 223 } 224 } 225 226 // Calculates the number of array slots required for the unwind code. 227 static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { 228 switch (UnwindCode.getUnwindOp()) { 229 default: llvm_unreachable("Invalid unwind code"); 230 case UOP_PushNonVol: 231 case UOP_AllocSmall: 232 case UOP_SetFPReg: 233 case UOP_PushMachFrame: 234 return 1; 235 case UOP_SaveNonVol: 236 case UOP_SaveXMM128: 237 return 2; 238 case UOP_SaveNonVolBig: 239 case UOP_SaveXMM128Big: 240 return 3; 241 case UOP_AllocLarge: 242 return (UnwindCode.getOpInfo() == 0) ? 2 : 3; 243 } 244 } 245 246 // Prints one unwind code. Because an unwind code can occupy up to 3 slots in 247 // the unwind codes array, this function requires that the correct number of 248 // slots is provided. 249 static void printUnwindCode(ArrayRef<UnwindCode> UCs) { 250 assert(UCs.size() >= getNumUsedSlots(UCs[0])); 251 outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) 252 << getUnwindCodeTypeName(UCs[0].getUnwindOp()); 253 switch (UCs[0].getUnwindOp()) { 254 case UOP_PushNonVol: 255 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()); 256 break; 257 case UOP_AllocLarge: 258 if (UCs[0].getOpInfo() == 0) { 259 outs() << " " << UCs[1].FrameOffset; 260 } else { 261 outs() << " " << UCs[1].FrameOffset 262 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); 263 } 264 break; 265 case UOP_AllocSmall: 266 outs() << " " << ((UCs[0].getOpInfo() + 1) * 8); 267 break; 268 case UOP_SetFPReg: 269 outs() << " "; 270 break; 271 case UOP_SaveNonVol: 272 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) 273 << format(" [0x%04x]", 8 * UCs[1].FrameOffset); 274 break; 275 case UOP_SaveNonVolBig: 276 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) 277 << format(" [0x%08x]", UCs[1].FrameOffset 278 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); 279 break; 280 case UOP_SaveXMM128: 281 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) 282 << format(" [0x%04x]", 16 * UCs[1].FrameOffset); 283 break; 284 case UOP_SaveXMM128Big: 285 outs() << " XMM" << UCs[0].getOpInfo() 286 << format(" [0x%08x]", UCs[1].FrameOffset 287 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); 288 break; 289 case UOP_PushMachFrame: 290 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w") 291 << " error code"; 292 break; 293 } 294 outs() << "\n"; 295 } 296 297 static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) { 298 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) { 299 unsigned UsedSlots = getNumUsedSlots(*I); 300 if (UsedSlots > UCs.size()) { 301 outs() << "Unwind data corrupted: Encountered unwind op " 302 << getUnwindCodeTypeName((*I).getUnwindOp()) 303 << " which requires " << UsedSlots 304 << " slots, but only " << UCs.size() 305 << " remaining in buffer"; 306 return ; 307 } 308 printUnwindCode(makeArrayRef(I, E)); 309 I += UsedSlots; 310 } 311 } 312 313 // Given a symbol sym this functions returns the address and section of it. 314 static Error resolveSectionAndAddress(const COFFObjectFile *Obj, 315 const SymbolRef &Sym, 316 const coff_section *&ResolvedSection, 317 uint64_t &ResolvedAddr) { 318 Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress(); 319 if (!ResolvedAddrOrErr) 320 return ResolvedAddrOrErr.takeError(); 321 ResolvedAddr = *ResolvedAddrOrErr; 322 Expected<section_iterator> Iter = Sym.getSection(); 323 if (!Iter) 324 return Iter.takeError(); 325 ResolvedSection = Obj->getCOFFSection(**Iter); 326 return Error::success(); 327 } 328 329 // Given a vector of relocations for a section and an offset into this section 330 // the function returns the symbol used for the relocation at the offset. 331 static Error resolveSymbol(const std::vector<RelocationRef> &Rels, 332 uint64_t Offset, SymbolRef &Sym) { 333 for (auto &R : Rels) { 334 uint64_t Ofs = R.getOffset(); 335 if (Ofs == Offset) { 336 Sym = *R.getSymbol(); 337 return Error::success(); 338 } 339 } 340 return make_error<BinaryError>(); 341 } 342 343 // Given a vector of relocations for a section and an offset into this section 344 // the function resolves the symbol used for the relocation at the offset and 345 // returns the section content and the address inside the content pointed to 346 // by the symbol. 347 static Error 348 getSectionContents(const COFFObjectFile *Obj, 349 const std::vector<RelocationRef> &Rels, uint64_t Offset, 350 ArrayRef<uint8_t> &Contents, uint64_t &Addr) { 351 SymbolRef Sym; 352 if (Error E = resolveSymbol(Rels, Offset, Sym)) 353 return E; 354 const coff_section *Section; 355 if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr)) 356 return E; 357 return Obj->getSectionContents(Section, Contents); 358 } 359 360 // Given a vector of relocations for a section and an offset into this section 361 // the function returns the name of the symbol used for the relocation at the 362 // offset. 363 static Error resolveSymbolName(const std::vector<RelocationRef> &Rels, 364 uint64_t Offset, StringRef &Name) { 365 SymbolRef Sym; 366 if (Error EC = resolveSymbol(Rels, Offset, Sym)) 367 return EC; 368 Expected<StringRef> NameOrErr = Sym.getName(); 369 if (!NameOrErr) 370 return NameOrErr.takeError(); 371 Name = *NameOrErr; 372 return Error::success(); 373 } 374 375 static void printCOFFSymbolAddress(raw_ostream &Out, 376 const std::vector<RelocationRef> &Rels, 377 uint64_t Offset, uint32_t Disp) { 378 StringRef Sym; 379 if (!resolveSymbolName(Rels, Offset, Sym)) { 380 Out << Sym; 381 if (Disp > 0) 382 Out << format(" + 0x%04x", Disp); 383 } else { 384 Out << format("0x%04x", Disp); 385 } 386 } 387 388 static void 389 printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { 390 if (Count == 0) 391 return; 392 393 uintptr_t IntPtr = 0; 394 if (Error E = Obj->getVaPtr(TableVA, IntPtr)) 395 reportError(std::move(E), Obj->getFileName()); 396 397 const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr; 398 outs() << "SEH Table:"; 399 for (int I = 0; I < Count; ++I) 400 outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase); 401 outs() << "\n\n"; 402 } 403 404 template <typename T> 405 static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) { 406 size_t FormatWidth = sizeof(T) * 2; 407 outs() << "TLS directory:" 408 << "\n StartAddressOfRawData: " 409 << format_hex(TLSDir->StartAddressOfRawData, FormatWidth) 410 << "\n EndAddressOfRawData: " 411 << format_hex(TLSDir->EndAddressOfRawData, FormatWidth) 412 << "\n AddressOfIndex: " 413 << format_hex(TLSDir->AddressOfIndex, FormatWidth) 414 << "\n AddressOfCallBacks: " 415 << format_hex(TLSDir->AddressOfCallBacks, FormatWidth) 416 << "\n SizeOfZeroFill: " 417 << TLSDir->SizeOfZeroFill 418 << "\n Characteristics: " 419 << TLSDir->Characteristics 420 << "\n Alignment: " 421 << TLSDir->getAlignment() 422 << "\n\n"; 423 } 424 425 static void printTLSDirectory(const COFFObjectFile *Obj) { 426 const pe32_header *PE32Header = Obj->getPE32Header(); 427 const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader(); 428 429 // Skip if it's not executable. 430 if (!PE32Header && !PE32PlusHeader) 431 return; 432 433 const data_directory *DataDir = Obj->getDataDirectory(COFF::TLS_TABLE); 434 if (!DataDir || DataDir->RelativeVirtualAddress == 0) 435 return; 436 437 uintptr_t IntPtr = 0; 438 if (Error E = 439 Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)) 440 reportError(std::move(E), Obj->getFileName()); 441 442 if (PE32Header) { 443 auto *TLSDir = reinterpret_cast<const coff_tls_directory32 *>(IntPtr); 444 printTLSDirectoryT(TLSDir); 445 } else { 446 auto *TLSDir = reinterpret_cast<const coff_tls_directory64 *>(IntPtr); 447 printTLSDirectoryT(TLSDir); 448 } 449 450 outs() << "\n"; 451 } 452 453 static void printLoadConfiguration(const COFFObjectFile *Obj) { 454 // Skip if it's not executable. 455 if (!Obj->getPE32Header()) 456 return; 457 458 // Currently only x86 is supported 459 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386) 460 return; 461 462 const data_directory *DataDir = Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE); 463 if (!DataDir) 464 reportError("no load config data dir", Obj->getFileName()); 465 466 uintptr_t IntPtr = 0; 467 if (DataDir->RelativeVirtualAddress == 0) 468 return; 469 470 if (Error E = 471 Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr)) 472 reportError(std::move(E), Obj->getFileName()); 473 474 auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr); 475 outs() << "Load configuration:" 476 << "\n Timestamp: " << LoadConf->TimeDateStamp 477 << "\n Major Version: " << LoadConf->MajorVersion 478 << "\n Minor Version: " << LoadConf->MinorVersion 479 << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear 480 << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet 481 << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout 482 << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold 483 << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold 484 << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable 485 << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize 486 << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold 487 << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask 488 << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags 489 << "\n CSD Version: " << LoadConf->CSDVersion 490 << "\n Security Cookie: " << LoadConf->SecurityCookie 491 << "\n SEH Table: " << LoadConf->SEHandlerTable 492 << "\n SEH Count: " << LoadConf->SEHandlerCount 493 << "\n\n"; 494 printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount); 495 outs() << "\n"; 496 } 497 498 // Prints import tables. The import table is a table containing the list of 499 // DLL name and symbol names which will be linked by the loader. 500 static void printImportTables(const COFFObjectFile *Obj) { 501 import_directory_iterator I = Obj->import_directory_begin(); 502 import_directory_iterator E = Obj->import_directory_end(); 503 if (I == E) 504 return; 505 outs() << "The Import Tables:\n"; 506 for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) { 507 const coff_import_directory_table_entry *Dir; 508 StringRef Name; 509 if (DirRef.getImportTableEntry(Dir)) return; 510 if (DirRef.getName(Name)) return; 511 512 outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", 513 static_cast<uint32_t>(Dir->ImportLookupTableRVA), 514 static_cast<uint32_t>(Dir->TimeDateStamp), 515 static_cast<uint32_t>(Dir->ForwarderChain), 516 static_cast<uint32_t>(Dir->NameRVA), 517 static_cast<uint32_t>(Dir->ImportAddressTableRVA)); 518 outs() << " DLL Name: " << Name << "\n"; 519 outs() << " Hint/Ord Name\n"; 520 for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) { 521 bool IsOrdinal; 522 if (Entry.isOrdinal(IsOrdinal)) 523 return; 524 if (IsOrdinal) { 525 uint16_t Ordinal; 526 if (Entry.getOrdinal(Ordinal)) 527 return; 528 outs() << format(" % 6d\n", Ordinal); 529 continue; 530 } 531 uint32_t HintNameRVA; 532 if (Entry.getHintNameRVA(HintNameRVA)) 533 return; 534 uint16_t Hint; 535 StringRef Name; 536 if (Obj->getHintName(HintNameRVA, Hint, Name)) 537 return; 538 outs() << format(" % 6d ", Hint) << Name << "\n"; 539 } 540 outs() << "\n"; 541 } 542 } 543 544 // Prints export tables. The export table is a table containing the list of 545 // exported symbol from the DLL. 546 static void printExportTable(const COFFObjectFile *Obj) { 547 outs() << "Export Table:\n"; 548 export_directory_iterator I = Obj->export_directory_begin(); 549 export_directory_iterator E = Obj->export_directory_end(); 550 if (I == E) 551 return; 552 StringRef DllName; 553 uint32_t OrdinalBase; 554 if (I->getDllName(DllName)) 555 return; 556 if (I->getOrdinalBase(OrdinalBase)) 557 return; 558 outs() << " DLL name: " << DllName << "\n"; 559 outs() << " Ordinal base: " << OrdinalBase << "\n"; 560 outs() << " Ordinal RVA Name\n"; 561 for (; I != E; I = ++I) { 562 uint32_t Ordinal; 563 if (I->getOrdinal(Ordinal)) 564 return; 565 uint32_t RVA; 566 if (I->getExportRVA(RVA)) 567 return; 568 bool IsForwarder; 569 if (I->isForwarder(IsForwarder)) 570 return; 571 572 if (IsForwarder) { 573 // Export table entries can be used to re-export symbols that 574 // this COFF file is imported from some DLLs. This is rare. 575 // In most cases IsForwarder is false. 576 outs() << format(" % 4d ", Ordinal); 577 } else { 578 outs() << format(" % 4d %# 8x", Ordinal, RVA); 579 } 580 581 StringRef Name; 582 if (I->getSymbolName(Name)) 583 continue; 584 if (!Name.empty()) 585 outs() << " " << Name; 586 if (IsForwarder) { 587 StringRef S; 588 if (I->getForwardTo(S)) 589 return; 590 outs() << " (forwarded to " << S << ")"; 591 } 592 outs() << "\n"; 593 } 594 } 595 596 // Given the COFF object file, this function returns the relocations for .pdata 597 // and the pointer to "runtime function" structs. 598 static bool getPDataSection(const COFFObjectFile *Obj, 599 std::vector<RelocationRef> &Rels, 600 const RuntimeFunction *&RFStart, int &NumRFs) { 601 for (const SectionRef &Section : Obj->sections()) { 602 StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); 603 if (Name != ".pdata") 604 continue; 605 606 const coff_section *Pdata = Obj->getCOFFSection(Section); 607 append_range(Rels, Section.relocations()); 608 609 // Sort relocations by address. 610 llvm::sort(Rels, isRelocAddressLess); 611 612 ArrayRef<uint8_t> Contents; 613 if (Error E = Obj->getSectionContents(Pdata, Contents)) 614 reportError(std::move(E), Obj->getFileName()); 615 616 if (Contents.empty()) 617 continue; 618 619 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data()); 620 NumRFs = Contents.size() / sizeof(RuntimeFunction); 621 return true; 622 } 623 return false; 624 } 625 626 Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj, 627 const RelocationRef &Rel, 628 SmallVectorImpl<char> &Result) { 629 symbol_iterator SymI = Rel.getSymbol(); 630 Expected<StringRef> SymNameOrErr = SymI->getName(); 631 if (!SymNameOrErr) 632 return SymNameOrErr.takeError(); 633 StringRef SymName = *SymNameOrErr; 634 Result.append(SymName.begin(), SymName.end()); 635 return Error::success(); 636 } 637 638 static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) { 639 // The casts to int are required in order to output the value as number. 640 // Without the casts the value would be interpreted as char data (which 641 // results in garbage output). 642 outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n"; 643 outs() << " Flags: " << static_cast<int>(UI->getFlags()); 644 if (UI->getFlags()) { 645 if (UI->getFlags() & UNW_ExceptionHandler) 646 outs() << " UNW_ExceptionHandler"; 647 if (UI->getFlags() & UNW_TerminateHandler) 648 outs() << " UNW_TerminateHandler"; 649 if (UI->getFlags() & UNW_ChainInfo) 650 outs() << " UNW_ChainInfo"; 651 } 652 outs() << "\n"; 653 outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n"; 654 outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n"; 655 // Maybe this should move to output of UOP_SetFPReg? 656 if (UI->getFrameRegister()) { 657 outs() << " Frame register: " 658 << getUnwindRegisterName(UI->getFrameRegister()) << "\n"; 659 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n"; 660 } else { 661 outs() << " No frame pointer used\n"; 662 } 663 if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 664 // FIXME: Output exception handler data 665 } else if (UI->getFlags() & UNW_ChainInfo) { 666 // FIXME: Output chained unwind info 667 } 668 669 if (UI->NumCodes) 670 outs() << " Unwind Codes:\n"; 671 672 printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes)); 673 674 outs() << "\n"; 675 outs().flush(); 676 } 677 678 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is 679 /// pointing to an executable file. 680 static void printRuntimeFunction(const COFFObjectFile *Obj, 681 const RuntimeFunction &RF) { 682 if (!RF.StartAddress) 683 return; 684 outs() << "Function Table:\n" 685 << format(" Start Address: 0x%04x\n", 686 static_cast<uint32_t>(RF.StartAddress)) 687 << format(" End Address: 0x%04x\n", 688 static_cast<uint32_t>(RF.EndAddress)) 689 << format(" Unwind Info Address: 0x%04x\n", 690 static_cast<uint32_t>(RF.UnwindInfoOffset)); 691 uintptr_t addr; 692 if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr)) 693 return; 694 printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr)); 695 } 696 697 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is 698 /// pointing to an object file. Unlike executable, fields in RuntimeFunction 699 /// struct are filled with zeros, but instead there are relocations pointing to 700 /// them so that the linker will fill targets' RVAs to the fields at link 701 /// time. This function interprets the relocations to find the data to be used 702 /// in the resulting executable. 703 static void printRuntimeFunctionRels(const COFFObjectFile *Obj, 704 const RuntimeFunction &RF, 705 uint64_t SectionOffset, 706 const std::vector<RelocationRef> &Rels) { 707 outs() << "Function Table:\n"; 708 outs() << " Start Address: "; 709 printCOFFSymbolAddress(outs(), Rels, 710 SectionOffset + 711 /*offsetof(RuntimeFunction, StartAddress)*/ 0, 712 RF.StartAddress); 713 outs() << "\n"; 714 715 outs() << " End Address: "; 716 printCOFFSymbolAddress(outs(), Rels, 717 SectionOffset + 718 /*offsetof(RuntimeFunction, EndAddress)*/ 4, 719 RF.EndAddress); 720 outs() << "\n"; 721 722 outs() << " Unwind Info Address: "; 723 printCOFFSymbolAddress(outs(), Rels, 724 SectionOffset + 725 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, 726 RF.UnwindInfoOffset); 727 outs() << "\n"; 728 729 ArrayRef<uint8_t> XContents; 730 uint64_t UnwindInfoOffset = 0; 731 if (Error E = getSectionContents( 732 Obj, Rels, 733 SectionOffset + 734 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, 735 XContents, UnwindInfoOffset)) 736 reportError(std::move(E), Obj->getFileName()); 737 if (XContents.empty()) 738 return; 739 740 UnwindInfoOffset += RF.UnwindInfoOffset; 741 if (UnwindInfoOffset > XContents.size()) 742 return; 743 744 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() + 745 UnwindInfoOffset); 746 printWin64EHUnwindInfo(UI); 747 } 748 749 void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) { 750 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) { 751 WithColor::error(errs(), "llvm-objdump") 752 << "unsupported image machine type " 753 "(currently only AMD64 is supported).\n"; 754 return; 755 } 756 757 std::vector<RelocationRef> Rels; 758 const RuntimeFunction *RFStart; 759 int NumRFs; 760 if (!getPDataSection(Obj, Rels, RFStart, NumRFs)) 761 return; 762 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs); 763 764 bool IsExecutable = Rels.empty(); 765 if (IsExecutable) { 766 for (const RuntimeFunction &RF : RFs) 767 printRuntimeFunction(Obj, RF); 768 return; 769 } 770 771 for (const RuntimeFunction &RF : RFs) { 772 uint64_t SectionOffset = 773 std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction); 774 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels); 775 } 776 } 777 778 void objdump::printCOFFFileHeader(const COFFObjectFile &Obj) { 779 COFFDumper CD(Obj); 780 const uint16_t Cha = Obj.getCharacteristics(); 781 outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n'; 782 #define FLAG(F, Name) \ 783 if (Cha & F) \ 784 outs() << '\t' << Name << '\n'; 785 FLAG(COFF::IMAGE_FILE_RELOCS_STRIPPED, "relocations stripped"); 786 FLAG(COFF::IMAGE_FILE_EXECUTABLE_IMAGE, "executable"); 787 FLAG(COFF::IMAGE_FILE_LINE_NUMS_STRIPPED, "line numbers stripped"); 788 FLAG(COFF::IMAGE_FILE_LOCAL_SYMS_STRIPPED, "symbols stripped"); 789 FLAG(COFF::IMAGE_FILE_LARGE_ADDRESS_AWARE, "large address aware"); 790 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_LO, "little endian"); 791 FLAG(COFF::IMAGE_FILE_32BIT_MACHINE, "32 bit words"); 792 FLAG(COFF::IMAGE_FILE_DEBUG_STRIPPED, "debugging information removed"); 793 FLAG(COFF::IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, 794 "copy to swap file if on removable media"); 795 FLAG(COFF::IMAGE_FILE_NET_RUN_FROM_SWAP, 796 "copy to swap file if on network media"); 797 FLAG(COFF::IMAGE_FILE_SYSTEM, "system file"); 798 FLAG(COFF::IMAGE_FILE_DLL, "DLL"); 799 FLAG(COFF::IMAGE_FILE_UP_SYSTEM_ONLY, "run only on uniprocessor machine"); 800 FLAG(COFF::IMAGE_FILE_BYTES_REVERSED_HI, "big endian"); 801 #undef FLAG 802 803 // TODO Support PE_IMAGE_DEBUG_TYPE_REPRO. 804 // Since ctime(3) returns a 26 character string of the form: 805 // "Sun Sep 16 01:03:52 1973\n\0" 806 // just print 24 characters. 807 const time_t Timestamp = Obj.getTimeDateStamp(); 808 outs() << format("\nTime/Date %.24s\n", ctime(&Timestamp)); 809 810 if (const pe32_header *Hdr = Obj.getPE32Header()) 811 CD.printPEHeader<pe32_header>(*Hdr); 812 else if (const pe32plus_header *Hdr = Obj.getPE32PlusHeader()) 813 CD.printPEHeader<pe32plus_header>(*Hdr); 814 815 printTLSDirectory(&Obj); 816 printLoadConfiguration(&Obj); 817 printImportTables(&Obj); 818 printExportTable(&Obj); 819 } 820 821 void objdump::printCOFFSymbolTable(const object::COFFImportFile *i) { 822 unsigned Index = 0; 823 bool IsCode = i->getCOFFImportHeader()->getType() == COFF::IMPORT_CODE; 824 825 for (const object::BasicSymbolRef &Sym : i->symbols()) { 826 std::string Name; 827 raw_string_ostream NS(Name); 828 829 cantFail(Sym.printName(NS)); 830 NS.flush(); 831 832 outs() << "[" << format("%2d", Index) << "]" 833 << "(sec " << format("%2d", 0) << ")" 834 << "(fl 0x00)" // Flag bits, which COFF doesn't have. 835 << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")" 836 << "(scl " << format("%3x", 0) << ") " 837 << "(nx " << 0 << ") " 838 << "0x" << format("%08x", 0) << " " << Name << '\n'; 839 840 ++Index; 841 } 842 } 843 844 void objdump::printCOFFSymbolTable(const COFFObjectFile *coff) { 845 for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) { 846 Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI); 847 if (!Symbol) 848 reportError(Symbol.takeError(), coff->getFileName()); 849 850 Expected<StringRef> NameOrErr = coff->getSymbolName(*Symbol); 851 if (!NameOrErr) 852 reportError(NameOrErr.takeError(), coff->getFileName()); 853 StringRef Name = *NameOrErr; 854 855 outs() << "[" << format("%2d", SI) << "]" 856 << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")" 857 << "(fl 0x00)" // Flag bits, which COFF doesn't have. 858 << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")" 859 << "(scl " << format("%3x", unsigned(Symbol->getStorageClass())) 860 << ") " 861 << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") " 862 << "0x" << format("%08x", unsigned(Symbol->getValue())) << " " 863 << Name; 864 if (Demangle && Name.startswith("?")) { 865 int Status = -1; 866 char *DemangledSymbol = 867 microsoftDemangle(Name.data(), nullptr, nullptr, nullptr, &Status); 868 869 if (Status == 0 && DemangledSymbol) { 870 outs() << " (" << StringRef(DemangledSymbol) << ")"; 871 std::free(DemangledSymbol); 872 } else { 873 outs() << " (invalid mangled name)"; 874 } 875 } 876 outs() << "\n"; 877 878 for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) { 879 if (Symbol->isSectionDefinition()) { 880 const coff_aux_section_definition *asd; 881 if (Error E = 882 coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)) 883 reportError(std::move(E), coff->getFileName()); 884 885 int32_t AuxNumber = asd->getNumber(Symbol->isBigObj()); 886 887 outs() << "AUX " 888 << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x " 889 , unsigned(asd->Length) 890 , unsigned(asd->NumberOfRelocations) 891 , unsigned(asd->NumberOfLinenumbers) 892 , unsigned(asd->CheckSum)) 893 << format("assoc %d comdat %d\n" 894 , unsigned(AuxNumber) 895 , unsigned(asd->Selection)); 896 } else if (Symbol->isFileRecord()) { 897 const char *FileName; 898 if (Error E = coff->getAuxSymbol<char>(SI + 1, FileName)) 899 reportError(std::move(E), coff->getFileName()); 900 901 StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() * 902 coff->getSymbolTableEntrySize()); 903 outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n'; 904 905 SI = SI + Symbol->getNumberOfAuxSymbols(); 906 break; 907 } else if (Symbol->isWeakExternal()) { 908 const coff_aux_weak_external *awe; 909 if (Error E = coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe)) 910 reportError(std::move(E), coff->getFileName()); 911 912 outs() << "AUX " << format("indx %d srch %d\n", 913 static_cast<uint32_t>(awe->TagIndex), 914 static_cast<uint32_t>(awe->Characteristics)); 915 } else { 916 outs() << "AUX Unknown\n"; 917 } 918 } 919 } 920 } 921