xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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