summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/llvm-readobj/CMakeLists.txt1
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp344
-rw-r--r--tools/llvm-readobj/Win64EHDumper.cpp327
-rw-r--r--tools/llvm-readobj/Win64EHDumper.h62
4 files changed, 406 insertions, 328 deletions
diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt
index deef7a1629..b057dcdc12 100644
--- a/tools/llvm-readobj/CMakeLists.txt
+++ b/tools/llvm-readobj/CMakeLists.txt
@@ -13,4 +13,5 @@ add_llvm_tool(llvm-readobj
MachODumper.cpp
ObjDumper.cpp
StreamWriter.cpp
+ Win64EHDumper.cpp
)
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 1a360f5bed..7b9595f84c 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -16,6 +16,7 @@
#include "Error.h"
#include "ObjDumper.h"
#include "StreamWriter.h"
+#include "Win64EHDumper.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Object/COFF.h"
@@ -58,35 +59,19 @@ private:
void printSymbol(const SymbolRef &Sym);
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
void printDataDirectory(uint32_t Index, const std::string &FieldName);
- void printX64UnwindInfo();
template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);
- void printRuntimeFunction(const RuntimeFunction& RTF,
- const coff_section *Section,
- uint64_t SectionOffset);
-
- void printUnwindInfo(const Win64EH::UnwindInfo& UI,
- const coff_section *Section, uint64_t SectionOffset);
-
- void printUnwindCode(const Win64EH::UnwindInfo &UI, ArrayRef<UnwindCode> UCs);
-
void printCodeViewLineTables(const SectionRef &Section);
void cacheRelocations();
- error_code resolveRelocation(const coff_section *Section, uint64_t Offset,
- const coff_section *&ReesolvedSection,
- uint64_t &ResolvedAddress);
-
error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
SymbolRef &Sym);
error_code resolveSymbolName(const coff_section *Section, uint64_t Offset,
StringRef &Name);
- std::string formatSymbol(const coff_section *Section, uint64_t Offset,
- uint32_t Disp);
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
@@ -111,66 +96,6 @@ error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer,
} // namespace llvm
-
-// Returns the name of the unwind code.
-static StringRef getUnwindCodeTypeName(uint8_t Code) {
- switch(Code) {
- default: llvm_unreachable("Invalid unwind code");
- case UOP_PushNonVol: return "PUSH_NONVOL";
- case UOP_AllocLarge: return "ALLOC_LARGE";
- case UOP_AllocSmall: return "ALLOC_SMALL";
- case UOP_SetFPReg: return "SET_FPREG";
- case UOP_SaveNonVol: return "SAVE_NONVOL";
- case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
- case UOP_SaveXMM128: return "SAVE_XMM128";
- case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
- case UOP_PushMachFrame: return "PUSH_MACHFRAME";
- }
-}
-
-// Returns the name of a referenced register.
-static StringRef getUnwindRegisterName(uint8_t Reg) {
- switch(Reg) {
- default: llvm_unreachable("Invalid register");
- case 0: return "RAX";
- case 1: return "RCX";
- case 2: return "RDX";
- case 3: return "RBX";
- case 4: return "RSP";
- case 5: return "RBP";
- case 6: return "RSI";
- case 7: return "RDI";
- case 8: return "R8";
- case 9: return "R9";
- case 10: return "R10";
- case 11: return "R11";
- case 12: return "R12";
- case 13: return "R13";
- case 14: return "R14";
- case 15: return "R15";
- }
-}
-
-// Calculates the number of array slots required for the unwind code.
-static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
- switch (UnwindCode.getUnwindOp()) {
- default: llvm_unreachable("Invalid unwind code");
- case UOP_PushNonVol:
- case UOP_AllocSmall:
- case UOP_SetFPReg:
- case UOP_PushMachFrame:
- return 1;
- case UOP_SaveNonVol:
- case UOP_SaveXMM128:
- return 2;
- case UOP_SaveNonVolBig:
- case UOP_SaveXMM128Big:
- return 3;
- case UOP_AllocLarge:
- return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
- }
-}
-
// Given a a section and an offset into this section the function returns the
// symbol used for the relocation at the offset.
error_code COFFDumper::resolveSymbol(const coff_section *Section,
@@ -381,43 +306,6 @@ WeakExternalCharacteristics[] = {
{ "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS }
};
-static const EnumEntry<unsigned> UnwindFlags[] = {
- { "ExceptionHandler", Win64EH::UNW_ExceptionHandler },
- { "TerminateHandler", Win64EH::UNW_TerminateHandler },
- { "ChainInfo" , Win64EH::UNW_ChainInfo }
-};
-
-static const EnumEntry<unsigned> UnwindOpInfo[] = {
- { "RAX", 0 },
- { "RCX", 1 },
- { "RDX", 2 },
- { "RBX", 3 },
- { "RSP", 4 },
- { "RBP", 5 },
- { "RSI", 6 },
- { "RDI", 7 },
- { "R8", 8 },
- { "R9", 9 },
- { "R10", 10 },
- { "R11", 11 },
- { "R12", 12 },
- { "R13", 13 },
- { "R14", 14 },
- { "R15", 15 }
-};
-
-static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) {
- return static_cast<const char*>(UI.getLanguageSpecificData())
- - reinterpret_cast<const char*>(&UI);
-}
-
-static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) {
- if (UCs.size() < 3)
- return 0;
-
- return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16);
-}
-
template<typename T>
static error_code getSymbolAuxData(const COFFObjectFile *Obj,
const coff_symbol *Symbol, const T* &Aux) {
@@ -426,46 +314,6 @@ static error_code getSymbolAuxData(const COFFObjectFile *Obj,
return readobj_error::success;
}
-std::string COFFDumper::formatSymbol(const coff_section *Section,
- uint64_t Offset, uint32_t Disp) {
- std::string Buffer;
- raw_string_ostream Str(Buffer);
-
- StringRef Sym;
- if (resolveSymbolName(Section, Offset, Sym)) {
- Str << format(" (0x%" PRIX64 ")", Offset);
- return Str.str();
- }
-
- Str << Sym;
- if (Disp > 0) {
- Str << format(" +0x%X (0x%" PRIX64 ")", Disp, Offset);
- } else {
- Str << format(" (0x%" PRIX64 ")", Offset);
- }
-
- return Str.str();
-}
-
-error_code COFFDumper::resolveRelocation(const coff_section *Section,
- uint64_t Offset,
- const coff_section *&ResolvedSection,
- uint64_t &ResolvedAddress) {
- SymbolRef Sym;
- if (error_code EC = resolveSymbol(Section, Offset, Sym))
- return EC;
-
- if (error_code EC = Sym.getAddress(ResolvedAddr))
- return EC;
-
- section_iterator SI(Obj->section_begin());
- if (error_code EC = Sym.getSection(SI))
- return EC;
-
- ResolvedSection = Obj->getCOFFSection(*SI);
- return object_error::success;
-}
-
void COFFDumper::cacheRelocations() {
for (const SectionRef &S : Obj->sections()) {
const coff_section *Section = Obj->getCOFFSection(S);
@@ -997,182 +845,22 @@ void COFFDumper::printUnwindInfo() {
return;
ListScope D(W, "UnwindInformation");
- if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
- W.startLine() << "Unsupported image machine type "
- "(currently only AMD64 is supported).\n";
- return;
- }
-
- printX64UnwindInfo();
-}
-
-void COFFDumper::printX64UnwindInfo() {
- for (const SectionRef &Section : Obj->sections()) {
- StringRef Name;
- if (error(Section.getName(Name)))
- continue;
- if (Name != ".pdata" && !Name.startswith(".pdata$"))
- continue;
-
- const coff_section *PData = Obj->getCOFFSection(Section);
-
- ArrayRef<uint8_t> Contents;
- if (error(Obj->getSectionContents(PData, Contents)) || Contents.empty())
- continue;
-
- ArrayRef<RuntimeFunction> RFs(
- reinterpret_cast<const RuntimeFunction *>(Contents.data()),
- Contents.size() / sizeof(RuntimeFunction));
-
- for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) {
- const uint64_t OffsetInSection = std::distance(RFs.begin(), I)
- * sizeof(RuntimeFunction);
-
- printRuntimeFunction(*I, PData, OffsetInSection);
- }
- }
-}
-
-void COFFDumper::printRuntimeFunction(const RuntimeFunction& RTF,
- const coff_section *Section,
- uint64_t SectionOffset) {
-
- DictScope D(W, "RuntimeFunction");
- W.printString("StartAddress",
- formatSymbol(Section, SectionOffset + 0, RTF.StartAddress));
- W.printString("EndAddress",
- formatSymbol(Section, SectionOffset + 4, RTF.EndAddress));
- W.printString("UnwindInfoAddress",
- formatSymbol(Section, SectionOffset + 8, RTF.UnwindInfoOffset));
-
- const coff_section* XData = nullptr;
- uint64_t UnwindInfoOffset = 0;
- if (error(getSectionFromRelocation(Section, SectionOffset + 8,
- XData, UnwindInfoOffset)))
- return;
-
- ArrayRef<uint8_t> XContents;
- if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty())
- return;
-
- UnwindInfoOffset += RTF.UnwindInfoOffset;
- if (UnwindInfoOffset > XContents.size())
- return;
-
- const Win64EH::UnwindInfo *UI =
- reinterpret_cast<const Win64EH::UnwindInfo *>(
- XContents.data() + UnwindInfoOffset);
-
- printUnwindInfo(*UI, XData, UnwindInfoOffset);
-}
-
-void COFFDumper::printUnwindInfo(const Win64EH::UnwindInfo& UI,
- const coff_section *Section,
- uint64_t SectionOffset) {
- DictScope D(W, "UnwindInfo");
- W.printNumber("Version", UI.getVersion());
- W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
- W.printNumber("PrologSize", UI.PrologSize);
- if (UI.getFrameRegister() != 0) {
- W.printEnum("FrameRegister", UI.getFrameRegister(),
- makeArrayRef(UnwindOpInfo));
- W.printHex("FrameOffset", UI.getFrameOffset());
- } else {
- W.printString("FrameRegister", StringRef("-"));
- W.printString("FrameOffset", StringRef("-"));
- }
-
- W.printNumber("UnwindCodeCount", UI.NumCodes);
- {
- ListScope CodesD(W, "UnwindCodes");
- ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes);
- for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) {
- unsigned UsedSlots = getNumUsedSlots(*I);
- if (UsedSlots > UCs.size()) {
- errs() << "Corrupt unwind data";
- return;
- }
- printUnwindCode(UI, ArrayRef<UnwindCode>(I, E));
- I += UsedSlots - 1;
- }
- }
-
- uint64_t LSDAOffset = SectionOffset + getOffsetOfLSDA(UI);
- if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
- W.printString("Handler",
- formatSymbol(Section, LSDAOffset,
- UI.getLanguageSpecificHandlerOffset()));
- } else if (UI.getFlags() & UNW_ChainInfo) {
- const RuntimeFunction *Chained = UI.getChainedFunctionEntry();
- if (Chained) {
- DictScope D(W, "Chained");
- W.printString("StartAddress", formatSymbol(Section, LSDAOffset + 0,
- Chained->StartAddress));
- W.printString("EndAddress", formatSymbol(Section, LSDAOffset + 4,
- Chained->EndAddress));
- W.printString("UnwindInfoAddress",
- formatSymbol(Section, LSDAOffset + 8,
- Chained->UnwindInfoOffset));
- }
- }
-}
-
-// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
-// the unwind codes array, this function requires that the correct number of
-// slots is provided.
-void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI,
- ArrayRef<UnwindCode> UCs) {
- assert(UCs.size() >= getNumUsedSlots(UCs[0]));
-
- W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset))
- << getUnwindCodeTypeName(UCs[0].getUnwindOp());
-
- uint32_t AllocSize = 0;
-
- switch (UCs[0].getUnwindOp()) {
- case UOP_PushNonVol:
- outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo());
+ switch (Header->Machine) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64: {
+ Win64EH::Dumper Dumper(W);
+ Win64EH::Dumper::SymbolResolver Resolver =
+ [this](const object::coff_section *Section, uint64_t Offset,
+ SymbolRef &Symbol) -> error_code {
+ return this->resolveSymbol(Section, Offset, Symbol);
+ };
+ Win64EH::Dumper::Context Ctx(*Obj, Resolver);
+ Dumper.printData(Ctx);
break;
-
- case UOP_AllocLarge:
- if (UCs[0].getOpInfo() == 0) {
- AllocSize = UCs[1].FrameOffset * 8;
- } else {
- AllocSize = getLargeSlotValue(UCs);
- }
- outs() << " size=" << AllocSize;
- break;
- case UOP_AllocSmall:
- outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8);
- break;
- case UOP_SetFPReg:
- if (UI.getFrameRegister() == 0) {
- outs() << " reg=<invalid>";
- } else {
- outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister())
- << format(", offset=0x%X", UI.getFrameOffset() * 16);
- }
- break;
- case UOP_SaveNonVol:
- outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
- << format(", offset=0x%X", UCs[1].FrameOffset * 8);
- break;
- case UOP_SaveNonVolBig:
- outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo())
- << format(", offset=0x%X", getLargeSlotValue(UCs));
- break;
- case UOP_SaveXMM128:
- outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
- << format(", offset=0x%X", UCs[1].FrameOffset * 16);
- break;
- case UOP_SaveXMM128Big:
- outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo())
- << format(", offset=0x%X", getLargeSlotValue(UCs));
- break;
- case UOP_PushMachFrame:
- outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes");
+ }
+ default:
+ W.printEnum("unsupported Image Machine", Header->Machine,
+ makeArrayRef(ImageFileMachineType));
break;
}
-
- outs() << "\n";
}
+
diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp
new file mode 100644
index 0000000000..449df001cc
--- /dev/null
+++ b/tools/llvm-readobj/Win64EHDumper.cpp
@@ -0,0 +1,327 @@
+//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Win64EHDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::Win64EH;
+
+static const EnumEntry<unsigned> UnwindFlags[] = {
+ { "ExceptionHandler", UNW_ExceptionHandler },
+ { "TerminateHandler", UNW_TerminateHandler },
+ { "ChainInfo" , UNW_ChainInfo }
+};
+
+static const EnumEntry<unsigned> UnwindOpInfo[] = {
+ { "RAX", 0 },
+ { "RCX", 1 },
+ { "RDX", 2 },
+ { "RBX", 3 },
+ { "RSP", 4 },
+ { "RBP", 5 },
+ { "RSI", 6 },
+ { "RDI", 7 },
+ { "R8", 8 },
+ { "R9", 9 },
+ { "R10", 10 },
+ { "R11", 11 },
+ { "R12", 12 },
+ { "R13", 13 },
+ { "R14", 14 },
+ { "R15", 15 }
+};
+
+static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) {
+ return static_cast<const char*>(UI.getLanguageSpecificData())
+ - reinterpret_cast<const char*>(&UI);
+}
+
+static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) {
+ if (UC.size() < 3)
+ return 0;
+ return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16);
+}
+
+// Returns the name of the unwind code.
+static StringRef getUnwindCodeTypeName(uint8_t Code) {
+ switch (Code) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol: return "PUSH_NONVOL";
+ case UOP_AllocLarge: return "ALLOC_LARGE";
+ case UOP_AllocSmall: return "ALLOC_SMALL";
+ case UOP_SetFPReg: return "SET_FPREG";
+ case UOP_SaveNonVol: return "SAVE_NONVOL";
+ case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR";
+ case UOP_SaveXMM128: return "SAVE_XMM128";
+ case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
+ case UOP_PushMachFrame: return "PUSH_MACHFRAME";
+ }
+}
+
+// Returns the name of a referenced register.
+static StringRef getUnwindRegisterName(uint8_t Reg) {
+ switch (Reg) {
+ default: llvm_unreachable("Invalid register");
+ case 0: return "RAX";
+ case 1: return "RCX";
+ case 2: return "RDX";
+ case 3: return "RBX";
+ case 4: return "RSP";
+ case 5: return "RBP";
+ case 6: return "RSI";
+ case 7: return "RDI";
+ case 8: return "R8";
+ case 9: return "R9";
+ case 10: return "R10";
+ case 11: return "R11";
+ case 12: return "R12";
+ case 13: return "R13";
+ case 14: return "R14";
+ case 15: return "R15";
+ }
+}
+
+// Calculates the number of array slots required for the unwind code.
+static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
+ switch (UnwindCode.getUnwindOp()) {
+ default: llvm_unreachable("Invalid unwind code");
+ case UOP_PushNonVol:
+ case UOP_AllocSmall:
+ case UOP_SetFPReg:
+ case UOP_PushMachFrame:
+ return 1;
+ case UOP_SaveNonVol:
+ case UOP_SaveXMM128:
+ return 2;
+ case UOP_SaveNonVolBig:
+ case UOP_SaveXMM128Big:
+ return 3;
+ case UOP_AllocLarge:
+ return (UnwindCode.getOpInfo() == 0) ? 2 : 3;
+ }
+}
+
+static std::string formatSymbol(const Dumper::Context &Ctx,
+ const coff_section *Section, uint64_t Offset,
+ uint32_t Displacement) {
+ std::string Buffer;
+ raw_string_ostream OS(Buffer);
+
+ StringRef Name;
+ SymbolRef Symbol;
+ if (Ctx.ResolveSymbol(Section, Offset, Symbol) || Symbol.getName(Name)) {
+ OS << format(" (0x%" PRIX64 ")", Offset);
+ return OS.str();
+ }
+
+ OS << Name;
+ if (Displacement > 0)
+ OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset);
+ else
+ OS << format(" (0x%" PRIX64 ")", Offset);
+ return OS.str();
+}
+
+static error_code resolveRelocation(const Dumper::Context &Ctx,
+ const coff_section *Section,
+ uint64_t Offset,
+ const coff_section *&ResolvedSection,
+ uint64_t &ResolvedAddress) {
+ SymbolRef Symbol;
+ if (error_code EC = Ctx.ResolveSymbol(Section, Offset, Symbol))
+ return EC;
+
+ if (error_code EC = Symbol.getAddress(ResolvedAddress))
+ return EC;
+
+ section_iterator SI = Ctx.COFF.section_begin();
+ if (error_code EC = Symbol.getSection(SI))
+ return EC;
+
+ ResolvedSection = Ctx.COFF.getCOFFSection(*SI);
+ return object_error::success;
+}
+
+namespace llvm {
+namespace Win64EH {
+void Dumper::printRuntimeFunctionEntry(const Context &Ctx,
+ const coff_section *Section,
+ uint64_t Offset,
+ const RuntimeFunction &RF) {
+ SW.printString("StartAddress",
+ formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress));
+ SW.printString("EndAddress",
+ formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress));
+ SW.printString("UnwindInfoAddress",
+ formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset));
+}
+
+// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
+// the unwind codes array, this function requires that the correct number of
+// slots is provided.
+void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
+ assert(UC.size() >= getNumUsedSlots(UC[0]));
+
+ SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset))
+ << getUnwindCodeTypeName(UC[0].getUnwindOp());
+
+ switch (UC[0].getUnwindOp()) {
+ case UOP_PushNonVol:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo());
+ break;
+
+ case UOP_AllocLarge:
+ OS << " size="
+ << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8
+ : getLargeSlotValue(UC));
+ break;
+
+ case UOP_AllocSmall:
+ OS << " size=" << (UC[0].getOpInfo() + 1) * 8;
+ break;
+
+ case UOP_SetFPReg:
+ if (UI.getFrameRegister() == 0)
+ OS << " reg=<invalid>";
+ else
+ OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister())
+ << format(", offset=0x%X", UI.getFrameOffset() * 16);
+ break;
+
+ case UOP_SaveNonVol:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo())
+ << format(", offset=0x%X", UC[1].FrameOffset * 8);
+ break;
+
+ case UOP_SaveNonVolBig:
+ OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UC));
+ break;
+
+ case UOP_SaveXMM128:
+ OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo())
+ << format(", offset=0x%X", UC[1].FrameOffset * 16);
+ break;
+
+ case UOP_SaveXMM128Big:
+ OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo())
+ << format(", offset=0x%X", getLargeSlotValue(UC));
+ break;
+
+ case UOP_PushMachFrame:
+ OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes");
+ break;
+ }
+
+ OS << "\n";
+}
+
+void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
+ off_t Offset, const UnwindInfo &UI) {
+ DictScope UIS(SW, "UnwindInfo");
+ SW.printNumber("Version", UI.getVersion());
+ SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags));
+ SW.printNumber("PrologSize", UI.PrologSize);
+ if (UI.getFrameRegister()) {
+ SW.printEnum("FrameRegister", UI.getFrameRegister(),
+ makeArrayRef(UnwindOpInfo));
+ SW.printHex("FrameOffset", UI.getFrameOffset());
+ } else {
+ SW.printString("FrameRegister", StringRef("-"));
+ SW.printString("FrameOffset", StringRef("-"));
+ }
+
+ SW.printNumber("UnwindCodeCount", UI.NumCodes);
+ {
+ ListScope UCS(SW, "UnwindCodes");
+ ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes);
+ for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) {
+ unsigned UsedSlots = getNumUsedSlots(*UCI);
+ if (UsedSlots > UC.size()) {
+ errs() << "corrupt unwind data";
+ return;
+ }
+
+ printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE));
+ UCI = UCI + UsedSlots - 1;
+ }
+ }
+
+ uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI);
+ if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) {
+ SW.printString("Handler",
+ formatSymbol(Ctx, Section, LSDAOffset,
+ UI.getLanguageSpecificHandlerOffset()));
+ } else if (UI.getFlags() & UNW_ChainInfo) {
+ if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) {
+ DictScope CS(SW, "Chained");
+ printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained);
+ }
+ }
+}
+
+void Dumper::printRuntimeFunction(const Context &Ctx,
+ const coff_section *Section,
+ uint64_t SectionOffset,
+ const RuntimeFunction &RF) {
+ DictScope RFS(SW, "RuntimeFunction");
+ printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF);
+
+ const coff_section *XData;
+ uint64_t Offset;
+ if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset)))
+ return;
+
+ ArrayRef<uint8_t> Contents;
+ if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty())
+ return;
+
+ Offset = Offset + RF.UnwindInfoOffset;
+ if (Offset > Contents.size())
+ return;
+
+ const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset);
+ printUnwindInfo(Ctx, XData, Offset, *UI);
+}
+
+void Dumper::printData(const Context &Ctx) {
+ for (const auto &Section : Ctx.COFF.sections()) {
+ StringRef Name;
+ if (error(Section.getName(Name)))
+ continue;
+
+ if (Name != ".pdata" && !Name.startswith(".pdata$"))
+ continue;
+
+ const coff_section *PData = Ctx.COFF.getCOFFSection(Section);
+ ArrayRef<uint8_t> Contents;
+ if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty())
+ continue;
+
+ const RuntimeFunction *Entries =
+ reinterpret_cast<const RuntimeFunction *>(Contents.data());
+ const size_t Count = Contents.size() / sizeof(RuntimeFunction);
+ ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count);
+
+ size_t Index = 0;
+ for (const auto &RF : RuntimeFunctions) {
+ printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section),
+ Index * sizeof(RuntimeFunction), RF);
+ ++Index;
+ }
+ }
+}
+}
+}
+
diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h
new file mode 100644
index 0000000000..d0c129c68b
--- /dev/null
+++ b/tools/llvm-readobj/Win64EHDumper.h
@@ -0,0 +1,62 @@
+//===- Win64EHDumper.h - Win64 EH Printing ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H
+#define LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H
+
+#include "StreamWriter.h"
+#include "llvm/Support/Win64EH.h"
+
+#include <functional>
+
+namespace llvm {
+namespace object {
+class COFFObjectFile;
+class SymbolRef;
+struct coff_section;
+}
+
+namespace Win64EH {
+class Dumper {
+ StreamWriter &SW;
+ raw_ostream &OS;
+
+public:
+ typedef std::function<error_code(const object::coff_section *, uint64_t,
+ object::SymbolRef &)> SymbolResolver;
+
+ struct Context {
+ const object::COFFObjectFile &COFF;
+ SymbolResolver ResolveSymbol;
+
+ Context(const object::COFFObjectFile &COFF, SymbolResolver Resolver)
+ : COFF(COFF), ResolveSymbol(Resolver) {}
+ };
+
+private:
+ void printRuntimeFunctionEntry(const Context &Ctx,
+ const object::coff_section *Section,
+ uint64_t SectionOffset,
+ const RuntimeFunction &RF);
+ void printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC);
+ void printUnwindInfo(const Context &Ctx, const object::coff_section *Section,
+ off_t Offset, const UnwindInfo &UI);
+ void printRuntimeFunction(const Context &Ctx,
+ const object::coff_section *Section,
+ uint64_t SectionOffset, const RuntimeFunction &RF);
+
+public:
+ Dumper(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
+
+ void printData(const Context &Ctx);
+};
+}
+}
+
+#endif