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 "llvm/ADT/STLExtras.h" 660b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 670b57cec5SDimitry Andric #include "llvm/Support/ARMWinEH.h" 680b57cec5SDimitry Andric #include "llvm/Support/Format.h" 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric using namespace llvm; 710b57cec5SDimitry Andric using namespace llvm::object; 720b57cec5SDimitry Andric using namespace llvm::support; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric namespace llvm { 750b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { 760b57cec5SDimitry Andric switch (RT) { 770b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_POP: 780b57cec5SDimitry Andric OS << "pop {pc}"; 790b57cec5SDimitry Andric break; 800b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_B: 8181ad6265SDimitry Andric OS << "bx <reg>"; 820b57cec5SDimitry Andric break; 830b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_BW: 8481ad6265SDimitry Andric OS << "b.w <target>"; 850b57cec5SDimitry Andric break; 860b57cec5SDimitry Andric case ARM::WinEH::ReturnType::RT_NoEpilogue: 870b57cec5SDimitry Andric OS << "(no epilogue)"; 880b57cec5SDimitry Andric break; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric return OS; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static std::string formatSymbol(StringRef Name, uint64_t Address, 950b57cec5SDimitry Andric uint64_t Offset = 0) { 960b57cec5SDimitry Andric std::string Buffer; 970b57cec5SDimitry Andric raw_string_ostream OS(Buffer); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric if (!Name.empty()) 1000b57cec5SDimitry Andric OS << Name << " "; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric if (Offset) 103fe6060f1SDimitry Andric OS << format("+0x%" PRIX64 " (0x%" PRIX64 ")", Offset, Address); 1040b57cec5SDimitry Andric else if (!Name.empty()) 1050b57cec5SDimitry Andric OS << format("(0x%" PRIX64 ")", Address); 1060b57cec5SDimitry Andric else 1070b57cec5SDimitry Andric OS << format("0x%" PRIX64, Address); 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric return OS.str(); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric namespace llvm { 1130b57cec5SDimitry Andric namespace ARM { 1140b57cec5SDimitry Andric namespace WinEH { 1150b57cec5SDimitry Andric const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // TODO name the uops more appropriately 1180b57cec5SDimitry Andric const Decoder::RingEntry Decoder::Ring[] = { 1190b57cec5SDimitry Andric { 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) 1200b57cec5SDimitry Andric { 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) 1210b57cec5SDimitry Andric { 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) 1220b57cec5SDimitry Andric { 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) 1230b57cec5SDimitry Andric { 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) 1240b57cec5SDimitry Andric { 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) 1250b57cec5SDimitry Andric { 0xfc, 0xe8, 2, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) 1260b57cec5SDimitry Andric { 0xfe, 0xec, 2, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) 1270b57cec5SDimitry Andric { 0xff, 0xee, 2, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) 1280b57cec5SDimitry Andric // UOP_PUSH_MACHINE_FRAME 1290b57cec5SDimitry Andric // UOP_PUSH_CONTEXT 1300b57cec5SDimitry Andric // UOP_PUSH_TRAP_FRAME 1310b57cec5SDimitry Andric // UOP_REDZONE_RESTORE_LR 1320b57cec5SDimitry Andric { 0xff, 0xef, 2, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) 1330b57cec5SDimitry Andric { 0xff, 0xf5, 2, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) 1340b57cec5SDimitry Andric { 0xff, 0xf6, 2, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) 1350b57cec5SDimitry Andric { 0xff, 0xf7, 3, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) 1360b57cec5SDimitry Andric { 0xff, 0xf8, 4, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) 1370b57cec5SDimitry Andric { 0xff, 0xf9, 3, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) 1380b57cec5SDimitry Andric { 0xff, 0xfa, 4, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) 1390b57cec5SDimitry Andric { 0xff, 0xfb, 1, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) 1400b57cec5SDimitry Andric { 0xff, 0xfc, 1, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) 1410b57cec5SDimitry Andric { 0xff, 0xfd, 1, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END 1420b57cec5SDimitry Andric { 0xff, 0xfe, 1, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END 1430b57cec5SDimitry Andric { 0xff, 0xff, 1, &Decoder::opcode_11111111 }, // UOP_END 1440b57cec5SDimitry Andric }; 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric // Unwind opcodes for ARM64. 1470b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling 1480b57cec5SDimitry Andric const Decoder::RingEntry Decoder::Ring64[] = { 1490b57cec5SDimitry Andric {0xe0, 0x00, 1, &Decoder::opcode_alloc_s}, 1500b57cec5SDimitry Andric {0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x}, 1510b57cec5SDimitry Andric {0xc0, 0x40, 1, &Decoder::opcode_save_fplr}, 1520b57cec5SDimitry Andric {0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x}, 1530b57cec5SDimitry Andric {0xf8, 0xc0, 2, &Decoder::opcode_alloc_m}, 1540b57cec5SDimitry Andric {0xfc, 0xc8, 2, &Decoder::opcode_save_regp}, 1550b57cec5SDimitry Andric {0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x}, 1560b57cec5SDimitry Andric {0xfc, 0xd0, 2, &Decoder::opcode_save_reg}, 1570b57cec5SDimitry Andric {0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x}, 1580b57cec5SDimitry Andric {0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair}, 1590b57cec5SDimitry Andric {0xfe, 0xd8, 2, &Decoder::opcode_save_fregp}, 1600b57cec5SDimitry Andric {0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x}, 1610b57cec5SDimitry Andric {0xfe, 0xdc, 2, &Decoder::opcode_save_freg}, 1620b57cec5SDimitry Andric {0xff, 0xde, 2, &Decoder::opcode_save_freg_x}, 1630b57cec5SDimitry Andric {0xff, 0xe0, 4, &Decoder::opcode_alloc_l}, 1640b57cec5SDimitry Andric {0xff, 0xe1, 1, &Decoder::opcode_setfp}, 1650b57cec5SDimitry Andric {0xff, 0xe2, 2, &Decoder::opcode_addfp}, 1660b57cec5SDimitry Andric {0xff, 0xe3, 1, &Decoder::opcode_nop}, 1670b57cec5SDimitry Andric {0xff, 0xe4, 1, &Decoder::opcode_end}, 1680b57cec5SDimitry Andric {0xff, 0xe5, 1, &Decoder::opcode_end_c}, 169e8d8bef9SDimitry Andric {0xff, 0xe6, 1, &Decoder::opcode_save_next}, 170bdd1243dSDimitry Andric {0xff, 0xe7, 3, &Decoder::opcode_save_any_reg}, 171e8d8bef9SDimitry Andric {0xff, 0xe8, 1, &Decoder::opcode_trap_frame}, 172e8d8bef9SDimitry Andric {0xff, 0xe9, 1, &Decoder::opcode_machine_frame}, 173e8d8bef9SDimitry Andric {0xff, 0xea, 1, &Decoder::opcode_context}, 174*5f757f3fSDimitry Andric {0xff, 0xeb, 1, &Decoder::opcode_ec_context}, 175e8d8bef9SDimitry Andric {0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call}, 176bdd1243dSDimitry Andric {0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr}, 1770b57cec5SDimitry Andric }; 1780b57cec5SDimitry Andric 17981ad6265SDimitry Andric static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First, 18081ad6265SDimitry Andric unsigned Last, char Letter) { 18181ad6265SDimitry Andric if (First == Last) 18281ad6265SDimitry Andric OS << LS << Letter << First; 18381ad6265SDimitry Andric else 18481ad6265SDimitry Andric OS << LS << Letter << First << "-" << Letter << Last; 18581ad6265SDimitry Andric } 1860b57cec5SDimitry Andric 18781ad6265SDimitry Andric static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS, 18881ad6265SDimitry Andric unsigned Start, unsigned End, char Letter) { 18981ad6265SDimitry Andric int First = -1; 19081ad6265SDimitry Andric for (unsigned RI = Start; RI <= End; ++RI) { 19181ad6265SDimitry Andric if (Mask & (1 << RI)) { 19281ad6265SDimitry Andric if (First < 0) 19381ad6265SDimitry Andric First = RI; 19481ad6265SDimitry Andric } else { 19581ad6265SDimitry Andric if (First >= 0) { 19681ad6265SDimitry Andric printRange(OS, LS, First, RI - 1, Letter); 19781ad6265SDimitry Andric First = -1; 19881ad6265SDimitry Andric } 19981ad6265SDimitry Andric } 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric if (First >= 0) 20281ad6265SDimitry Andric printRange(OS, LS, First, End, Letter); 20381ad6265SDimitry Andric } 2040b57cec5SDimitry Andric 20581ad6265SDimitry Andric void Decoder::printGPRMask(uint16_t GPRMask) { 2060b57cec5SDimitry Andric OS << '{'; 207fe6060f1SDimitry Andric ListSeparator LS; 20881ad6265SDimitry Andric printRange(OS, GPRMask, LS, 0, 12, 'r'); 20981ad6265SDimitry Andric if (GPRMask & (1 << 14)) 21081ad6265SDimitry Andric OS << LS << "lr"; 21181ad6265SDimitry Andric if (GPRMask & (1 << 15)) 21281ad6265SDimitry Andric OS << LS << "pc"; 21381ad6265SDimitry Andric OS << '}'; 21481ad6265SDimitry Andric } 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric void Decoder::printVFPMask(uint32_t VFPMask) { 21781ad6265SDimitry Andric OS << '{'; 21881ad6265SDimitry Andric ListSeparator LS; 21981ad6265SDimitry Andric printRange(OS, VFPMask, LS, 0, 31, 'd'); 2200b57cec5SDimitry Andric OS << '}'; 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric ErrorOr<object::SectionRef> 2240b57cec5SDimitry Andric Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { 2250b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 2260b57cec5SDimitry Andric uint64_t Address = Section.getAddress(); 2270b57cec5SDimitry Andric uint64_t Size = Section.getSize(); 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric if (VA >= Address && (VA - Address) <= Size) 2300b57cec5SDimitry Andric return Section; 2310b57cec5SDimitry Andric } 232e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, 2360b57cec5SDimitry Andric uint64_t VA, bool FunctionOnly) { 2370b57cec5SDimitry Andric for (const auto &Symbol : COFF.symbols()) { 2380b57cec5SDimitry Andric Expected<SymbolRef::Type> Type = Symbol.getType(); 2390b57cec5SDimitry Andric if (!Type) 2400b57cec5SDimitry Andric return errorToErrorCode(Type.takeError()); 2410b57cec5SDimitry Andric if (FunctionOnly && *Type != SymbolRef::ST_Function) 2420b57cec5SDimitry Andric continue; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric Expected<uint64_t> Address = Symbol.getAddress(); 2450b57cec5SDimitry Andric if (!Address) 2460b57cec5SDimitry Andric return errorToErrorCode(Address.takeError()); 2470b57cec5SDimitry Andric if (*Address == VA) 2480b57cec5SDimitry Andric return Symbol; 2490b57cec5SDimitry Andric } 250e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, 2540b57cec5SDimitry Andric const SectionRef &Section, 2550b57cec5SDimitry Andric uint64_t Offset) { 2560b57cec5SDimitry Andric for (const auto &Relocation : Section.relocations()) { 2570b57cec5SDimitry Andric uint64_t RelocationOffset = Relocation.getOffset(); 2580b57cec5SDimitry Andric if (RelocationOffset == Offset) 2590b57cec5SDimitry Andric return *Relocation.getSymbol(); 2600b57cec5SDimitry Andric } 261e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 264349cc55cSDimitry Andric SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym, 265349cc55cSDimitry Andric uint64_t &SymbolOffset) { 266fe6060f1SDimitry Andric // The symbol resolved by getRelocatedSymbol can be any internal 267fe6060f1SDimitry Andric // nondescriptive symbol; try to resolve a more descriptive one. 268fe6060f1SDimitry Andric COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym); 269349cc55cSDimitry Andric if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 270349cc55cSDimitry Andric CoffSym.getSectionDefinition() == nullptr) 271fe6060f1SDimitry Andric return Sym; 272fe6060f1SDimitry Andric for (const auto &S : COFF.symbols()) { 273fe6060f1SDimitry Andric COFFSymbolRef CS = COFF.getCOFFSymbol(S); 274fe6060f1SDimitry Andric if (CS.getSectionNumber() == CoffSym.getSectionNumber() && 275349cc55cSDimitry Andric CS.getValue() <= CoffSym.getValue() + SymbolOffset && 276349cc55cSDimitry Andric CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 277349cc55cSDimitry Andric CS.getSectionDefinition() == nullptr) { 278349cc55cSDimitry Andric uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue(); 279349cc55cSDimitry Andric if (Offset <= SymbolOffset) { 280349cc55cSDimitry Andric SymbolOffset = Offset; 281fe6060f1SDimitry Andric Sym = S; 282fe6060f1SDimitry Andric CoffSym = CS; 283349cc55cSDimitry Andric if (CS.isExternal() && SymbolOffset == 0) 284349cc55cSDimitry Andric return Sym; 285fe6060f1SDimitry Andric } 286fe6060f1SDimitry Andric } 287fe6060f1SDimitry Andric } 288fe6060f1SDimitry Andric return Sym; 289fe6060f1SDimitry Andric } 290fe6060f1SDimitry Andric 291fe6060f1SDimitry Andric ErrorOr<SymbolRef> Decoder::getSymbolForLocation( 292fe6060f1SDimitry Andric const COFFObjectFile &COFF, const SectionRef &Section, 293fe6060f1SDimitry Andric uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress, 294fe6060f1SDimitry Andric uint64_t &SymbolOffset, bool FunctionOnly) { 295fe6060f1SDimitry Andric // Try to locate a relocation that points at the offset in the section 296fe6060f1SDimitry Andric ErrorOr<SymbolRef> SymOrErr = 297fe6060f1SDimitry Andric getRelocatedSymbol(COFF, Section, OffsetInSection); 298fe6060f1SDimitry Andric if (SymOrErr) { 299fe6060f1SDimitry Andric // We found a relocation symbol; the immediate offset needs to be added 300fe6060f1SDimitry Andric // to the symbol address. 301fe6060f1SDimitry Andric SymbolOffset = ImmediateOffset; 302fe6060f1SDimitry Andric 303fe6060f1SDimitry Andric Expected<uint64_t> AddressOrErr = SymOrErr->getAddress(); 304fe6060f1SDimitry Andric if (!AddressOrErr) { 305fe6060f1SDimitry Andric std::string Buf; 306fe6060f1SDimitry Andric llvm::raw_string_ostream OS(Buf); 307fe6060f1SDimitry Andric logAllUnhandledErrors(AddressOrErr.takeError(), OS); 308349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 309fe6060f1SDimitry Andric } 310fe6060f1SDimitry Andric // We apply SymbolOffset here directly. We return it separately to allow 311fe6060f1SDimitry Andric // the caller to print it as an offset on the symbol name. 312fe6060f1SDimitry Andric SymbolAddress = *AddressOrErr + SymbolOffset; 313349cc55cSDimitry Andric 314349cc55cSDimitry Andric if (FunctionOnly) // Resolve label/section symbols into function names. 315349cc55cSDimitry Andric SymOrErr = getPreferredSymbol(COFF, *SymOrErr, SymbolOffset); 316fe6060f1SDimitry Andric } else { 317fe6060f1SDimitry Andric // No matching relocation found; operating on a linked image. Try to 318fe6060f1SDimitry Andric // find a descriptive symbol if possible. The immediate offset contains 319fe6060f1SDimitry Andric // the image relative address, and we shouldn't add any offset to the 320fe6060f1SDimitry Andric // symbol. 321fe6060f1SDimitry Andric SymbolAddress = COFF.getImageBase() + ImmediateOffset; 322fe6060f1SDimitry Andric SymbolOffset = 0; 323fe6060f1SDimitry Andric SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly); 324fe6060f1SDimitry Andric } 325fe6060f1SDimitry Andric return SymOrErr; 326fe6060f1SDimitry Andric } 327fe6060f1SDimitry Andric 3280b57cec5SDimitry Andric bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, 3290b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3300b57cec5SDimitry Andric uint8_t Imm = OC[Offset] & 0x7f; 3310b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", 3320b57cec5SDimitry Andric OC[Offset], 3330b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 3340b57cec5SDimitry Andric Imm); 3350b57cec5SDimitry Andric ++Offset; 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, 3400b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3410b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x20) >> 5; 3420b57cec5SDimitry Andric uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) 3430b57cec5SDimitry Andric | ((OC[Offset + 0] & 0x1f) << 8) 3440b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 3450b57cec5SDimitry Andric assert((~RegisterMask & (1 << 13)) && "sp must not be set"); 3460b57cec5SDimitry Andric assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w ", 3490b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 3500b57cec5SDimitry Andric Prologue ? "push" : "pop"); 35181ad6265SDimitry Andric printGPRMask(RegisterMask); 3520b57cec5SDimitry Andric OS << '\n'; 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric Offset += 2; 3550b57cec5SDimitry Andric return false; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, 3590b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3600b57cec5SDimitry Andric if (Prologue) 3610b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov r%u, sp\n", 3620b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 3630b57cec5SDimitry Andric else 3640b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov sp, r%u\n", 3650b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 3660b57cec5SDimitry Andric ++Offset; 3670b57cec5SDimitry Andric return false; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, 3710b57cec5SDimitry Andric unsigned Length, bool Prologue) { 37281ad6265SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 2; 3730b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3); 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3760b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 3790b57cec5SDimitry Andric Prologue ? "push" : "pop"); 38081ad6265SDimitry Andric printGPRMask(GPRMask); 3810b57cec5SDimitry Andric OS << '\n'; 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric ++Offset; 3840b57cec5SDimitry Andric return false; 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, 3880b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3890b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 2; 3900b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3) + 4; 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3930b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], 3960b57cec5SDimitry Andric Prologue ? "push" : "pop"); 39781ad6265SDimitry Andric printGPRMask(GPRMask); 3980b57cec5SDimitry Andric OS << '\n'; 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric ++Offset; 4010b57cec5SDimitry Andric return false; 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, 4050b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4060b57cec5SDimitry Andric unsigned High = (OC[Offset] & 0x7); 4070b57cec5SDimitry Andric uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 4100b57cec5SDimitry Andric Prologue ? "vpush" : "vpop"); 41181ad6265SDimitry Andric printVFPMask(VFPMask); 4120b57cec5SDimitry Andric OS << '\n'; 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric ++Offset; 4150b57cec5SDimitry Andric return false; 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, 4190b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4200b57cec5SDimitry Andric uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", 4230b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 4240b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 4250b57cec5SDimitry Andric Imm); 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric Offset += 2; 4280b57cec5SDimitry Andric return false; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, 4320b57cec5SDimitry Andric unsigned Length, bool Prologue) { 43381ad6265SDimitry Andric uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) 4340b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4370b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "push" : "pop"); 43881ad6265SDimitry Andric printGPRMask(GPRMask); 4390b57cec5SDimitry Andric OS << '\n'; 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric Offset += 2; 4420b57cec5SDimitry Andric return false; 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, 4460b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4470b57cec5SDimitry Andric assert(!Prologue && "may not be used in prologue"); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 4500b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 4510b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 4520b57cec5SDimitry Andric else 4530b57cec5SDimitry Andric SW.startLine() 4540b57cec5SDimitry Andric << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", 4550b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric Offset += 2; 4580b57cec5SDimitry Andric return false; 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, 4620b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4630b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 4640b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 4650b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 46681ad6265SDimitry Andric else if (Prologue) 46781ad6265SDimitry Andric SW.startLine() 46881ad6265SDimitry Andric << format("0x%02x 0x%02x ; str.w lr, [sp, #-%u]!\n", 46981ad6265SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); 4700b57cec5SDimitry Andric else 4710b57cec5SDimitry Andric SW.startLine() 4720b57cec5SDimitry Andric << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", 4730b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric Offset += 2; 4760b57cec5SDimitry Andric return false; 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, 4800b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4810b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4820b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 48381ad6265SDimitry Andric uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start; 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4860b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 48781ad6265SDimitry Andric printVFPMask(VFPMask); 4880b57cec5SDimitry Andric OS << '\n'; 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric Offset += 2; 4910b57cec5SDimitry Andric return false; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, 4950b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4960b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4970b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 49881ad6265SDimitry Andric uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start); 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 5010b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 50281ad6265SDimitry Andric printVFPMask(VFPMask); 5030b57cec5SDimitry Andric OS << '\n'; 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric Offset += 2; 5060b57cec5SDimitry Andric return false; 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, 5100b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5110b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 5140b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 5150b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 5160b57cec5SDimitry Andric Imm); 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric Offset += 3; 5190b57cec5SDimitry Andric return false; 5200b57cec5SDimitry Andric } 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, 5230b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5240b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 5250b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 5260b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric SW.startLine() 5290b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 5300b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 5310b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric Offset += 4; 5340b57cec5SDimitry Andric return false; 5350b57cec5SDimitry Andric } 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, 5380b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5390b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric SW.startLine() 5420b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 5430b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 5440b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric Offset += 3; 5470b57cec5SDimitry Andric return false; 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, 5510b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5520b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 5530b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 5540b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric SW.startLine() 5570b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 5580b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 5590b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric Offset += 4; 5620b57cec5SDimitry Andric return false; 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, 5660b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5670b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 5680b57cec5SDimitry Andric ++Offset; 5690b57cec5SDimitry Andric return false; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, 5730b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5740b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); 5750b57cec5SDimitry Andric ++Offset; 5760b57cec5SDimitry Andric return false; 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, 5800b57cec5SDimitry Andric unsigned Length, bool Prologue) { 58181ad6265SDimitry Andric SW.startLine() << format("0x%02x ; bx <reg>\n", OC[Offset]); 5820b57cec5SDimitry Andric ++Offset; 5830b57cec5SDimitry Andric return true; 5840b57cec5SDimitry Andric } 5850b57cec5SDimitry Andric 5860b57cec5SDimitry Andric bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, 5870b57cec5SDimitry Andric unsigned Length, bool Prologue) { 58881ad6265SDimitry Andric SW.startLine() << format("0x%02x ; b.w <target>\n", OC[Offset]); 5890b57cec5SDimitry Andric ++Offset; 5900b57cec5SDimitry Andric return true; 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, 5940b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5950b57cec5SDimitry Andric ++Offset; 5960b57cec5SDimitry Andric return true; 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric 5990b57cec5SDimitry Andric // ARM64 unwind codes start here. 6000b57cec5SDimitry Andric bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset, 6010b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6020b57cec5SDimitry Andric uint32_t NumBytes = (OC[Offset] & 0x1F) << 4; 6030b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #%u\n", OC[Offset], 6040b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 6050b57cec5SDimitry Andric NumBytes); 6060b57cec5SDimitry Andric ++Offset; 6070b57cec5SDimitry Andric return false; 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset, 6110b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6120b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x1F) << 3; 6130b57cec5SDimitry Andric if (Prologue) 6140b57cec5SDimitry Andric SW.startLine() << format( 6150b57cec5SDimitry Andric "0x%02x ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off); 6160b57cec5SDimitry Andric else 6170b57cec5SDimitry Andric SW.startLine() << format( 6180b57cec5SDimitry Andric "0x%02x ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off); 6190b57cec5SDimitry Andric ++Offset; 6200b57cec5SDimitry Andric return false; 6210b57cec5SDimitry Andric } 6220b57cec5SDimitry Andric 6230b57cec5SDimitry Andric bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset, 6240b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6250b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x3F) << 3; 6260b57cec5SDimitry Andric SW.startLine() << format( 6270b57cec5SDimitry Andric "0x%02x ; %s x29, x30, [sp, #%u]\n", OC[Offset], 6280b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Off); 6290b57cec5SDimitry Andric ++Offset; 6300b57cec5SDimitry Andric return false; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset, 6340b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6350b57cec5SDimitry Andric uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3; 6360b57cec5SDimitry Andric if (Prologue) 6370b57cec5SDimitry Andric SW.startLine() << format( 6380b57cec5SDimitry Andric "0x%02x ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off); 6390b57cec5SDimitry Andric else 6400b57cec5SDimitry Andric SW.startLine() << format( 6410b57cec5SDimitry Andric "0x%02x ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off); 6420b57cec5SDimitry Andric ++Offset; 6430b57cec5SDimitry Andric return false; 6440b57cec5SDimitry Andric } 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset, 6470b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6480b57cec5SDimitry Andric uint32_t NumBytes = ((OC[Offset] & 0x07) << 8); 6490b57cec5SDimitry Andric NumBytes |= (OC[Offset + 1] & 0xFF); 6500b57cec5SDimitry Andric NumBytes <<= 4; 6510b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s sp, #%u\n", 6520b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6530b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 6540b57cec5SDimitry Andric NumBytes); 6550b57cec5SDimitry Andric Offset += 2; 6560b57cec5SDimitry Andric return false; 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset, 6600b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6610b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 6620b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6630b57cec5SDimitry Andric Reg >>= 6; 6640b57cec5SDimitry Andric Reg += 19; 6650b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 6660b57cec5SDimitry Andric SW.startLine() << format( 6670b57cec5SDimitry Andric "0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n", 6680b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6690b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off); 6700b57cec5SDimitry Andric Offset += 2; 6710b57cec5SDimitry Andric return false; 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset, 6750b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6760b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 6770b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6780b57cec5SDimitry Andric Reg >>= 6; 6790b57cec5SDimitry Andric Reg += 19; 6800b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 6810b57cec5SDimitry Andric if (Prologue) 6820b57cec5SDimitry Andric SW.startLine() << format( 6830b57cec5SDimitry Andric "0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n", 6840b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6850b57cec5SDimitry Andric Reg + 1, Off); 6860b57cec5SDimitry Andric else 6870b57cec5SDimitry Andric SW.startLine() << format( 6880b57cec5SDimitry Andric "0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n", 6890b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6900b57cec5SDimitry Andric Reg + 1, Off); 6910b57cec5SDimitry Andric Offset += 2; 6920b57cec5SDimitry Andric return false; 6930b57cec5SDimitry Andric } 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset, 6960b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6970b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x03) << 8; 6980b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6990b57cec5SDimitry Andric Reg >>= 6; 7000b57cec5SDimitry Andric Reg += 19; 7010b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7020b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, [sp, #%u]\n", 7030b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7040b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 7050b57cec5SDimitry Andric Reg, Off); 7060b57cec5SDimitry Andric Offset += 2; 7070b57cec5SDimitry Andric return false; 7080b57cec5SDimitry Andric } 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset, 7110b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7120b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7130b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xE0); 7140b57cec5SDimitry Andric Reg >>= 5; 7150b57cec5SDimitry Andric Reg += 19; 7160b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 7170b57cec5SDimitry Andric if (Prologue) 718e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #-%u]!\n", 7190b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 7200b57cec5SDimitry Andric else 7210b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n", 7220b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 7230b57cec5SDimitry Andric Offset += 2; 7240b57cec5SDimitry Andric return false; 7250b57cec5SDimitry Andric } 7260b57cec5SDimitry Andric 7270b57cec5SDimitry Andric bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset, 7280b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7290b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7300b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7310b57cec5SDimitry Andric Reg >>= 6; 7320b57cec5SDimitry Andric Reg *= 2; 7330b57cec5SDimitry Andric Reg += 19; 7340b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7350b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, lr, [sp, #%u]\n", 7360b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7370b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 7380b57cec5SDimitry Andric Reg, Off); 7390b57cec5SDimitry Andric Offset += 2; 7400b57cec5SDimitry Andric return false; 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset, 7440b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7450b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7460b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7470b57cec5SDimitry Andric Reg >>= 6; 7480b57cec5SDimitry Andric Reg += 8; 7490b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7500b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n", 7510b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7520b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 7530b57cec5SDimitry Andric Reg, Reg + 1, Off); 7540b57cec5SDimitry Andric Offset += 2; 7550b57cec5SDimitry Andric return false; 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset, 7590b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7600b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7610b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7620b57cec5SDimitry Andric Reg >>= 6; 7630b57cec5SDimitry Andric Reg += 8; 7640b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 7650b57cec5SDimitry Andric if (Prologue) 7660b57cec5SDimitry Andric SW.startLine() << format( 7670b57cec5SDimitry Andric "0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset], 7680b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 7690b57cec5SDimitry Andric else 7700b57cec5SDimitry Andric SW.startLine() << format( 7710b57cec5SDimitry Andric "0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n", OC[Offset], 7720b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 7730b57cec5SDimitry Andric Offset += 2; 7740b57cec5SDimitry Andric return false; 7750b57cec5SDimitry Andric } 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset, 7780b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7790b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7800b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7810b57cec5SDimitry Andric Reg >>= 6; 7820b57cec5SDimitry Andric Reg += 8; 7830b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7840b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n", 7850b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7860b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 7870b57cec5SDimitry Andric Reg, Off); 7880b57cec5SDimitry Andric Offset += 2; 7890b57cec5SDimitry Andric return false; 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric 7920b57cec5SDimitry Andric bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset, 7930b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7940b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8; 7950b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 7960b57cec5SDimitry Andric if (Prologue) 7970b57cec5SDimitry Andric SW.startLine() << format( 7980b57cec5SDimitry Andric "0x%02x%02x ; str d%u, [sp, #-%u]!\n", OC[Offset], 7990b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 8000b57cec5SDimitry Andric else 8010b57cec5SDimitry Andric SW.startLine() << format( 8020b57cec5SDimitry Andric "0x%02x%02x ; ldr d%u, [sp], #%u\n", OC[Offset], 8030b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 8040b57cec5SDimitry Andric Offset += 2; 8050b57cec5SDimitry Andric return false; 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset, 8090b57cec5SDimitry Andric unsigned Length, bool Prologue) { 8100b57cec5SDimitry Andric unsigned Off = 8110b57cec5SDimitry Andric (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0); 8120b57cec5SDimitry Andric Off <<= 4; 8130b57cec5SDimitry Andric SW.startLine() << format( 8140b57cec5SDimitry Andric "0x%02x%02x%02x%02x ; %s sp, #%u\n", OC[Offset], OC[Offset + 1], 8150b57cec5SDimitry Andric OC[Offset + 2], OC[Offset + 3], 8160b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Off); 8170b57cec5SDimitry Andric Offset += 4; 8180b57cec5SDimitry Andric return false; 8190b57cec5SDimitry Andric } 8200b57cec5SDimitry Andric 8210b57cec5SDimitry Andric bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 8220b57cec5SDimitry Andric bool Prologue) { 823e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; mov %s, %s\n", OC[Offset], 824e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "fp" : "sp"), 825e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "sp" : "fp")); 8260b57cec5SDimitry Andric ++Offset; 8270b57cec5SDimitry Andric return false; 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 8310b57cec5SDimitry Andric bool Prologue) { 8320b57cec5SDimitry Andric unsigned NumBytes = OC[Offset + 1] << 3; 833e8d8bef9SDimitry Andric SW.startLine() << format( 834e8d8bef9SDimitry Andric "0x%02x%02x ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1], 835e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "add" : "sub"), 836e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "fp" : "sp"), 837e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes); 8380b57cec5SDimitry Andric Offset += 2; 8390b57cec5SDimitry Andric return false; 8400b57cec5SDimitry Andric } 8410b57cec5SDimitry Andric 8420b57cec5SDimitry Andric bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length, 8430b57cec5SDimitry Andric bool Prologue) { 8440b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 8450b57cec5SDimitry Andric ++Offset; 8460b57cec5SDimitry Andric return false; 8470b57cec5SDimitry Andric } 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length, 8500b57cec5SDimitry Andric bool Prologue) { 8510b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end\n", OC[Offset]); 8520b57cec5SDimitry Andric ++Offset; 8530b57cec5SDimitry Andric return true; 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric 8560b57cec5SDimitry Andric bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length, 8570b57cec5SDimitry Andric bool Prologue) { 8580b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]); 8590b57cec5SDimitry Andric ++Offset; 860bdd1243dSDimitry Andric return false; 8610b57cec5SDimitry Andric } 8620b57cec5SDimitry Andric 863e8d8bef9SDimitry Andric bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset, 864e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 865e8d8bef9SDimitry Andric if (Prologue) 866e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; save next\n", OC[Offset]); 867e8d8bef9SDimitry Andric else 868e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; restore next\n", 869e8d8bef9SDimitry Andric OC[Offset]); 870e8d8bef9SDimitry Andric ++Offset; 871e8d8bef9SDimitry Andric return false; 872e8d8bef9SDimitry Andric } 873e8d8bef9SDimitry Andric 874bdd1243dSDimitry Andric bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset, 875bdd1243dSDimitry Andric unsigned Length, bool Prologue) { 876bdd1243dSDimitry Andric // Whether the instruction has writeback 877bdd1243dSDimitry Andric bool Writeback = (OC[Offset + 1] & 0x20) == 0x20; 878bdd1243dSDimitry Andric // Whether the instruction is paired. (Paired instructions are required 879bdd1243dSDimitry Andric // to save/restore adjacent registers.) 880bdd1243dSDimitry Andric bool Paired = (OC[Offset + 1] & 0x40) == 0x40; 881bdd1243dSDimitry Andric // The kind of register saved: 882bdd1243dSDimitry Andric // - 0 is an x register 883bdd1243dSDimitry Andric // - 1 is the low half of a q register 884bdd1243dSDimitry Andric // - 2 is a whole q register 885bdd1243dSDimitry Andric int RegKind = (OC[Offset + 2] & 0xC0) >> 6; 886bdd1243dSDimitry Andric // Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.) 887bdd1243dSDimitry Andric int Reg = OC[Offset + 1] & 0x1F; 888bdd1243dSDimitry Andric // Encoded stack offset of load/store instruction; decoding varies by mode. 889bdd1243dSDimitry Andric int StackOffset = OC[Offset + 2] & 0x3F; 890bdd1243dSDimitry Andric if (Writeback) 891bdd1243dSDimitry Andric StackOffset++; 892bdd1243dSDimitry Andric if (!Writeback && !Paired && RegKind != 2) 893bdd1243dSDimitry Andric StackOffset *= 8; 894bdd1243dSDimitry Andric else 895bdd1243dSDimitry Andric StackOffset *= 16; 896bdd1243dSDimitry Andric 897bdd1243dSDimitry Andric SW.startLine() << format("0x%02x%02x%02x ; ", OC[Offset], 898bdd1243dSDimitry Andric OC[Offset + 1], OC[Offset + 2]); 899bdd1243dSDimitry Andric 900bdd1243dSDimitry Andric // Verify the encoding is in a form we understand. The high bit of the first 901bdd1243dSDimitry Andric // byte, and mode 3 for the register kind are apparently reserved. The 902bdd1243dSDimitry Andric // encoded register must refer to a valid register. 903bdd1243dSDimitry Andric int MaxReg = 0x1F; 904bdd1243dSDimitry Andric if (Paired) 905bdd1243dSDimitry Andric --MaxReg; 906bdd1243dSDimitry Andric if (RegKind == 0) 907bdd1243dSDimitry Andric --MaxReg; 908bdd1243dSDimitry Andric if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) { 909bdd1243dSDimitry Andric SW.getOStream() << "invalid save_any_reg encoding\n"; 910bdd1243dSDimitry Andric Offset += 3; 911bdd1243dSDimitry Andric return false; 912bdd1243dSDimitry Andric } 913bdd1243dSDimitry Andric 914bdd1243dSDimitry Andric if (Paired) { 915bdd1243dSDimitry Andric if (Prologue) 916bdd1243dSDimitry Andric SW.getOStream() << "stp "; 917bdd1243dSDimitry Andric else 918bdd1243dSDimitry Andric SW.getOStream() << "ldp "; 919bdd1243dSDimitry Andric } else { 920bdd1243dSDimitry Andric if (Prologue) 921bdd1243dSDimitry Andric SW.getOStream() << "str "; 922bdd1243dSDimitry Andric else 923bdd1243dSDimitry Andric SW.getOStream() << "ldr "; 924bdd1243dSDimitry Andric } 925bdd1243dSDimitry Andric 926bdd1243dSDimitry Andric char RegChar = 'x'; 927bdd1243dSDimitry Andric if (RegKind == 1) { 928bdd1243dSDimitry Andric RegChar = 'd'; 929bdd1243dSDimitry Andric } else if (RegKind == 2) { 930bdd1243dSDimitry Andric RegChar = 'q'; 931bdd1243dSDimitry Andric } 932bdd1243dSDimitry Andric 933bdd1243dSDimitry Andric if (Paired) 934bdd1243dSDimitry Andric SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1); 935bdd1243dSDimitry Andric else 936bdd1243dSDimitry Andric SW.getOStream() << format("%c%d, ", RegChar, Reg); 937bdd1243dSDimitry Andric 938bdd1243dSDimitry Andric if (Writeback) { 939bdd1243dSDimitry Andric if (Prologue) 940bdd1243dSDimitry Andric SW.getOStream() << format("[sp, #-%d]!\n", StackOffset); 941bdd1243dSDimitry Andric else 942bdd1243dSDimitry Andric SW.getOStream() << format("[sp], #%d\n", StackOffset); 943bdd1243dSDimitry Andric } else { 944bdd1243dSDimitry Andric SW.getOStream() << format("[sp, #%d]\n", StackOffset); 945bdd1243dSDimitry Andric } 946bdd1243dSDimitry Andric 947bdd1243dSDimitry Andric Offset += 3; 948bdd1243dSDimitry Andric return false; 949bdd1243dSDimitry Andric } 950bdd1243dSDimitry Andric 951e8d8bef9SDimitry Andric bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset, 952e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 953e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]); 954e8d8bef9SDimitry Andric ++Offset; 955e8d8bef9SDimitry Andric return false; 956e8d8bef9SDimitry Andric } 957e8d8bef9SDimitry Andric 958e8d8bef9SDimitry Andric bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset, 959e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 960e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; machine frame\n", 961e8d8bef9SDimitry Andric OC[Offset]); 962e8d8bef9SDimitry Andric ++Offset; 963e8d8bef9SDimitry Andric return false; 964e8d8bef9SDimitry Andric } 965e8d8bef9SDimitry Andric 966e8d8bef9SDimitry Andric bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset, 967e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 968e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; context\n", OC[Offset]); 969e8d8bef9SDimitry Andric ++Offset; 970e8d8bef9SDimitry Andric return false; 971e8d8bef9SDimitry Andric } 972e8d8bef9SDimitry Andric 973*5f757f3fSDimitry Andric bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset, 974*5f757f3fSDimitry Andric unsigned Length, bool Prologue) { 975*5f757f3fSDimitry Andric SW.startLine() << format("0x%02x ; EC context\n", OC[Offset]); 976*5f757f3fSDimitry Andric ++Offset; 977*5f757f3fSDimitry Andric return false; 978*5f757f3fSDimitry Andric } 979*5f757f3fSDimitry Andric 980e8d8bef9SDimitry Andric bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset, 981e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 982e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; clear unwound to call\n", 983e8d8bef9SDimitry Andric OC[Offset]); 984e8d8bef9SDimitry Andric ++Offset; 985e8d8bef9SDimitry Andric return false; 986e8d8bef9SDimitry Andric } 987e8d8bef9SDimitry Andric 988bdd1243dSDimitry Andric bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset, 989bdd1243dSDimitry Andric unsigned Length, bool Prologue) { 990bdd1243dSDimitry Andric if (Prologue) 991bdd1243dSDimitry Andric SW.startLine() << format("0x%02x ; pacibsp\n", OC[Offset]); 992bdd1243dSDimitry Andric else 993bdd1243dSDimitry Andric SW.startLine() << format("0x%02x ; autibsp\n", OC[Offset]); 994bdd1243dSDimitry Andric ++Offset; 995bdd1243dSDimitry Andric return false; 996bdd1243dSDimitry Andric } 997bdd1243dSDimitry Andric 9980b57cec5SDimitry Andric void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, 9990b57cec5SDimitry Andric bool Prologue) { 10000b57cec5SDimitry Andric assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); 10010b57cec5SDimitry Andric const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring; 10020b57cec5SDimitry Andric bool Terminated = false; 10030b57cec5SDimitry Andric for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { 10040b57cec5SDimitry Andric for (unsigned DI = 0;; ++DI) { 1005bdd1243dSDimitry Andric if ((isAArch64 && (DI >= std::size(Ring64))) || 1006bdd1243dSDimitry Andric (!isAArch64 && (DI >= std::size(Ring)))) { 10070b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; Bad opcode!\n", 10080b57cec5SDimitry Andric Opcodes.data()[OI]); 10090b57cec5SDimitry Andric ++OI; 10100b57cec5SDimitry Andric break; 10110b57cec5SDimitry Andric } 10120b57cec5SDimitry Andric 10130b57cec5SDimitry Andric if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) { 10140b57cec5SDimitry Andric if (OI + DecodeRing[DI].Length > OE) { 10150b57cec5SDimitry Andric SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n", 10160b57cec5SDimitry Andric Opcodes[OI]); 10170b57cec5SDimitry Andric OI += DecodeRing[DI].Length; 10180b57cec5SDimitry Andric break; 10190b57cec5SDimitry Andric } 10200b57cec5SDimitry Andric Terminated = 10210b57cec5SDimitry Andric (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue); 10220b57cec5SDimitry Andric break; 10230b57cec5SDimitry Andric } 10240b57cec5SDimitry Andric } 10250b57cec5SDimitry Andric } 10260b57cec5SDimitry Andric } 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, 10290b57cec5SDimitry Andric const SectionRef &Section, 10300b57cec5SDimitry Andric uint64_t FunctionAddress, uint64_t VA) { 10310b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 10320b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 10330b57cec5SDimitry Andric return false; 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric uint64_t SectionVA = Section.getAddress(); 10360b57cec5SDimitry Andric uint64_t Offset = VA - SectionVA; 10370b57cec5SDimitry Andric const ulittle32_t *Data = 10380b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric // Sanity check to ensure that the .xdata header is present. 10410b57cec5SDimitry Andric // A header is one or two words, followed by at least one word to describe 10420b57cec5SDimitry Andric // the unwind codes. Applicable to both ARM and AArch64. 10430b57cec5SDimitry Andric if (Contents.size() - Offset < 8) 10440b57cec5SDimitry Andric report_fatal_error(".xdata must be at least 8 bytes in size"); 10450b57cec5SDimitry Andric 10460b57cec5SDimitry Andric const ExceptionDataRecord XData(Data, isAArch64); 10470b57cec5SDimitry Andric DictScope XRS(SW, "ExceptionData"); 10480b57cec5SDimitry Andric SW.printNumber("FunctionLength", 10490b57cec5SDimitry Andric isAArch64 ? XData.FunctionLengthInBytesAArch64() : 10500b57cec5SDimitry Andric XData.FunctionLengthInBytesARM()); 10510b57cec5SDimitry Andric SW.printNumber("Version", XData.Vers()); 10520b57cec5SDimitry Andric SW.printBoolean("ExceptionData", XData.X()); 10530b57cec5SDimitry Andric SW.printBoolean("EpiloguePacked", XData.E()); 10540b57cec5SDimitry Andric if (!isAArch64) 10550b57cec5SDimitry Andric SW.printBoolean("Fragment", XData.F()); 10560b57cec5SDimitry Andric SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", 10570b57cec5SDimitry Andric XData.EpilogueCount()); 10580b57cec5SDimitry Andric uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t); 10590b57cec5SDimitry Andric SW.printNumber("ByteCodeLength", ByteCodeLength); 10600b57cec5SDimitry Andric 10610b57cec5SDimitry Andric if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) - 10620b57cec5SDimitry Andric (XData.E() ? 0 : XData.EpilogueCount() * 4) - 10638bcb0991SDimitry Andric (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { 10648bcb0991SDimitry Andric SW.flush(); 10650b57cec5SDimitry Andric report_fatal_error("Malformed unwind data"); 10668bcb0991SDimitry Andric } 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric if (XData.E()) { 10690b57cec5SDimitry Andric ArrayRef<uint8_t> UC = XData.UnwindByteCode(); 107081ad6265SDimitry Andric { 10710b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 10720b57cec5SDimitry Andric decodeOpcodes(UC, 0, /*Prologue=*/true); 10730b57cec5SDimitry Andric } 10740b57cec5SDimitry Andric if (XData.EpilogueCount()) { 10750b57cec5SDimitry Andric ListScope ES(SW, "Epilogue"); 10760b57cec5SDimitry Andric decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); 10770b57cec5SDimitry Andric } 10780b57cec5SDimitry Andric } else { 10790b57cec5SDimitry Andric { 10800b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 10810b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true); 10820b57cec5SDimitry Andric } 10830b57cec5SDimitry Andric ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); 10840b57cec5SDimitry Andric ListScope ESS(SW, "EpilogueScopes"); 10850b57cec5SDimitry Andric for (const EpilogueScope ES : EpilogueScopes) { 10860b57cec5SDimitry Andric DictScope ESES(SW, "EpilogueScope"); 10870b57cec5SDimitry Andric SW.printNumber("StartOffset", ES.EpilogueStartOffset()); 10880b57cec5SDimitry Andric if (!isAArch64) 10890b57cec5SDimitry Andric SW.printNumber("Condition", ES.Condition()); 10900b57cec5SDimitry Andric SW.printNumber("EpilogueStartIndex", 10910b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 10920b57cec5SDimitry Andric : ES.EpilogueStartIndexARM()); 109381ad6265SDimitry Andric unsigned ReservedMask = isAArch64 ? 0xF : 0x3; 109481ad6265SDimitry Andric if ((ES.ES >> 18) & ReservedMask) 109581ad6265SDimitry Andric SW.printNumber("ReservedBits", (ES.ES >> 18) & ReservedMask); 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric ListScope Opcodes(SW, "Opcodes"); 10980b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 10990b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 11000b57cec5SDimitry Andric : ES.EpilogueStartIndexARM(), 11010b57cec5SDimitry Andric /*Prologue=*/false); 11020b57cec5SDimitry Andric } 11030b57cec5SDimitry Andric } 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric if (XData.X()) { 11060b57cec5SDimitry Andric const uint32_t Parameter = XData.ExceptionHandlerParameter(); 1107fe6060f1SDimitry Andric const size_t HandlerOffset = HeaderWords(XData) + 1108fe6060f1SDimitry Andric (XData.E() ? 0 : XData.EpilogueCount()) + 1109fe6060f1SDimitry Andric XData.CodeWords(); 11100b57cec5SDimitry Andric 1111fe6060f1SDimitry Andric uint64_t Address, SymbolOffset; 1112fe6060f1SDimitry Andric ErrorOr<SymbolRef> Symbol = getSymbolForLocation( 1113fe6060f1SDimitry Andric COFF, Section, Offset + HandlerOffset * sizeof(uint32_t), 1114fe6060f1SDimitry Andric XData.ExceptionHandlerRVA(), Address, SymbolOffset, 1115fe6060f1SDimitry Andric /*FunctionOnly=*/true); 11160b57cec5SDimitry Andric if (!Symbol) { 11170b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 1118480093f4SDimitry Andric SW.printHex("Routine", Address); 1119480093f4SDimitry Andric SW.printHex("Parameter", Parameter); 11200b57cec5SDimitry Andric return true; 11210b57cec5SDimitry Andric } 11220b57cec5SDimitry Andric 11230b57cec5SDimitry Andric Expected<StringRef> Name = Symbol->getName(); 11240b57cec5SDimitry Andric if (!Name) { 11250b57cec5SDimitry Andric std::string Buf; 11260b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11270b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 1128349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 1132fe6060f1SDimitry Andric SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset)); 11330b57cec5SDimitry Andric SW.printHex("Parameter", Parameter); 11340b57cec5SDimitry Andric } 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric return true; 11370b57cec5SDimitry Andric } 11380b57cec5SDimitry Andric 11390b57cec5SDimitry Andric bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, 11400b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 11410b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 11420b57cec5SDimitry Andric assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && 11430b57cec5SDimitry Andric "packed entry cannot be treated as an unpacked entry"); 11440b57cec5SDimitry Andric 1145fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1146fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1147fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1148480093f4SDimitry Andric /*FunctionOnly=*/true); 11490b57cec5SDimitry Andric 1150fe6060f1SDimitry Andric uint64_t XDataAddress, XDataOffset; 1151fe6060f1SDimitry Andric ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation( 1152fe6060f1SDimitry Andric COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress, 1153fe6060f1SDimitry Andric XDataOffset); 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric if (!RF.BeginAddress && !Function) 11560b57cec5SDimitry Andric return false; 11570b57cec5SDimitry Andric if (!RF.UnwindData && !XDataRecord) 11580b57cec5SDimitry Andric return false; 11590b57cec5SDimitry Andric 11600b57cec5SDimitry Andric StringRef FunctionName; 11610b57cec5SDimitry Andric if (Function) { 11620b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 11630b57cec5SDimitry Andric if (!FunctionNameOrErr) { 11640b57cec5SDimitry Andric std::string Buf; 11650b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11660b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1167349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11680b57cec5SDimitry Andric } 11690b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 11700b57cec5SDimitry Andric } 11710b57cec5SDimitry Andric 1172fe6060f1SDimitry Andric SW.printString("Function", 1173fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric if (XDataRecord) { 11760b57cec5SDimitry Andric Expected<StringRef> Name = XDataRecord->getName(); 11770b57cec5SDimitry Andric if (!Name) { 11780b57cec5SDimitry Andric std::string Buf; 11790b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11800b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 1181349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11820b57cec5SDimitry Andric } 11830b57cec5SDimitry Andric 1184fe6060f1SDimitry Andric SW.printString("ExceptionRecord", 1185fe6060f1SDimitry Andric formatSymbol(*Name, XDataAddress, XDataOffset)); 11860b57cec5SDimitry Andric 11870b57cec5SDimitry Andric Expected<section_iterator> SIOrErr = XDataRecord->getSection(); 11880b57cec5SDimitry Andric if (!SIOrErr) { 11890b57cec5SDimitry Andric // TODO: Actually report errors helpfully. 11900b57cec5SDimitry Andric consumeError(SIOrErr.takeError()); 11910b57cec5SDimitry Andric return false; 11920b57cec5SDimitry Andric } 11930b57cec5SDimitry Andric section_iterator SI = *SIOrErr; 11940b57cec5SDimitry Andric 1195fe6060f1SDimitry Andric return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress); 11960b57cec5SDimitry Andric } else { 1197fe6060f1SDimitry Andric SW.printString("ExceptionRecord", formatSymbol("", XDataAddress)); 11980b57cec5SDimitry Andric 1199fe6060f1SDimitry Andric ErrorOr<SectionRef> Section = getSectionContaining(COFF, XDataAddress); 12000b57cec5SDimitry Andric if (!Section) 12010b57cec5SDimitry Andric return false; 12020b57cec5SDimitry Andric 1203fe6060f1SDimitry Andric return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress); 12040b57cec5SDimitry Andric } 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric 12070b57cec5SDimitry Andric bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, 12080b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 12090b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 12100b57cec5SDimitry Andric assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || 12110b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && 12120b57cec5SDimitry Andric "unpacked entry cannot be treated as a packed entry"); 12130b57cec5SDimitry Andric 1214fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1215fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1216fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1217fe6060f1SDimitry Andric /*FunctionOnly=*/true); 12180b57cec5SDimitry Andric 12190b57cec5SDimitry Andric StringRef FunctionName; 12200b57cec5SDimitry Andric if (Function) { 12210b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 12220b57cec5SDimitry Andric if (!FunctionNameOrErr) { 12230b57cec5SDimitry Andric std::string Buf; 12240b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 12250b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1226349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 12270b57cec5SDimitry Andric } 12280b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 12290b57cec5SDimitry Andric } 12300b57cec5SDimitry Andric 1231fe6060f1SDimitry Andric SW.printString("Function", 1232fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 12330b57cec5SDimitry Andric SW.printBoolean("Fragment", 12340b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); 12350b57cec5SDimitry Andric SW.printNumber("FunctionLength", RF.FunctionLength()); 12360b57cec5SDimitry Andric SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; 12370b57cec5SDimitry Andric SW.printBoolean("HomedParameters", RF.H()); 123881ad6265SDimitry Andric SW.printNumber("Reg", RF.Reg()); 123981ad6265SDimitry Andric SW.printNumber("R", RF.R()); 124081ad6265SDimitry Andric SW.printBoolean("LinkRegister", RF.L()); 124181ad6265SDimitry Andric SW.printBoolean("Chaining", RF.C()); 12420b57cec5SDimitry Andric SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); 12430b57cec5SDimitry Andric 124481ad6265SDimitry Andric { 124581ad6265SDimitry Andric ListScope PS(SW, "Prologue"); 124681ad6265SDimitry Andric 124781ad6265SDimitry Andric uint16_t GPRMask, VFPMask; 124881ad6265SDimitry Andric std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true); 124981ad6265SDimitry Andric 125081ad6265SDimitry Andric if (StackAdjustment(RF) && !PrologueFolding(RF)) 125181ad6265SDimitry Andric SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; 125281ad6265SDimitry Andric if (VFPMask) { 125381ad6265SDimitry Andric SW.startLine() << "vpush "; 125481ad6265SDimitry Andric printVFPMask(VFPMask); 125581ad6265SDimitry Andric OS << "\n"; 125681ad6265SDimitry Andric } 125781ad6265SDimitry Andric if (RF.C()) { 125881ad6265SDimitry Andric // Count the number of registers pushed below R11 1259bdd1243dSDimitry Andric int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1)); 126081ad6265SDimitry Andric if (FpOffset) 126181ad6265SDimitry Andric SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n"; 126281ad6265SDimitry Andric else 126381ad6265SDimitry Andric SW.startLine() << "mov r11, sp\n"; 126481ad6265SDimitry Andric } 126581ad6265SDimitry Andric if (GPRMask) { 126681ad6265SDimitry Andric SW.startLine() << "push "; 126781ad6265SDimitry Andric printGPRMask(GPRMask); 126881ad6265SDimitry Andric OS << "\n"; 126981ad6265SDimitry Andric } 127081ad6265SDimitry Andric if (RF.H()) 127181ad6265SDimitry Andric SW.startLine() << "push {r0-r3}\n"; 127281ad6265SDimitry Andric } 127381ad6265SDimitry Andric 127481ad6265SDimitry Andric if (RF.Ret() != ReturnType::RT_NoEpilogue) { 127581ad6265SDimitry Andric ListScope PS(SW, "Epilogue"); 127681ad6265SDimitry Andric 127781ad6265SDimitry Andric uint16_t GPRMask, VFPMask; 127881ad6265SDimitry Andric std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false); 127981ad6265SDimitry Andric 128081ad6265SDimitry Andric if (StackAdjustment(RF) && !EpilogueFolding(RF)) 128181ad6265SDimitry Andric SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; 128281ad6265SDimitry Andric if (VFPMask) { 128381ad6265SDimitry Andric SW.startLine() << "vpop "; 128481ad6265SDimitry Andric printVFPMask(VFPMask); 128581ad6265SDimitry Andric OS << "\n"; 128681ad6265SDimitry Andric } 128781ad6265SDimitry Andric if (GPRMask) { 128881ad6265SDimitry Andric SW.startLine() << "pop "; 128981ad6265SDimitry Andric printGPRMask(GPRMask); 129081ad6265SDimitry Andric OS << "\n"; 129181ad6265SDimitry Andric } 129281ad6265SDimitry Andric if (RF.H()) { 129381ad6265SDimitry Andric if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP) 129481ad6265SDimitry Andric SW.startLine() << "add sp, sp, #16\n"; 129581ad6265SDimitry Andric else 129681ad6265SDimitry Andric SW.startLine() << "ldr pc, [sp], #20\n"; 129781ad6265SDimitry Andric } 129881ad6265SDimitry Andric if (RF.Ret() != ReturnType::RT_POP) 129981ad6265SDimitry Andric SW.startLine() << RF.Ret() << '\n'; 130081ad6265SDimitry Andric } 130181ad6265SDimitry Andric 13020b57cec5SDimitry Andric return true; 13030b57cec5SDimitry Andric } 13040b57cec5SDimitry Andric 1305e8d8bef9SDimitry Andric bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF, 1306e8d8bef9SDimitry Andric const SectionRef Section, uint64_t Offset, 1307e8d8bef9SDimitry Andric unsigned Index, 1308e8d8bef9SDimitry Andric const RuntimeFunctionARM64 &RF) { 1309e8d8bef9SDimitry Andric assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || 1310e8d8bef9SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && 1311e8d8bef9SDimitry Andric "unpacked entry cannot be treated as a packed entry"); 1312e8d8bef9SDimitry Andric 1313fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1314fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1315fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1316fe6060f1SDimitry Andric /*FunctionOnly=*/true); 1317e8d8bef9SDimitry Andric 1318e8d8bef9SDimitry Andric StringRef FunctionName; 1319e8d8bef9SDimitry Andric if (Function) { 1320e8d8bef9SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 1321e8d8bef9SDimitry Andric if (!FunctionNameOrErr) { 1322e8d8bef9SDimitry Andric std::string Buf; 1323e8d8bef9SDimitry Andric llvm::raw_string_ostream OS(Buf); 1324e8d8bef9SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1325349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 1326e8d8bef9SDimitry Andric } 1327e8d8bef9SDimitry Andric FunctionName = *FunctionNameOrErr; 1328e8d8bef9SDimitry Andric } 1329e8d8bef9SDimitry Andric 1330fe6060f1SDimitry Andric SW.printString("Function", 1331fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 1332e8d8bef9SDimitry Andric SW.printBoolean("Fragment", 1333e8d8bef9SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); 1334e8d8bef9SDimitry Andric SW.printNumber("FunctionLength", RF.FunctionLength()); 1335e8d8bef9SDimitry Andric SW.printNumber("RegF", RF.RegF()); 1336e8d8bef9SDimitry Andric SW.printNumber("RegI", RF.RegI()); 1337e8d8bef9SDimitry Andric SW.printBoolean("HomedParameters", RF.H()); 1338e8d8bef9SDimitry Andric SW.printNumber("CR", RF.CR()); 1339e8d8bef9SDimitry Andric SW.printNumber("FrameSize", RF.FrameSize() << 4); 1340e8d8bef9SDimitry Andric ListScope PS(SW, "Prologue"); 1341e8d8bef9SDimitry Andric 1342e8d8bef9SDimitry Andric // Synthesize the equivalent prologue according to the documentation 1343e8d8bef9SDimitry Andric // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling, 1344e8d8bef9SDimitry Andric // printed in reverse order compared to the docs, to match how prologues 1345e8d8bef9SDimitry Andric // are printed for the non-packed case. 1346e8d8bef9SDimitry Andric int IntSZ = 8 * RF.RegI(); 1347e8d8bef9SDimitry Andric if (RF.CR() == 1) 1348e8d8bef9SDimitry Andric IntSZ += 8; 1349e8d8bef9SDimitry Andric int FpSZ = 8 * RF.RegF(); 1350e8d8bef9SDimitry Andric if (RF.RegF()) 1351e8d8bef9SDimitry Andric FpSZ += 8; 1352e8d8bef9SDimitry Andric int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf; 1353e8d8bef9SDimitry Andric int LocSZ = (RF.FrameSize() << 4) - SavSZ; 1354e8d8bef9SDimitry Andric 1355bdd1243dSDimitry Andric if (RF.CR() == 2 || RF.CR() == 3) { 1356e8d8bef9SDimitry Andric SW.startLine() << "mov x29, sp\n"; 1357e8d8bef9SDimitry Andric if (LocSZ <= 512) { 1358e8d8bef9SDimitry Andric SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ); 1359e8d8bef9SDimitry Andric } else { 1360e8d8bef9SDimitry Andric SW.startLine() << "stp x29, lr, [sp, #0]\n"; 1361e8d8bef9SDimitry Andric } 1362e8d8bef9SDimitry Andric } 1363e8d8bef9SDimitry Andric if (LocSZ > 4080) { 1364e8d8bef9SDimitry Andric SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080); 1365e8d8bef9SDimitry Andric SW.startLine() << "sub sp, sp, #4080\n"; 1366bdd1243dSDimitry Andric } else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) { 1367e8d8bef9SDimitry Andric SW.startLine() << format("sub sp, sp, #%d\n", LocSZ); 1368e8d8bef9SDimitry Andric } 1369e8d8bef9SDimitry Andric if (RF.H()) { 137081ad6265SDimitry Andric SW.startLine() << format("stp x6, x7, [sp, #%d]\n", SavSZ - 16); 137181ad6265SDimitry Andric SW.startLine() << format("stp x4, x5, [sp, #%d]\n", SavSZ - 32); 137281ad6265SDimitry Andric SW.startLine() << format("stp x2, x3, [sp, #%d]\n", SavSZ - 48); 1373e8d8bef9SDimitry Andric if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) { 137481ad6265SDimitry Andric SW.startLine() << format("stp x0, x1, [sp, #%d]\n", SavSZ - 64); 1375e8d8bef9SDimitry Andric } else { 1376e8d8bef9SDimitry Andric // This case isn't documented; if neither RegI nor RegF nor CR=1 1377e8d8bef9SDimitry Andric // have decremented the stack pointer by SavSZ, we need to do it here 1378e8d8bef9SDimitry Andric // (as the final stack adjustment of LocSZ excludes SavSZ). 1379e8d8bef9SDimitry Andric SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ); 1380e8d8bef9SDimitry Andric } 1381e8d8bef9SDimitry Andric } 1382e8d8bef9SDimitry Andric int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0; 1383e8d8bef9SDimitry Andric for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) { 1384e8d8bef9SDimitry Andric if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) { 1385e8d8bef9SDimitry Andric // The last register, an odd register without a pair 1386e8d8bef9SDimitry Andric SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I, 1387e8d8bef9SDimitry Andric IntSZ + 16 * I); 1388e8d8bef9SDimitry Andric } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) { 1389e8d8bef9SDimitry Andric SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I, 1390e8d8bef9SDimitry Andric 8 + 2 * I + 1, SavSZ); 1391e8d8bef9SDimitry Andric } else { 1392e8d8bef9SDimitry Andric SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I, 1393e8d8bef9SDimitry Andric 8 + 2 * I + 1, IntSZ + 16 * I); 1394e8d8bef9SDimitry Andric } 1395e8d8bef9SDimitry Andric } 1396e8d8bef9SDimitry Andric if (RF.CR() == 1 && (RF.RegI() % 2) == 0) { 1397e8d8bef9SDimitry Andric if (RF.RegI() == 0) 1398e8d8bef9SDimitry Andric SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ); 1399e8d8bef9SDimitry Andric else 1400e8d8bef9SDimitry Andric SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8); 1401e8d8bef9SDimitry Andric } 1402e8d8bef9SDimitry Andric for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) { 1403e8d8bef9SDimitry Andric if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) { 1404e8d8bef9SDimitry Andric // The last register, an odd register without a pair 1405e8d8bef9SDimitry Andric if (RF.CR() == 1) { 1406e8d8bef9SDimitry Andric if (I == 0) { // If this is the only register pair 1407e8d8bef9SDimitry Andric // CR=1 combined with RegI=1 doesn't map to a documented case; 1408e8d8bef9SDimitry Andric // it doesn't map to any regular unwind info opcode, and the 1409e8d8bef9SDimitry Andric // actual unwinder doesn't support it. 1410e8d8bef9SDimitry Andric SW.startLine() << "INVALID!\n"; 1411e8d8bef9SDimitry Andric } else 1412e8d8bef9SDimitry Andric SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I, 1413e8d8bef9SDimitry Andric 16 * I); 1414e8d8bef9SDimitry Andric } else { 1415e8d8bef9SDimitry Andric if (I == 0) 1416e8d8bef9SDimitry Andric SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ); 1417e8d8bef9SDimitry Andric else 1418e8d8bef9SDimitry Andric SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I); 1419e8d8bef9SDimitry Andric } 1420e8d8bef9SDimitry Andric } else if (I == 0) { 1421e8d8bef9SDimitry Andric // The first register pair 1422e8d8bef9SDimitry Andric SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ); 1423e8d8bef9SDimitry Andric } else { 1424e8d8bef9SDimitry Andric SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I, 1425e8d8bef9SDimitry Andric 19 + 2 * I + 1, 16 * I); 1426e8d8bef9SDimitry Andric } 1427e8d8bef9SDimitry Andric } 1428bdd1243dSDimitry Andric // CR=2 is yet undocumented, see 1429bdd1243dSDimitry Andric // https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream 1430bdd1243dSDimitry Andric // progress on getting it documented. 1431bdd1243dSDimitry Andric if (RF.CR() == 2) 1432bdd1243dSDimitry Andric SW.startLine() << "pacibsp\n"; 1433e8d8bef9SDimitry Andric SW.startLine() << "end\n"; 1434e8d8bef9SDimitry Andric 1435e8d8bef9SDimitry Andric return true; 1436e8d8bef9SDimitry Andric } 1437e8d8bef9SDimitry Andric 14380b57cec5SDimitry Andric bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, 14390b57cec5SDimitry Andric const SectionRef Section, unsigned Index, 14400b57cec5SDimitry Andric ArrayRef<uint8_t> Contents) { 14410b57cec5SDimitry Andric uint64_t Offset = PDataEntrySize * Index; 14420b57cec5SDimitry Andric const ulittle32_t *Data = 14430b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 14440b57cec5SDimitry Andric 14450b57cec5SDimitry Andric const RuntimeFunction Entry(Data); 14460b57cec5SDimitry Andric DictScope RFS(SW, "RuntimeFunction"); 14470b57cec5SDimitry Andric if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) 14480b57cec5SDimitry Andric return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); 14490b57cec5SDimitry Andric if (isAArch64) { 1450e8d8bef9SDimitry Andric const RuntimeFunctionARM64 EntryARM64(Data); 1451e8d8bef9SDimitry Andric return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64); 14520b57cec5SDimitry Andric } 14530b57cec5SDimitry Andric return dumpPackedEntry(COFF, Section, Offset, Index, Entry); 14540b57cec5SDimitry Andric } 14550b57cec5SDimitry Andric 14560b57cec5SDimitry Andric void Decoder::dumpProcedureData(const COFFObjectFile &COFF, 14570b57cec5SDimitry Andric const SectionRef Section) { 14580b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 14590b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 14600b57cec5SDimitry Andric return; 14610b57cec5SDimitry Andric 14620b57cec5SDimitry Andric if (Contents.size() % PDataEntrySize) { 14630b57cec5SDimitry Andric errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; 14640b57cec5SDimitry Andric return; 14650b57cec5SDimitry Andric } 14660b57cec5SDimitry Andric 14670b57cec5SDimitry Andric for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) 14680b57cec5SDimitry Andric if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) 14690b57cec5SDimitry Andric break; 14700b57cec5SDimitry Andric } 14710b57cec5SDimitry Andric 14720b57cec5SDimitry Andric Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) { 14730b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 14740b57cec5SDimitry Andric Expected<StringRef> NameOrErr = 14750b57cec5SDimitry Andric COFF.getSectionName(COFF.getCOFFSection(Section)); 14760b57cec5SDimitry Andric if (!NameOrErr) 14770b57cec5SDimitry Andric return NameOrErr.takeError(); 14780b57cec5SDimitry Andric 1479*5f757f3fSDimitry Andric if (NameOrErr->starts_with(".pdata")) 14800b57cec5SDimitry Andric dumpProcedureData(COFF, Section); 14810b57cec5SDimitry Andric } 14820b57cec5SDimitry Andric return Error::success(); 14830b57cec5SDimitry Andric } 14840b57cec5SDimitry Andric } 14850b57cec5SDimitry Andric } 14860b57cec5SDimitry Andric } 1487