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 SymbolRef Symbol; 122288943Sdim if (!Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) { 123288943Sdim if (ErrorOr<StringRef> Name = Symbol.getName()) { 124288943Sdim OS << *Name; 125288943Sdim if (Displacement > 0) 126288943Sdim OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset); 127288943Sdim else 128288943Sdim OS << format(" (0x%" PRIX64 ")", Offset); 129288943Sdim return OS.str(); 130288943Sdim } 131274955Ssvnmir } 132274955Ssvnmir 133288943Sdim 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 147288943Sdim ErrorOr<uint64_t> ResolvedAddressOrErr = Symbol.getAddress(); 148288943Sdim if (std::error_code EC = ResolvedAddressOrErr.getError()) 149274955Ssvnmir return EC; 150288943Sdim ResolvedAddress = *ResolvedAddressOrErr; 151274955Ssvnmir 152296417Sdim ErrorOr<section_iterator> SI = Symbol.getSection(); 153296417Sdim ResolvedSection = Ctx.COFF.getCOFFSection(**SI); 154288943Sdim return std::error_code(); 155274955Ssvnmir} 156274955Ssvnmir 157274955Ssvnmirnamespace llvm { 158274955Ssvnmirnamespace Win64EH { 159274955Ssvnmirvoid Dumper::printRuntimeFunctionEntry(const Context &Ctx, 160274955Ssvnmir const coff_section *Section, 161274955Ssvnmir uint64_t Offset, 162274955Ssvnmir const RuntimeFunction &RF) { 163274955Ssvnmir SW.printString("StartAddress", 164274955Ssvnmir formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress)); 165274955Ssvnmir SW.printString("EndAddress", 166274955Ssvnmir formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress)); 167274955Ssvnmir SW.printString("UnwindInfoAddress", 168274955Ssvnmir formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset)); 169274955Ssvnmir} 170274955Ssvnmir 171274955Ssvnmir// Prints one unwind code. Because an unwind code can occupy up to 3 slots in 172274955Ssvnmir// the unwind codes array, this function requires that the correct number of 173274955Ssvnmir// slots is provided. 174274955Ssvnmirvoid Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) { 175274955Ssvnmir assert(UC.size() >= getNumUsedSlots(UC[0])); 176274955Ssvnmir 177274955Ssvnmir SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) 178274955Ssvnmir << getUnwindCodeTypeName(UC[0].getUnwindOp()); 179274955Ssvnmir 180274955Ssvnmir switch (UC[0].getUnwindOp()) { 181274955Ssvnmir case UOP_PushNonVol: 182274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()); 183274955Ssvnmir break; 184274955Ssvnmir 185274955Ssvnmir case UOP_AllocLarge: 186274955Ssvnmir OS << " size=" 187274955Ssvnmir << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8 188274955Ssvnmir : getLargeSlotValue(UC)); 189274955Ssvnmir break; 190274955Ssvnmir 191274955Ssvnmir case UOP_AllocSmall: 192274955Ssvnmir OS << " size=" << (UC[0].getOpInfo() + 1) * 8; 193274955Ssvnmir break; 194274955Ssvnmir 195274955Ssvnmir case UOP_SetFPReg: 196274955Ssvnmir if (UI.getFrameRegister() == 0) 197274955Ssvnmir OS << " reg=<invalid>"; 198274955Ssvnmir else 199274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) 200274955Ssvnmir << format(", offset=0x%X", UI.getFrameOffset() * 16); 201274955Ssvnmir break; 202274955Ssvnmir 203274955Ssvnmir case UOP_SaveNonVol: 204274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 205274955Ssvnmir << format(", offset=0x%X", UC[1].FrameOffset * 8); 206274955Ssvnmir break; 207274955Ssvnmir 208274955Ssvnmir case UOP_SaveNonVolBig: 209274955Ssvnmir OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 210274955Ssvnmir << format(", offset=0x%X", getLargeSlotValue(UC)); 211274955Ssvnmir break; 212274955Ssvnmir 213274955Ssvnmir case UOP_SaveXMM128: 214274955Ssvnmir OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 215274955Ssvnmir << format(", offset=0x%X", UC[1].FrameOffset * 16); 216274955Ssvnmir break; 217274955Ssvnmir 218274955Ssvnmir case UOP_SaveXMM128Big: 219274955Ssvnmir OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 220274955Ssvnmir << format(", offset=0x%X", getLargeSlotValue(UC)); 221274955Ssvnmir break; 222274955Ssvnmir 223274955Ssvnmir case UOP_PushMachFrame: 224274955Ssvnmir OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); 225274955Ssvnmir break; 226274955Ssvnmir } 227274955Ssvnmir 228274955Ssvnmir OS << "\n"; 229274955Ssvnmir} 230274955Ssvnmir 231274955Ssvnmirvoid Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, 232274955Ssvnmir off_t Offset, const UnwindInfo &UI) { 233274955Ssvnmir DictScope UIS(SW, "UnwindInfo"); 234274955Ssvnmir SW.printNumber("Version", UI.getVersion()); 235274955Ssvnmir SW.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); 236274955Ssvnmir SW.printNumber("PrologSize", UI.PrologSize); 237274955Ssvnmir if (UI.getFrameRegister()) { 238274955Ssvnmir SW.printEnum("FrameRegister", UI.getFrameRegister(), 239274955Ssvnmir makeArrayRef(UnwindOpInfo)); 240274955Ssvnmir SW.printHex("FrameOffset", UI.getFrameOffset()); 241274955Ssvnmir } else { 242274955Ssvnmir SW.printString("FrameRegister", StringRef("-")); 243274955Ssvnmir SW.printString("FrameOffset", StringRef("-")); 244274955Ssvnmir } 245274955Ssvnmir 246274955Ssvnmir SW.printNumber("UnwindCodeCount", UI.NumCodes); 247274955Ssvnmir { 248274955Ssvnmir ListScope UCS(SW, "UnwindCodes"); 249274955Ssvnmir ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes); 250274955Ssvnmir for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) { 251274955Ssvnmir unsigned UsedSlots = getNumUsedSlots(*UCI); 252274955Ssvnmir if (UsedSlots > UC.size()) { 253274955Ssvnmir errs() << "corrupt unwind data"; 254274955Ssvnmir return; 255274955Ssvnmir } 256274955Ssvnmir 257296417Sdim printUnwindCode(UI, makeArrayRef(UCI, UCE)); 258274955Ssvnmir UCI = UCI + UsedSlots - 1; 259274955Ssvnmir } 260274955Ssvnmir } 261274955Ssvnmir 262274955Ssvnmir uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI); 263274955Ssvnmir if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 264274955Ssvnmir SW.printString("Handler", 265274955Ssvnmir formatSymbol(Ctx, Section, LSDAOffset, 266274955Ssvnmir UI.getLanguageSpecificHandlerOffset())); 267274955Ssvnmir } else if (UI.getFlags() & UNW_ChainInfo) { 268274955Ssvnmir if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) { 269274955Ssvnmir DictScope CS(SW, "Chained"); 270274955Ssvnmir printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained); 271274955Ssvnmir } 272274955Ssvnmir } 273274955Ssvnmir} 274274955Ssvnmir 275274955Ssvnmirvoid Dumper::printRuntimeFunction(const Context &Ctx, 276274955Ssvnmir const coff_section *Section, 277274955Ssvnmir uint64_t SectionOffset, 278274955Ssvnmir const RuntimeFunction &RF) { 279274955Ssvnmir DictScope RFS(SW, "RuntimeFunction"); 280274955Ssvnmir printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); 281274955Ssvnmir 282274955Ssvnmir const coff_section *XData; 283274955Ssvnmir uint64_t Offset; 284296417Sdim resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); 285274955Ssvnmir 286274955Ssvnmir ArrayRef<uint8_t> Contents; 287296417Sdim error(Ctx.COFF.getSectionContents(XData, Contents)); 288296417Sdim if (Contents.empty()) 289274955Ssvnmir return; 290274955Ssvnmir 291274955Ssvnmir Offset = Offset + RF.UnwindInfoOffset; 292274955Ssvnmir if (Offset > Contents.size()) 293274955Ssvnmir return; 294274955Ssvnmir 295274955Ssvnmir const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset); 296274955Ssvnmir printUnwindInfo(Ctx, XData, Offset, *UI); 297274955Ssvnmir} 298274955Ssvnmir 299274955Ssvnmirvoid Dumper::printData(const Context &Ctx) { 300274955Ssvnmir for (const auto &Section : Ctx.COFF.sections()) { 301274955Ssvnmir StringRef Name; 302296417Sdim Section.getName(Name); 303274955Ssvnmir 304274955Ssvnmir if (Name != ".pdata" && !Name.startswith(".pdata$")) 305274955Ssvnmir continue; 306274955Ssvnmir 307274955Ssvnmir const coff_section *PData = Ctx.COFF.getCOFFSection(Section); 308274955Ssvnmir ArrayRef<uint8_t> Contents; 309296417Sdim error(Ctx.COFF.getSectionContents(PData, Contents)); 310296417Sdim if (Contents.empty()) 311274955Ssvnmir continue; 312274955Ssvnmir 313274955Ssvnmir const RuntimeFunction *Entries = 314274955Ssvnmir reinterpret_cast<const RuntimeFunction *>(Contents.data()); 315274955Ssvnmir const size_t Count = Contents.size() / sizeof(RuntimeFunction); 316274955Ssvnmir ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count); 317274955Ssvnmir 318274955Ssvnmir size_t Index = 0; 319274955Ssvnmir for (const auto &RF : RuntimeFunctions) { 320274955Ssvnmir printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), 321274955Ssvnmir Index * sizeof(RuntimeFunction), RF); 322274955Ssvnmir ++Index; 323274955Ssvnmir } 324274955Ssvnmir } 325274955Ssvnmir} 326274955Ssvnmir} 327274955Ssvnmir} 328274955Ssvnmir 329