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}, 170*bdd1243dSDimitry 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}, 174e8d8bef9SDimitry Andric {0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call}, 175*bdd1243dSDimitry Andric {0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr}, 1760b57cec5SDimitry Andric }; 1770b57cec5SDimitry Andric 17881ad6265SDimitry Andric static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First, 17981ad6265SDimitry Andric unsigned Last, char Letter) { 18081ad6265SDimitry Andric if (First == Last) 18181ad6265SDimitry Andric OS << LS << Letter << First; 18281ad6265SDimitry Andric else 18381ad6265SDimitry Andric OS << LS << Letter << First << "-" << Letter << Last; 18481ad6265SDimitry Andric } 1850b57cec5SDimitry Andric 18681ad6265SDimitry Andric static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS, 18781ad6265SDimitry Andric unsigned Start, unsigned End, char Letter) { 18881ad6265SDimitry Andric int First = -1; 18981ad6265SDimitry Andric for (unsigned RI = Start; RI <= End; ++RI) { 19081ad6265SDimitry Andric if (Mask & (1 << RI)) { 19181ad6265SDimitry Andric if (First < 0) 19281ad6265SDimitry Andric First = RI; 19381ad6265SDimitry Andric } else { 19481ad6265SDimitry Andric if (First >= 0) { 19581ad6265SDimitry Andric printRange(OS, LS, First, RI - 1, Letter); 19681ad6265SDimitry Andric First = -1; 19781ad6265SDimitry Andric } 19881ad6265SDimitry Andric } 19981ad6265SDimitry Andric } 20081ad6265SDimitry Andric if (First >= 0) 20181ad6265SDimitry Andric printRange(OS, LS, First, End, Letter); 20281ad6265SDimitry Andric } 2030b57cec5SDimitry Andric 20481ad6265SDimitry Andric void Decoder::printGPRMask(uint16_t GPRMask) { 2050b57cec5SDimitry Andric OS << '{'; 206fe6060f1SDimitry Andric ListSeparator LS; 20781ad6265SDimitry Andric printRange(OS, GPRMask, LS, 0, 12, 'r'); 20881ad6265SDimitry Andric if (GPRMask & (1 << 14)) 20981ad6265SDimitry Andric OS << LS << "lr"; 21081ad6265SDimitry Andric if (GPRMask & (1 << 15)) 21181ad6265SDimitry Andric OS << LS << "pc"; 21281ad6265SDimitry Andric OS << '}'; 21381ad6265SDimitry Andric } 21481ad6265SDimitry Andric 21581ad6265SDimitry Andric void Decoder::printVFPMask(uint32_t VFPMask) { 21681ad6265SDimitry Andric OS << '{'; 21781ad6265SDimitry Andric ListSeparator LS; 21881ad6265SDimitry Andric printRange(OS, VFPMask, LS, 0, 31, 'd'); 2190b57cec5SDimitry Andric OS << '}'; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric ErrorOr<object::SectionRef> 2230b57cec5SDimitry Andric Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { 2240b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 2250b57cec5SDimitry Andric uint64_t Address = Section.getAddress(); 2260b57cec5SDimitry Andric uint64_t Size = Section.getSize(); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric if (VA >= Address && (VA - Address) <= Size) 2290b57cec5SDimitry Andric return Section; 2300b57cec5SDimitry Andric } 231e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, 2350b57cec5SDimitry Andric uint64_t VA, bool FunctionOnly) { 2360b57cec5SDimitry Andric for (const auto &Symbol : COFF.symbols()) { 2370b57cec5SDimitry Andric Expected<SymbolRef::Type> Type = Symbol.getType(); 2380b57cec5SDimitry Andric if (!Type) 2390b57cec5SDimitry Andric return errorToErrorCode(Type.takeError()); 2400b57cec5SDimitry Andric if (FunctionOnly && *Type != SymbolRef::ST_Function) 2410b57cec5SDimitry Andric continue; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric Expected<uint64_t> Address = Symbol.getAddress(); 2440b57cec5SDimitry Andric if (!Address) 2450b57cec5SDimitry Andric return errorToErrorCode(Address.takeError()); 2460b57cec5SDimitry Andric if (*Address == VA) 2470b57cec5SDimitry Andric return Symbol; 2480b57cec5SDimitry Andric } 249e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, 2530b57cec5SDimitry Andric const SectionRef &Section, 2540b57cec5SDimitry Andric uint64_t Offset) { 2550b57cec5SDimitry Andric for (const auto &Relocation : Section.relocations()) { 2560b57cec5SDimitry Andric uint64_t RelocationOffset = Relocation.getOffset(); 2570b57cec5SDimitry Andric if (RelocationOffset == Offset) 2580b57cec5SDimitry Andric return *Relocation.getSymbol(); 2590b57cec5SDimitry Andric } 260e8d8bef9SDimitry Andric return inconvertibleErrorCode(); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 263349cc55cSDimitry Andric SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym, 264349cc55cSDimitry Andric uint64_t &SymbolOffset) { 265fe6060f1SDimitry Andric // The symbol resolved by getRelocatedSymbol can be any internal 266fe6060f1SDimitry Andric // nondescriptive symbol; try to resolve a more descriptive one. 267fe6060f1SDimitry Andric COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym); 268349cc55cSDimitry Andric if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 269349cc55cSDimitry Andric CoffSym.getSectionDefinition() == nullptr) 270fe6060f1SDimitry Andric return Sym; 271fe6060f1SDimitry Andric for (const auto &S : COFF.symbols()) { 272fe6060f1SDimitry Andric COFFSymbolRef CS = COFF.getCOFFSymbol(S); 273fe6060f1SDimitry Andric if (CS.getSectionNumber() == CoffSym.getSectionNumber() && 274349cc55cSDimitry Andric CS.getValue() <= CoffSym.getValue() + SymbolOffset && 275349cc55cSDimitry Andric CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL && 276349cc55cSDimitry Andric CS.getSectionDefinition() == nullptr) { 277349cc55cSDimitry Andric uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue(); 278349cc55cSDimitry Andric if (Offset <= SymbolOffset) { 279349cc55cSDimitry Andric SymbolOffset = Offset; 280fe6060f1SDimitry Andric Sym = S; 281fe6060f1SDimitry Andric CoffSym = CS; 282349cc55cSDimitry Andric if (CS.isExternal() && SymbolOffset == 0) 283349cc55cSDimitry Andric return Sym; 284fe6060f1SDimitry Andric } 285fe6060f1SDimitry Andric } 286fe6060f1SDimitry Andric } 287fe6060f1SDimitry Andric return Sym; 288fe6060f1SDimitry Andric } 289fe6060f1SDimitry Andric 290fe6060f1SDimitry Andric ErrorOr<SymbolRef> Decoder::getSymbolForLocation( 291fe6060f1SDimitry Andric const COFFObjectFile &COFF, const SectionRef &Section, 292fe6060f1SDimitry Andric uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress, 293fe6060f1SDimitry Andric uint64_t &SymbolOffset, bool FunctionOnly) { 294fe6060f1SDimitry Andric // Try to locate a relocation that points at the offset in the section 295fe6060f1SDimitry Andric ErrorOr<SymbolRef> SymOrErr = 296fe6060f1SDimitry Andric getRelocatedSymbol(COFF, Section, OffsetInSection); 297fe6060f1SDimitry Andric if (SymOrErr) { 298fe6060f1SDimitry Andric // We found a relocation symbol; the immediate offset needs to be added 299fe6060f1SDimitry Andric // to the symbol address. 300fe6060f1SDimitry Andric SymbolOffset = ImmediateOffset; 301fe6060f1SDimitry Andric 302fe6060f1SDimitry Andric Expected<uint64_t> AddressOrErr = SymOrErr->getAddress(); 303fe6060f1SDimitry Andric if (!AddressOrErr) { 304fe6060f1SDimitry Andric std::string Buf; 305fe6060f1SDimitry Andric llvm::raw_string_ostream OS(Buf); 306fe6060f1SDimitry Andric logAllUnhandledErrors(AddressOrErr.takeError(), OS); 307349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 308fe6060f1SDimitry Andric } 309fe6060f1SDimitry Andric // We apply SymbolOffset here directly. We return it separately to allow 310fe6060f1SDimitry Andric // the caller to print it as an offset on the symbol name. 311fe6060f1SDimitry Andric SymbolAddress = *AddressOrErr + SymbolOffset; 312349cc55cSDimitry Andric 313349cc55cSDimitry Andric if (FunctionOnly) // Resolve label/section symbols into function names. 314349cc55cSDimitry Andric SymOrErr = getPreferredSymbol(COFF, *SymOrErr, SymbolOffset); 315fe6060f1SDimitry Andric } else { 316fe6060f1SDimitry Andric // No matching relocation found; operating on a linked image. Try to 317fe6060f1SDimitry Andric // find a descriptive symbol if possible. The immediate offset contains 318fe6060f1SDimitry Andric // the image relative address, and we shouldn't add any offset to the 319fe6060f1SDimitry Andric // symbol. 320fe6060f1SDimitry Andric SymbolAddress = COFF.getImageBase() + ImmediateOffset; 321fe6060f1SDimitry Andric SymbolOffset = 0; 322fe6060f1SDimitry Andric SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly); 323fe6060f1SDimitry Andric } 324fe6060f1SDimitry Andric return SymOrErr; 325fe6060f1SDimitry Andric } 326fe6060f1SDimitry Andric 3270b57cec5SDimitry Andric bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, 3280b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3290b57cec5SDimitry Andric uint8_t Imm = OC[Offset] & 0x7f; 3300b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", 3310b57cec5SDimitry Andric OC[Offset], 3320b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 3330b57cec5SDimitry Andric Imm); 3340b57cec5SDimitry Andric ++Offset; 3350b57cec5SDimitry Andric return false; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, 3390b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3400b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x20) >> 5; 3410b57cec5SDimitry Andric uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) 3420b57cec5SDimitry Andric | ((OC[Offset + 0] & 0x1f) << 8) 3430b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 3440b57cec5SDimitry Andric assert((~RegisterMask & (1 << 13)) && "sp must not be set"); 3450b57cec5SDimitry Andric assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w ", 3480b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 3490b57cec5SDimitry Andric Prologue ? "push" : "pop"); 35081ad6265SDimitry Andric printGPRMask(RegisterMask); 3510b57cec5SDimitry Andric OS << '\n'; 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric Offset += 2; 3540b57cec5SDimitry Andric return false; 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, 3580b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3590b57cec5SDimitry Andric if (Prologue) 3600b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov r%u, sp\n", 3610b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 3620b57cec5SDimitry Andric else 3630b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; mov sp, r%u\n", 3640b57cec5SDimitry Andric OC[Offset], OC[Offset] & 0xf); 3650b57cec5SDimitry Andric ++Offset; 3660b57cec5SDimitry Andric return false; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, 3700b57cec5SDimitry Andric unsigned Length, bool Prologue) { 37181ad6265SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 2; 3720b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3); 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3750b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 3780b57cec5SDimitry Andric Prologue ? "push" : "pop"); 37981ad6265SDimitry Andric printGPRMask(GPRMask); 3800b57cec5SDimitry Andric OS << '\n'; 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric ++Offset; 3830b57cec5SDimitry Andric return false; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, 3870b57cec5SDimitry Andric unsigned Length, bool Prologue) { 3880b57cec5SDimitry Andric unsigned Link = (OC[Offset] & 0x4) >> 2; 3890b57cec5SDimitry Andric unsigned Count = (OC[Offset] & 0x3) + 4; 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) 3920b57cec5SDimitry Andric | (((1 << (Count + 1)) - 1) << 4); 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], 3950b57cec5SDimitry Andric Prologue ? "push" : "pop"); 39681ad6265SDimitry Andric printGPRMask(GPRMask); 3970b57cec5SDimitry Andric OS << '\n'; 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric ++Offset; 4000b57cec5SDimitry Andric return false; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, 4040b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4050b57cec5SDimitry Andric unsigned High = (OC[Offset] & 0x7); 4060b57cec5SDimitry Andric uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s ", OC[Offset], 4090b57cec5SDimitry Andric Prologue ? "vpush" : "vpop"); 41081ad6265SDimitry Andric printVFPMask(VFPMask); 4110b57cec5SDimitry Andric OS << '\n'; 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric ++Offset; 4140b57cec5SDimitry Andric return false; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, 4180b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4190b57cec5SDimitry Andric uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", 4220b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], 4230b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 4240b57cec5SDimitry Andric Imm); 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric Offset += 2; 4270b57cec5SDimitry Andric return false; 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, 4310b57cec5SDimitry Andric unsigned Length, bool Prologue) { 43281ad6265SDimitry Andric uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) 4330b57cec5SDimitry Andric | ((OC[Offset + 1] & 0xff) << 0); 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4360b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "push" : "pop"); 43781ad6265SDimitry Andric printGPRMask(GPRMask); 4380b57cec5SDimitry Andric OS << '\n'; 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric Offset += 2; 4410b57cec5SDimitry Andric return false; 4420b57cec5SDimitry Andric } 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, 4450b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4460b57cec5SDimitry Andric assert(!Prologue && "may not be used in prologue"); 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 4490b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 4500b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 4510b57cec5SDimitry Andric else 4520b57cec5SDimitry Andric SW.startLine() 4530b57cec5SDimitry Andric << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", 4540b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric Offset += 2; 4570b57cec5SDimitry Andric return false; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, 4610b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4620b57cec5SDimitry Andric if (OC[Offset + 1] & 0xf0) 4630b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; reserved\n", 4640b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1]); 46581ad6265SDimitry Andric else if (Prologue) 46681ad6265SDimitry Andric SW.startLine() 46781ad6265SDimitry Andric << format("0x%02x 0x%02x ; str.w lr, [sp, #-%u]!\n", 46881ad6265SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); 4690b57cec5SDimitry Andric else 4700b57cec5SDimitry Andric SW.startLine() 4710b57cec5SDimitry Andric << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", 4720b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric Offset += 2; 4750b57cec5SDimitry Andric return false; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, 4790b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4800b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4810b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 48281ad6265SDimitry Andric uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start; 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 4850b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 48681ad6265SDimitry Andric printVFPMask(VFPMask); 4870b57cec5SDimitry Andric OS << '\n'; 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric Offset += 2; 4900b57cec5SDimitry Andric return false; 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, 4940b57cec5SDimitry Andric unsigned Length, bool Prologue) { 4950b57cec5SDimitry Andric unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; 4960b57cec5SDimitry Andric unsigned End = (OC[Offset + 1] & 0x0f) >> 0; 49781ad6265SDimitry Andric uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start); 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], 5000b57cec5SDimitry Andric OC[Offset + 1], Prologue ? "vpush" : "vpop"); 50181ad6265SDimitry Andric printVFPMask(VFPMask); 5020b57cec5SDimitry Andric OS << '\n'; 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric Offset += 2; 5050b57cec5SDimitry Andric return false; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, 5090b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5100b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 5130b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 5140b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 5150b57cec5SDimitry Andric Imm); 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric Offset += 3; 5180b57cec5SDimitry Andric return false; 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, 5220b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5230b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 5240b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 5250b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric SW.startLine() 5280b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", 5290b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 5300b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric Offset += 4; 5330b57cec5SDimitry Andric return false; 5340b57cec5SDimitry Andric } 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, 5370b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5380b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric SW.startLine() 5410b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 5420b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], 5430b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric Offset += 3; 5460b57cec5SDimitry Andric return false; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, 5500b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5510b57cec5SDimitry Andric uint32_t Imm = (OC[Offset + 1] << 16) 5520b57cec5SDimitry Andric | (OC[Offset + 2] << 8) 5530b57cec5SDimitry Andric | (OC[Offset + 3] << 0); 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric SW.startLine() 5560b57cec5SDimitry Andric << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", 5570b57cec5SDimitry Andric OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], 5580b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Imm); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric Offset += 4; 5610b57cec5SDimitry Andric return false; 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, 5650b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5660b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 5670b57cec5SDimitry Andric ++Offset; 5680b57cec5SDimitry Andric return false; 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, 5720b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5730b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); 5740b57cec5SDimitry Andric ++Offset; 5750b57cec5SDimitry Andric return false; 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, 5790b57cec5SDimitry Andric unsigned Length, bool Prologue) { 58081ad6265SDimitry Andric SW.startLine() << format("0x%02x ; bx <reg>\n", OC[Offset]); 5810b57cec5SDimitry Andric ++Offset; 5820b57cec5SDimitry Andric return true; 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, 5860b57cec5SDimitry Andric unsigned Length, bool Prologue) { 58781ad6265SDimitry Andric SW.startLine() << format("0x%02x ; b.w <target>\n", OC[Offset]); 5880b57cec5SDimitry Andric ++Offset; 5890b57cec5SDimitry Andric return true; 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, 5930b57cec5SDimitry Andric unsigned Length, bool Prologue) { 5940b57cec5SDimitry Andric ++Offset; 5950b57cec5SDimitry Andric return true; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric // ARM64 unwind codes start here. 5990b57cec5SDimitry Andric bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset, 6000b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6010b57cec5SDimitry Andric uint32_t NumBytes = (OC[Offset] & 0x1F) << 4; 6020b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; %s sp, #%u\n", OC[Offset], 6030b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 6040b57cec5SDimitry Andric NumBytes); 6050b57cec5SDimitry Andric ++Offset; 6060b57cec5SDimitry Andric return false; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset, 6100b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6110b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x1F) << 3; 6120b57cec5SDimitry Andric if (Prologue) 6130b57cec5SDimitry Andric SW.startLine() << format( 6140b57cec5SDimitry Andric "0x%02x ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off); 6150b57cec5SDimitry Andric else 6160b57cec5SDimitry Andric SW.startLine() << format( 6170b57cec5SDimitry Andric "0x%02x ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off); 6180b57cec5SDimitry Andric ++Offset; 6190b57cec5SDimitry Andric return false; 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset, 6230b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6240b57cec5SDimitry Andric uint32_t Off = (OC[Offset] & 0x3F) << 3; 6250b57cec5SDimitry Andric SW.startLine() << format( 6260b57cec5SDimitry Andric "0x%02x ; %s x29, x30, [sp, #%u]\n", OC[Offset], 6270b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Off); 6280b57cec5SDimitry Andric ++Offset; 6290b57cec5SDimitry Andric return false; 6300b57cec5SDimitry Andric } 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset, 6330b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6340b57cec5SDimitry Andric uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3; 6350b57cec5SDimitry Andric if (Prologue) 6360b57cec5SDimitry Andric SW.startLine() << format( 6370b57cec5SDimitry Andric "0x%02x ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off); 6380b57cec5SDimitry Andric else 6390b57cec5SDimitry Andric SW.startLine() << format( 6400b57cec5SDimitry Andric "0x%02x ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off); 6410b57cec5SDimitry Andric ++Offset; 6420b57cec5SDimitry Andric return false; 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset, 6460b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6470b57cec5SDimitry Andric uint32_t NumBytes = ((OC[Offset] & 0x07) << 8); 6480b57cec5SDimitry Andric NumBytes |= (OC[Offset + 1] & 0xFF); 6490b57cec5SDimitry Andric NumBytes <<= 4; 6500b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s sp, #%u\n", 6510b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6520b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), 6530b57cec5SDimitry Andric NumBytes); 6540b57cec5SDimitry Andric Offset += 2; 6550b57cec5SDimitry Andric return false; 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset, 6590b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6600b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 6610b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6620b57cec5SDimitry Andric Reg >>= 6; 6630b57cec5SDimitry Andric Reg += 19; 6640b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 6650b57cec5SDimitry Andric SW.startLine() << format( 6660b57cec5SDimitry Andric "0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n", 6670b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 6680b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off); 6690b57cec5SDimitry Andric Offset += 2; 6700b57cec5SDimitry Andric return false; 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset, 6740b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6750b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset] & 0x03) << 8); 6760b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6770b57cec5SDimitry Andric Reg >>= 6; 6780b57cec5SDimitry Andric Reg += 19; 6790b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 6800b57cec5SDimitry Andric if (Prologue) 6810b57cec5SDimitry Andric SW.startLine() << format( 6820b57cec5SDimitry Andric "0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n", 6830b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6840b57cec5SDimitry Andric Reg + 1, Off); 6850b57cec5SDimitry Andric else 6860b57cec5SDimitry Andric SW.startLine() << format( 6870b57cec5SDimitry Andric "0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n", 6880b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, 6890b57cec5SDimitry Andric Reg + 1, Off); 6900b57cec5SDimitry Andric Offset += 2; 6910b57cec5SDimitry Andric return false; 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset, 6950b57cec5SDimitry Andric unsigned Length, bool Prologue) { 6960b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x03) << 8; 6970b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 6980b57cec5SDimitry Andric Reg >>= 6; 6990b57cec5SDimitry Andric Reg += 19; 7000b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7010b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, [sp, #%u]\n", 7020b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7030b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 7040b57cec5SDimitry Andric Reg, Off); 7050b57cec5SDimitry Andric Offset += 2; 7060b57cec5SDimitry Andric return false; 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset, 7100b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7110b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7120b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xE0); 7130b57cec5SDimitry Andric Reg >>= 5; 7140b57cec5SDimitry Andric Reg += 19; 7150b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 7160b57cec5SDimitry Andric if (Prologue) 717e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #-%u]!\n", 7180b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 7190b57cec5SDimitry Andric else 7200b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n", 7210b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], Reg, Off); 7220b57cec5SDimitry Andric Offset += 2; 7230b57cec5SDimitry Andric return false; 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset, 7270b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7280b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7290b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7300b57cec5SDimitry Andric Reg >>= 6; 7310b57cec5SDimitry Andric Reg *= 2; 7320b57cec5SDimitry Andric Reg += 19; 7330b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7340b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s x%u, lr, [sp, #%u]\n", 7350b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7360b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 7370b57cec5SDimitry Andric Reg, Off); 7380b57cec5SDimitry Andric Offset += 2; 7390b57cec5SDimitry Andric return false; 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset, 7430b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7440b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7450b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7460b57cec5SDimitry Andric Reg >>= 6; 7470b57cec5SDimitry Andric Reg += 8; 7480b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7490b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n", 7500b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7510b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "stp" : "ldp"), 7520b57cec5SDimitry Andric Reg, Reg + 1, Off); 7530b57cec5SDimitry Andric Offset += 2; 7540b57cec5SDimitry Andric return false; 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset, 7580b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7590b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7600b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7610b57cec5SDimitry Andric Reg >>= 6; 7620b57cec5SDimitry Andric Reg += 8; 7630b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3; 7640b57cec5SDimitry Andric if (Prologue) 7650b57cec5SDimitry Andric SW.startLine() << format( 7660b57cec5SDimitry Andric "0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset], 7670b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 7680b57cec5SDimitry Andric else 7690b57cec5SDimitry Andric SW.startLine() << format( 7700b57cec5SDimitry Andric "0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n", OC[Offset], 7710b57cec5SDimitry Andric OC[Offset + 1], Reg, Reg + 1, Off); 7720b57cec5SDimitry Andric Offset += 2; 7730b57cec5SDimitry Andric return false; 7740b57cec5SDimitry Andric } 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset, 7770b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7780b57cec5SDimitry Andric uint32_t Reg = (OC[Offset] & 0x01) << 8; 7790b57cec5SDimitry Andric Reg |= (OC[Offset + 1] & 0xC0); 7800b57cec5SDimitry Andric Reg >>= 6; 7810b57cec5SDimitry Andric Reg += 8; 7820b57cec5SDimitry Andric uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; 7830b57cec5SDimitry Andric SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n", 7840b57cec5SDimitry Andric OC[Offset], OC[Offset + 1], 7850b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "str" : "ldr"), 7860b57cec5SDimitry Andric Reg, Off); 7870b57cec5SDimitry Andric Offset += 2; 7880b57cec5SDimitry Andric return false; 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset, 7920b57cec5SDimitry Andric unsigned Length, bool Prologue) { 7930b57cec5SDimitry Andric uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8; 7940b57cec5SDimitry Andric uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; 7950b57cec5SDimitry Andric if (Prologue) 7960b57cec5SDimitry Andric SW.startLine() << format( 7970b57cec5SDimitry Andric "0x%02x%02x ; str d%u, [sp, #-%u]!\n", OC[Offset], 7980b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 7990b57cec5SDimitry Andric else 8000b57cec5SDimitry Andric SW.startLine() << format( 8010b57cec5SDimitry Andric "0x%02x%02x ; ldr d%u, [sp], #%u\n", OC[Offset], 8020b57cec5SDimitry Andric OC[Offset + 1], Reg, Off); 8030b57cec5SDimitry Andric Offset += 2; 8040b57cec5SDimitry Andric return false; 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset, 8080b57cec5SDimitry Andric unsigned Length, bool Prologue) { 8090b57cec5SDimitry Andric unsigned Off = 8100b57cec5SDimitry Andric (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0); 8110b57cec5SDimitry Andric Off <<= 4; 8120b57cec5SDimitry Andric SW.startLine() << format( 8130b57cec5SDimitry Andric "0x%02x%02x%02x%02x ; %s sp, #%u\n", OC[Offset], OC[Offset + 1], 8140b57cec5SDimitry Andric OC[Offset + 2], OC[Offset + 3], 8150b57cec5SDimitry Andric static_cast<const char *>(Prologue ? "sub" : "add"), Off); 8160b57cec5SDimitry Andric Offset += 4; 8170b57cec5SDimitry Andric return false; 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 8210b57cec5SDimitry Andric bool Prologue) { 822e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; mov %s, %s\n", OC[Offset], 823e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "fp" : "sp"), 824e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "sp" : "fp")); 8250b57cec5SDimitry Andric ++Offset; 8260b57cec5SDimitry Andric return false; 8270b57cec5SDimitry Andric } 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length, 8300b57cec5SDimitry Andric bool Prologue) { 8310b57cec5SDimitry Andric unsigned NumBytes = OC[Offset + 1] << 3; 832e8d8bef9SDimitry Andric SW.startLine() << format( 833e8d8bef9SDimitry Andric "0x%02x%02x ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1], 834e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "add" : "sub"), 835e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "fp" : "sp"), 836e8d8bef9SDimitry Andric static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes); 8370b57cec5SDimitry Andric Offset += 2; 8380b57cec5SDimitry Andric return false; 8390b57cec5SDimitry Andric } 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length, 8420b57cec5SDimitry Andric bool Prologue) { 8430b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); 8440b57cec5SDimitry Andric ++Offset; 8450b57cec5SDimitry Andric return false; 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric 8480b57cec5SDimitry Andric bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length, 8490b57cec5SDimitry Andric bool Prologue) { 8500b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end\n", OC[Offset]); 8510b57cec5SDimitry Andric ++Offset; 8520b57cec5SDimitry Andric return true; 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length, 8560b57cec5SDimitry Andric bool Prologue) { 8570b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]); 8580b57cec5SDimitry Andric ++Offset; 859*bdd1243dSDimitry Andric return false; 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric 862e8d8bef9SDimitry Andric bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset, 863e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 864e8d8bef9SDimitry Andric if (Prologue) 865e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; save next\n", OC[Offset]); 866e8d8bef9SDimitry Andric else 867e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; restore next\n", 868e8d8bef9SDimitry Andric OC[Offset]); 869e8d8bef9SDimitry Andric ++Offset; 870e8d8bef9SDimitry Andric return false; 871e8d8bef9SDimitry Andric } 872e8d8bef9SDimitry Andric 873*bdd1243dSDimitry Andric bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset, 874*bdd1243dSDimitry Andric unsigned Length, bool Prologue) { 875*bdd1243dSDimitry Andric // Whether the instruction has writeback 876*bdd1243dSDimitry Andric bool Writeback = (OC[Offset + 1] & 0x20) == 0x20; 877*bdd1243dSDimitry Andric // Whether the instruction is paired. (Paired instructions are required 878*bdd1243dSDimitry Andric // to save/restore adjacent registers.) 879*bdd1243dSDimitry Andric bool Paired = (OC[Offset + 1] & 0x40) == 0x40; 880*bdd1243dSDimitry Andric // The kind of register saved: 881*bdd1243dSDimitry Andric // - 0 is an x register 882*bdd1243dSDimitry Andric // - 1 is the low half of a q register 883*bdd1243dSDimitry Andric // - 2 is a whole q register 884*bdd1243dSDimitry Andric int RegKind = (OC[Offset + 2] & 0xC0) >> 6; 885*bdd1243dSDimitry Andric // Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.) 886*bdd1243dSDimitry Andric int Reg = OC[Offset + 1] & 0x1F; 887*bdd1243dSDimitry Andric // Encoded stack offset of load/store instruction; decoding varies by mode. 888*bdd1243dSDimitry Andric int StackOffset = OC[Offset + 2] & 0x3F; 889*bdd1243dSDimitry Andric if (Writeback) 890*bdd1243dSDimitry Andric StackOffset++; 891*bdd1243dSDimitry Andric if (!Writeback && !Paired && RegKind != 2) 892*bdd1243dSDimitry Andric StackOffset *= 8; 893*bdd1243dSDimitry Andric else 894*bdd1243dSDimitry Andric StackOffset *= 16; 895*bdd1243dSDimitry Andric 896*bdd1243dSDimitry Andric SW.startLine() << format("0x%02x%02x%02x ; ", OC[Offset], 897*bdd1243dSDimitry Andric OC[Offset + 1], OC[Offset + 2]); 898*bdd1243dSDimitry Andric 899*bdd1243dSDimitry Andric // Verify the encoding is in a form we understand. The high bit of the first 900*bdd1243dSDimitry Andric // byte, and mode 3 for the register kind are apparently reserved. The 901*bdd1243dSDimitry Andric // encoded register must refer to a valid register. 902*bdd1243dSDimitry Andric int MaxReg = 0x1F; 903*bdd1243dSDimitry Andric if (Paired) 904*bdd1243dSDimitry Andric --MaxReg; 905*bdd1243dSDimitry Andric if (RegKind == 0) 906*bdd1243dSDimitry Andric --MaxReg; 907*bdd1243dSDimitry Andric if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) { 908*bdd1243dSDimitry Andric SW.getOStream() << "invalid save_any_reg encoding\n"; 909*bdd1243dSDimitry Andric Offset += 3; 910*bdd1243dSDimitry Andric return false; 911*bdd1243dSDimitry Andric } 912*bdd1243dSDimitry Andric 913*bdd1243dSDimitry Andric if (Paired) { 914*bdd1243dSDimitry Andric if (Prologue) 915*bdd1243dSDimitry Andric SW.getOStream() << "stp "; 916*bdd1243dSDimitry Andric else 917*bdd1243dSDimitry Andric SW.getOStream() << "ldp "; 918*bdd1243dSDimitry Andric } else { 919*bdd1243dSDimitry Andric if (Prologue) 920*bdd1243dSDimitry Andric SW.getOStream() << "str "; 921*bdd1243dSDimitry Andric else 922*bdd1243dSDimitry Andric SW.getOStream() << "ldr "; 923*bdd1243dSDimitry Andric } 924*bdd1243dSDimitry Andric 925*bdd1243dSDimitry Andric char RegChar = 'x'; 926*bdd1243dSDimitry Andric if (RegKind == 1) { 927*bdd1243dSDimitry Andric RegChar = 'd'; 928*bdd1243dSDimitry Andric } else if (RegKind == 2) { 929*bdd1243dSDimitry Andric RegChar = 'q'; 930*bdd1243dSDimitry Andric } 931*bdd1243dSDimitry Andric 932*bdd1243dSDimitry Andric if (Paired) 933*bdd1243dSDimitry Andric SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1); 934*bdd1243dSDimitry Andric else 935*bdd1243dSDimitry Andric SW.getOStream() << format("%c%d, ", RegChar, Reg); 936*bdd1243dSDimitry Andric 937*bdd1243dSDimitry Andric if (Writeback) { 938*bdd1243dSDimitry Andric if (Prologue) 939*bdd1243dSDimitry Andric SW.getOStream() << format("[sp, #-%d]!\n", StackOffset); 940*bdd1243dSDimitry Andric else 941*bdd1243dSDimitry Andric SW.getOStream() << format("[sp], #%d\n", StackOffset); 942*bdd1243dSDimitry Andric } else { 943*bdd1243dSDimitry Andric SW.getOStream() << format("[sp, #%d]\n", StackOffset); 944*bdd1243dSDimitry Andric } 945*bdd1243dSDimitry Andric 946*bdd1243dSDimitry Andric Offset += 3; 947*bdd1243dSDimitry Andric return false; 948*bdd1243dSDimitry Andric } 949*bdd1243dSDimitry Andric 950e8d8bef9SDimitry Andric bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset, 951e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 952e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]); 953e8d8bef9SDimitry Andric ++Offset; 954e8d8bef9SDimitry Andric return false; 955e8d8bef9SDimitry Andric } 956e8d8bef9SDimitry Andric 957e8d8bef9SDimitry Andric bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset, 958e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 959e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; machine frame\n", 960e8d8bef9SDimitry Andric OC[Offset]); 961e8d8bef9SDimitry Andric ++Offset; 962e8d8bef9SDimitry Andric return false; 963e8d8bef9SDimitry Andric } 964e8d8bef9SDimitry Andric 965e8d8bef9SDimitry Andric bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset, 966e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 967e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; context\n", OC[Offset]); 968e8d8bef9SDimitry Andric ++Offset; 969e8d8bef9SDimitry Andric return false; 970e8d8bef9SDimitry Andric } 971e8d8bef9SDimitry Andric 972e8d8bef9SDimitry Andric bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset, 973e8d8bef9SDimitry Andric unsigned Length, bool Prologue) { 974e8d8bef9SDimitry Andric SW.startLine() << format("0x%02x ; clear unwound to call\n", 975e8d8bef9SDimitry Andric OC[Offset]); 976e8d8bef9SDimitry Andric ++Offset; 977e8d8bef9SDimitry Andric return false; 978e8d8bef9SDimitry Andric } 979e8d8bef9SDimitry Andric 980*bdd1243dSDimitry Andric bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset, 981*bdd1243dSDimitry Andric unsigned Length, bool Prologue) { 982*bdd1243dSDimitry Andric if (Prologue) 983*bdd1243dSDimitry Andric SW.startLine() << format("0x%02x ; pacibsp\n", OC[Offset]); 984*bdd1243dSDimitry Andric else 985*bdd1243dSDimitry Andric SW.startLine() << format("0x%02x ; autibsp\n", OC[Offset]); 986*bdd1243dSDimitry Andric ++Offset; 987*bdd1243dSDimitry Andric return false; 988*bdd1243dSDimitry Andric } 989*bdd1243dSDimitry Andric 9900b57cec5SDimitry Andric void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, 9910b57cec5SDimitry Andric bool Prologue) { 9920b57cec5SDimitry Andric assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); 9930b57cec5SDimitry Andric const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring; 9940b57cec5SDimitry Andric bool Terminated = false; 9950b57cec5SDimitry Andric for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { 9960b57cec5SDimitry Andric for (unsigned DI = 0;; ++DI) { 997*bdd1243dSDimitry Andric if ((isAArch64 && (DI >= std::size(Ring64))) || 998*bdd1243dSDimitry Andric (!isAArch64 && (DI >= std::size(Ring)))) { 9990b57cec5SDimitry Andric SW.startLine() << format("0x%02x ; Bad opcode!\n", 10000b57cec5SDimitry Andric Opcodes.data()[OI]); 10010b57cec5SDimitry Andric ++OI; 10020b57cec5SDimitry Andric break; 10030b57cec5SDimitry Andric } 10040b57cec5SDimitry Andric 10050b57cec5SDimitry Andric if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) { 10060b57cec5SDimitry Andric if (OI + DecodeRing[DI].Length > OE) { 10070b57cec5SDimitry Andric SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n", 10080b57cec5SDimitry Andric Opcodes[OI]); 10090b57cec5SDimitry Andric OI += DecodeRing[DI].Length; 10100b57cec5SDimitry Andric break; 10110b57cec5SDimitry Andric } 10120b57cec5SDimitry Andric Terminated = 10130b57cec5SDimitry Andric (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue); 10140b57cec5SDimitry Andric break; 10150b57cec5SDimitry Andric } 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric } 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, 10210b57cec5SDimitry Andric const SectionRef &Section, 10220b57cec5SDimitry Andric uint64_t FunctionAddress, uint64_t VA) { 10230b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 10240b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 10250b57cec5SDimitry Andric return false; 10260b57cec5SDimitry Andric 10270b57cec5SDimitry Andric uint64_t SectionVA = Section.getAddress(); 10280b57cec5SDimitry Andric uint64_t Offset = VA - SectionVA; 10290b57cec5SDimitry Andric const ulittle32_t *Data = 10300b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric // Sanity check to ensure that the .xdata header is present. 10330b57cec5SDimitry Andric // A header is one or two words, followed by at least one word to describe 10340b57cec5SDimitry Andric // the unwind codes. Applicable to both ARM and AArch64. 10350b57cec5SDimitry Andric if (Contents.size() - Offset < 8) 10360b57cec5SDimitry Andric report_fatal_error(".xdata must be at least 8 bytes in size"); 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric const ExceptionDataRecord XData(Data, isAArch64); 10390b57cec5SDimitry Andric DictScope XRS(SW, "ExceptionData"); 10400b57cec5SDimitry Andric SW.printNumber("FunctionLength", 10410b57cec5SDimitry Andric isAArch64 ? XData.FunctionLengthInBytesAArch64() : 10420b57cec5SDimitry Andric XData.FunctionLengthInBytesARM()); 10430b57cec5SDimitry Andric SW.printNumber("Version", XData.Vers()); 10440b57cec5SDimitry Andric SW.printBoolean("ExceptionData", XData.X()); 10450b57cec5SDimitry Andric SW.printBoolean("EpiloguePacked", XData.E()); 10460b57cec5SDimitry Andric if (!isAArch64) 10470b57cec5SDimitry Andric SW.printBoolean("Fragment", XData.F()); 10480b57cec5SDimitry Andric SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", 10490b57cec5SDimitry Andric XData.EpilogueCount()); 10500b57cec5SDimitry Andric uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t); 10510b57cec5SDimitry Andric SW.printNumber("ByteCodeLength", ByteCodeLength); 10520b57cec5SDimitry Andric 10530b57cec5SDimitry Andric if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) - 10540b57cec5SDimitry Andric (XData.E() ? 0 : XData.EpilogueCount() * 4) - 10558bcb0991SDimitry Andric (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { 10568bcb0991SDimitry Andric SW.flush(); 10570b57cec5SDimitry Andric report_fatal_error("Malformed unwind data"); 10588bcb0991SDimitry Andric } 10590b57cec5SDimitry Andric 10600b57cec5SDimitry Andric if (XData.E()) { 10610b57cec5SDimitry Andric ArrayRef<uint8_t> UC = XData.UnwindByteCode(); 106281ad6265SDimitry Andric { 10630b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 10640b57cec5SDimitry Andric decodeOpcodes(UC, 0, /*Prologue=*/true); 10650b57cec5SDimitry Andric } 10660b57cec5SDimitry Andric if (XData.EpilogueCount()) { 10670b57cec5SDimitry Andric ListScope ES(SW, "Epilogue"); 10680b57cec5SDimitry Andric decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric } else { 10710b57cec5SDimitry Andric { 10720b57cec5SDimitry Andric ListScope PS(SW, "Prologue"); 10730b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true); 10740b57cec5SDimitry Andric } 10750b57cec5SDimitry Andric ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); 10760b57cec5SDimitry Andric ListScope ESS(SW, "EpilogueScopes"); 10770b57cec5SDimitry Andric for (const EpilogueScope ES : EpilogueScopes) { 10780b57cec5SDimitry Andric DictScope ESES(SW, "EpilogueScope"); 10790b57cec5SDimitry Andric SW.printNumber("StartOffset", ES.EpilogueStartOffset()); 10800b57cec5SDimitry Andric if (!isAArch64) 10810b57cec5SDimitry Andric SW.printNumber("Condition", ES.Condition()); 10820b57cec5SDimitry Andric SW.printNumber("EpilogueStartIndex", 10830b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 10840b57cec5SDimitry Andric : ES.EpilogueStartIndexARM()); 108581ad6265SDimitry Andric unsigned ReservedMask = isAArch64 ? 0xF : 0x3; 108681ad6265SDimitry Andric if ((ES.ES >> 18) & ReservedMask) 108781ad6265SDimitry Andric SW.printNumber("ReservedBits", (ES.ES >> 18) & ReservedMask); 10880b57cec5SDimitry Andric 10890b57cec5SDimitry Andric ListScope Opcodes(SW, "Opcodes"); 10900b57cec5SDimitry Andric decodeOpcodes(XData.UnwindByteCode(), 10910b57cec5SDimitry Andric isAArch64 ? ES.EpilogueStartIndexAArch64() 10920b57cec5SDimitry Andric : ES.EpilogueStartIndexARM(), 10930b57cec5SDimitry Andric /*Prologue=*/false); 10940b57cec5SDimitry Andric } 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10970b57cec5SDimitry Andric if (XData.X()) { 10980b57cec5SDimitry Andric const uint32_t Parameter = XData.ExceptionHandlerParameter(); 1099fe6060f1SDimitry Andric const size_t HandlerOffset = HeaderWords(XData) + 1100fe6060f1SDimitry Andric (XData.E() ? 0 : XData.EpilogueCount()) + 1101fe6060f1SDimitry Andric XData.CodeWords(); 11020b57cec5SDimitry Andric 1103fe6060f1SDimitry Andric uint64_t Address, SymbolOffset; 1104fe6060f1SDimitry Andric ErrorOr<SymbolRef> Symbol = getSymbolForLocation( 1105fe6060f1SDimitry Andric COFF, Section, Offset + HandlerOffset * sizeof(uint32_t), 1106fe6060f1SDimitry Andric XData.ExceptionHandlerRVA(), Address, SymbolOffset, 1107fe6060f1SDimitry Andric /*FunctionOnly=*/true); 11080b57cec5SDimitry Andric if (!Symbol) { 11090b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 1110480093f4SDimitry Andric SW.printHex("Routine", Address); 1111480093f4SDimitry Andric SW.printHex("Parameter", Parameter); 11120b57cec5SDimitry Andric return true; 11130b57cec5SDimitry Andric } 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric Expected<StringRef> Name = Symbol->getName(); 11160b57cec5SDimitry Andric if (!Name) { 11170b57cec5SDimitry Andric std::string Buf; 11180b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11190b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 1120349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11210b57cec5SDimitry Andric } 11220b57cec5SDimitry Andric 11230b57cec5SDimitry Andric ListScope EHS(SW, "ExceptionHandler"); 1124fe6060f1SDimitry Andric SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset)); 11250b57cec5SDimitry Andric SW.printHex("Parameter", Parameter); 11260b57cec5SDimitry Andric } 11270b57cec5SDimitry Andric 11280b57cec5SDimitry Andric return true; 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, 11320b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 11330b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 11340b57cec5SDimitry Andric assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && 11350b57cec5SDimitry Andric "packed entry cannot be treated as an unpacked entry"); 11360b57cec5SDimitry Andric 1137fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1138fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1139fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1140480093f4SDimitry Andric /*FunctionOnly=*/true); 11410b57cec5SDimitry Andric 1142fe6060f1SDimitry Andric uint64_t XDataAddress, XDataOffset; 1143fe6060f1SDimitry Andric ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation( 1144fe6060f1SDimitry Andric COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress, 1145fe6060f1SDimitry Andric XDataOffset); 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric if (!RF.BeginAddress && !Function) 11480b57cec5SDimitry Andric return false; 11490b57cec5SDimitry Andric if (!RF.UnwindData && !XDataRecord) 11500b57cec5SDimitry Andric return false; 11510b57cec5SDimitry Andric 11520b57cec5SDimitry Andric StringRef FunctionName; 11530b57cec5SDimitry Andric if (Function) { 11540b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 11550b57cec5SDimitry Andric if (!FunctionNameOrErr) { 11560b57cec5SDimitry Andric std::string Buf; 11570b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11580b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1159349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 11620b57cec5SDimitry Andric } 11630b57cec5SDimitry Andric 1164fe6060f1SDimitry Andric SW.printString("Function", 1165fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric if (XDataRecord) { 11680b57cec5SDimitry Andric Expected<StringRef> Name = XDataRecord->getName(); 11690b57cec5SDimitry Andric if (!Name) { 11700b57cec5SDimitry Andric std::string Buf; 11710b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 11720b57cec5SDimitry Andric logAllUnhandledErrors(Name.takeError(), OS); 1173349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 11740b57cec5SDimitry Andric } 11750b57cec5SDimitry Andric 1176fe6060f1SDimitry Andric SW.printString("ExceptionRecord", 1177fe6060f1SDimitry Andric formatSymbol(*Name, XDataAddress, XDataOffset)); 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric Expected<section_iterator> SIOrErr = XDataRecord->getSection(); 11800b57cec5SDimitry Andric if (!SIOrErr) { 11810b57cec5SDimitry Andric // TODO: Actually report errors helpfully. 11820b57cec5SDimitry Andric consumeError(SIOrErr.takeError()); 11830b57cec5SDimitry Andric return false; 11840b57cec5SDimitry Andric } 11850b57cec5SDimitry Andric section_iterator SI = *SIOrErr; 11860b57cec5SDimitry Andric 1187fe6060f1SDimitry Andric return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress); 11880b57cec5SDimitry Andric } else { 1189fe6060f1SDimitry Andric SW.printString("ExceptionRecord", formatSymbol("", XDataAddress)); 11900b57cec5SDimitry Andric 1191fe6060f1SDimitry Andric ErrorOr<SectionRef> Section = getSectionContaining(COFF, XDataAddress); 11920b57cec5SDimitry Andric if (!Section) 11930b57cec5SDimitry Andric return false; 11940b57cec5SDimitry Andric 1195fe6060f1SDimitry Andric return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress); 11960b57cec5SDimitry Andric } 11970b57cec5SDimitry Andric } 11980b57cec5SDimitry Andric 11990b57cec5SDimitry Andric bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, 12000b57cec5SDimitry Andric const SectionRef Section, uint64_t Offset, 12010b57cec5SDimitry Andric unsigned Index, const RuntimeFunction &RF) { 12020b57cec5SDimitry Andric assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || 12030b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && 12040b57cec5SDimitry Andric "unpacked entry cannot be treated as a packed entry"); 12050b57cec5SDimitry Andric 1206fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1207fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1208fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1209fe6060f1SDimitry Andric /*FunctionOnly=*/true); 12100b57cec5SDimitry Andric 12110b57cec5SDimitry Andric StringRef FunctionName; 12120b57cec5SDimitry Andric if (Function) { 12130b57cec5SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 12140b57cec5SDimitry Andric if (!FunctionNameOrErr) { 12150b57cec5SDimitry Andric std::string Buf; 12160b57cec5SDimitry Andric llvm::raw_string_ostream OS(Buf); 12170b57cec5SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1218349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 12190b57cec5SDimitry Andric } 12200b57cec5SDimitry Andric FunctionName = *FunctionNameOrErr; 12210b57cec5SDimitry Andric } 12220b57cec5SDimitry Andric 1223fe6060f1SDimitry Andric SW.printString("Function", 1224fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 12250b57cec5SDimitry Andric SW.printBoolean("Fragment", 12260b57cec5SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); 12270b57cec5SDimitry Andric SW.printNumber("FunctionLength", RF.FunctionLength()); 12280b57cec5SDimitry Andric SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; 12290b57cec5SDimitry Andric SW.printBoolean("HomedParameters", RF.H()); 123081ad6265SDimitry Andric SW.printNumber("Reg", RF.Reg()); 123181ad6265SDimitry Andric SW.printNumber("R", RF.R()); 123281ad6265SDimitry Andric SW.printBoolean("LinkRegister", RF.L()); 123381ad6265SDimitry Andric SW.printBoolean("Chaining", RF.C()); 12340b57cec5SDimitry Andric SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); 12350b57cec5SDimitry Andric 123681ad6265SDimitry Andric { 123781ad6265SDimitry Andric ListScope PS(SW, "Prologue"); 123881ad6265SDimitry Andric 123981ad6265SDimitry Andric uint16_t GPRMask, VFPMask; 124081ad6265SDimitry Andric std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true); 124181ad6265SDimitry Andric 124281ad6265SDimitry Andric if (StackAdjustment(RF) && !PrologueFolding(RF)) 124381ad6265SDimitry Andric SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; 124481ad6265SDimitry Andric if (VFPMask) { 124581ad6265SDimitry Andric SW.startLine() << "vpush "; 124681ad6265SDimitry Andric printVFPMask(VFPMask); 124781ad6265SDimitry Andric OS << "\n"; 124881ad6265SDimitry Andric } 124981ad6265SDimitry Andric if (RF.C()) { 125081ad6265SDimitry Andric // Count the number of registers pushed below R11 1251*bdd1243dSDimitry Andric int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1)); 125281ad6265SDimitry Andric if (FpOffset) 125381ad6265SDimitry Andric SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n"; 125481ad6265SDimitry Andric else 125581ad6265SDimitry Andric SW.startLine() << "mov r11, sp\n"; 125681ad6265SDimitry Andric } 125781ad6265SDimitry Andric if (GPRMask) { 125881ad6265SDimitry Andric SW.startLine() << "push "; 125981ad6265SDimitry Andric printGPRMask(GPRMask); 126081ad6265SDimitry Andric OS << "\n"; 126181ad6265SDimitry Andric } 126281ad6265SDimitry Andric if (RF.H()) 126381ad6265SDimitry Andric SW.startLine() << "push {r0-r3}\n"; 126481ad6265SDimitry Andric } 126581ad6265SDimitry Andric 126681ad6265SDimitry Andric if (RF.Ret() != ReturnType::RT_NoEpilogue) { 126781ad6265SDimitry Andric ListScope PS(SW, "Epilogue"); 126881ad6265SDimitry Andric 126981ad6265SDimitry Andric uint16_t GPRMask, VFPMask; 127081ad6265SDimitry Andric std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false); 127181ad6265SDimitry Andric 127281ad6265SDimitry Andric if (StackAdjustment(RF) && !EpilogueFolding(RF)) 127381ad6265SDimitry Andric SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; 127481ad6265SDimitry Andric if (VFPMask) { 127581ad6265SDimitry Andric SW.startLine() << "vpop "; 127681ad6265SDimitry Andric printVFPMask(VFPMask); 127781ad6265SDimitry Andric OS << "\n"; 127881ad6265SDimitry Andric } 127981ad6265SDimitry Andric if (GPRMask) { 128081ad6265SDimitry Andric SW.startLine() << "pop "; 128181ad6265SDimitry Andric printGPRMask(GPRMask); 128281ad6265SDimitry Andric OS << "\n"; 128381ad6265SDimitry Andric } 128481ad6265SDimitry Andric if (RF.H()) { 128581ad6265SDimitry Andric if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP) 128681ad6265SDimitry Andric SW.startLine() << "add sp, sp, #16\n"; 128781ad6265SDimitry Andric else 128881ad6265SDimitry Andric SW.startLine() << "ldr pc, [sp], #20\n"; 128981ad6265SDimitry Andric } 129081ad6265SDimitry Andric if (RF.Ret() != ReturnType::RT_POP) 129181ad6265SDimitry Andric SW.startLine() << RF.Ret() << '\n'; 129281ad6265SDimitry Andric } 129381ad6265SDimitry Andric 12940b57cec5SDimitry Andric return true; 12950b57cec5SDimitry Andric } 12960b57cec5SDimitry Andric 1297e8d8bef9SDimitry Andric bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF, 1298e8d8bef9SDimitry Andric const SectionRef Section, uint64_t Offset, 1299e8d8bef9SDimitry Andric unsigned Index, 1300e8d8bef9SDimitry Andric const RuntimeFunctionARM64 &RF) { 1301e8d8bef9SDimitry Andric assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || 1302e8d8bef9SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && 1303e8d8bef9SDimitry Andric "unpacked entry cannot be treated as a packed entry"); 1304e8d8bef9SDimitry Andric 1305fe6060f1SDimitry Andric uint64_t FunctionAddress, FunctionOffset; 1306fe6060f1SDimitry Andric ErrorOr<SymbolRef> Function = getSymbolForLocation( 1307fe6060f1SDimitry Andric COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset, 1308fe6060f1SDimitry Andric /*FunctionOnly=*/true); 1309e8d8bef9SDimitry Andric 1310e8d8bef9SDimitry Andric StringRef FunctionName; 1311e8d8bef9SDimitry Andric if (Function) { 1312e8d8bef9SDimitry Andric Expected<StringRef> FunctionNameOrErr = Function->getName(); 1313e8d8bef9SDimitry Andric if (!FunctionNameOrErr) { 1314e8d8bef9SDimitry Andric std::string Buf; 1315e8d8bef9SDimitry Andric llvm::raw_string_ostream OS(Buf); 1316e8d8bef9SDimitry Andric logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); 1317349cc55cSDimitry Andric report_fatal_error(Twine(OS.str())); 1318e8d8bef9SDimitry Andric } 1319e8d8bef9SDimitry Andric FunctionName = *FunctionNameOrErr; 1320e8d8bef9SDimitry Andric } 1321e8d8bef9SDimitry Andric 1322fe6060f1SDimitry Andric SW.printString("Function", 1323fe6060f1SDimitry Andric formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); 1324e8d8bef9SDimitry Andric SW.printBoolean("Fragment", 1325e8d8bef9SDimitry Andric RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); 1326e8d8bef9SDimitry Andric SW.printNumber("FunctionLength", RF.FunctionLength()); 1327e8d8bef9SDimitry Andric SW.printNumber("RegF", RF.RegF()); 1328e8d8bef9SDimitry Andric SW.printNumber("RegI", RF.RegI()); 1329e8d8bef9SDimitry Andric SW.printBoolean("HomedParameters", RF.H()); 1330e8d8bef9SDimitry Andric SW.printNumber("CR", RF.CR()); 1331e8d8bef9SDimitry Andric SW.printNumber("FrameSize", RF.FrameSize() << 4); 1332e8d8bef9SDimitry Andric ListScope PS(SW, "Prologue"); 1333e8d8bef9SDimitry Andric 1334e8d8bef9SDimitry Andric // Synthesize the equivalent prologue according to the documentation 1335e8d8bef9SDimitry Andric // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling, 1336e8d8bef9SDimitry Andric // printed in reverse order compared to the docs, to match how prologues 1337e8d8bef9SDimitry Andric // are printed for the non-packed case. 1338e8d8bef9SDimitry Andric int IntSZ = 8 * RF.RegI(); 1339e8d8bef9SDimitry Andric if (RF.CR() == 1) 1340e8d8bef9SDimitry Andric IntSZ += 8; 1341e8d8bef9SDimitry Andric int FpSZ = 8 * RF.RegF(); 1342e8d8bef9SDimitry Andric if (RF.RegF()) 1343e8d8bef9SDimitry Andric FpSZ += 8; 1344e8d8bef9SDimitry Andric int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf; 1345e8d8bef9SDimitry Andric int LocSZ = (RF.FrameSize() << 4) - SavSZ; 1346e8d8bef9SDimitry Andric 1347*bdd1243dSDimitry Andric if (RF.CR() == 2 || RF.CR() == 3) { 1348e8d8bef9SDimitry Andric SW.startLine() << "mov x29, sp\n"; 1349e8d8bef9SDimitry Andric if (LocSZ <= 512) { 1350e8d8bef9SDimitry Andric SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ); 1351e8d8bef9SDimitry Andric } else { 1352e8d8bef9SDimitry Andric SW.startLine() << "stp x29, lr, [sp, #0]\n"; 1353e8d8bef9SDimitry Andric } 1354e8d8bef9SDimitry Andric } 1355e8d8bef9SDimitry Andric if (LocSZ > 4080) { 1356e8d8bef9SDimitry Andric SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080); 1357e8d8bef9SDimitry Andric SW.startLine() << "sub sp, sp, #4080\n"; 1358*bdd1243dSDimitry Andric } else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) { 1359e8d8bef9SDimitry Andric SW.startLine() << format("sub sp, sp, #%d\n", LocSZ); 1360e8d8bef9SDimitry Andric } 1361e8d8bef9SDimitry Andric if (RF.H()) { 136281ad6265SDimitry Andric SW.startLine() << format("stp x6, x7, [sp, #%d]\n", SavSZ - 16); 136381ad6265SDimitry Andric SW.startLine() << format("stp x4, x5, [sp, #%d]\n", SavSZ - 32); 136481ad6265SDimitry Andric SW.startLine() << format("stp x2, x3, [sp, #%d]\n", SavSZ - 48); 1365e8d8bef9SDimitry Andric if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) { 136681ad6265SDimitry Andric SW.startLine() << format("stp x0, x1, [sp, #%d]\n", SavSZ - 64); 1367e8d8bef9SDimitry Andric } else { 1368e8d8bef9SDimitry Andric // This case isn't documented; if neither RegI nor RegF nor CR=1 1369e8d8bef9SDimitry Andric // have decremented the stack pointer by SavSZ, we need to do it here 1370e8d8bef9SDimitry Andric // (as the final stack adjustment of LocSZ excludes SavSZ). 1371e8d8bef9SDimitry Andric SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ); 1372e8d8bef9SDimitry Andric } 1373e8d8bef9SDimitry Andric } 1374e8d8bef9SDimitry Andric int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0; 1375e8d8bef9SDimitry Andric for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) { 1376e8d8bef9SDimitry Andric if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) { 1377e8d8bef9SDimitry Andric // The last register, an odd register without a pair 1378e8d8bef9SDimitry Andric SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I, 1379e8d8bef9SDimitry Andric IntSZ + 16 * I); 1380e8d8bef9SDimitry Andric } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) { 1381e8d8bef9SDimitry Andric SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I, 1382e8d8bef9SDimitry Andric 8 + 2 * I + 1, SavSZ); 1383e8d8bef9SDimitry Andric } else { 1384e8d8bef9SDimitry Andric SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I, 1385e8d8bef9SDimitry Andric 8 + 2 * I + 1, IntSZ + 16 * I); 1386e8d8bef9SDimitry Andric } 1387e8d8bef9SDimitry Andric } 1388e8d8bef9SDimitry Andric if (RF.CR() == 1 && (RF.RegI() % 2) == 0) { 1389e8d8bef9SDimitry Andric if (RF.RegI() == 0) 1390e8d8bef9SDimitry Andric SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ); 1391e8d8bef9SDimitry Andric else 1392e8d8bef9SDimitry Andric SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8); 1393e8d8bef9SDimitry Andric } 1394e8d8bef9SDimitry Andric for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) { 1395e8d8bef9SDimitry Andric if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) { 1396e8d8bef9SDimitry Andric // The last register, an odd register without a pair 1397e8d8bef9SDimitry Andric if (RF.CR() == 1) { 1398e8d8bef9SDimitry Andric if (I == 0) { // If this is the only register pair 1399e8d8bef9SDimitry Andric // CR=1 combined with RegI=1 doesn't map to a documented case; 1400e8d8bef9SDimitry Andric // it doesn't map to any regular unwind info opcode, and the 1401e8d8bef9SDimitry Andric // actual unwinder doesn't support it. 1402e8d8bef9SDimitry Andric SW.startLine() << "INVALID!\n"; 1403e8d8bef9SDimitry Andric } else 1404e8d8bef9SDimitry Andric SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I, 1405e8d8bef9SDimitry Andric 16 * I); 1406e8d8bef9SDimitry Andric } else { 1407e8d8bef9SDimitry Andric if (I == 0) 1408e8d8bef9SDimitry Andric SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ); 1409e8d8bef9SDimitry Andric else 1410e8d8bef9SDimitry Andric SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I); 1411e8d8bef9SDimitry Andric } 1412e8d8bef9SDimitry Andric } else if (I == 0) { 1413e8d8bef9SDimitry Andric // The first register pair 1414e8d8bef9SDimitry Andric SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ); 1415e8d8bef9SDimitry Andric } else { 1416e8d8bef9SDimitry Andric SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I, 1417e8d8bef9SDimitry Andric 19 + 2 * I + 1, 16 * I); 1418e8d8bef9SDimitry Andric } 1419e8d8bef9SDimitry Andric } 1420*bdd1243dSDimitry Andric // CR=2 is yet undocumented, see 1421*bdd1243dSDimitry Andric // https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream 1422*bdd1243dSDimitry Andric // progress on getting it documented. 1423*bdd1243dSDimitry Andric if (RF.CR() == 2) 1424*bdd1243dSDimitry Andric SW.startLine() << "pacibsp\n"; 1425e8d8bef9SDimitry Andric SW.startLine() << "end\n"; 1426e8d8bef9SDimitry Andric 1427e8d8bef9SDimitry Andric return true; 1428e8d8bef9SDimitry Andric } 1429e8d8bef9SDimitry Andric 14300b57cec5SDimitry Andric bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, 14310b57cec5SDimitry Andric const SectionRef Section, unsigned Index, 14320b57cec5SDimitry Andric ArrayRef<uint8_t> Contents) { 14330b57cec5SDimitry Andric uint64_t Offset = PDataEntrySize * Index; 14340b57cec5SDimitry Andric const ulittle32_t *Data = 14350b57cec5SDimitry Andric reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); 14360b57cec5SDimitry Andric 14370b57cec5SDimitry Andric const RuntimeFunction Entry(Data); 14380b57cec5SDimitry Andric DictScope RFS(SW, "RuntimeFunction"); 14390b57cec5SDimitry Andric if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) 14400b57cec5SDimitry Andric return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); 14410b57cec5SDimitry Andric if (isAArch64) { 1442e8d8bef9SDimitry Andric const RuntimeFunctionARM64 EntryARM64(Data); 1443e8d8bef9SDimitry Andric return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64); 14440b57cec5SDimitry Andric } 14450b57cec5SDimitry Andric return dumpPackedEntry(COFF, Section, Offset, Index, Entry); 14460b57cec5SDimitry Andric } 14470b57cec5SDimitry Andric 14480b57cec5SDimitry Andric void Decoder::dumpProcedureData(const COFFObjectFile &COFF, 14490b57cec5SDimitry Andric const SectionRef Section) { 14500b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 14510b57cec5SDimitry Andric if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) 14520b57cec5SDimitry Andric return; 14530b57cec5SDimitry Andric 14540b57cec5SDimitry Andric if (Contents.size() % PDataEntrySize) { 14550b57cec5SDimitry Andric errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; 14560b57cec5SDimitry Andric return; 14570b57cec5SDimitry Andric } 14580b57cec5SDimitry Andric 14590b57cec5SDimitry Andric for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) 14600b57cec5SDimitry Andric if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) 14610b57cec5SDimitry Andric break; 14620b57cec5SDimitry Andric } 14630b57cec5SDimitry Andric 14640b57cec5SDimitry Andric Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) { 14650b57cec5SDimitry Andric for (const auto &Section : COFF.sections()) { 14660b57cec5SDimitry Andric Expected<StringRef> NameOrErr = 14670b57cec5SDimitry Andric COFF.getSectionName(COFF.getCOFFSection(Section)); 14680b57cec5SDimitry Andric if (!NameOrErr) 14690b57cec5SDimitry Andric return NameOrErr.takeError(); 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric if (NameOrErr->startswith(".pdata")) 14720b57cec5SDimitry Andric dumpProcedureData(COFF, Section); 14730b57cec5SDimitry Andric } 14740b57cec5SDimitry Andric return Error::success(); 14750b57cec5SDimitry Andric } 14760b57cec5SDimitry Andric } 14770b57cec5SDimitry Andric } 14780b57cec5SDimitry Andric } 1479