Win64EHDumper.cpp revision 274955
1274955Ssvnmir//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===// 2274955Ssvnmir// 3274955Ssvnmir// The LLVM Compiler Infrastructure 4274955Ssvnmir// 5274955Ssvnmir// This file is distributed under the University of Illinois Open Source 6274955Ssvnmir// License. See LICENSE.TXT for details. 7274955Ssvnmir// 8274955Ssvnmir//===----------------------------------------------------------------------===// 9274955Ssvnmir 10274955Ssvnmir#include "Win64EHDumper.h" 11274955Ssvnmir#include "llvm-readobj.h" 12274955Ssvnmir#include "llvm/Object/COFF.h" 13274955Ssvnmir#include "llvm/Support/ErrorHandling.h" 14274955Ssvnmir#include "llvm/Support/Format.h" 15274955Ssvnmir 16274955Ssvnmirusing namespace llvm; 17274955Ssvnmirusing namespace llvm::object; 18274955Ssvnmirusing namespace llvm::Win64EH; 19274955Ssvnmir 20274955Ssvnmirstatic const EnumEntry<unsigned> UnwindFlags[] = { 21274955Ssvnmir { "ExceptionHandler", UNW_ExceptionHandler }, 22274955Ssvnmir { "TerminateHandler", UNW_TerminateHandler }, 23274955Ssvnmir { "ChainInfo" , UNW_ChainInfo } 24274955Ssvnmir}; 25274955Ssvnmir 26274955Ssvnmirstatic const EnumEntry<unsigned> UnwindOpInfo[] = { 27274955Ssvnmir { "RAX", 0 }, 28274955Ssvnmir { "RCX", 1 }, 29274955Ssvnmir { "RDX", 2 }, 30274955Ssvnmir { "RBX", 3 }, 31274955Ssvnmir { "RSP", 4 }, 32274955Ssvnmir { "RBP", 5 }, 33274955Ssvnmir { "RSI", 6 }, 34274955Ssvnmir { "RDI", 7 }, 35274955Ssvnmir { "R8", 8 }, 36274955Ssvnmir { "R9", 9 }, 37274955Ssvnmir { "R10", 10 }, 38274955Ssvnmir { "R11", 11 }, 39274955Ssvnmir { "R12", 12 }, 40274955Ssvnmir { "R13", 13 }, 41274955Ssvnmir { "R14", 14 }, 42274955Ssvnmir { "R15", 15 } 43274955Ssvnmir}; 44274955Ssvnmir 45274955Ssvnmirstatic uint64_t getOffsetOfLSDA(const UnwindInfo& UI) { 46274955Ssvnmir return static_cast<const char*>(UI.getLanguageSpecificData()) 47274955Ssvnmir - reinterpret_cast<const char*>(&UI); 48274955Ssvnmir} 49274955Ssvnmir 50274955Ssvnmirstatic uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) { 51274955Ssvnmir if (UC.size() < 3) 52274955Ssvnmir return 0; 53274955Ssvnmir return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16); 54274955Ssvnmir} 55274955Ssvnmir 56274955Ssvnmir// Returns the name of the unwind code. 57274955Ssvnmirstatic StringRef getUnwindCodeTypeName(uint8_t Code) { 58274955Ssvnmir switch (Code) { 59274955Ssvnmir default: llvm_unreachable("Invalid unwind code"); 60274955Ssvnmir case UOP_PushNonVol: return "PUSH_NONVOL"; 61274955Ssvnmir case UOP_AllocLarge: return "ALLOC_LARGE"; 62274955Ssvnmir case UOP_AllocSmall: return "ALLOC_SMALL"; 63274955Ssvnmir case UOP_SetFPReg: return "SET_FPREG"; 64274955Ssvnmir case UOP_SaveNonVol: return "SAVE_NONVOL"; 65274955Ssvnmir case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; 66274955Ssvnmir case UOP_SaveXMM128: return "SAVE_XMM128"; 67274955Ssvnmir case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; 68274955Ssvnmir case UOP_PushMachFrame: return "PUSH_MACHFRAME"; 69274955Ssvnmir } 70274955Ssvnmir} 71274955Ssvnmir 72274955Ssvnmir// Returns the name of a referenced register. 73274955Ssvnmirstatic StringRef getUnwindRegisterName(uint8_t Reg) { 74274955Ssvnmir switch (Reg) { 75274955Ssvnmir default: llvm_unreachable("Invalid register"); 76274955Ssvnmir case 0: return "RAX"; 77274955Ssvnmir case 1: return "RCX"; 78274955Ssvnmir case 2: return "RDX"; 79274955Ssvnmir case 3: return "RBX"; 80274955Ssvnmir case 4: return "RSP"; 81274955Ssvnmir case 5: return "RBP"; 82274955Ssvnmir case 6: return "RSI"; 83274955Ssvnmir case 7: return "RDI"; 84274955Ssvnmir case 8: return "R8"; 85274955Ssvnmir case 9: return "R9"; 86274955Ssvnmir case 10: return "R10"; 87274955Ssvnmir case 11: return "R11"; 88274955Ssvnmir case 12: return "R12"; 89274955Ssvnmir case 13: return "R13"; 90274955Ssvnmir case 14: return "R14"; 91274955Ssvnmir case 15: return "R15"; 92274955Ssvnmir } 93274955Ssvnmir} 94274955Ssvnmir 95274955Ssvnmir// Calculates the number of array slots required for the unwind code. 96274955Ssvnmirstatic unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { 97274955Ssvnmir switch (UnwindCode.getUnwindOp()) { 98274955Ssvnmir default: llvm_unreachable("Invalid unwind code"); 99274955Ssvnmir case UOP_PushNonVol: 100274955Ssvnmir case UOP_AllocSmall: 101274955Ssvnmir case UOP_SetFPReg: 102274955Ssvnmir case UOP_PushMachFrame: 103274955Ssvnmir return 1; 104274955Ssvnmir case UOP_SaveNonVol: 105274955Ssvnmir case UOP_SaveXMM128: 106274955Ssvnmir return 2; 107274955Ssvnmir case UOP_SaveNonVolBig: 108274955Ssvnmir case UOP_SaveXMM128Big: 109274955Ssvnmir return 3; 110274955Ssvnmir case UOP_AllocLarge: 111274955Ssvnmir return (UnwindCode.getOpInfo() == 0) ? 2 : 3; 112274955Ssvnmir } 113274955Ssvnmir} 114274955Ssvnmir 115274955Ssvnmirstatic std::string formatSymbol(const Dumper::Context &Ctx, 116274955Ssvnmir const coff_section *Section, uint64_t Offset, 117274955Ssvnmir uint32_t Displacement) { 118274955Ssvnmir std::string Buffer; 119274955Ssvnmir raw_string_ostream OS(Buffer); 120274955Ssvnmir 121274955Ssvnmir StringRef Name; 122274955Ssvnmir SymbolRef Symbol; 123274955Ssvnmir if (Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData) || 124274955Ssvnmir Symbol.getName(Name)) { 125274955Ssvnmir OS << format(" (0x%" PRIX64 ")", Offset); 126274955Ssvnmir return OS.str(); 127274955Ssvnmir } 128274955Ssvnmir 129274955Ssvnmir OS << Name; 130274955Ssvnmir if (Displacement > 0) 131274955Ssvnmir OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset); 132274955Ssvnmir else 133274955Ssvnmir OS << format(" (0x%" PRIX64 ")", Offset); 134274955Ssvnmir return OS.str(); 135274955Ssvnmir} 136274955Ssvnmir 137274955Ssvnmirstatic std::error_code resolveRelocation(const Dumper::Context &Ctx, 138274955Ssvnmir const coff_section *Section, 139274955Ssvnmir uint64_t Offset, 140274955Ssvnmir const coff_section *&ResolvedSection, 141274955Ssvnmir uint64_t &ResolvedAddress) { 142274955Ssvnmir SymbolRef Symbol; 143274955Ssvnmir if (std::error_code EC = 144274955Ssvnmir Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) 145274955Ssvnmir return EC; 146274955Ssvnmir 147274955Ssvnmir if (std::error_code EC = Symbol.getAddress(ResolvedAddress)) 148274955Ssvnmir return EC; 149274955Ssvnmir 150274955Ssvnmir section_iterator SI = Ctx.COFF.section_begin(); 151274955Ssvnmir if (std::error_code EC = Symbol.getSection(SI)) 152274955Ssvnmir return EC; 153274955Ssvnmir 154274955Ssvnmir ResolvedSection = Ctx.COFF.getCOFFSection(*SI); 155274955Ssvnmir return object_error::success; 156274955Ssvnmir} 157274955Ssvnmir 158274955Ssvnmirnamespace llvm { 159274955Ssvnmirnamespace Win64EH { 160274955Ssvnmirvoid Dumper::printRuntimeFunctionEntry(const Context &Ctx, 161274955Ssvnmir const coff_section *Section, 162274955Ssvnmir uint64_t Offset, 163274955Ssvnmir const RuntimeFunction &RF) { 164274955Ssvnmir SW.printString("StartAddress", 165274955Ssvnmir formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress)); 166274955Ssvnmir SW.printString("EndAddress", 167274955Ssvnmir formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress)); 168274955Ssvnmir SW.printString("UnwindInfoAddress", 169274955Ssvnmir formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset)); 170274955Ssvnmir} 171274955Ssvnmir 172274955Ssvnmir// Prints one unwind code. Because an unwind code can occupy up to 3 slots in 173274955Ssvnmir// the unwind codes array, this function requires that the correct number of 174274955Ssvnmir// slots is provided. 175274955Ssvnmirvoid Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) { 176274955Ssvnmir assert(UC.size() >= getNumUsedSlots(UC[0])); 177274955Ssvnmir 178274955Ssvnmir SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) 179274955Ssvnmir << getUnwindCodeTypeName(UC[0].getUnwindOp()); 180274955Ssvnmir 181274955Ssvnmir switch (UC[0].getUnwindOp()) { 182274955Ssvnmir case UOP_PushNonVol: 183274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()); 184274955Ssvnmir break; 185274955Ssvnmir 186274955Ssvnmir case UOP_AllocLarge: 187274955Ssvnmir OS << " size=" 188274955Ssvnmir << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8 189274955Ssvnmir : getLargeSlotValue(UC)); 190274955Ssvnmir break; 191274955Ssvnmir 192274955Ssvnmir case UOP_AllocSmall: 193274955Ssvnmir OS << " size=" << (UC[0].getOpInfo() + 1) * 8; 194274955Ssvnmir break; 195274955Ssvnmir 196274955Ssvnmir case UOP_SetFPReg: 197274955Ssvnmir if (UI.getFrameRegister() == 0) 198274955Ssvnmir OS << " reg=<invalid>"; 199274955Ssvnmir else 200274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) 201274955Ssvnmir << format(", offset=0x%X", UI.getFrameOffset() * 16); 202274955Ssvnmir break; 203274955Ssvnmir 204274955Ssvnmir case UOP_SaveNonVol: 205274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 206274955Ssvnmir << format(", offset=0x%X", UC[1].FrameOffset * 8); 207274955Ssvnmir break; 208274955Ssvnmir 209274955Ssvnmir case UOP_SaveNonVolBig: 210274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 211274955Ssvnmir << format(", offset=0x%X", getLargeSlotValue(UC)); 212274955Ssvnmir break; 213274955Ssvnmir 214274955Ssvnmir case UOP_SaveXMM128: 215274955Ssvnmir OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 216274955Ssvnmir << format(", offset=0x%X", UC[1].FrameOffset * 16); 217274955Ssvnmir break; 218274955Ssvnmir 219274955Ssvnmir case UOP_SaveXMM128Big: 220274955Ssvnmir OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 221274955Ssvnmir << format(", offset=0x%X", getLargeSlotValue(UC)); 222274955Ssvnmir break; 223274955Ssvnmir 224274955Ssvnmir case UOP_PushMachFrame: 225274955Ssvnmir OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); 226274955Ssvnmir break; 227274955Ssvnmir } 228274955Ssvnmir 229274955Ssvnmir OS << "\n"; 230274955Ssvnmir} 231274955Ssvnmir 232274955Ssvnmirvoid Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, 233274955Ssvnmir off_t Offset, const UnwindInfo &UI) { 234274955Ssvnmir DictScope UIS(SW, "UnwindInfo"); 235274955Ssvnmir SW.printNumber("Version", UI.getVersion()); 236274955Ssvnmir SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); 237274955Ssvnmir SW.printNumber("PrologSize", UI.PrologSize); 238274955Ssvnmir if (UI.getFrameRegister()) { 239274955Ssvnmir SW.printEnum("FrameRegister", UI.getFrameRegister(), 240274955Ssvnmir makeArrayRef(UnwindOpInfo)); 241274955Ssvnmir SW.printHex("FrameOffset", UI.getFrameOffset()); 242274955Ssvnmir } else { 243274955Ssvnmir SW.printString("FrameRegister", StringRef("-")); 244274955Ssvnmir SW.printString("FrameOffset", StringRef("-")); 245274955Ssvnmir } 246274955Ssvnmir 247274955Ssvnmir SW.printNumber("UnwindCodeCount", UI.NumCodes); 248274955Ssvnmir { 249274955Ssvnmir ListScope UCS(SW, "UnwindCodes"); 250274955Ssvnmir ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes); 251274955Ssvnmir for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) { 252274955Ssvnmir unsigned UsedSlots = getNumUsedSlots(*UCI); 253274955Ssvnmir if (UsedSlots > UC.size()) { 254274955Ssvnmir errs() << "corrupt unwind data"; 255274955Ssvnmir return; 256274955Ssvnmir } 257274955Ssvnmir 258274955Ssvnmir printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE)); 259274955Ssvnmir UCI = UCI + UsedSlots - 1; 260274955Ssvnmir } 261274955Ssvnmir } 262274955Ssvnmir 263274955Ssvnmir uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI); 264274955Ssvnmir if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 265274955Ssvnmir SW.printString("Handler", 266274955Ssvnmir formatSymbol(Ctx, Section, LSDAOffset, 267274955Ssvnmir UI.getLanguageSpecificHandlerOffset())); 268274955Ssvnmir } else if (UI.getFlags() & UNW_ChainInfo) { 269274955Ssvnmir if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) { 270274955Ssvnmir DictScope CS(SW, "Chained"); 271274955Ssvnmir printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained); 272274955Ssvnmir } 273274955Ssvnmir } 274274955Ssvnmir} 275274955Ssvnmir 276274955Ssvnmirvoid Dumper::printRuntimeFunction(const Context &Ctx, 277274955Ssvnmir const coff_section *Section, 278274955Ssvnmir uint64_t SectionOffset, 279274955Ssvnmir const RuntimeFunction &RF) { 280274955Ssvnmir DictScope RFS(SW, "RuntimeFunction"); 281274955Ssvnmir printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); 282274955Ssvnmir 283274955Ssvnmir const coff_section *XData; 284274955Ssvnmir uint64_t Offset; 285274955Ssvnmir if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset))) 286274955Ssvnmir return; 287274955Ssvnmir 288274955Ssvnmir ArrayRef<uint8_t> Contents; 289274955Ssvnmir if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty()) 290274955Ssvnmir return; 291274955Ssvnmir 292274955Ssvnmir Offset = Offset + RF.UnwindInfoOffset; 293274955Ssvnmir if (Offset > Contents.size()) 294274955Ssvnmir return; 295274955Ssvnmir 296274955Ssvnmir const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset); 297274955Ssvnmir printUnwindInfo(Ctx, XData, Offset, *UI); 298274955Ssvnmir} 299274955Ssvnmir 300274955Ssvnmirvoid Dumper::printData(const Context &Ctx) { 301274955Ssvnmir for (const auto &Section : Ctx.COFF.sections()) { 302274955Ssvnmir StringRef Name; 303274955Ssvnmir if (error(Section.getName(Name))) 304274955Ssvnmir continue; 305274955Ssvnmir 306274955Ssvnmir if (Name != ".pdata" && !Name.startswith(".pdata$")) 307274955Ssvnmir continue; 308274955Ssvnmir 309274955Ssvnmir const coff_section *PData = Ctx.COFF.getCOFFSection(Section); 310274955Ssvnmir ArrayRef<uint8_t> Contents; 311274955Ssvnmir if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty()) 312274955Ssvnmir continue; 313274955Ssvnmir 314274955Ssvnmir const RuntimeFunction *Entries = 315274955Ssvnmir reinterpret_cast<const RuntimeFunction *>(Contents.data()); 316274955Ssvnmir const size_t Count = Contents.size() / sizeof(RuntimeFunction); 317274955Ssvnmir ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count); 318274955Ssvnmir 319274955Ssvnmir size_t Index = 0; 320274955Ssvnmir for (const auto &RF : RuntimeFunctions) { 321274955Ssvnmir printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), 322274955Ssvnmir Index * sizeof(RuntimeFunction), RF); 323274955Ssvnmir ++Index; 324274955Ssvnmir } 325274955Ssvnmir } 326274955Ssvnmir} 327274955Ssvnmir} 328274955Ssvnmir} 329274955Ssvnmir 330