10b57cec5SDimitry Andric //===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data 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 // Windows on ARM uses a series of serialised data structures (RuntimeFunction) 100b57cec5SDimitry Andric // to create a table of information for unwinding. In order to conserve space, 110b57cec5SDimitry Andric // there are two different ways that this data is represented. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric // For functions with canonical forms for the prologue and epilogue, the data 140b57cec5SDimitry Andric // can be stored in a "packed" form. In this case, the data is packed into the 150b57cec5SDimitry Andric // RuntimeFunction's remaining 30-bits and can fully describe the entire frame. 160b57cec5SDimitry Andric // 170b57cec5SDimitry Andric // +---------------------------------------+ 180b57cec5SDimitry Andric // | Function Entry Address | 190b57cec5SDimitry Andric // +---------------------------------------+ 200b57cec5SDimitry Andric // | Packed Form Data | 210b57cec5SDimitry Andric // +---------------------------------------+ 220b57cec5SDimitry Andric // 230b57cec5SDimitry Andric // This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is 240b57cec5SDimitry Andric // associated with such a frame as they can be derived from the provided data. 250b57cec5SDimitry Andric // The decoder does not synthesize this data as it is unnecessary for the 260b57cec5SDimitry Andric // purposes of validation, with the synthesis being required only by a proper 270b57cec5SDimitry Andric // unwinder. 280b57cec5SDimitry Andric // 290b57cec5SDimitry Andric // For functions that are large or do not match canonical forms, the data is 300b57cec5SDimitry Andric // split up into two portions, with the actual data residing in the "exception 310b57cec5SDimitry Andric // data" table (.xdata) with a reference to the entry from the "procedure data" 320b57cec5SDimitry Andric // (.pdata) entry. 330b57cec5SDimitry Andric // 340b57cec5SDimitry Andric // The exception data contains information about the frame setup, all of the 350b57cec5SDimitry Andric // epilogue scopes (for functions for which there are multiple exit points) and 360b57cec5SDimitry Andric // the associated exception handler. Additionally, the entry contains byte-code 370b57cec5SDimitry Andric // describing how to unwind the function (c.f. Decoder::decodeOpcodes). 380b57cec5SDimitry Andric // 390b57cec5SDimitry Andric // +---------------------------------------+ 400b57cec5SDimitry Andric // | Function Entry Address | 410b57cec5SDimitry Andric // +---------------------------------------+ 420b57cec5SDimitry Andric // | Exception Data Entry Address | 430b57cec5SDimitry Andric // +---------------------------------------+ 440b57cec5SDimitry Andric // 450b57cec5SDimitry Andric // This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must 460b57cec5SDimitry Andric // first resolve the exception data entry address. This structure 470b57cec5SDimitry Andric // (ExceptionDataRecord) has a variable sized header 480b57cec5SDimitry Andric // (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as 490b57cec5SDimitry Andric // the packed form. However, because this information is insufficient to 500b57cec5SDimitry Andric // synthesize the unwinding, there are associated unwinding bytecode which make 510b57cec5SDimitry Andric // up the bulk of the Decoder. 520b57cec5SDimitry Andric // 530b57cec5SDimitry Andric // The decoder itself is table-driven, using the first byte to determine the 540b57cec5SDimitry Andric // opcode and dispatching to the associated printing routine. The bytecode 550b57cec5SDimitry Andric // itself is a variable length instruction encoding that can fully describe the 560b57cec5SDimitry Andric // state of the stack and the necessary operations for unwinding to the 570b57cec5SDimitry Andric // beginning of the frame. 580b57cec5SDimitry Andric // 590b57cec5SDimitry Andric // The byte-code maintains a 1-1 instruction mapping, indicating both the width 600b57cec5SDimitry Andric // of the instruction (Thumb2 instructions are variable length, 16 or 32 bits 610b57cec5SDimitry Andric // wide) allowing the program to unwind from any point in the prologue, body, or 620b57cec5SDimitry Andric // epilogue of the function. 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric #include "ARMWinEHPrinter.h" 650b57cec5SDimitry Andric #include "Error.h" 660b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 670b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 680b57cec5SDimitry Andric #include "llvm/Support/ARMWinEH.h" 690b57cec5SDimitry Andric #include "llvm/Support/Format.h" 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric using namespace llvm; 720b57cec5SDimitry Andric using namespace llvm::object; 730b57cec5SDimitry Andric using namespace llvm::support; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric namespace llvm { 760b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { 770b57cec5SDimitry Andric switch (RT) { 780b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_POP: 790b57cec5SDimitry Andric OS << "pop {pc}"; 800b57cec5SDimitry Andric break; 810b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_B: 820b57cec5SDimitry Andric OS << "b target"; 830b57cec5SDimitry Andric break; 840b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_BW: 850b57cec5SDimitry Andric OS << "b.w target"; 860b57cec5SDimitry Andric break; 870b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_NoEpilogue: 880b57cec5SDimitry Andric OS << "(no epilogue)"; 890b57cec5SDimitry Andric break; 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric return OS; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric static std::string formatSymbol(StringRef Name, uint64_t Address, 960b57cec5SDimitry Andric uint64_t Offset = 0) { 970b57cec5SDimitry Andric std::string Buffer; 980b57cec5SDimitry Andric raw_string_ostream OS(Buffer); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric if (!Name.empty()) 1010b57cec5SDimitry Andric OS << Name << " "; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric if (Offset) 1040b57cec5SDimitry Andric OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address); 1050b57cec5SDimitry Andric else if (!Name.empty()) 1060b57cec5SDimitry Andric OS << format("(0x%" PRIX64 ")", Address); 1070b57cec5SDimitry Andric else 1080b57cec5SDimitry Andric OS << format("0x%" PRIX64, Address); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric return OS.str(); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric namespace llvm { 1140b57cec5SDimitry Andric namespace ARM { 1150b57cec5SDimitry Andric namespace WinEH { 1160b57cec5SDimitry Andric const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric // TODO name the uops more appropriately 1190b57cec5SDimitry Andric const Decoder::RingEntry Decoder::Ring[] = { 1200b57cec5SDimitry Andric { 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) 1210b57cec5SDimitry Andric { 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) 1220b57cec5SDimitry Andric { 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) 1230b57cec5SDimitry Andric { 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) 1240b57cec5SDimitry Andric { 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) 1250b57cec5SDimitry Andric { 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) 1260b57cec5SDimitry Andric { 0xfc, 0xe8, 2, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) 1270b57cec5SDimitry Andric { 0xfe, 0xec, 2, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) 1280b57cec5SDimitry Andric { 0xff, 0xee, 2, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) 1290b57cec5SDimitry Andric // UOP_PUSH_MACHINE_FRAME 1300b57cec5SDimitry Andric // UOP_PUSH_CONTEXT 1310b57cec5SDimitry Andric // UOP_PUSH_TRAP_FRAME 1320b57cec5SDimitry Andric // UOP_REDZONE_RESTORE_LR 1330b57cec5SDimitry Andric { 0xff, 0xef, 2, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) 1340b57cec5SDimitry Andric { 0xff, 0xf5, 2, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) 1350b57cec5SDimitry Andric { 0xff, 0xf6, 2, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) 1360b57cec5SDimitry Andric { 0xff, 0xf7, 3, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) 1370b57cec5SDimitry Andric { 0xff, 0xf8, 4, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) 1380b57cec5SDimitry Andric { 0xff, 0xf9, 3, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) 1390b57cec5SDimitry Andric { 0xff, 0xfa, 4, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) 1400b57cec5SDimitry Andric { 0xff, 0xfb, 1, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) 1410b57cec5SDimitry Andric { 0xff, 0xfc, 1, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) 1420b57cec5SDimitry Andric { 0xff, 0xfd, 1, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END 1430b57cec5SDimitry Andric { 0xff, 0xfe, 1, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END 1440b57cec5SDimitry Andric { 0xff, 0xff, 1, &Decoder::opcode_11111111 }, // UOP_END 1450b57cec5SDimitry Andric }; 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric // Unwind opcodes for ARM64. 1490b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 1500b57cec5SDimitry Andric const Decoder::RingEntry Decoder::Ring64[] = { 1510b57cec5SDimitry Andric { 0xe0, 0x00, 1, &Decoder::opcode_alloc_s }, 1520b57cec5SDimitry Andric { 0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x }, 1530b57cec5SDimitry Andric { 0xc0, 0x40, 1, &Decoder::opcode_save_fplr }, 1540b57cec5SDimitry Andric { 0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x }, 1550b57cec5SDimitry Andric { 0xf8, 0xc0, 2, &Decoder::opcode_alloc_m }, 1560b57cec5SDimitry Andric { 0xfc, 0xc8, 2, &Decoder::opcode_save_regp }, 1570b57cec5SDimitry Andric { 0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x }, 1580b57cec5SDimitry Andric { 0xfc, 0xd0, 2, &Decoder::opcode_save_reg }, 1590b57cec5SDimitry Andric { 0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x }, 1600b57cec5SDimitry Andric { 0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair }, 1610b57cec5SDimitry Andric { 0xfe, 0xd8, 2, &Decoder::opcode_save_fregp }, 1620b57cec5SDimitry Andric { 0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x }, 1630b57cec5SDimitry Andric { 0xfe, 0xdc, 2, &Decoder::opcode_save_freg }, 1640b57cec5SDimitry Andric { 0xff, 0xde, 2, &Decoder::opcode_save_freg_x }, 1650b57cec5SDimitry Andric { 0xff, 0xe0, 4, &Decoder::opcode_alloc_l }, 1660b57cec5SDimitry Andric { 0xff, 0xe1, 1, &Decoder::opcode_setfp }, 1670b57cec5SDimitry Andric { 0xff, 0xe2, 2, &Decoder::opcode_addfp }, 1680b57cec5SDimitry Andric { 0xff, 0xe3, 1, &Decoder::opcode_nop }, 1690b57cec5SDimitry Andric { 0xff, 0xe4, 1, &Decoder::opcode_end }, 1700b57cec5SDimitry Andric { 0xff, 0xe5, 1, &Decoder::opcode_end_c }, 1710b57cec5SDimitry Andric }; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) { 1740b57cec5SDimitry Andric static const char * const GPRRegisterNames[16] = { 1750b57cec5SDimitry Andric "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", 1760b57cec5SDimitry Andric "r11", "ip", "sp", "lr", "pc", 1770b57cec5SDimitry Andric }; 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric const uint16_t GPRMask = std::get<0>(RegisterMask); 1800b57cec5SDimitry Andric const uint16_t VFPMask = std::get<1>(RegisterMask); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric OS << '{'; 1830b57cec5SDimitry Andric bool Comma = false; 1840b57cec5SDimitry Andric for (unsigned RI = 0, RE = 11; RI < RE; ++RI) { 1850b57cec5SDimitry Andric if (GPRMask & (1 << RI)) { 1860b57cec5SDimitry Andric if (Comma) 1870b57cec5SDimitry Andric OS << ", "; 1880b57cec5SDimitry Andric OS << GPRRegisterNames[RI]; 1890b57cec5SDimitry Andric Comma = true; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { 1930b57cec5SDimitry Andric if (VFPMask & (1 << RI)) { 1940b57cec5SDimitry Andric if (Comma) 1950b57cec5SDimitry Andric OS << ", "; 1960b57cec5SDimitry Andric OS << "d" << unsigned(RI); 1970b57cec5SDimitry Andric Comma = true; 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric for (unsigned RI = 11, RE = 16; RI < RE; ++RI) { 2010b57cec5SDimitry Andric if (GPRMask & (1 << RI)) { 2020b57cec5SDimitry Andric if (Comma) 2030b57cec5SDimitry Andric OS << ", "; 2040b57cec5SDimitry Andric OS << GPRRegisterNames[RI]; 2050b57cec5SDimitry Andric Comma = true; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric OS << '}'; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric ErrorOr<object::SectionRef> 2120b57cec5SDimitry Andric Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { 2130b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 2140b57cec5SDimitry Andric uint64_t Address = Section.getAddress(); 2150b57cec5SDimitry Andric uint64_t Size = Section.getSize(); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric if (VA >= Address && (VA - Address) <= Size) 2180b57cec5SDimitry Andric return Section; 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric return readobj_error::unknown_symbol; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, 2240b57cec5SDimitry Andric uint64_t VA, bool FunctionOnly) { 2250b57cec5SDimitry Andric for (const auto &Symbol : COFF.symbols()) { 2260b57cec5SDimitry Andric Expected<SymbolRef::Type> Type = Symbol.getType(); 2270b57cec5SDimitry Andric if (!Type) 2280b57cec5SDimitry Andric return errorToErrorCode(Type.takeError()); 2290b57cec5SDimitry Andric if (FunctionOnly && *Type != SymbolRef::ST_Function) 2300b57cec5SDimitry Andric continue; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric Expected<uint64_t> Address = Symbol.getAddress(); 2330b57cec5SDimitry Andric if (!Address) 2340b57cec5SDimitry Andric return errorToErrorCode(Address.takeError()); 2350b57cec5SDimitry Andric if (*Address == VA) 2360b57cec5SDimitry Andric return Symbol; 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric return readobj_error::unknown_symbol; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, 2420b57cec5SDimitry Andric const SectionRef &Section, 2430b57cec5SDimitry Andric uint64_t Offset) { 2440b57cec5SDimitry Andric for (const auto &Relocation : Section.relocations()) { 2450b57cec5SDimitry Andric uint64_t RelocationOffset = Relocation.getOffset(); 2460b57cec5SDimitry Andric if (RelocationOffset == Offset) 2470b57cec5SDimitry Andric return *Relocation.getSymbol(); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric return readobj_error::unknown_symbol; 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, 2530b57cec5SDimitry Andric unsigned Length, bool Prologue) { 2540b57cec5SDimitry Andric uint8_t Imm = OC[Offset] & 0x7f; 2550b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", 2560b57cec5SDimitry Andric OC[Offset], 2570b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 2580b57cec5SDimitry Andric Imm); 2590b57cec5SDimitry Andric ++Offset; 2600b57cec5SDimitry Andric return false; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, 2640b57cec5SDimitry Andric unsigned Length, bool Prologue) { 2650b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x20) >> 5; 2660b57cec5SDimitry Andric uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) 2670b57cec5SDimitry Andric | ((OC[Offset + 0] & 0x1f) << 8) 2680b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 2690b57cec5SDimitry Andric assert((~RegisterMask & (1 << 13)) && "sp must not be set"); 2700b57cec5SDimitry Andric assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w ", 2730b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 2740b57cec5SDimitry Andric Prologue ? "push" : "pop"); 2750b57cec5SDimitry Andric printRegisters(std::make_pair(RegisterMask, 0)); 2760b57cec5SDimitry Andric OS << '\n'; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric Offset += 2; 2790b57cec5SDimitry Andric return false; 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, 2830b57cec5SDimitry Andric unsigned Length, bool Prologue) { 2840b57cec5SDimitry Andric if (Prologue) 2850b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov r%u, sp\n", 2860b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 2870b57cec5SDimitry Andric else 2880b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov sp, r%u\n", 2890b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 2900b57cec5SDimitry Andric ++Offset; 2910b57cec5SDimitry Andric return false; 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, 2950b57cec5SDimitry Andric unsigned Length, bool Prologue) { 2960b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 3; 2970b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3000b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 3030b57cec5SDimitry Andric Prologue ? "push" : "pop"); 3040b57cec5SDimitry Andric printRegisters(std::make_pair(GPRMask, 0)); 3050b57cec5SDimitry Andric OS << '\n'; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric ++Offset; 3080b57cec5SDimitry Andric return false; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, 3120b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3130b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 2; 3140b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3) + 4; 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3170b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], 3200b57cec5SDimitry Andric Prologue ? "push" : "pop"); 3210b57cec5SDimitry Andric printRegisters(std::make_pair(GPRMask, 0)); 3220b57cec5SDimitry Andric OS << '\n'; 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric ++Offset; 3250b57cec5SDimitry Andric return false; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, 3290b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3300b57cec5SDimitry Andric unsigned High = (OC[Offset] & 0x7); 3310b57cec5SDimitry Andric uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 3340b57cec5SDimitry Andric Prologue ? "vpush" : "vpop"); 3350b57cec5SDimitry Andric printRegisters(std::make_pair(0, VFPMask)); 3360b57cec5SDimitry Andric OS << '\n'; 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric ++Offset; 3390b57cec5SDimitry Andric return false; 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, 3430b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3440b57cec5SDimitry Andric uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", 3470b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 3480b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 3490b57cec5SDimitry Andric Imm); 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric Offset += 2; 3520b57cec5SDimitry Andric return false; 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, 3560b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3570b57cec5SDimitry Andric uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) 3580b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 3610b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "push" : "pop"); 3620b57cec5SDimitry Andric printRegisters(std::make_pair(GPRMask, 0)); 3630b57cec5SDimitry Andric OS << '\n'; 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric Offset += 2; 3660b57cec5SDimitry Andric return false; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, 3700b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3710b57cec5SDimitry Andric assert(!Prologue && "may not be used in prologue"); 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 3740b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 3750b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 3760b57cec5SDimitry Andric else 3770b57cec5SDimitry Andric SW.startLine() 3780b57cec5SDimitry Andric << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", 3790b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric Offset += 2; 3820b57cec5SDimitry Andric return false; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, 3860b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3870b57cec5SDimitry Andric assert(!Prologue && "may not be used in prologue"); 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 3900b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 3910b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 3920b57cec5SDimitry Andric else 3930b57cec5SDimitry Andric SW.startLine() 3940b57cec5SDimitry Andric << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", 3950b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric Offset += 2; 3980b57cec5SDimitry Andric return false; 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, 4020b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4030b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4040b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 4050b57cec5SDimitry Andric uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start; 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4080b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 4090b57cec5SDimitry Andric printRegisters(std::make_pair(0, VFPMask)); 4100b57cec5SDimitry Andric OS << '\n'; 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric Offset += 2; 4130b57cec5SDimitry Andric return false; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, 4170b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4180b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4190b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 4200b57cec5SDimitry Andric uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16; 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4230b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 4240b57cec5SDimitry Andric printRegisters(std::make_pair(0, VFPMask)); 4250b57cec5SDimitry Andric OS << '\n'; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric Offset += 2; 4280b57cec5SDimitry Andric return false; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, 4320b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4330b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 4360b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 4370b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 4380b57cec5SDimitry Andric Imm); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric Offset += 3; 4410b57cec5SDimitry Andric return false; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, 4450b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4460b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 4470b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 4480b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric SW.startLine() 4510b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 4520b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 4530b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric Offset += 4; 4560b57cec5SDimitry Andric return false; 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, 4600b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4610b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric SW.startLine() 4640b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 4650b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 4660b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric Offset += 3; 4690b57cec5SDimitry Andric return false; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, 4730b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4740b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 4750b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 4760b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric SW.startLine() 4790b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 4800b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 4810b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric Offset += 4; 4840b57cec5SDimitry Andric return false; 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, 4880b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4890b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 4900b57cec5SDimitry Andric ++Offset; 4910b57cec5SDimitry Andric return false; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, 4950b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4960b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); 4970b57cec5SDimitry Andric ++Offset; 4980b57cec5SDimitry Andric return false; 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, 5020b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5030b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; b\n", OC[Offset]); 5040b57cec5SDimitry Andric ++Offset; 5050b57cec5SDimitry Andric return true; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, 5090b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5100b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]); 5110b57cec5SDimitry Andric ++Offset; 5120b57cec5SDimitry Andric return true; 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, 5160b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5170b57cec5SDimitry Andric ++Offset; 5180b57cec5SDimitry Andric return true; 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric // ARM64 unwind codes start here. 5220b57cec5SDimitry Andric bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset, 5230b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5240b57cec5SDimitry Andric uint32_t NumBytes = (OC[Offset] & 0x1F) << 4; 5250b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #%u\n", OC[Offset], 5260b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 5270b57cec5SDimitry Andric NumBytes); 5280b57cec5SDimitry Andric ++Offset; 5290b57cec5SDimitry Andric return false; 5300b57cec5SDimitry Andric } 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset, 5330b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5340b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x1F) << 3; 5350b57cec5SDimitry Andric if (Prologue) 5360b57cec5SDimitry Andric SW.startLine() << format( 5370b57cec5SDimitry Andric "0x%02x ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off); 5380b57cec5SDimitry Andric else 5390b57cec5SDimitry Andric SW.startLine() << format( 5400b57cec5SDimitry Andric "0x%02x ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off); 5410b57cec5SDimitry Andric ++Offset; 5420b57cec5SDimitry Andric return false; 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset, 5460b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5470b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x3F) << 3; 5480b57cec5SDimitry Andric SW.startLine() << format( 5490b57cec5SDimitry Andric "0x%02x ; %s x29, x30, [sp, #%u]\n", OC[Offset], 5500b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Off); 5510b57cec5SDimitry Andric ++Offset; 5520b57cec5SDimitry Andric return false; 5530b57cec5SDimitry Andric } 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset, 5560b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5570b57cec5SDimitry Andric uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3; 5580b57cec5SDimitry Andric if (Prologue) 5590b57cec5SDimitry Andric SW.startLine() << format( 5600b57cec5SDimitry Andric "0x%02x ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off); 5610b57cec5SDimitry Andric else 5620b57cec5SDimitry Andric SW.startLine() << format( 5630b57cec5SDimitry Andric "0x%02x ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off); 5640b57cec5SDimitry Andric ++Offset; 5650b57cec5SDimitry Andric return false; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset, 5690b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5700b57cec5SDimitry Andric uint32_t NumBytes = ((OC[Offset] & 0x07) << 8); 5710b57cec5SDimitry Andric NumBytes |= (OC[Offset + 1] & 0xFF); 5720b57cec5SDimitry Andric NumBytes <<= 4; 5730b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s sp, #%u\n", 5740b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 5750b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 5760b57cec5SDimitry Andric NumBytes); 5770b57cec5SDimitry Andric Offset += 2; 5780b57cec5SDimitry Andric return false; 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset, 5820b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5830b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 5840b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 5850b57cec5SDimitry Andric Reg >>= 6; 5860b57cec5SDimitry Andric Reg += 19; 5870b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 5880b57cec5SDimitry Andric SW.startLine() << format( 5890b57cec5SDimitry Andric "0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n", 5900b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 5910b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off); 5920b57cec5SDimitry Andric Offset += 2; 5930b57cec5SDimitry Andric return false; 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset, 5970b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5980b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 5990b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6000b57cec5SDimitry Andric Reg >>= 6; 6010b57cec5SDimitry Andric Reg += 19; 6020b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 6030b57cec5SDimitry Andric if (Prologue) 6040b57cec5SDimitry Andric SW.startLine() << format( 6050b57cec5SDimitry Andric "0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n", 6060b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6070b57cec5SDimitry Andric Reg + 1, Off); 6080b57cec5SDimitry Andric else 6090b57cec5SDimitry Andric SW.startLine() << format( 6100b57cec5SDimitry Andric "0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n", 6110b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6120b57cec5SDimitry Andric Reg + 1, Off); 6130b57cec5SDimitry Andric Offset += 2; 6140b57cec5SDimitry Andric return false; 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset, 6180b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6190b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x03) << 8; 6200b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6210b57cec5SDimitry Andric Reg >>= 6; 6220b57cec5SDimitry Andric Reg += 19; 6230b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 6240b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, [sp, #%u]\n", 6250b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6260b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 6270b57cec5SDimitry Andric Reg, Off); 6280b57cec5SDimitry Andric Offset += 2; 6290b57cec5SDimitry Andric return false; 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset, 6330b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6340b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 6350b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xE0); 6360b57cec5SDimitry Andric Reg >>= 5; 6370b57cec5SDimitry Andric Reg += 19; 6380b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 6390b57cec5SDimitry Andric if (Prologue) 6400b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #%u]!\n", 6410b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 6420b57cec5SDimitry Andric else 6430b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n", 6440b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 6450b57cec5SDimitry Andric Offset += 2; 6460b57cec5SDimitry Andric return false; 6470b57cec5SDimitry Andric } 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset, 6500b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6510b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 6520b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6530b57cec5SDimitry Andric Reg >>= 6; 6540b57cec5SDimitry Andric Reg *= 2; 6550b57cec5SDimitry Andric Reg += 19; 6560b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 6570b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, lr, [sp, #%u]\n", 6580b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6590b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 6600b57cec5SDimitry Andric Reg, Off); 6610b57cec5SDimitry Andric Offset += 2; 6620b57cec5SDimitry Andric return false; 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset, 6660b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6670b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 6680b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6690b57cec5SDimitry Andric Reg >>= 6; 6700b57cec5SDimitry Andric Reg += 8; 6710b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 6720b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n", 6730b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6740b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 6750b57cec5SDimitry Andric Reg, Reg + 1, Off); 6760b57cec5SDimitry Andric Offset += 2; 6770b57cec5SDimitry Andric return false; 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset, 6810b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6820b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 6830b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6840b57cec5SDimitry Andric Reg >>= 6; 6850b57cec5SDimitry Andric Reg += 8; 6860b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 6870b57cec5SDimitry Andric if (Prologue) 6880b57cec5SDimitry Andric SW.startLine() << format( 6890b57cec5SDimitry Andric "0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset], 6900b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 6910b57cec5SDimitry Andric else 6920b57cec5SDimitry Andric SW.startLine() << format( 6930b57cec5SDimitry Andric "0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n", OC[Offset], 6940b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 6950b57cec5SDimitry Andric Offset += 2; 6960b57cec5SDimitry Andric return false; 6970b57cec5SDimitry Andric } 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset, 7000b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7010b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7020b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7030b57cec5SDimitry Andric Reg >>= 6; 7040b57cec5SDimitry Andric Reg += 8; 7050b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7060b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n", 7070b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7080b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 7090b57cec5SDimitry Andric Reg, Off); 7100b57cec5SDimitry Andric Offset += 2; 7110b57cec5SDimitry Andric return false; 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset, 7150b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7160b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8; 7170b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 7180b57cec5SDimitry Andric if (Prologue) 7190b57cec5SDimitry Andric SW.startLine() << format( 7200b57cec5SDimitry Andric "0x%02x%02x ; str d%u, [sp, #-%u]!\n", OC[Offset], 7210b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 7220b57cec5SDimitry Andric else 7230b57cec5SDimitry Andric SW.startLine() << format( 7240b57cec5SDimitry Andric "0x%02x%02x ; ldr d%u, [sp], #%u\n", OC[Offset], 7250b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 7260b57cec5SDimitry Andric Offset += 2; 7270b57cec5SDimitry Andric return false; 7280b57cec5SDimitry Andric } 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset, 7310b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7320b57cec5SDimitry Andric unsigned Off = 7330b57cec5SDimitry Andric (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0); 7340b57cec5SDimitry Andric Off <<= 4; 7350b57cec5SDimitry Andric SW.startLine() << format( 7360b57cec5SDimitry Andric "0x%02x%02x%02x%02x ; %s sp, #%u\n", OC[Offset], OC[Offset + 1], 7370b57cec5SDimitry Andric OC[Offset + 2], OC[Offset + 3], 7380b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Off); 7390b57cec5SDimitry Andric Offset += 4; 7400b57cec5SDimitry Andric return false; 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 7440b57cec5SDimitry Andric bool Prologue) { 7450b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov fp, sp\n", OC[Offset]); 7460b57cec5SDimitry Andric ++Offset; 7470b57cec5SDimitry Andric return false; 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 7510b57cec5SDimitry Andric bool Prologue) { 7520b57cec5SDimitry Andric unsigned NumBytes = OC[Offset + 1] << 3; 7530b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; add fp, sp, #%u\n", 7540b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], NumBytes); 7550b57cec5SDimitry Andric Offset += 2; 7560b57cec5SDimitry Andric return false; 7570b57cec5SDimitry Andric } 7580b57cec5SDimitry Andric 7590b57cec5SDimitry Andric bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length, 7600b57cec5SDimitry Andric bool Prologue) { 7610b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 7620b57cec5SDimitry Andric ++Offset; 7630b57cec5SDimitry Andric return false; 7640b57cec5SDimitry Andric } 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length, 7670b57cec5SDimitry Andric bool Prologue) { 7680b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end\n", OC[Offset]); 7690b57cec5SDimitry Andric ++Offset; 7700b57cec5SDimitry Andric return true; 7710b57cec5SDimitry Andric } 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length, 7740b57cec5SDimitry Andric bool Prologue) { 7750b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]); 7760b57cec5SDimitry Andric ++Offset; 7770b57cec5SDimitry Andric return true; 7780b57cec5SDimitry Andric } 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, 7810b57cec5SDimitry Andric bool Prologue) { 7820b57cec5SDimitry Andric assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); 7830b57cec5SDimitry Andric const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring; 7840b57cec5SDimitry Andric bool Terminated = false; 7850b57cec5SDimitry Andric for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { 7860b57cec5SDimitry Andric for (unsigned DI = 0;; ++DI) { 7870b57cec5SDimitry Andric if ((isAArch64 && (DI >= array_lengthof(Ring64))) || 7880b57cec5SDimitry Andric (!isAArch64 && (DI >= array_lengthof(Ring)))) { 7890b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; Bad opcode!\n", 7900b57cec5SDimitry Andric Opcodes.data()[OI]); 7910b57cec5SDimitry Andric ++OI; 7920b57cec5SDimitry Andric break; 7930b57cec5SDimitry Andric } 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) { 7960b57cec5SDimitry Andric if (OI + DecodeRing[DI].Length > OE) { 7970b57cec5SDimitry Andric SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n", 7980b57cec5SDimitry Andric Opcodes[OI]); 7990b57cec5SDimitry Andric OI += DecodeRing[DI].Length; 8000b57cec5SDimitry Andric break; 8010b57cec5SDimitry Andric } 8020b57cec5SDimitry Andric Terminated = 8030b57cec5SDimitry Andric (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue); 8040b57cec5SDimitry Andric break; 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric } 8080b57cec5SDimitry Andric } 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, 8110b57cec5SDimitry Andric const SectionRef &Section, 8120b57cec5SDimitry Andric uint64_t FunctionAddress, uint64_t VA) { 8130b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 8140b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 8150b57cec5SDimitry Andric return false; 8160b57cec5SDimitry Andric 8170b57cec5SDimitry Andric uint64_t SectionVA = Section.getAddress(); 8180b57cec5SDimitry Andric uint64_t Offset = VA - SectionVA; 8190b57cec5SDimitry Andric const ulittle32_t *Data = 8200b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric // Sanity check to ensure that the .xdata header is present. 8230b57cec5SDimitry Andric // A header is one or two words, followed by at least one word to describe 8240b57cec5SDimitry Andric // the unwind codes. Applicable to both ARM and AArch64. 8250b57cec5SDimitry Andric if (Contents.size() - Offset < 8) 8260b57cec5SDimitry Andric report_fatal_error(".xdata must be at least 8 bytes in size"); 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric const ExceptionDataRecord XData(Data, isAArch64); 8290b57cec5SDimitry Andric DictScope XRS(SW, "ExceptionData"); 8300b57cec5SDimitry Andric SW.printNumber("FunctionLength", 8310b57cec5SDimitry Andric isAArch64 ? XData.FunctionLengthInBytesAArch64() : 8320b57cec5SDimitry Andric XData.FunctionLengthInBytesARM()); 8330b57cec5SDimitry Andric SW.printNumber("Version", XData.Vers()); 8340b57cec5SDimitry Andric SW.printBoolean("ExceptionData", XData.X()); 8350b57cec5SDimitry Andric SW.printBoolean("EpiloguePacked", XData.E()); 8360b57cec5SDimitry Andric if (!isAArch64) 8370b57cec5SDimitry Andric SW.printBoolean("Fragment", XData.F()); 8380b57cec5SDimitry Andric SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", 8390b57cec5SDimitry Andric XData.EpilogueCount()); 8400b57cec5SDimitry Andric uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t); 8410b57cec5SDimitry Andric SW.printNumber("ByteCodeLength", ByteCodeLength); 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) - 8440b57cec5SDimitry Andric (XData.E() ? 0 : XData.EpilogueCount() * 4) - 845*8bcb0991SDimitry Andric (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { 846*8bcb0991SDimitry Andric SW.flush(); 8470b57cec5SDimitry Andric report_fatal_error("Malformed unwind data"); 848*8bcb0991SDimitry Andric } 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric if (XData.E()) { 8510b57cec5SDimitry Andric ArrayRef<uint8_t> UC = XData.UnwindByteCode(); 8520b57cec5SDimitry Andric if (isAArch64 || !XData.F()) { 8530b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 8540b57cec5SDimitry Andric decodeOpcodes(UC, 0, /*Prologue=*/true); 8550b57cec5SDimitry Andric } 8560b57cec5SDimitry Andric if (XData.EpilogueCount()) { 8570b57cec5SDimitry Andric ListScope ES(SW, "Epilogue"); 8580b57cec5SDimitry Andric decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric } else { 8610b57cec5SDimitry Andric { 8620b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 8630b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true); 8640b57cec5SDimitry Andric } 8650b57cec5SDimitry Andric ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); 8660b57cec5SDimitry Andric ListScope ESS(SW, "EpilogueScopes"); 8670b57cec5SDimitry Andric for (const EpilogueScope ES : EpilogueScopes) { 8680b57cec5SDimitry Andric DictScope ESES(SW, "EpilogueScope"); 8690b57cec5SDimitry Andric SW.printNumber("StartOffset", ES.EpilogueStartOffset()); 8700b57cec5SDimitry Andric if (!isAArch64) 8710b57cec5SDimitry Andric SW.printNumber("Condition", ES.Condition()); 8720b57cec5SDimitry Andric SW.printNumber("EpilogueStartIndex", 8730b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 8740b57cec5SDimitry Andric : ES.EpilogueStartIndexARM()); 8750b57cec5SDimitry Andric if (ES.ES & ~0xffc3ffff) 8760b57cec5SDimitry Andric SW.printNumber("ReservedBits", (ES.ES >> 18) & 0xF); 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric ListScope Opcodes(SW, "Opcodes"); 8790b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 8800b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 8810b57cec5SDimitry Andric : ES.EpilogueStartIndexARM(), 8820b57cec5SDimitry Andric /*Prologue=*/false); 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric } 8850b57cec5SDimitry Andric 8860b57cec5SDimitry Andric if (XData.X()) { 8870b57cec5SDimitry Andric const uint32_t Address = XData.ExceptionHandlerRVA(); 8880b57cec5SDimitry Andric const uint32_t Parameter = XData.ExceptionHandlerParameter(); 8890b57cec5SDimitry Andric const size_t HandlerOffset = HeaderWords(XData) 8900b57cec5SDimitry Andric + (XData.E() ? 0 : XData.EpilogueCount()) 8910b57cec5SDimitry Andric + XData.CodeWords(); 8920b57cec5SDimitry Andric 8930b57cec5SDimitry Andric ErrorOr<SymbolRef> Symbol = getRelocatedSymbol( 8940b57cec5SDimitry Andric COFF, Section, Offset + HandlerOffset * sizeof(uint32_t)); 8950b57cec5SDimitry Andric if (!Symbol) 8960b57cec5SDimitry Andric Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); 8970b57cec5SDimitry Andric if (!Symbol) { 8980b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 8990b57cec5SDimitry Andric SW.printString("Routine", "(null)"); 9000b57cec5SDimitry Andric return true; 9010b57cec5SDimitry Andric } 9020b57cec5SDimitry Andric 9030b57cec5SDimitry Andric Expected<StringRef> Name = Symbol->getName(); 9040b57cec5SDimitry Andric if (!Name) { 9050b57cec5SDimitry Andric std::string Buf; 9060b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 9070b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 9080b57cec5SDimitry Andric OS.flush(); 9090b57cec5SDimitry Andric report_fatal_error(Buf); 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric 9120b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 9130b57cec5SDimitry Andric SW.printString("Routine", formatSymbol(*Name, Address)); 9140b57cec5SDimitry Andric SW.printHex("Parameter", Parameter); 9150b57cec5SDimitry Andric } 9160b57cec5SDimitry Andric 9170b57cec5SDimitry Andric return true; 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, 9210b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 9220b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 9230b57cec5SDimitry Andric assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && 9240b57cec5SDimitry Andric "packed entry cannot be treated as an unpacked entry"); 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); 9270b57cec5SDimitry Andric if (!Function) 9280b57cec5SDimitry Andric Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); 9310b57cec5SDimitry Andric if (!XDataRecord) 9320b57cec5SDimitry Andric XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA()); 9330b57cec5SDimitry Andric 9340b57cec5SDimitry Andric if (!RF.BeginAddress && !Function) 9350b57cec5SDimitry Andric return false; 9360b57cec5SDimitry Andric if (!RF.UnwindData && !XDataRecord) 9370b57cec5SDimitry Andric return false; 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric StringRef FunctionName; 9400b57cec5SDimitry Andric uint64_t FunctionAddress; 9410b57cec5SDimitry Andric if (Function) { 9420b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 9430b57cec5SDimitry Andric if (!FunctionNameOrErr) { 9440b57cec5SDimitry Andric std::string Buf; 9450b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 9460b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 9470b57cec5SDimitry Andric OS.flush(); 9480b57cec5SDimitry Andric report_fatal_error(Buf); 9490b57cec5SDimitry Andric } 9500b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 9510b57cec5SDimitry Andric Expected<uint64_t> FunctionAddressOrErr = Function->getAddress(); 9520b57cec5SDimitry Andric if (!FunctionAddressOrErr) { 9530b57cec5SDimitry Andric std::string Buf; 9540b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 9550b57cec5SDimitry Andric logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); 9560b57cec5SDimitry Andric OS.flush(); 9570b57cec5SDimitry Andric report_fatal_error(Buf); 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric FunctionAddress = *FunctionAddressOrErr; 9600b57cec5SDimitry Andric } else { 9610b57cec5SDimitry Andric FunctionAddress = COFF.getImageBase() + RF.BeginAddress; 9620b57cec5SDimitry Andric } 9630b57cec5SDimitry Andric 9640b57cec5SDimitry Andric SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric if (XDataRecord) { 9670b57cec5SDimitry Andric Expected<StringRef> Name = XDataRecord->getName(); 9680b57cec5SDimitry Andric if (!Name) { 9690b57cec5SDimitry Andric std::string Buf; 9700b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 9710b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 9720b57cec5SDimitry Andric OS.flush(); 9730b57cec5SDimitry Andric report_fatal_error(Buf); 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric Expected<uint64_t> AddressOrErr = XDataRecord->getAddress(); 9770b57cec5SDimitry Andric if (!AddressOrErr) { 9780b57cec5SDimitry Andric std::string Buf; 9790b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 9800b57cec5SDimitry Andric logAllUnhandledErrors(AddressOrErr.takeError(), OS); 9810b57cec5SDimitry Andric OS.flush(); 9820b57cec5SDimitry Andric report_fatal_error(Buf); 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric uint64_t Address = *AddressOrErr; 9850b57cec5SDimitry Andric 9860b57cec5SDimitry Andric SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); 9870b57cec5SDimitry Andric 9880b57cec5SDimitry Andric Expected<section_iterator> SIOrErr = XDataRecord->getSection(); 9890b57cec5SDimitry Andric if (!SIOrErr) { 9900b57cec5SDimitry Andric // TODO: Actually report errors helpfully. 9910b57cec5SDimitry Andric consumeError(SIOrErr.takeError()); 9920b57cec5SDimitry Andric return false; 9930b57cec5SDimitry Andric } 9940b57cec5SDimitry Andric section_iterator SI = *SIOrErr; 9950b57cec5SDimitry Andric 9960b57cec5SDimitry Andric // FIXME: Do we need to add an offset from the relocation? 9970b57cec5SDimitry Andric return dumpXDataRecord(COFF, *SI, FunctionAddress, 9980b57cec5SDimitry Andric RF.ExceptionInformationRVA()); 9990b57cec5SDimitry Andric } else { 10000b57cec5SDimitry Andric uint64_t Address = COFF.getImageBase() + RF.ExceptionInformationRVA(); 10010b57cec5SDimitry Andric SW.printString("ExceptionRecord", formatSymbol("", Address)); 10020b57cec5SDimitry Andric 10030b57cec5SDimitry Andric ErrorOr<SectionRef> Section = getSectionContaining(COFF, Address); 10040b57cec5SDimitry Andric if (!Section) 10050b57cec5SDimitry Andric return false; 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric return dumpXDataRecord(COFF, *Section, FunctionAddress, Address); 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric } 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, 10120b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 10130b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 10140b57cec5SDimitry Andric assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || 10150b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && 10160b57cec5SDimitry Andric "unpacked entry cannot be treated as a packed entry"); 10170b57cec5SDimitry Andric 10180b57cec5SDimitry Andric ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); 10190b57cec5SDimitry Andric if (!Function) 10200b57cec5SDimitry Andric Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric StringRef FunctionName; 10230b57cec5SDimitry Andric uint64_t FunctionAddress; 10240b57cec5SDimitry Andric if (Function) { 10250b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 10260b57cec5SDimitry Andric if (!FunctionNameOrErr) { 10270b57cec5SDimitry Andric std::string Buf; 10280b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 10290b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 10300b57cec5SDimitry Andric OS.flush(); 10310b57cec5SDimitry Andric report_fatal_error(Buf); 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 10340b57cec5SDimitry Andric Expected<uint64_t> FunctionAddressOrErr = Function->getAddress(); 10350b57cec5SDimitry Andric if (!FunctionAddressOrErr) { 10360b57cec5SDimitry Andric std::string Buf; 10370b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 10380b57cec5SDimitry Andric logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); 10390b57cec5SDimitry Andric OS.flush(); 10400b57cec5SDimitry Andric report_fatal_error(Buf); 10410b57cec5SDimitry Andric } 10420b57cec5SDimitry Andric FunctionAddress = *FunctionAddressOrErr; 10430b57cec5SDimitry Andric } else { 1044*8bcb0991SDimitry Andric FunctionAddress = COFF.getPE32Header()->ImageBase + RF.BeginAddress; 10450b57cec5SDimitry Andric } 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); 10480b57cec5SDimitry Andric if (!isAArch64) 10490b57cec5SDimitry Andric SW.printBoolean("Fragment", 10500b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); 10510b57cec5SDimitry Andric SW.printNumber("FunctionLength", RF.FunctionLength()); 10520b57cec5SDimitry Andric SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; 10530b57cec5SDimitry Andric SW.printBoolean("HomedParameters", RF.H()); 10540b57cec5SDimitry Andric SW.startLine() << "SavedRegisters: "; 10550b57cec5SDimitry Andric printRegisters(SavedRegisterMask(RF)); 10560b57cec5SDimitry Andric OS << '\n'; 10570b57cec5SDimitry Andric SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric return true; 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric 10620b57cec5SDimitry Andric bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, 10630b57cec5SDimitry Andric const SectionRef Section, unsigned Index, 10640b57cec5SDimitry Andric ArrayRef<uint8_t> Contents) { 10650b57cec5SDimitry Andric uint64_t Offset = PDataEntrySize * Index; 10660b57cec5SDimitry Andric const ulittle32_t *Data = 10670b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 10680b57cec5SDimitry Andric 10690b57cec5SDimitry Andric const RuntimeFunction Entry(Data); 10700b57cec5SDimitry Andric DictScope RFS(SW, "RuntimeFunction"); 10710b57cec5SDimitry Andric if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) 10720b57cec5SDimitry Andric return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); 10730b57cec5SDimitry Andric if (isAArch64) { 10740b57cec5SDimitry Andric SW.startLine() << "Packed unwind data not yet supported for ARM64\n"; 10750b57cec5SDimitry Andric return true; 10760b57cec5SDimitry Andric } 10770b57cec5SDimitry Andric return dumpPackedEntry(COFF, Section, Offset, Index, Entry); 10780b57cec5SDimitry Andric } 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric void Decoder::dumpProcedureData(const COFFObjectFile &COFF, 10810b57cec5SDimitry Andric const SectionRef Section) { 10820b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 10830b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 10840b57cec5SDimitry Andric return; 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric if (Contents.size() % PDataEntrySize) { 10870b57cec5SDimitry Andric errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; 10880b57cec5SDimitry Andric return; 10890b57cec5SDimitry Andric } 10900b57cec5SDimitry Andric 10910b57cec5SDimitry Andric for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) 10920b57cec5SDimitry Andric if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) 10930b57cec5SDimitry Andric break; 10940b57cec5SDimitry Andric } 10950b57cec5SDimitry Andric 10960b57cec5SDimitry Andric Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) { 10970b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 10980b57cec5SDimitry Andric Expected<StringRef> NameOrErr = 10990b57cec5SDimitry Andric COFF.getSectionName(COFF.getCOFFSection(Section)); 11000b57cec5SDimitry Andric if (!NameOrErr) 11010b57cec5SDimitry Andric return NameOrErr.takeError(); 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric if (NameOrErr->startswith(".pdata")) 11040b57cec5SDimitry Andric dumpProcedureData(COFF, Section); 11050b57cec5SDimitry Andric } 11060b57cec5SDimitry Andric return Error::success(); 11070b57cec5SDimitry Andric } 11080b57cec5SDimitry Andric } 11090b57cec5SDimitry Andric } 11100b57cec5SDimitry Andric } 1111