COFFDump.cpp revision 288943
1126475Sgrehan//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===// 2126475Sgrehan// 3126475Sgrehan// The LLVM Compiler Infrastructure 4126475Sgrehan// 5126475Sgrehan// This file is distributed under the University of Illinois Open Source 6126475Sgrehan// License. See LICENSE.TXT for details. 7126475Sgrehan// 8126475Sgrehan//===----------------------------------------------------------------------===// 9126475Sgrehan/// 10126475Sgrehan/// \file 11126475Sgrehan/// \brief This file implements the COFF-specific dumper for llvm-objdump. 12126475Sgrehan/// It outputs the Win64 EH data structures as plain text. 13126475Sgrehan/// The encoding of the unwind codes is described in MSDN: 14126475Sgrehan/// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx 15126475Sgrehan/// 16126475Sgrehan//===----------------------------------------------------------------------===// 17126475Sgrehan 18126475Sgrehan#include "llvm-objdump.h" 19126475Sgrehan#include "llvm/Object/COFF.h" 20126475Sgrehan#include "llvm/Object/ObjectFile.h" 21126475Sgrehan#include "llvm/Support/Format.h" 22126475Sgrehan#include "llvm/Support/SourceMgr.h" 23126475Sgrehan#include "llvm/Support/Win64EH.h" 24126475Sgrehan#include "llvm/Support/raw_ostream.h" 25126475Sgrehan#include <algorithm> 26126475Sgrehan#include <cstring> 27126475Sgrehan#include <system_error> 28126475Sgrehan 29126475Sgrehanusing namespace llvm; 30126475Sgrehanusing namespace object; 31126475Sgrehanusing namespace llvm::Win64EH; 32126475Sgrehan 33126475Sgrehan// Returns the name of the unwind code. 34126475Sgrehanstatic StringRef getUnwindCodeTypeName(uint8_t Code) { 35126475Sgrehan switch(Code) { 36126475Sgrehan default: llvm_unreachable("Invalid unwind code"); 37126475Sgrehan case UOP_PushNonVol: return "UOP_PushNonVol"; 38126475Sgrehan case UOP_AllocLarge: return "UOP_AllocLarge"; 39126475Sgrehan case UOP_AllocSmall: return "UOP_AllocSmall"; 40126475Sgrehan case UOP_SetFPReg: return "UOP_SetFPReg"; 41126475Sgrehan case UOP_SaveNonVol: return "UOP_SaveNonVol"; 42126475Sgrehan case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig"; 43126475Sgrehan case UOP_SaveXMM128: return "UOP_SaveXMM128"; 44126475Sgrehan case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big"; 45126475Sgrehan case UOP_PushMachFrame: return "UOP_PushMachFrame"; 46126475Sgrehan } 47126475Sgrehan} 48126475Sgrehan 49126475Sgrehan// Returns the name of a referenced register. 50126475Sgrehanstatic StringRef getUnwindRegisterName(uint8_t Reg) { 51126475Sgrehan switch(Reg) { 52126475Sgrehan default: llvm_unreachable("Invalid register"); 53126475Sgrehan case 0: return "RAX"; 54126475Sgrehan case 1: return "RCX"; 55126475Sgrehan case 2: return "RDX"; 56126475Sgrehan case 3: return "RBX"; 57126475Sgrehan case 4: return "RSP"; 58126475Sgrehan case 5: return "RBP"; 59126475Sgrehan case 6: return "RSI"; 60126475Sgrehan case 7: return "RDI"; 61126475Sgrehan case 8: return "R8"; 62126475Sgrehan case 9: return "R9"; 63126475Sgrehan case 10: return "R10"; 64126475Sgrehan case 11: return "R11"; 65126475Sgrehan case 12: return "R12"; 66126475Sgrehan case 13: return "R13"; 67126475Sgrehan case 14: return "R14"; 68126475Sgrehan case 15: return "R15"; 69126475Sgrehan } 70126475Sgrehan} 71126475Sgrehan 72126475Sgrehan// Calculates the number of array slots required for the unwind code. 73126475Sgrehanstatic unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { 74126475Sgrehan switch (UnwindCode.getUnwindOp()) { 75126475Sgrehan default: llvm_unreachable("Invalid unwind code"); 76126475Sgrehan case UOP_PushNonVol: 77126475Sgrehan case UOP_AllocSmall: 78126475Sgrehan case UOP_SetFPReg: 79126475Sgrehan case UOP_PushMachFrame: 80126475Sgrehan return 1; 81126475Sgrehan case UOP_SaveNonVol: 82126475Sgrehan case UOP_SaveXMM128: 83126475Sgrehan return 2; 84126475Sgrehan case UOP_SaveNonVolBig: 85126475Sgrehan case UOP_SaveXMM128Big: 86126475Sgrehan return 3; 87126475Sgrehan case UOP_AllocLarge: 88126475Sgrehan return (UnwindCode.getOpInfo() == 0) ? 2 : 3; 89126475Sgrehan } 90126475Sgrehan} 91126475Sgrehan 92126475Sgrehan// Prints one unwind code. Because an unwind code can occupy up to 3 slots in 93126475Sgrehan// the unwind codes array, this function requires that the correct number of 94126475Sgrehan// slots is provided. 95126475Sgrehanstatic void printUnwindCode(ArrayRef<UnwindCode> UCs) { 96126475Sgrehan assert(UCs.size() >= getNumUsedSlots(UCs[0])); 97126475Sgrehan outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) 98126475Sgrehan << getUnwindCodeTypeName(UCs[0].getUnwindOp()); 99126475Sgrehan switch (UCs[0].getUnwindOp()) { 100126475Sgrehan case UOP_PushNonVol: 101126475Sgrehan outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()); 102126475Sgrehan break; 103126475Sgrehan case UOP_AllocLarge: 104126475Sgrehan if (UCs[0].getOpInfo() == 0) { 105126475Sgrehan outs() << " " << UCs[1].FrameOffset; 106126475Sgrehan } else { 107126475Sgrehan outs() << " " << UCs[1].FrameOffset 108126475Sgrehan + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); 109126475Sgrehan } 110126475Sgrehan break; 111126475Sgrehan case UOP_AllocSmall: 112126475Sgrehan outs() << " " << ((UCs[0].getOpInfo() + 1) * 8); 113126475Sgrehan break; 114126475Sgrehan case UOP_SetFPReg: 115126475Sgrehan outs() << " "; 116132398Sgrehan break; 117126475Sgrehan case UOP_SaveNonVol: 118126475Sgrehan outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) 119126475Sgrehan << format(" [0x%04x]", 8 * UCs[1].FrameOffset); 120126475Sgrehan break; 121 case UOP_SaveNonVolBig: 122 outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) 123 << format(" [0x%08x]", UCs[1].FrameOffset 124 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); 125 break; 126 case UOP_SaveXMM128: 127 outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) 128 << format(" [0x%04x]", 16 * UCs[1].FrameOffset); 129 break; 130 case UOP_SaveXMM128Big: 131 outs() << " XMM" << UCs[0].getOpInfo() 132 << format(" [0x%08x]", UCs[1].FrameOffset 133 + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); 134 break; 135 case UOP_PushMachFrame: 136 outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w") 137 << " error code"; 138 break; 139 } 140 outs() << "\n"; 141} 142 143static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) { 144 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) { 145 unsigned UsedSlots = getNumUsedSlots(*I); 146 if (UsedSlots > UCs.size()) { 147 outs() << "Unwind data corrupted: Encountered unwind op " 148 << getUnwindCodeTypeName((*I).getUnwindOp()) 149 << " which requires " << UsedSlots 150 << " slots, but only " << UCs.size() 151 << " remaining in buffer"; 152 return ; 153 } 154 printUnwindCode(ArrayRef<UnwindCode>(I, E)); 155 I += UsedSlots; 156 } 157} 158 159// Given a symbol sym this functions returns the address and section of it. 160static std::error_code 161resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, 162 const coff_section *&ResolvedSection, 163 uint64_t &ResolvedAddr) { 164 ErrorOr<uint64_t> ResolvedAddrOrErr = Sym.getAddress(); 165 if (std::error_code EC = ResolvedAddrOrErr.getError()) 166 return EC; 167 ResolvedAddr = *ResolvedAddrOrErr; 168 section_iterator iter(Obj->section_begin()); 169 if (std::error_code EC = Sym.getSection(iter)) 170 return EC; 171 ResolvedSection = Obj->getCOFFSection(*iter); 172 return std::error_code(); 173} 174 175// Given a vector of relocations for a section and an offset into this section 176// the function returns the symbol used for the relocation at the offset. 177static std::error_code resolveSymbol(const std::vector<RelocationRef> &Rels, 178 uint64_t Offset, SymbolRef &Sym) { 179 for (std::vector<RelocationRef>::const_iterator I = Rels.begin(), 180 E = Rels.end(); 181 I != E; ++I) { 182 uint64_t Ofs = I->getOffset(); 183 if (Ofs == Offset) { 184 Sym = *I->getSymbol(); 185 return std::error_code(); 186 } 187 } 188 return object_error::parse_failed; 189} 190 191// Given a vector of relocations for a section and an offset into this section 192// the function resolves the symbol used for the relocation at the offset and 193// returns the section content and the address inside the content pointed to 194// by the symbol. 195static std::error_code 196getSectionContents(const COFFObjectFile *Obj, 197 const std::vector<RelocationRef> &Rels, uint64_t Offset, 198 ArrayRef<uint8_t> &Contents, uint64_t &Addr) { 199 SymbolRef Sym; 200 if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) 201 return EC; 202 const coff_section *Section; 203 if (std::error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) 204 return EC; 205 if (std::error_code EC = Obj->getSectionContents(Section, Contents)) 206 return EC; 207 return std::error_code(); 208} 209 210// Given a vector of relocations for a section and an offset into this section 211// the function returns the name of the symbol used for the relocation at the 212// offset. 213static std::error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, 214 uint64_t Offset, StringRef &Name) { 215 SymbolRef Sym; 216 if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) 217 return EC; 218 ErrorOr<StringRef> NameOrErr = Sym.getName(); 219 if (std::error_code EC = NameOrErr.getError()) 220 return EC; 221 Name = *NameOrErr; 222 return std::error_code(); 223} 224 225static void printCOFFSymbolAddress(llvm::raw_ostream &Out, 226 const std::vector<RelocationRef> &Rels, 227 uint64_t Offset, uint32_t Disp) { 228 StringRef Sym; 229 if (!resolveSymbolName(Rels, Offset, Sym)) { 230 Out << Sym; 231 if (Disp > 0) 232 Out << format(" + 0x%04x", Disp); 233 } else { 234 Out << format("0x%04x", Disp); 235 } 236} 237 238static void 239printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) { 240 if (Count == 0) 241 return; 242 243 const pe32_header *PE32Header; 244 if (error(Obj->getPE32Header(PE32Header))) 245 return; 246 uint32_t ImageBase = PE32Header->ImageBase; 247 uintptr_t IntPtr = 0; 248 if (error(Obj->getVaPtr(TableVA, IntPtr))) 249 return; 250 const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr; 251 outs() << "SEH Table:"; 252 for (int I = 0; I < Count; ++I) 253 outs() << format(" 0x%x", P[I] + ImageBase); 254 outs() << "\n\n"; 255} 256 257static void printLoadConfiguration(const COFFObjectFile *Obj) { 258 // Skip if it's not executable. 259 const pe32_header *PE32Header; 260 if (error(Obj->getPE32Header(PE32Header))) 261 return; 262 if (!PE32Header) 263 return; 264 265 // Currently only x86 is supported 266 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386) 267 return; 268 269 const data_directory *DataDir; 270 if (error(Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataDir))) 271 return; 272 uintptr_t IntPtr = 0; 273 if (DataDir->RelativeVirtualAddress == 0) 274 return; 275 if (error(Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))) 276 return; 277 278 auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr); 279 outs() << "Load configuration:" 280 << "\n Timestamp: " << LoadConf->TimeDateStamp 281 << "\n Major Version: " << LoadConf->MajorVersion 282 << "\n Minor Version: " << LoadConf->MinorVersion 283 << "\n GlobalFlags Clear: " << LoadConf->GlobalFlagsClear 284 << "\n GlobalFlags Set: " << LoadConf->GlobalFlagsSet 285 << "\n Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout 286 << "\n Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold 287 << "\n Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold 288 << "\n Lock Prefix Table: " << LoadConf->LockPrefixTable 289 << "\n Maximum Allocation Size: " << LoadConf->MaximumAllocationSize 290 << "\n Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold 291 << "\n Process Affinity Mask: " << LoadConf->ProcessAffinityMask 292 << "\n Process Heap Flags: " << LoadConf->ProcessHeapFlags 293 << "\n CSD Version: " << LoadConf->CSDVersion 294 << "\n Security Cookie: " << LoadConf->SecurityCookie 295 << "\n SEH Table: " << LoadConf->SEHandlerTable 296 << "\n SEH Count: " << LoadConf->SEHandlerCount 297 << "\n\n"; 298 printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount); 299 outs() << "\n"; 300} 301 302// Prints import tables. The import table is a table containing the list of 303// DLL name and symbol names which will be linked by the loader. 304static void printImportTables(const COFFObjectFile *Obj) { 305 import_directory_iterator I = Obj->import_directory_begin(); 306 import_directory_iterator E = Obj->import_directory_end(); 307 if (I == E) 308 return; 309 outs() << "The Import Tables:\n"; 310 for (; I != E; I = ++I) { 311 const import_directory_table_entry *Dir; 312 StringRef Name; 313 if (I->getImportTableEntry(Dir)) return; 314 if (I->getName(Name)) return; 315 316 outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", 317 static_cast<uint32_t>(Dir->ImportLookupTableRVA), 318 static_cast<uint32_t>(Dir->TimeDateStamp), 319 static_cast<uint32_t>(Dir->ForwarderChain), 320 static_cast<uint32_t>(Dir->NameRVA), 321 static_cast<uint32_t>(Dir->ImportAddressTableRVA)); 322 outs() << " DLL Name: " << Name << "\n"; 323 outs() << " Hint/Ord Name\n"; 324 const import_lookup_table_entry32 *entry; 325 if (I->getImportLookupEntry(entry)) 326 return; 327 for (; entry->Data; ++entry) { 328 if (entry->isOrdinal()) { 329 outs() << format(" % 6d\n", entry->getOrdinal()); 330 continue; 331 } 332 uint16_t Hint; 333 StringRef Name; 334 if (Obj->getHintName(entry->getHintNameRVA(), Hint, Name)) 335 return; 336 outs() << format(" % 6d ", Hint) << Name << "\n"; 337 } 338 outs() << "\n"; 339 } 340} 341 342// Prints export tables. The export table is a table containing the list of 343// exported symbol from the DLL. 344static void printExportTable(const COFFObjectFile *Obj) { 345 outs() << "Export Table:\n"; 346 export_directory_iterator I = Obj->export_directory_begin(); 347 export_directory_iterator E = Obj->export_directory_end(); 348 if (I == E) 349 return; 350 StringRef DllName; 351 uint32_t OrdinalBase; 352 if (I->getDllName(DllName)) 353 return; 354 if (I->getOrdinalBase(OrdinalBase)) 355 return; 356 outs() << " DLL name: " << DllName << "\n"; 357 outs() << " Ordinal base: " << OrdinalBase << "\n"; 358 outs() << " Ordinal RVA Name\n"; 359 for (; I != E; I = ++I) { 360 uint32_t Ordinal; 361 if (I->getOrdinal(Ordinal)) 362 return; 363 uint32_t RVA; 364 if (I->getExportRVA(RVA)) 365 return; 366 outs() << format(" % 4d %# 8x", Ordinal, RVA); 367 368 StringRef Name; 369 if (I->getSymbolName(Name)) 370 continue; 371 if (!Name.empty()) 372 outs() << " " << Name; 373 outs() << "\n"; 374 } 375} 376 377// Given the COFF object file, this function returns the relocations for .pdata 378// and the pointer to "runtime function" structs. 379static bool getPDataSection(const COFFObjectFile *Obj, 380 std::vector<RelocationRef> &Rels, 381 const RuntimeFunction *&RFStart, int &NumRFs) { 382 for (const SectionRef &Section : Obj->sections()) { 383 StringRef Name; 384 if (error(Section.getName(Name))) 385 continue; 386 if (Name != ".pdata") 387 continue; 388 389 const coff_section *Pdata = Obj->getCOFFSection(Section); 390 for (const RelocationRef &Reloc : Section.relocations()) 391 Rels.push_back(Reloc); 392 393 // Sort relocations by address. 394 std::sort(Rels.begin(), Rels.end(), RelocAddressLess); 395 396 ArrayRef<uint8_t> Contents; 397 if (error(Obj->getSectionContents(Pdata, Contents))) 398 continue; 399 if (Contents.empty()) 400 continue; 401 402 RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data()); 403 NumRFs = Contents.size() / sizeof(RuntimeFunction); 404 return true; 405 } 406 return false; 407} 408 409static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) { 410 // The casts to int are required in order to output the value as number. 411 // Without the casts the value would be interpreted as char data (which 412 // results in garbage output). 413 outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n"; 414 outs() << " Flags: " << static_cast<int>(UI->getFlags()); 415 if (UI->getFlags()) { 416 if (UI->getFlags() & UNW_ExceptionHandler) 417 outs() << " UNW_ExceptionHandler"; 418 if (UI->getFlags() & UNW_TerminateHandler) 419 outs() << " UNW_TerminateHandler"; 420 if (UI->getFlags() & UNW_ChainInfo) 421 outs() << " UNW_ChainInfo"; 422 } 423 outs() << "\n"; 424 outs() << " Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n"; 425 outs() << " Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n"; 426 // Maybe this should move to output of UOP_SetFPReg? 427 if (UI->getFrameRegister()) { 428 outs() << " Frame register: " 429 << getUnwindRegisterName(UI->getFrameRegister()) << "\n"; 430 outs() << " Frame offset: " << 16 * UI->getFrameOffset() << "\n"; 431 } else { 432 outs() << " No frame pointer used\n"; 433 } 434 if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 435 // FIXME: Output exception handler data 436 } else if (UI->getFlags() & UNW_ChainInfo) { 437 // FIXME: Output chained unwind info 438 } 439 440 if (UI->NumCodes) 441 outs() << " Unwind Codes:\n"; 442 443 printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0], UI->NumCodes)); 444 445 outs() << "\n"; 446 outs().flush(); 447} 448 449/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is 450/// pointing to an executable file. 451static void printRuntimeFunction(const COFFObjectFile *Obj, 452 const RuntimeFunction &RF) { 453 if (!RF.StartAddress) 454 return; 455 outs() << "Function Table:\n" 456 << format(" Start Address: 0x%04x\n", 457 static_cast<uint32_t>(RF.StartAddress)) 458 << format(" End Address: 0x%04x\n", 459 static_cast<uint32_t>(RF.EndAddress)) 460 << format(" Unwind Info Address: 0x%04x\n", 461 static_cast<uint32_t>(RF.UnwindInfoOffset)); 462 uintptr_t addr; 463 if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr)) 464 return; 465 printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr)); 466} 467 468/// Prints out the given RuntimeFunction struct for x64, assuming that Obj is 469/// pointing to an object file. Unlike executable, fields in RuntimeFunction 470/// struct are filled with zeros, but instead there are relocations pointing to 471/// them so that the linker will fill targets' RVAs to the fields at link 472/// time. This function interprets the relocations to find the data to be used 473/// in the resulting executable. 474static void printRuntimeFunctionRels(const COFFObjectFile *Obj, 475 const RuntimeFunction &RF, 476 uint64_t SectionOffset, 477 const std::vector<RelocationRef> &Rels) { 478 outs() << "Function Table:\n"; 479 outs() << " Start Address: "; 480 printCOFFSymbolAddress(outs(), Rels, 481 SectionOffset + 482 /*offsetof(RuntimeFunction, StartAddress)*/ 0, 483 RF.StartAddress); 484 outs() << "\n"; 485 486 outs() << " End Address: "; 487 printCOFFSymbolAddress(outs(), Rels, 488 SectionOffset + 489 /*offsetof(RuntimeFunction, EndAddress)*/ 4, 490 RF.EndAddress); 491 outs() << "\n"; 492 493 outs() << " Unwind Info Address: "; 494 printCOFFSymbolAddress(outs(), Rels, 495 SectionOffset + 496 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, 497 RF.UnwindInfoOffset); 498 outs() << "\n"; 499 500 ArrayRef<uint8_t> XContents; 501 uint64_t UnwindInfoOffset = 0; 502 if (error(getSectionContents( 503 Obj, Rels, SectionOffset + 504 /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, 505 XContents, UnwindInfoOffset))) 506 return; 507 if (XContents.empty()) 508 return; 509 510 UnwindInfoOffset += RF.UnwindInfoOffset; 511 if (UnwindInfoOffset > XContents.size()) 512 return; 513 514 auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() + 515 UnwindInfoOffset); 516 printWin64EHUnwindInfo(UI); 517} 518 519void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { 520 if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) { 521 errs() << "Unsupported image machine type " 522 "(currently only AMD64 is supported).\n"; 523 return; 524 } 525 526 std::vector<RelocationRef> Rels; 527 const RuntimeFunction *RFStart; 528 int NumRFs; 529 if (!getPDataSection(Obj, Rels, RFStart, NumRFs)) 530 return; 531 ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs); 532 533 bool IsExecutable = Rels.empty(); 534 if (IsExecutable) { 535 for (const RuntimeFunction &RF : RFs) 536 printRuntimeFunction(Obj, RF); 537 return; 538 } 539 540 for (const RuntimeFunction &RF : RFs) { 541 uint64_t SectionOffset = 542 std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction); 543 printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels); 544 } 545} 546 547void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { 548 const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj); 549 printLoadConfiguration(file); 550 printImportTables(file); 551 printExportTable(file); 552} 553