COFFDump.cpp revision 249423
1100616Smp//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===//
259243Sobrien//
359243Sobrien//                     The LLVM Compiler Infrastructure
459243Sobrien//
559243Sobrien// This file is distributed under the University of Illinois Open Source
659243Sobrien// License. See LICENSE.TXT for details.
759243Sobrien//
859243Sobrien//===----------------------------------------------------------------------===//
959243Sobrien///
1059243Sobrien/// \file
1159243Sobrien/// \brief This file implements the COFF-specific dumper for llvm-objdump.
1259243Sobrien/// It outputs the Win64 EH data structures as plain text.
1359243Sobrien/// The encoding of the unwind codes is decribed in MSDN:
1459243Sobrien/// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx
1559243Sobrien///
1659243Sobrien//===----------------------------------------------------------------------===//
17100616Smp
1859243Sobrien#include "llvm-objdump.h"
1959243Sobrien#include "llvm/Object/COFF.h"
2059243Sobrien#include "llvm/Object/ObjectFile.h"
2159243Sobrien#include "llvm/Support/Format.h"
2259243Sobrien#include "llvm/Support/SourceMgr.h"
2359243Sobrien#include "llvm/Support/Win64EH.h"
2459243Sobrien#include "llvm/Support/raw_ostream.h"
2559243Sobrien#include "llvm/Support/system_error.h"
2659243Sobrien#include <algorithm>
2759243Sobrien#include <cstring>
2859243Sobrien
2959243Sobrienusing namespace llvm;
3059243Sobrienusing namespace object;
3159243Sobrienusing namespace llvm::Win64EH;
3259243Sobrien
3359243Sobrien// Returns the name of the unwind code.
3459243Sobrienstatic StringRef getUnwindCodeTypeName(uint8_t Code) {
35100616Smp  switch(Code) {
3659243Sobrien  default: llvm_unreachable("Invalid unwind code");
3759243Sobrien  case UOP_PushNonVol: return "UOP_PushNonVol";
3859243Sobrien  case UOP_AllocLarge: return "UOP_AllocLarge";
3959243Sobrien  case UOP_AllocSmall: return "UOP_AllocSmall";
4059243Sobrien  case UOP_SetFPReg: return "UOP_SetFPReg";
4159243Sobrien  case UOP_SaveNonVol: return "UOP_SaveNonVol";
4259243Sobrien  case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
4359243Sobrien  case UOP_SaveXMM128: return "UOP_SaveXMM128";
4459243Sobrien  case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
4559243Sobrien  case UOP_PushMachFrame: return "UOP_PushMachFrame";
4659243Sobrien  }
4759243Sobrien}
4859243Sobrien
4959243Sobrien// Returns the name of a referenced register.
5059243Sobrienstatic StringRef getUnwindRegisterName(uint8_t Reg) {
5159243Sobrien  switch(Reg) {
5259243Sobrien  default: llvm_unreachable("Invalid register");
5359243Sobrien  case 0: return "RAX";
5459243Sobrien  case 1: return "RCX";
5559243Sobrien  case 2: return "RDX";
5659243Sobrien  case 3: return "RBX";
5759243Sobrien  case 4: return "RSP";
5859243Sobrien  case 5: return "RBP";
5959243Sobrien  case 6: return "RSI";
6059243Sobrien  case 7: return "RDI";
6159243Sobrien  case 8: return "R8";
6259243Sobrien  case 9: return "R9";
6359243Sobrien  case 10: return "R10";
6459243Sobrien  case 11: return "R11";
6559243Sobrien  case 12: return "R12";
6659243Sobrien  case 13: return "R13";
6759243Sobrien  case 14: return "R14";
6859243Sobrien  case 15: return "R15";
6959243Sobrien  }
7059243Sobrien}
7159243Sobrien
7259243Sobrien// Calculates the number of array slots required for the unwind code.
7359243Sobrienstatic unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
7459243Sobrien  switch (UnwindCode.getUnwindOp()) {
7559243Sobrien  default: llvm_unreachable("Invalid unwind code");
7659243Sobrien  case UOP_PushNonVol:
7759243Sobrien  case UOP_AllocSmall:
7859243Sobrien  case UOP_SetFPReg:
7959243Sobrien  case UOP_PushMachFrame:
8059243Sobrien    return 1;
8159243Sobrien  case UOP_SaveNonVol:
8259243Sobrien  case UOP_SaveXMM128:
8359243Sobrien    return 2;
8459243Sobrien  case UOP_SaveNonVolBig:
8559243Sobrien  case UOP_SaveXMM128Big:
8659243Sobrien    return 3;
8759243Sobrien  case UOP_AllocLarge:
8859243Sobrien    return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
8959243Sobrien  }
9059243Sobrien}
9159243Sobrien
9259243Sobrien// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
9359243Sobrien// the unwind codes array, this function requires that the correct number of
9459243Sobrien// slots is provided.
9559243Sobrienstatic void printUnwindCode(ArrayRef<UnwindCode> UCs) {
9659243Sobrien  assert(UCs.size() >= getNumUsedSlots(UCs[0]));
9759243Sobrien  outs() <<  format("    0x%02x: ", unsigned(UCs[0].u.CodeOffset))
9859243Sobrien         << getUnwindCodeTypeName(UCs[0].getUnwindOp());
9959243Sobrien  switch (UCs[0].getUnwindOp()) {
10059243Sobrien  case UOP_PushNonVol:
10159243Sobrien    outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo());
10259243Sobrien    break;
10359243Sobrien  case UOP_AllocLarge:
10459243Sobrien    if (UCs[0].getOpInfo() == 0) {
10559243Sobrien      outs() << " " << UCs[1].FrameOffset;
10659243Sobrien    } else {
10759243Sobrien      outs() << " " << UCs[1].FrameOffset
10859243Sobrien                       + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
10959243Sobrien    }
11059243Sobrien    break;
11159243Sobrien  case UOP_AllocSmall:
11259243Sobrien    outs() << " " << ((UCs[0].getOpInfo() + 1) * 8);
11359243Sobrien    break;
11469408Sache  case UOP_SetFPReg:
11569408Sache    outs() << " ";
116100616Smp    break;
11769408Sache  case UOP_SaveNonVol:
11859243Sobrien    outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
11959243Sobrien           << format(" [0x%04x]", 8 * UCs[1].FrameOffset);
12059243Sobrien    break;
12159243Sobrien  case UOP_SaveNonVolBig:
12259243Sobrien    outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo())
12359243Sobrien           << format(" [0x%08x]", UCs[1].FrameOffset
12459243Sobrien                    + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
12583098Smp    break;
126100616Smp  case UOP_SaveXMM128:
12759243Sobrien    outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
12859243Sobrien           << format(" [0x%04x]", 16 * UCs[1].FrameOffset);
12959243Sobrien    break;
13059243Sobrien  case UOP_SaveXMM128Big:
13159243Sobrien    outs() << " XMM" << UCs[0].getOpInfo()
13259415Sobrien           << format(" [0x%08x]", UCs[1].FrameOffset
13359415Sobrien                           + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16));
13490446Smp    break;
13559243Sobrien  case UOP_PushMachFrame:
13690446Smp    outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
13759415Sobrien           << " error code";
13859415Sobrien    break;
13959243Sobrien  }
14059415Sobrien  outs() << "\n";
14159415Sobrien}
14259243Sobrien
14359415Sobrienstatic void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
14459243Sobrien  for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
14559415Sobrien    unsigned UsedSlots = getNumUsedSlots(*I);
14659243Sobrien    if (UsedSlots > UCs.size()) {
14759415Sobrien      outs() << "Unwind data corrupted: Encountered unwind op "
14859415Sobrien             << getUnwindCodeTypeName((*I).getUnwindOp())
14959243Sobrien             << " which requires " << UsedSlots
15059415Sobrien             << " slots, but only " << UCs.size()
15159415Sobrien             << " remaining in buffer";
15259243Sobrien      return ;
15359243Sobrien    }
15459243Sobrien    printUnwindCode(ArrayRef<UnwindCode>(I, E));
15559243Sobrien    I += UsedSlots;
15683098Smp  }
15783098Smp}
15890446Smp
15990446Smp// Given a symbol sym this functions returns the address and section of it.
16090446Smpstatic error_code resolveSectionAndAddress(const COFFObjectFile *Obj,
16190446Smp                                           const SymbolRef &Sym,
16269408Sache                                           const coff_section *&ResolvedSection,
16390446Smp                                           uint64_t &ResolvedAddr) {
16490446Smp  if (error_code ec = Sym.getAddress(ResolvedAddr)) return ec;
16590446Smp  section_iterator iter(Obj->begin_sections());
16690446Smp  if (error_code ec = Sym.getSection(iter)) return ec;
16790446Smp  ResolvedSection = Obj->getCOFFSection(iter);
16890446Smp  return object_error::success;
16990446Smp}
17069408Sache
17169408Sache// Given a vector of relocations for a section and an offset into this section
17290446Smp// the function returns the symbol used for the relocation at the offset.
17390446Smpstatic error_code resolveSymbol(const std::vector<RelocationRef> &Rels,
17490446Smp                                uint64_t Offset, SymbolRef &Sym) {
17590446Smp  for (std::vector<RelocationRef>::const_iterator I = Rels.begin(),
17659243Sobrien                                                  E = Rels.end();
17759415Sobrien                                                  I != E; ++I) {
17859415Sobrien    uint64_t Ofs;
17990446Smp    if (error_code ec = I->getOffset(Ofs)) return ec;
18059415Sobrien    if (Ofs == Offset) {
18159415Sobrien      if (error_code ec = I->getSymbol(Sym)) return ec;
18290446Smp      break;
18359243Sobrien    }
18459243Sobrien  }
18583098Smp  return object_error::success;
18659243Sobrien}
18759415Sobrien
18859415Sobrien// Given a vector of relocations for a section and an offset into this section
18990446Smp// the function resolves the symbol used for the relocation at the offset and
19059415Sobrien// returns the section content and the address inside the content pointed to
19159415Sobrien// by the symbol.
19290446Smpstatic error_code getSectionContents(const COFFObjectFile *Obj,
19359243Sobrien                                     const std::vector<RelocationRef> &Rels,
19459243Sobrien                                     uint64_t Offset,
19583098Smp                                     ArrayRef<uint8_t> &Contents,
19659243Sobrien                                     uint64_t &Addr) {
19759415Sobrien  SymbolRef Sym;
19859415Sobrien  if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec;
19990446Smp  const coff_section *Section;
20059415Sobrien  if (error_code ec = resolveSectionAndAddress(Obj, Sym, Section, Addr))
20159415Sobrien    return ec;
20290446Smp  if (error_code ec = Obj->getSectionContents(Section, Contents)) return ec;
20359243Sobrien  return object_error::success;
20459243Sobrien}
20583098Smp
20659243Sobrien// Given a vector of relocations for a section and an offset into this section
20759415Sobrien// the function returns the name of the symbol used for the relocation at the
20859415Sobrien// offset.
20990446Smpstatic error_code resolveSymbolName(const std::vector<RelocationRef> &Rels,
21059415Sobrien                                    uint64_t Offset, StringRef &Name) {
21159415Sobrien  SymbolRef Sym;
21290446Smp  if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec;
21359243Sobrien  if (error_code ec = Sym.getName(Name)) return ec;
21459243Sobrien  return object_error::success;
21583098Smp}
21659243Sobrien
21759243Sobrienstatic void printCOFFSymbolAddress(llvm::raw_ostream &Out,
21859243Sobrien                                   const std::vector<RelocationRef> &Rels,
21959243Sobrien                                   uint64_t Offset, uint32_t Disp) {
22059243Sobrien  StringRef Sym;
22159243Sobrien  if (error_code ec = resolveSymbolName(Rels, Offset, Sym)) {
22259243Sobrien    error(ec);
22359243Sobrien    return ;
22459243Sobrien  }
22559243Sobrien  Out << Sym;
22659243Sobrien  if (Disp > 0)
22759243Sobrien    Out << format(" + 0x%04x", Disp);
22859243Sobrien}
22959243Sobrien
23059243Sobrienvoid llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
23159243Sobrien  const coff_file_header *Header;
23259243Sobrien  if (error(Obj->getHeader(Header))) return;
23359243Sobrien
23459243Sobrien  if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
23559243Sobrien    errs() << "Unsupported image machine type "
23659243Sobrien              "(currently only AMD64 is supported).\n";
23759243Sobrien    return;
23859243Sobrien  }
23959243Sobrien
24059243Sobrien  const coff_section *Pdata = 0;
24183098Smp
24259243Sobrien  error_code ec;
24359243Sobrien  for (section_iterator SI = Obj->begin_sections(),
24459243Sobrien                        SE = Obj->end_sections();
24559243Sobrien                        SI != SE; SI.increment(ec)) {
24659243Sobrien    if (error(ec)) return;
24759243Sobrien
24859243Sobrien    StringRef Name;
24959243Sobrien    if (error(SI->getName(Name))) continue;
25059243Sobrien
25159243Sobrien    if (Name != ".pdata") continue;
25259243Sobrien
25359243Sobrien    Pdata = Obj->getCOFFSection(SI);
25459243Sobrien    std::vector<RelocationRef> Rels;
25559243Sobrien    for (relocation_iterator RI = SI->begin_relocations(),
25659243Sobrien                             RE = SI->end_relocations();
25759243Sobrien                             RI != RE; RI.increment(ec)) {
25859243Sobrien      if (error(ec)) break;
25959243Sobrien      Rels.push_back(*RI);
26059243Sobrien    }
26159243Sobrien
26259243Sobrien    // Sort relocations by address.
26359243Sobrien    std::sort(Rels.begin(), Rels.end(), RelocAddressLess);
26459243Sobrien
26559243Sobrien    ArrayRef<uint8_t> Contents;
26659243Sobrien    if (error(Obj->getSectionContents(Pdata, Contents))) continue;
26759243Sobrien    if (Contents.empty()) continue;
26859243Sobrien
26959243Sobrien    ArrayRef<RuntimeFunction> RFs(
27059243Sobrien                  reinterpret_cast<const RuntimeFunction *>(Contents.data()),
27159243Sobrien                                  Contents.size() / sizeof(RuntimeFunction));
27259243Sobrien    for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) {
27359243Sobrien      const uint64_t SectionOffset = std::distance(RFs.begin(), I)
27459243Sobrien                                     * sizeof(RuntimeFunction);
27559243Sobrien
27659243Sobrien      outs() << "Function Table:\n";
27759243Sobrien
27859243Sobrien      outs() << "  Start Address: ";
27959243Sobrien      printCOFFSymbolAddress(outs(), Rels, SectionOffset +
28059243Sobrien                             /*offsetof(RuntimeFunction, StartAddress)*/ 0,
28159243Sobrien                             I->StartAddress);
28259243Sobrien      outs() << "\n";
28359243Sobrien
28459243Sobrien      outs() << "  End Address: ";
28559243Sobrien      printCOFFSymbolAddress(outs(), Rels, SectionOffset +
28659243Sobrien                             /*offsetof(RuntimeFunction, EndAddress)*/ 4,
28759243Sobrien                             I->EndAddress);
28859243Sobrien      outs() << "\n";
28959243Sobrien
29059243Sobrien      outs() << "  Unwind Info Address: ";
29159243Sobrien      printCOFFSymbolAddress(outs(), Rels, SectionOffset +
29259243Sobrien                             /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
29359243Sobrien                             I->UnwindInfoOffset);
29459243Sobrien      outs() << "\n";
29559243Sobrien
29659243Sobrien      ArrayRef<uint8_t> XContents;
29759243Sobrien      uint64_t UnwindInfoOffset = 0;
29859243Sobrien      if (error(getSectionContents(Obj, Rels, SectionOffset +
29959243Sobrien                              /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8,
30059243Sobrien                                   XContents, UnwindInfoOffset))) continue;
30159243Sobrien      if (XContents.empty()) continue;
30259243Sobrien
30359243Sobrien      UnwindInfoOffset += I->UnwindInfoOffset;
30459243Sobrien      if (UnwindInfoOffset > XContents.size()) continue;
30559243Sobrien
30659243Sobrien      const Win64EH::UnwindInfo *UI =
30759243Sobrien                            reinterpret_cast<const Win64EH::UnwindInfo *>
30859243Sobrien                              (XContents.data() + UnwindInfoOffset);
30959243Sobrien
31059243Sobrien      // The casts to int are required in order to output the value as number.
31159243Sobrien      // Without the casts the value would be interpreted as char data (which
31259243Sobrien      // results in garbage output).
31359243Sobrien      outs() << "  Version: " << static_cast<int>(UI->getVersion()) << "\n";
31459243Sobrien      outs() << "  Flags: " << static_cast<int>(UI->getFlags());
31559243Sobrien      if (UI->getFlags()) {
31659243Sobrien          if (UI->getFlags() & UNW_ExceptionHandler)
31759243Sobrien            outs() << " UNW_ExceptionHandler";
31859243Sobrien          if (UI->getFlags() & UNW_TerminateHandler)
31959243Sobrien            outs() << " UNW_TerminateHandler";
32059243Sobrien          if (UI->getFlags() & UNW_ChainInfo)
321100616Smp            outs() << " UNW_ChainInfo";
322100616Smp      }
323100616Smp      outs() << "\n";
32459243Sobrien      outs() << "  Size of prolog: "
32559243Sobrien             << static_cast<int>(UI->PrologSize) << "\n";
32659243Sobrien      outs() << "  Number of Codes: "
32759243Sobrien             << static_cast<int>(UI->NumCodes) << "\n";
32859243Sobrien      // Maybe this should move to output of UOP_SetFPReg?
32959243Sobrien      if (UI->getFrameRegister()) {
33059243Sobrien        outs() << "  Frame register: "
33159243Sobrien                << getUnwindRegisterName(UI->getFrameRegister())
33259243Sobrien                << "\n";
33359243Sobrien        outs() << "  Frame offset: "
33459243Sobrien                << 16 * UI->getFrameOffset()
33559243Sobrien                << "\n";
33659243Sobrien      } else {
33759243Sobrien        outs() << "  No frame pointer used\n";
33859243Sobrien      }
33959243Sobrien      if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
34059243Sobrien        // FIXME: Output exception handler data
34159243Sobrien      } else if (UI->getFlags() & UNW_ChainInfo) {
34259243Sobrien        // FIXME: Output chained unwind info
34359243Sobrien      }
34459243Sobrien
34559243Sobrien      if (UI->NumCodes)
34659243Sobrien        outs() << "  Unwind Codes:\n";
34759243Sobrien
34859243Sobrien      printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0],
34959243Sobrien                          UI->NumCodes));
35059243Sobrien
35159243Sobrien      outs() << "\n\n";
35259243Sobrien      outs().flush();
35359243Sobrien    }
35459243Sobrien  }
35559243Sobrien}
35659243Sobrien