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