10b57cec5SDimitry Andric //===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "Win64EHDumper.h" 100b57cec5SDimitry Andric #include "llvm-readobj.h" 110b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 120b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 130b57cec5SDimitry Andric #include "llvm/Support/Format.h" 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric using namespace llvm; 160b57cec5SDimitry Andric using namespace llvm::object; 170b57cec5SDimitry Andric using namespace llvm::Win64EH; 180b57cec5SDimitry Andric 19349cc55cSDimitry Andric const EnumEntry<unsigned> UnwindFlags[] = { 200b57cec5SDimitry Andric { "ExceptionHandler", UNW_ExceptionHandler }, 210b57cec5SDimitry Andric { "TerminateHandler", UNW_TerminateHandler }, 220b57cec5SDimitry Andric { "ChainInfo" , UNW_ChainInfo } 230b57cec5SDimitry Andric }; 240b57cec5SDimitry Andric 25349cc55cSDimitry Andric const EnumEntry<unsigned> UnwindOpInfo[] = { 260b57cec5SDimitry Andric { "RAX", 0 }, 270b57cec5SDimitry Andric { "RCX", 1 }, 280b57cec5SDimitry Andric { "RDX", 2 }, 290b57cec5SDimitry Andric { "RBX", 3 }, 300b57cec5SDimitry Andric { "RSP", 4 }, 310b57cec5SDimitry Andric { "RBP", 5 }, 320b57cec5SDimitry Andric { "RSI", 6 }, 330b57cec5SDimitry Andric { "RDI", 7 }, 340b57cec5SDimitry Andric { "R8", 8 }, 350b57cec5SDimitry Andric { "R9", 9 }, 360b57cec5SDimitry Andric { "R10", 10 }, 370b57cec5SDimitry Andric { "R11", 11 }, 380b57cec5SDimitry Andric { "R12", 12 }, 390b57cec5SDimitry Andric { "R13", 13 }, 400b57cec5SDimitry Andric { "R14", 14 }, 410b57cec5SDimitry Andric { "R15", 15 } 420b57cec5SDimitry Andric }; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static uint64_t getOffsetOfLSDA(const UnwindInfo& UI) { 450b57cec5SDimitry Andric return static_cast<const char*>(UI.getLanguageSpecificData()) 460b57cec5SDimitry Andric - reinterpret_cast<const char*>(&UI); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UC) { 500b57cec5SDimitry Andric if (UC.size() < 3) 510b57cec5SDimitry Andric return 0; 520b57cec5SDimitry Andric return UC[1].FrameOffset + (static_cast<uint32_t>(UC[2].FrameOffset) << 16); 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Returns the name of the unwind code. 560b57cec5SDimitry Andric static StringRef getUnwindCodeTypeName(uint8_t Code) { 570b57cec5SDimitry Andric switch (Code) { 580b57cec5SDimitry Andric default: llvm_unreachable("Invalid unwind code"); 590b57cec5SDimitry Andric case UOP_PushNonVol: return "PUSH_NONVOL"; 600b57cec5SDimitry Andric case UOP_AllocLarge: return "ALLOC_LARGE"; 610b57cec5SDimitry Andric case UOP_AllocSmall: return "ALLOC_SMALL"; 620b57cec5SDimitry Andric case UOP_SetFPReg: return "SET_FPREG"; 630b57cec5SDimitry Andric case UOP_SaveNonVol: return "SAVE_NONVOL"; 640b57cec5SDimitry Andric case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; 650b57cec5SDimitry Andric case UOP_SaveXMM128: return "SAVE_XMM128"; 660b57cec5SDimitry Andric case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; 670b57cec5SDimitry Andric case UOP_PushMachFrame: return "PUSH_MACHFRAME"; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Returns the name of a referenced register. 720b57cec5SDimitry Andric static StringRef getUnwindRegisterName(uint8_t Reg) { 730b57cec5SDimitry Andric switch (Reg) { 740b57cec5SDimitry Andric default: llvm_unreachable("Invalid register"); 750b57cec5SDimitry Andric case 0: return "RAX"; 760b57cec5SDimitry Andric case 1: return "RCX"; 770b57cec5SDimitry Andric case 2: return "RDX"; 780b57cec5SDimitry Andric case 3: return "RBX"; 790b57cec5SDimitry Andric case 4: return "RSP"; 800b57cec5SDimitry Andric case 5: return "RBP"; 810b57cec5SDimitry Andric case 6: return "RSI"; 820b57cec5SDimitry Andric case 7: return "RDI"; 830b57cec5SDimitry Andric case 8: return "R8"; 840b57cec5SDimitry Andric case 9: return "R9"; 850b57cec5SDimitry Andric case 10: return "R10"; 860b57cec5SDimitry Andric case 11: return "R11"; 870b57cec5SDimitry Andric case 12: return "R12"; 880b57cec5SDimitry Andric case 13: return "R13"; 890b57cec5SDimitry Andric case 14: return "R14"; 900b57cec5SDimitry Andric case 15: return "R15"; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric // Calculates the number of array slots required for the unwind code. 950b57cec5SDimitry Andric static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { 960b57cec5SDimitry Andric switch (UnwindCode.getUnwindOp()) { 970b57cec5SDimitry Andric default: llvm_unreachable("Invalid unwind code"); 980b57cec5SDimitry Andric case UOP_PushNonVol: 990b57cec5SDimitry Andric case UOP_AllocSmall: 1000b57cec5SDimitry Andric case UOP_SetFPReg: 1010b57cec5SDimitry Andric case UOP_PushMachFrame: 1020b57cec5SDimitry Andric return 1; 1030b57cec5SDimitry Andric case UOP_SaveNonVol: 1040b57cec5SDimitry Andric case UOP_SaveXMM128: 1050b57cec5SDimitry Andric return 2; 1060b57cec5SDimitry Andric case UOP_SaveNonVolBig: 1070b57cec5SDimitry Andric case UOP_SaveXMM128Big: 1080b57cec5SDimitry Andric return 3; 1090b57cec5SDimitry Andric case UOP_AllocLarge: 1100b57cec5SDimitry Andric return (UnwindCode.getOpInfo() == 0) ? 2 : 3; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 114480093f4SDimitry Andric static std::error_code getSymbol(const COFFObjectFile &COFF, uint64_t VA, 115480093f4SDimitry Andric object::SymbolRef &Sym) { 116480093f4SDimitry Andric for (const auto &Symbol : COFF.symbols()) { 117480093f4SDimitry Andric Expected<uint64_t> Address = Symbol.getAddress(); 118480093f4SDimitry Andric if (!Address) 119480093f4SDimitry Andric return errorToErrorCode(Address.takeError()); 120480093f4SDimitry Andric if (*Address == VA) { 121480093f4SDimitry Andric Sym = Symbol; 122e8d8bef9SDimitry Andric return std::error_code(); 123480093f4SDimitry Andric } 124480093f4SDimitry Andric } 125e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 126480093f4SDimitry Andric } 127480093f4SDimitry Andric 128349cc55cSDimitry Andric static object::SymbolRef getPreferredSymbol(const COFFObjectFile &COFF, 129349cc55cSDimitry Andric object::SymbolRef Sym, 130349cc55cSDimitry Andric uint32_t &SymbolOffset, 131349cc55cSDimitry Andric bool IsRangeEnd) { 132349cc55cSDimitry Andric // The symbol resolved by ResolveSymbol can be any internal 133349cc55cSDimitry Andric // nondescriptive symbol; try to resolve a more descriptive one. 134349cc55cSDimitry Andric COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym); 135349cc55cSDimitry Andric if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 136349cc55cSDimitry Andric CoffSym.getSectionDefinition() == nullptr) 137349cc55cSDimitry Andric return Sym; 138349cc55cSDimitry Andric for (const auto &S : COFF.symbols()) { 139349cc55cSDimitry Andric COFFSymbolRef CS = COFF.getCOFFSymbol(S); 140349cc55cSDimitry Andric if (CS.getSectionNumber() == CoffSym.getSectionNumber() && 141349cc55cSDimitry Andric CS.getValue() <= CoffSym.getValue() + SymbolOffset && 142349cc55cSDimitry Andric CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 143349cc55cSDimitry Andric CS.getSectionDefinition() == nullptr) { 144349cc55cSDimitry Andric uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue(); 145349cc55cSDimitry Andric // For the end of a range, don't pick a symbol with a zero offset; 146349cc55cSDimitry Andric // prefer a symbol with a small positive offset. 147349cc55cSDimitry Andric if (Offset <= SymbolOffset && (!IsRangeEnd || Offset > 0)) { 148349cc55cSDimitry Andric SymbolOffset = Offset; 149349cc55cSDimitry Andric Sym = S; 150349cc55cSDimitry Andric CoffSym = CS; 151349cc55cSDimitry Andric if (CS.isExternal() && SymbolOffset == 0) 152349cc55cSDimitry Andric return Sym; 153349cc55cSDimitry Andric } 154349cc55cSDimitry Andric } 155349cc55cSDimitry Andric } 156349cc55cSDimitry Andric return Sym; 157349cc55cSDimitry Andric } 158349cc55cSDimitry Andric 1590b57cec5SDimitry Andric static std::string formatSymbol(const Dumper::Context &Ctx, 1600b57cec5SDimitry Andric const coff_section *Section, uint64_t Offset, 161349cc55cSDimitry Andric uint32_t Displacement, 162349cc55cSDimitry Andric bool IsRangeEnd = false) { 1630b57cec5SDimitry Andric std::string Buffer; 1640b57cec5SDimitry Andric raw_string_ostream OS(Buffer); 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric SymbolRef Symbol; 1670b57cec5SDimitry Andric if (!Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) { 168349cc55cSDimitry Andric // We found a relocation at the given offset in the section, pointing 169349cc55cSDimitry Andric // at a symbol. 170349cc55cSDimitry Andric 171349cc55cSDimitry Andric // Try to resolve label/section symbols into function names. 172349cc55cSDimitry Andric Symbol = getPreferredSymbol(Ctx.COFF, Symbol, Displacement, IsRangeEnd); 173349cc55cSDimitry Andric 1740b57cec5SDimitry Andric Expected<StringRef> Name = Symbol.getName(); 1750b57cec5SDimitry Andric if (Name) { 1760b57cec5SDimitry Andric OS << *Name; 1770b57cec5SDimitry Andric if (Displacement > 0) 1780b57cec5SDimitry Andric OS << format(" +0x%X (0x%" PRIX64 ")", Displacement, Offset); 1790b57cec5SDimitry Andric else 1800b57cec5SDimitry Andric OS << format(" (0x%" PRIX64 ")", Offset); 1810b57cec5SDimitry Andric return OS.str(); 1820b57cec5SDimitry Andric } else { 1830b57cec5SDimitry Andric // TODO: Actually report errors helpfully. 1840b57cec5SDimitry Andric consumeError(Name.takeError()); 1850b57cec5SDimitry Andric } 186480093f4SDimitry Andric } else if (!getSymbol(Ctx.COFF, Ctx.COFF.getImageBase() + Displacement, 187480093f4SDimitry Andric Symbol)) { 188480093f4SDimitry Andric Expected<StringRef> Name = Symbol.getName(); 189480093f4SDimitry Andric if (Name) { 190480093f4SDimitry Andric OS << *Name; 191480093f4SDimitry Andric OS << format(" (0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); 192480093f4SDimitry Andric return OS.str(); 193480093f4SDimitry Andric } else { 194480093f4SDimitry Andric consumeError(Name.takeError()); 195480093f4SDimitry Andric } 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 198480093f4SDimitry Andric if (Displacement > 0) 199480093f4SDimitry Andric OS << format("(0x%" PRIX64 ")", Ctx.COFF.getImageBase() + Displacement); 200480093f4SDimitry Andric else 2010b57cec5SDimitry Andric OS << format("(0x%" PRIX64 ")", Offset); 2020b57cec5SDimitry Andric return OS.str(); 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric static std::error_code resolveRelocation(const Dumper::Context &Ctx, 2060b57cec5SDimitry Andric const coff_section *Section, 2070b57cec5SDimitry Andric uint64_t Offset, 2080b57cec5SDimitry Andric const coff_section *&ResolvedSection, 2090b57cec5SDimitry Andric uint64_t &ResolvedAddress) { 2100b57cec5SDimitry Andric SymbolRef Symbol; 2110b57cec5SDimitry Andric if (std::error_code EC = 2120b57cec5SDimitry Andric Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) 2130b57cec5SDimitry Andric return EC; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric Expected<uint64_t> ResolvedAddressOrErr = Symbol.getAddress(); 2160b57cec5SDimitry Andric if (!ResolvedAddressOrErr) 2170b57cec5SDimitry Andric return errorToErrorCode(ResolvedAddressOrErr.takeError()); 2180b57cec5SDimitry Andric ResolvedAddress = *ResolvedAddressOrErr; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric Expected<section_iterator> SI = Symbol.getSection(); 2210b57cec5SDimitry Andric if (!SI) 2220b57cec5SDimitry Andric return errorToErrorCode(SI.takeError()); 2230b57cec5SDimitry Andric ResolvedSection = Ctx.COFF.getCOFFSection(**SI); 2240b57cec5SDimitry Andric return std::error_code(); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 227480093f4SDimitry Andric static const object::coff_section * 228480093f4SDimitry Andric getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { 229480093f4SDimitry Andric for (const auto &Section : COFF.sections()) { 230480093f4SDimitry Andric uint64_t Address = Section.getAddress(); 231480093f4SDimitry Andric uint64_t Size = Section.getSize(); 232480093f4SDimitry Andric 233480093f4SDimitry Andric if (VA >= Address && (VA - Address) <= Size) 234480093f4SDimitry Andric return COFF.getCOFFSection(Section); 235480093f4SDimitry Andric } 236480093f4SDimitry Andric return nullptr; 237480093f4SDimitry Andric } 238480093f4SDimitry Andric 2390b57cec5SDimitry Andric namespace llvm { 2400b57cec5SDimitry Andric namespace Win64EH { 2410b57cec5SDimitry Andric void Dumper::printRuntimeFunctionEntry(const Context &Ctx, 2420b57cec5SDimitry Andric const coff_section *Section, 2430b57cec5SDimitry Andric uint64_t Offset, 2440b57cec5SDimitry Andric const RuntimeFunction &RF) { 2450b57cec5SDimitry Andric SW.printString("StartAddress", 2460b57cec5SDimitry Andric formatSymbol(Ctx, Section, Offset + 0, RF.StartAddress)); 2470b57cec5SDimitry Andric SW.printString("EndAddress", 248349cc55cSDimitry Andric formatSymbol(Ctx, Section, Offset + 4, RF.EndAddress, 249349cc55cSDimitry Andric /*IsRangeEnd=*/true)); 2500b57cec5SDimitry Andric SW.printString("UnwindInfoAddress", 2510b57cec5SDimitry Andric formatSymbol(Ctx, Section, Offset + 8, RF.UnwindInfoOffset)); 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // Prints one unwind code. Because an unwind code can occupy up to 3 slots in 2550b57cec5SDimitry Andric // the unwind codes array, this function requires that the correct number of 2560b57cec5SDimitry Andric // slots is provided. 2570b57cec5SDimitry Andric void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) { 2580b57cec5SDimitry Andric assert(UC.size() >= getNumUsedSlots(UC[0])); 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset)) 2610b57cec5SDimitry Andric << getUnwindCodeTypeName(UC[0].getUnwindOp()); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric switch (UC[0].getUnwindOp()) { 2640b57cec5SDimitry Andric case UOP_PushNonVol: 2650b57cec5SDimitry Andric OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()); 2660b57cec5SDimitry Andric break; 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric case UOP_AllocLarge: 2690b57cec5SDimitry Andric OS << " size=" 2700b57cec5SDimitry Andric << ((UC[0].getOpInfo() == 0) ? UC[1].FrameOffset * 8 2710b57cec5SDimitry Andric : getLargeSlotValue(UC)); 2720b57cec5SDimitry Andric break; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric case UOP_AllocSmall: 2750b57cec5SDimitry Andric OS << " size=" << (UC[0].getOpInfo() + 1) * 8; 2760b57cec5SDimitry Andric break; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric case UOP_SetFPReg: 2790b57cec5SDimitry Andric if (UI.getFrameRegister() == 0) 2800b57cec5SDimitry Andric OS << " reg=<invalid>"; 2810b57cec5SDimitry Andric else 2820b57cec5SDimitry Andric OS << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) 2830b57cec5SDimitry Andric << format(", offset=0x%X", UI.getFrameOffset() * 16); 2840b57cec5SDimitry Andric break; 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric case UOP_SaveNonVol: 2870b57cec5SDimitry Andric OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 2880b57cec5SDimitry Andric << format(", offset=0x%X", UC[1].FrameOffset * 8); 2890b57cec5SDimitry Andric break; 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric case UOP_SaveNonVolBig: 2920b57cec5SDimitry Andric OS << " reg=" << getUnwindRegisterName(UC[0].getOpInfo()) 2930b57cec5SDimitry Andric << format(", offset=0x%X", getLargeSlotValue(UC)); 2940b57cec5SDimitry Andric break; 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric case UOP_SaveXMM128: 2970b57cec5SDimitry Andric OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 2980b57cec5SDimitry Andric << format(", offset=0x%X", UC[1].FrameOffset * 16); 2990b57cec5SDimitry Andric break; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric case UOP_SaveXMM128Big: 3020b57cec5SDimitry Andric OS << " reg=XMM" << static_cast<uint32_t>(UC[0].getOpInfo()) 3030b57cec5SDimitry Andric << format(", offset=0x%X", getLargeSlotValue(UC)); 3040b57cec5SDimitry Andric break; 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric case UOP_PushMachFrame: 3070b57cec5SDimitry Andric OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes"); 3080b57cec5SDimitry Andric break; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric OS << "\n"; 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, 3150b57cec5SDimitry Andric off_t Offset, const UnwindInfo &UI) { 3160b57cec5SDimitry Andric DictScope UIS(SW, "UnwindInfo"); 3170b57cec5SDimitry Andric SW.printNumber("Version", UI.getVersion()); 318bdd1243dSDimitry Andric SW.printFlags("Flags", UI.getFlags(), ArrayRef(UnwindFlags)); 3190b57cec5SDimitry Andric SW.printNumber("PrologSize", UI.PrologSize); 3200b57cec5SDimitry Andric if (UI.getFrameRegister()) { 3210b57cec5SDimitry Andric SW.printEnum("FrameRegister", UI.getFrameRegister(), 322bdd1243dSDimitry Andric ArrayRef(UnwindOpInfo)); 3230b57cec5SDimitry Andric SW.printHex("FrameOffset", UI.getFrameOffset()); 3240b57cec5SDimitry Andric } else { 3250b57cec5SDimitry Andric SW.printString("FrameRegister", StringRef("-")); 3260b57cec5SDimitry Andric SW.printString("FrameOffset", StringRef("-")); 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric SW.printNumber("UnwindCodeCount", UI.NumCodes); 3300b57cec5SDimitry Andric { 3310b57cec5SDimitry Andric ListScope UCS(SW, "UnwindCodes"); 3320b57cec5SDimitry Andric ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes); 3330b57cec5SDimitry Andric for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) { 3340b57cec5SDimitry Andric unsigned UsedSlots = getNumUsedSlots(*UCI); 3350b57cec5SDimitry Andric if (UsedSlots > UC.size()) { 3360b57cec5SDimitry Andric errs() << "corrupt unwind data"; 3370b57cec5SDimitry Andric return; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 340bdd1243dSDimitry Andric printUnwindCode(UI, ArrayRef(UCI, UCE)); 3410b57cec5SDimitry Andric UCI = UCI + UsedSlots - 1; 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric uint64_t LSDAOffset = Offset + getOffsetOfLSDA(UI); 3460b57cec5SDimitry Andric if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 3470b57cec5SDimitry Andric SW.printString("Handler", 3480b57cec5SDimitry Andric formatSymbol(Ctx, Section, LSDAOffset, 3490b57cec5SDimitry Andric UI.getLanguageSpecificHandlerOffset())); 3500b57cec5SDimitry Andric } else if (UI.getFlags() & UNW_ChainInfo) { 3510b57cec5SDimitry Andric if (const RuntimeFunction *Chained = UI.getChainedFunctionEntry()) { 3520b57cec5SDimitry Andric DictScope CS(SW, "Chained"); 3530b57cec5SDimitry Andric printRuntimeFunctionEntry(Ctx, Section, LSDAOffset, *Chained); 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric void Dumper::printRuntimeFunction(const Context &Ctx, 3590b57cec5SDimitry Andric const coff_section *Section, 3600b57cec5SDimitry Andric uint64_t SectionOffset, 3610b57cec5SDimitry Andric const RuntimeFunction &RF) { 3620b57cec5SDimitry Andric DictScope RFS(SW, "RuntimeFunction"); 3630b57cec5SDimitry Andric printRuntimeFunctionEntry(Ctx, Section, SectionOffset, RF); 3640b57cec5SDimitry Andric 365480093f4SDimitry Andric const coff_section *XData = nullptr; 3660b57cec5SDimitry Andric uint64_t Offset; 3670b57cec5SDimitry Andric resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); 368480093f4SDimitry Andric Offset = Offset + RF.UnwindInfoOffset; 369480093f4SDimitry Andric 370480093f4SDimitry Andric if (!XData) { 371480093f4SDimitry Andric uint64_t Address = Ctx.COFF.getImageBase() + RF.UnwindInfoOffset; 372480093f4SDimitry Andric XData = getSectionContaining(Ctx.COFF, Address); 373480093f4SDimitry Andric if (!XData) 374480093f4SDimitry Andric return; 375480093f4SDimitry Andric Offset = RF.UnwindInfoOffset - XData->VirtualAddress; 376480093f4SDimitry Andric } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 3798bcb0991SDimitry Andric if (Error E = Ctx.COFF.getSectionContents(XData, Contents)) 3808bcb0991SDimitry Andric reportError(std::move(E), Ctx.COFF.getFileName()); 3818bcb0991SDimitry Andric 3820b57cec5SDimitry Andric if (Contents.empty()) 3830b57cec5SDimitry Andric return; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric if (Offset > Contents.size()) 3860b57cec5SDimitry Andric return; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric const auto UI = reinterpret_cast<const UnwindInfo*>(Contents.data() + Offset); 3890b57cec5SDimitry Andric printUnwindInfo(Ctx, XData, Offset, *UI); 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric void Dumper::printData(const Context &Ctx) { 3930b57cec5SDimitry Andric for (const auto &Section : Ctx.COFF.sections()) { 3940b57cec5SDimitry Andric StringRef Name; 3958bcb0991SDimitry Andric if (Expected<StringRef> NameOrErr = Section.getName()) 3968bcb0991SDimitry Andric Name = *NameOrErr; 3978bcb0991SDimitry Andric else 3988bcb0991SDimitry Andric consumeError(NameOrErr.takeError()); 3990b57cec5SDimitry Andric 400*5f757f3fSDimitry Andric if (Name != ".pdata" && !Name.starts_with(".pdata$")) 4010b57cec5SDimitry Andric continue; 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric const coff_section *PData = Ctx.COFF.getCOFFSection(Section); 4040b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 4058bcb0991SDimitry Andric 4068bcb0991SDimitry Andric if (Error E = Ctx.COFF.getSectionContents(PData, Contents)) 4078bcb0991SDimitry Andric reportError(std::move(E), Ctx.COFF.getFileName()); 4080b57cec5SDimitry Andric if (Contents.empty()) 4090b57cec5SDimitry Andric continue; 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric const RuntimeFunction *Entries = 4120b57cec5SDimitry Andric reinterpret_cast<const RuntimeFunction *>(Contents.data()); 4130b57cec5SDimitry Andric const size_t Count = Contents.size() / sizeof(RuntimeFunction); 4140b57cec5SDimitry Andric ArrayRef<RuntimeFunction> RuntimeFunctions(Entries, Count); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric size_t Index = 0; 4170b57cec5SDimitry Andric for (const auto &RF : RuntimeFunctions) { 4180b57cec5SDimitry Andric printRuntimeFunction(Ctx, Ctx.COFF.getCOFFSection(Section), 4190b57cec5SDimitry Andric Index * sizeof(RuntimeFunction), RF); 4200b57cec5SDimitry Andric ++Index; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 427