forked from OSchip/llvm-project
tools: split out Win64EHDumper from COFFDumper
Move the implementation of the Win64 EH printer from the COFFDumper into its own class. This is in preparation for adding support to print ARM EH information. The only real change here is in printUnwindInfo where we now lambda lift the implicit this parameter for the resolveFunction. Also setup the printing to handle ARM. This now has set the stage to introduce ARM EH printing. llvm-svn: 209606
This commit is contained in:
parent
4e08f62775
commit
e8839a755a
|
@ -13,4 +13,5 @@ add_llvm_tool(llvm-readobj
|
|||
MachODumper.cpp
|
||||
ObjDumper.cpp
|
||||
StreamWriter.cpp
|
||||
Win64EHDumper.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;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
default:
|
||||
W.printEnum("unsupported Image Machine", Header->Machine,
|
||||
makeArrayRef(ImageFileMachineType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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");
|
||||
break;
|
||||
}
|
||||
|
||||
outs() << "\n";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue