Home | History | Annotate | Line # | Download | only in llvm-objdump
      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 // Returns the name of the unwind code.
     35 static StringRef getUnwindCodeTypeName(uint8_t Code) {
     36   switch(Code) {
     37   default: llvm_unreachable("Invalid unwind code");
     38   case UOP_PushNonVol: return "UOP_PushNonVol";
     39   case UOP_AllocLarge: return "UOP_AllocLarge";
     40   case UOP_AllocSmall: return "UOP_AllocSmall";
     41   case UOP_SetFPReg: return "UOP_SetFPReg";
     42   case UOP_SaveNonVol: return "UOP_SaveNonVol";
     43   case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
     44   case UOP_SaveXMM128: return "UOP_SaveXMM128";
     45   case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
     46   case UOP_PushMachFrame: return "UOP_PushMachFrame";
     47   }
     48 }
     49 
     50 // Returns the name of a referenced register.
     51 static StringRef getUnwindRegisterName(uint8_t Reg) {
     52   switch(Reg) {
     53   default: llvm_unreachable("Invalid register");
     54   case 0: return "RAX";
     55   case 1: return "RCX";
     56   case 2: return "RDX";
     57   case 3: return "RBX";
     58   case 4: return "RSP";
     59   case 5: return "RBP";
     60   case 6: return "RSI";
     61   case 7: return "RDI";
     62   case 8: return "R8";
     63   case 9: return "R9";
     64   case 10: return "R10";
     65   case 11: return "R11";
     66   case 12: return "R12";
     67   case 13: return "R13";
     68   case 14: return "R14";
     69   case 15: return "R15";
     70   }
     71 }
     72 
     73 // Calculates the number of array slots required for the unwind code.
     74 static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
     75   switch (UnwindCode.getUnwindOp()) {
     76   default: llvm_unreachable("Invalid unwind code");
     77   case UOP_PushNonVol:
     78   case UOP_AllocSmall:
     79   case UOP_SetFPReg:
     80   case UOP_PushMachFrame:
     81     return 1;
     82   case UOP_SaveNonVol:
     83   case UOP_SaveXMM128:
     84     return 2;
     85   case UOP_SaveNonVolBig:
     86   case UOP_SaveXMM128Big:
     87     return 3;
     88   case UOP_AllocLarge:
     89     return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
     90   }
     91 }
     92 
     93 // Prints one unwind code. Because an unwind code can occupy up to 3 slots in
     94 // the unwind codes array, this function requires that the correct number of
     95 // slots is provided.
     96 static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
     97   assert(UCs.size() >= getNumUsedSlots(UCs[0]));
     98   outs() <<  format("      0x%02x: ", unsigned(UCs[0].u.CodeOffset))
     99          << getUnwindCodeTypeName(UCs[0].getUnwindOp());
    100   switch (UCs[0].getUnwindOp()) {
    101   case UOP_PushNonVol:
    102     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
    103     break;
    104   case UOP_AllocLarge:
    105     if (UCs[0].getOpInfo() == 0) {
    106       outs() << " " << UCs[1].FrameOffset;
    107     } else {
    108       outs() << " " << UCs[1].FrameOffset
    109                        + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
    110     }
    111     break;
    112   case UOP_AllocSmall:
    113     outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
    114     break;
    115   case UOP_SetFPReg:
    116     outs() << " ";
    117     break;
    118   case UOP_SaveNonVol:
    119     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
    120            << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
    121     break;
    122   case UOP_SaveNonVolBig:
    123     outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
    124            << format(" [0x%08x]", UCs[1].FrameOffset
    125                     + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
    126     break;
    127   case UOP_SaveXMM128:
    128     outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
    129            << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
    130     break;
    131   case UOP_SaveXMM128Big:
    132     outs() << " XMM" << UCs[0].getOpInfo()
    133            << format(" [0x%08x]", UCs[1].FrameOffset
    134                            + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
    135     break;
    136   case UOP_PushMachFrame:
    137     outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
    138            << " error code";
    139     break;
    140   }
    141   outs() << "\n";
    142 }
    143 
    144 static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
    145   for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
    146     unsigned UsedSlots = getNumUsedSlots(*I);
    147     if (UsedSlots > UCs.size()) {
    148       outs() << "Unwind data corrupted: Encountered unwind op "
    149              << getUnwindCodeTypeName((*I).getUnwindOp())
    150              << " which requires " << UsedSlots
    151              << " slots, but only " << UCs.size()
    152              << " remaining in buffer";
    153       return ;
    154     }
    155     printUnwindCode(makeArrayRef(I, E));
    156     I += UsedSlots;
    157   }
    158 }
    159 
    160 // Given a symbol sym this functions returns the address and section of it.
    161 static Error resolveSectionAndAddress(const COFFObjectFile *Obj,
    162                                       const SymbolRef &Sym,
    163                                       const coff_section *&ResolvedSection,
    164                                       uint64_t &ResolvedAddr) {
    165   Expected<uint64_t> ResolvedAddrOrErr = Sym.getAddress();
    166   if (!ResolvedAddrOrErr)
    167     return ResolvedAddrOrErr.takeError();
    168   ResolvedAddr = *ResolvedAddrOrErr;
    169   Expected<section_iterator> Iter = Sym.getSection();
    170   if (!Iter)
    171     return Iter.takeError();
    172   ResolvedSection = Obj->getCOFFSection(**Iter);
    173   return Error::success();
    174 }
    175 
    176 // Given a vector of relocations for a section and an offset into this section
    177 // the function returns the symbol used for the relocation at the offset.
    178 static Error resolveSymbol(const std::vector<RelocationRef> &Rels,
    179                                      uint64_t Offset, SymbolRef &Sym) {
    180   for (auto &R : Rels) {
    181     uint64_t Ofs = R.getOffset();
    182     if (Ofs == Offset) {
    183       Sym = *R.getSymbol();
    184       return Error::success();
    185     }
    186   }
    187   return make_error<BinaryError>();
    188 }
    189 
    190 // Given a vector of relocations for a section and an offset into this section
    191 // the function resolves the symbol used for the relocation at the offset and
    192 // returns the section content and the address inside the content pointed to
    193 // by the symbol.
    194 static Error
    195 getSectionContents(const COFFObjectFile *Obj,
    196                    const std::vector<RelocationRef> &Rels, uint64_t Offset,
    197                    ArrayRef<uint8_t> &Contents, uint64_t &Addr) {
    198   SymbolRef Sym;
    199   if (Error E = resolveSymbol(Rels, Offset, Sym))
    200     return E;
    201   const coff_section *Section;
    202   if (Error E = resolveSectionAndAddress(Obj, Sym, Section, Addr))
    203     return E;
    204   return Obj->getSectionContents(Section, Contents);
    205 }
    206 
    207 // Given a vector of relocations for a section and an offset into this section
    208 // the function returns the name of the symbol used for the relocation at the
    209 // offset.
    210 static Error resolveSymbolName(const std::vector<RelocationRef> &Rels,
    211                                uint64_t Offset, StringRef &Name) {
    212   SymbolRef Sym;
    213   if (Error EC = resolveSymbol(Rels, Offset, Sym))
    214     return EC;
    215   Expected<StringRef> NameOrErr = Sym.getName();
    216   if (!NameOrErr)
    217     return NameOrErr.takeError();
    218   Name = *NameOrErr;
    219   return Error::success();
    220 }
    221 
    222 static void printCOFFSymbolAddress(raw_ostream &Out,
    223                                    const std::vector<RelocationRef> &Rels,
    224                                    uint64_t Offset, uint32_t Disp) {
    225   StringRef Sym;
    226   if (!resolveSymbolName(Rels, Offset, Sym)) {
    227     Out << Sym;
    228     if (Disp > 0)
    229       Out << format(" + 0x%04x", Disp);
    230   } else {
    231     Out << format("0x%04x", Disp);
    232   }
    233 }
    234 
    235 static void
    236 printSEHTable(const COFFObjectFile *Obj, uint32_t TableVA, int Count) {
    237   if (Count == 0)
    238     return;
    239 
    240   uintptr_t IntPtr = 0;
    241   if (Error E = Obj->getVaPtr(TableVA, IntPtr))
    242     reportError(std::move(E), Obj->getFileName());
    243 
    244   const support::ulittle32_t *P = (const support::ulittle32_t *)IntPtr;
    245   outs() << "SEH Table:";
    246   for (int I = 0; I < Count; ++I)
    247     outs() << format(" 0x%x", P[I] + Obj->getPE32Header()->ImageBase);
    248   outs() << "\n\n";
    249 }
    250 
    251 template <typename T>
    252 static void printTLSDirectoryT(const coff_tls_directory<T> *TLSDir) {
    253   size_t FormatWidth = sizeof(T) * 2;
    254   outs() << "TLS directory:"
    255          << "\n  StartAddressOfRawData: "
    256          << format_hex(TLSDir->StartAddressOfRawData, FormatWidth)
    257          << "\n  EndAddressOfRawData: "
    258          << format_hex(TLSDir->EndAddressOfRawData, FormatWidth)
    259          << "\n  AddressOfIndex: "
    260          << format_hex(TLSDir->AddressOfIndex, FormatWidth)
    261          << "\n  AddressOfCallBacks: "
    262          << format_hex(TLSDir->AddressOfCallBacks, FormatWidth)
    263          << "\n  SizeOfZeroFill: "
    264          << TLSDir->SizeOfZeroFill
    265          << "\n  Characteristics: "
    266          << TLSDir->Characteristics
    267          << "\n  Alignment: "
    268          << TLSDir->getAlignment()
    269          << "\n\n";
    270 }
    271 
    272 static void printTLSDirectory(const COFFObjectFile *Obj) {
    273   const pe32_header *PE32Header = Obj->getPE32Header();
    274   const pe32plus_header *PE32PlusHeader = Obj->getPE32PlusHeader();
    275 
    276   // Skip if it's not executable.
    277   if (!PE32Header && !PE32PlusHeader)
    278     return;
    279 
    280   const data_directory *DataDir = Obj->getDataDirectory(COFF::TLS_TABLE);
    281   if (!DataDir)
    282     reportError("missing data dir for TLS table", Obj->getFileName());
    283 
    284   if (DataDir->RelativeVirtualAddress == 0)
    285     return;
    286 
    287   uintptr_t IntPtr = 0;
    288   if (Error E =
    289           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
    290     reportError(std::move(E), Obj->getFileName());
    291 
    292   if (PE32Header) {
    293     auto *TLSDir = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
    294     printTLSDirectoryT(TLSDir);
    295   } else {
    296     auto *TLSDir = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
    297     printTLSDirectoryT(TLSDir);
    298   }
    299 
    300   outs() << "\n";
    301 }
    302 
    303 static void printLoadConfiguration(const COFFObjectFile *Obj) {
    304   // Skip if it's not executable.
    305   if (!Obj->getPE32Header())
    306     return;
    307 
    308   // Currently only x86 is supported
    309   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
    310     return;
    311 
    312   const data_directory *DataDir = Obj->getDataDirectory(COFF::LOAD_CONFIG_TABLE);
    313   if (!DataDir)
    314     reportError("no load config data dir", Obj->getFileName());
    315 
    316   uintptr_t IntPtr = 0;
    317   if (DataDir->RelativeVirtualAddress == 0)
    318     return;
    319 
    320   if (Error E =
    321           Obj->getRvaPtr(DataDir->RelativeVirtualAddress, IntPtr))
    322     reportError(std::move(E), Obj->getFileName());
    323 
    324   auto *LoadConf = reinterpret_cast<const coff_load_configuration32 *>(IntPtr);
    325   outs() << "Load configuration:"
    326          << "\n  Timestamp: " << LoadConf->TimeDateStamp
    327          << "\n  Major Version: " << LoadConf->MajorVersion
    328          << "\n  Minor Version: " << LoadConf->MinorVersion
    329          << "\n  GlobalFlags Clear: " << LoadConf->GlobalFlagsClear
    330          << "\n  GlobalFlags Set: " << LoadConf->GlobalFlagsSet
    331          << "\n  Critical Section Default Timeout: " << LoadConf->CriticalSectionDefaultTimeout
    332          << "\n  Decommit Free Block Threshold: " << LoadConf->DeCommitFreeBlockThreshold
    333          << "\n  Decommit Total Free Threshold: " << LoadConf->DeCommitTotalFreeThreshold
    334          << "\n  Lock Prefix Table: " << LoadConf->LockPrefixTable
    335          << "\n  Maximum Allocation Size: " << LoadConf->MaximumAllocationSize
    336          << "\n  Virtual Memory Threshold: " << LoadConf->VirtualMemoryThreshold
    337          << "\n  Process Affinity Mask: " << LoadConf->ProcessAffinityMask
    338          << "\n  Process Heap Flags: " << LoadConf->ProcessHeapFlags
    339          << "\n  CSD Version: " << LoadConf->CSDVersion
    340          << "\n  Security Cookie: " << LoadConf->SecurityCookie
    341          << "\n  SEH Table: " << LoadConf->SEHandlerTable
    342          << "\n  SEH Count: " << LoadConf->SEHandlerCount
    343          << "\n\n";
    344   printSEHTable(Obj, LoadConf->SEHandlerTable, LoadConf->SEHandlerCount);
    345   outs() << "\n";
    346 }
    347 
    348 // Prints import tables. The import table is a table containing the list of
    349 // DLL name and symbol names which will be linked by the loader.
    350 static void printImportTables(const COFFObjectFile *Obj) {
    351   import_directory_iterator I = Obj->import_directory_begin();
    352   import_directory_iterator E = Obj->import_directory_end();
    353   if (I == E)
    354     return;
    355   outs() << "The Import Tables:\n";
    356   for (const ImportDirectoryEntryRef &DirRef : Obj->import_directories()) {
    357     const coff_import_directory_table_entry *Dir;
    358     StringRef Name;
    359     if (DirRef.getImportTableEntry(Dir)) return;
    360     if (DirRef.getName(Name)) return;
    361 
    362     outs() << format("  lookup %08x time %08x fwd %08x name %08x addr %08x\n\n",
    363                      static_cast<uint32_t>(Dir->ImportLookupTableRVA),
    364                      static_cast<uint32_t>(Dir->TimeDateStamp),
    365                      static_cast<uint32_t>(Dir->ForwarderChain),
    366                      static_cast<uint32_t>(Dir->NameRVA),
    367                      static_cast<uint32_t>(Dir->ImportAddressTableRVA));
    368     outs() << "    DLL Name: " << Name << "\n";
    369     outs() << "    Hint/Ord  Name\n";
    370     for (const ImportedSymbolRef &Entry : DirRef.imported_symbols()) {
    371       bool IsOrdinal;
    372       if (Entry.isOrdinal(IsOrdinal))
    373         return;
    374       if (IsOrdinal) {
    375         uint16_t Ordinal;
    376         if (Entry.getOrdinal(Ordinal))
    377           return;
    378         outs() << format("      % 6d\n", Ordinal);
    379         continue;
    380       }
    381       uint32_t HintNameRVA;
    382       if (Entry.getHintNameRVA(HintNameRVA))
    383         return;
    384       uint16_t Hint;
    385       StringRef Name;
    386       if (Obj->getHintName(HintNameRVA, Hint, Name))
    387         return;
    388       outs() << format("      % 6d  ", Hint) << Name << "\n";
    389     }
    390     outs() << "\n";
    391   }
    392 }
    393 
    394 // Prints export tables. The export table is a table containing the list of
    395 // exported symbol from the DLL.
    396 static void printExportTable(const COFFObjectFile *Obj) {
    397   outs() << "Export Table:\n";
    398   export_directory_iterator I = Obj->export_directory_begin();
    399   export_directory_iterator E = Obj->export_directory_end();
    400   if (I == E)
    401     return;
    402   StringRef DllName;
    403   uint32_t OrdinalBase;
    404   if (I->getDllName(DllName))
    405     return;
    406   if (I->getOrdinalBase(OrdinalBase))
    407     return;
    408   outs() << " DLL name: " << DllName << "\n";
    409   outs() << " Ordinal base: " << OrdinalBase << "\n";
    410   outs() << " Ordinal      RVA  Name\n";
    411   for (; I != E; I = ++I) {
    412     uint32_t Ordinal;
    413     if (I->getOrdinal(Ordinal))
    414       return;
    415     uint32_t RVA;
    416     if (I->getExportRVA(RVA))
    417       return;
    418     bool IsForwarder;
    419     if (I->isForwarder(IsForwarder))
    420       return;
    421 
    422     if (IsForwarder) {
    423       // Export table entries can be used to re-export symbols that
    424       // this COFF file is imported from some DLLs. This is rare.
    425       // In most cases IsForwarder is false.
    426       outs() << format("    % 4d         ", Ordinal);
    427     } else {
    428       outs() << format("    % 4d %# 8x", Ordinal, RVA);
    429     }
    430 
    431     StringRef Name;
    432     if (I->getSymbolName(Name))
    433       continue;
    434     if (!Name.empty())
    435       outs() << "  " << Name;
    436     if (IsForwarder) {
    437       StringRef S;
    438       if (I->getForwardTo(S))
    439         return;
    440       outs() << " (forwarded to " << S << ")";
    441     }
    442     outs() << "\n";
    443   }
    444 }
    445 
    446 // Given the COFF object file, this function returns the relocations for .pdata
    447 // and the pointer to "runtime function" structs.
    448 static bool getPDataSection(const COFFObjectFile *Obj,
    449                             std::vector<RelocationRef> &Rels,
    450                             const RuntimeFunction *&RFStart, int &NumRFs) {
    451   for (const SectionRef &Section : Obj->sections()) {
    452     StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());
    453     if (Name != ".pdata")
    454       continue;
    455 
    456     const coff_section *Pdata = Obj->getCOFFSection(Section);
    457     append_range(Rels, Section.relocations());
    458 
    459     // Sort relocations by address.
    460     llvm::sort(Rels, isRelocAddressLess);
    461 
    462     ArrayRef<uint8_t> Contents;
    463     if (Error E = Obj->getSectionContents(Pdata, Contents))
    464       reportError(std::move(E), Obj->getFileName());
    465 
    466     if (Contents.empty())
    467       continue;
    468 
    469     RFStart = reinterpret_cast<const RuntimeFunction *>(Contents.data());
    470     NumRFs = Contents.size() / sizeof(RuntimeFunction);
    471     return true;
    472   }
    473   return false;
    474 }
    475 
    476 Error objdump::getCOFFRelocationValueString(const COFFObjectFile *Obj,
    477                                             const RelocationRef &Rel,
    478                                             SmallVectorImpl<char> &Result) {
    479   symbol_iterator SymI = Rel.getSymbol();
    480   Expected<StringRef> SymNameOrErr = SymI->getName();
    481   if (!SymNameOrErr)
    482     return SymNameOrErr.takeError();
    483   StringRef SymName = *SymNameOrErr;
    484   Result.append(SymName.begin(), SymName.end());
    485   return Error::success();
    486 }
    487 
    488 static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
    489   // The casts to int are required in order to output the value as number.
    490   // Without the casts the value would be interpreted as char data (which
    491   // results in garbage output).
    492   outs() << "    Version: " << static_cast<int>(UI->getVersion()) << "\n";
    493   outs() << "    Flags: " << static_cast<int>(UI->getFlags());
    494   if (UI->getFlags()) {
    495     if (UI->getFlags() & UNW_ExceptionHandler)
    496       outs() << " UNW_ExceptionHandler";
    497     if (UI->getFlags() & UNW_TerminateHandler)
    498       outs() << " UNW_TerminateHandler";
    499     if (UI->getFlags() & UNW_ChainInfo)
    500       outs() << " UNW_ChainInfo";
    501   }
    502   outs() << "\n";
    503   outs() << "    Size of prolog: " << static_cast<int>(UI->PrologSize) << "\n";
    504   outs() << "    Number of Codes: " << static_cast<int>(UI->NumCodes) << "\n";
    505   // Maybe this should move to output of UOP_SetFPReg?
    506   if (UI->getFrameRegister()) {
    507     outs() << "    Frame register: "
    508            << getUnwindRegisterName(UI->getFrameRegister()) << "\n";
    509     outs() << "    Frame offset: " << 16 * UI->getFrameOffset() << "\n";
    510   } else {
    511     outs() << "    No frame pointer used\n";
    512   }
    513   if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
    514     // FIXME: Output exception handler data
    515   } else if (UI->getFlags() & UNW_ChainInfo) {
    516     // FIXME: Output chained unwind info
    517   }
    518 
    519   if (UI->NumCodes)
    520     outs() << "    Unwind Codes:\n";
    521 
    522   printAllUnwindCodes(makeArrayRef(&UI->UnwindCodes[0], UI->NumCodes));
    523 
    524   outs() << "\n";
    525   outs().flush();
    526 }
    527 
    528 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
    529 /// pointing to an executable file.
    530 static void printRuntimeFunction(const COFFObjectFile *Obj,
    531                                  const RuntimeFunction &RF) {
    532   if (!RF.StartAddress)
    533     return;
    534   outs() << "Function Table:\n"
    535          << format("  Start Address: 0x%04x\n",
    536                    static_cast<uint32_t>(RF.StartAddress))
    537          << format("  End Address: 0x%04x\n",
    538                    static_cast<uint32_t>(RF.EndAddress))
    539          << format("  Unwind Info Address: 0x%04x\n",
    540                    static_cast<uint32_t>(RF.UnwindInfoOffset));
    541   uintptr_t addr;
    542   if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
    543     return;
    544   printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
    545 }
    546 
    547 /// Prints out the given RuntimeFunction struct for x64, assuming that Obj is
    548 /// pointing to an object file. Unlike executable, fields in RuntimeFunction
    549 /// struct are filled with zeros, but instead there are relocations pointing to
    550 /// them so that the linker will fill targets' RVAs to the fields at link
    551 /// time. This function interprets the relocations to find the data to be used
    552 /// in the resulting executable.
    553 static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
    554                                      const RuntimeFunction &RF,
    555                                      uint64_t SectionOffset,
    556                                      const std::vector<RelocationRef> &Rels) {
    557   outs() << "Function Table:\n";
    558   outs() << "  Start Address: ";
    559   printCOFFSymbolAddress(outs(), Rels,
    560                          SectionOffset +
    561                              /*offsetof(RuntimeFunction, StartAddress)*/ 0,
    562                          RF.StartAddress);
    563   outs() << "\n";
    564 
    565   outs() << "  End Address: ";
    566   printCOFFSymbolAddress(outs(), Rels,
    567                          SectionOffset +
    568                              /*offsetof(RuntimeFunction, EndAddress)*/ 4,
    569                          RF.EndAddress);
    570   outs() << "\n";
    571 
    572   outs() << "  Unwind Info Address: ";
    573   printCOFFSymbolAddress(outs(), Rels,
    574                          SectionOffset +
    575                              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
    576                          RF.UnwindInfoOffset);
    577   outs() << "\n";
    578 
    579   ArrayRef<uint8_t> XContents;
    580   uint64_t UnwindInfoOffset = 0;
    581   if (Error E = getSectionContents(
    582           Obj, Rels,
    583           SectionOffset +
    584               /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
    585           XContents, UnwindInfoOffset))
    586     reportError(std::move(E), Obj->getFileName());
    587   if (XContents.empty())
    588     return;
    589 
    590   UnwindInfoOffset += RF.UnwindInfoOffset;
    591   if (UnwindInfoOffset > XContents.size())
    592     return;
    593 
    594   auto *UI = reinterpret_cast<const Win64EH::UnwindInfo *>(XContents.data() +
    595                                                            UnwindInfoOffset);
    596   printWin64EHUnwindInfo(UI);
    597 }
    598 
    599 void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
    600   if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
    601     WithColor::error(errs(), "llvm-objdump")
    602         << "unsupported image machine type "
    603            "(currently only AMD64 is supported).\n";
    604     return;
    605   }
    606 
    607   std::vector<RelocationRef> Rels;
    608   const RuntimeFunction *RFStart;
    609   int NumRFs;
    610   if (!getPDataSection(Obj, Rels, RFStart, NumRFs))
    611     return;
    612   ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
    613 
    614   bool IsExecutable = Rels.empty();
    615   if (IsExecutable) {
    616     for (const RuntimeFunction &RF : RFs)
    617       printRuntimeFunction(Obj, RF);
    618     return;
    619   }
    620 
    621   for (const RuntimeFunction &RF : RFs) {
    622     uint64_t SectionOffset =
    623         std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
    624     printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
    625   }
    626 }
    627 
    628 void objdump::printCOFFFileHeader(const object::ObjectFile *Obj) {
    629   const COFFObjectFile *file = dyn_cast<const COFFObjectFile>(Obj);
    630   printTLSDirectory(file);
    631   printLoadConfiguration(file);
    632   printImportTables(file);
    633   printExportTable(file);
    634 }
    635 
    636 void objdump::printCOFFSymbolTable(const object::COFFImportFile *i) {
    637   unsigned Index = 0;
    638   bool IsCode = i->getCOFFImportHeader()->getType() == COFF::IMPORT_CODE;
    639 
    640   for (const object::BasicSymbolRef &Sym : i->symbols()) {
    641     std::string Name;
    642     raw_string_ostream NS(Name);
    643 
    644     cantFail(Sym.printName(NS));
    645     NS.flush();
    646 
    647     outs() << "[" << format("%2d", Index) << "]"
    648            << "(sec " << format("%2d", 0) << ")"
    649            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
    650            << "(ty " << format("%3x", (IsCode && Index) ? 32 : 0) << ")"
    651            << "(scl " << format("%3x", 0) << ") "
    652            << "(nx " << 0 << ") "
    653            << "0x" << format("%08x", 0) << " " << Name << '\n';
    654 
    655     ++Index;
    656   }
    657 }
    658 
    659 void objdump::printCOFFSymbolTable(const COFFObjectFile *coff) {
    660   for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
    661     Expected<COFFSymbolRef> Symbol = coff->getSymbol(SI);
    662     if (!Symbol)
    663       reportError(Symbol.takeError(), coff->getFileName());
    664 
    665     Expected<StringRef> NameOrErr = coff->getSymbolName(*Symbol);
    666     if (!NameOrErr)
    667       reportError(NameOrErr.takeError(), coff->getFileName());
    668     StringRef Name = *NameOrErr;
    669 
    670     outs() << "[" << format("%2d", SI) << "]"
    671            << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
    672            << "(fl 0x00)" // Flag bits, which COFF doesn't have.
    673            << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
    674            << "(scl " << format("%3x", unsigned(Symbol->getStorageClass()))
    675            << ") "
    676            << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
    677            << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
    678            << Name;
    679     if (Demangle && Name.startswith("?")) {
    680       int Status = -1;
    681       char *DemangledSymbol =
    682           microsoftDemangle(Name.data(), nullptr, nullptr, nullptr, &Status);
    683 
    684       if (Status == 0 && DemangledSymbol) {
    685         outs() << " (" << StringRef(DemangledSymbol) << ")";
    686         std::free(DemangledSymbol);
    687       } else {
    688         outs() << " (invalid mangled name)";
    689       }
    690     }
    691     outs() << "\n";
    692 
    693     for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
    694       if (Symbol->isSectionDefinition()) {
    695         const coff_aux_section_definition *asd;
    696         if (Error E =
    697                 coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd))
    698           reportError(std::move(E), coff->getFileName());
    699 
    700         int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
    701 
    702         outs() << "AUX "
    703                << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
    704                          , unsigned(asd->Length)
    705                          , unsigned(asd->NumberOfRelocations)
    706                          , unsigned(asd->NumberOfLinenumbers)
    707                          , unsigned(asd->CheckSum))
    708                << format("assoc %d comdat %d\n"
    709                          , unsigned(AuxNumber)
    710                          , unsigned(asd->Selection));
    711       } else if (Symbol->isFileRecord()) {
    712         const char *FileName;
    713         if (Error E = coff->getAuxSymbol<char>(SI + 1, FileName))
    714           reportError(std::move(E), coff->getFileName());
    715 
    716         StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
    717                                      coff->getSymbolTableEntrySize());
    718         outs() << "AUX " << Name.rtrim(StringRef("\0", 1))  << '\n';
    719 
    720         SI = SI + Symbol->getNumberOfAuxSymbols();
    721         break;
    722       } else if (Symbol->isWeakExternal()) {
    723         const coff_aux_weak_external *awe;
    724         if (Error E = coff->getAuxSymbol<coff_aux_weak_external>(SI + 1, awe))
    725           reportError(std::move(E), coff->getFileName());
    726 
    727         outs() << "AUX " << format("indx %d srch %d\n",
    728                                    static_cast<uint32_t>(awe->TagIndex),
    729                                    static_cast<uint32_t>(awe->Characteristics));
    730       } else {
    731         outs() << "AUX Unknown\n";
    732       }
    733     }
    734   }
    735 }
    736