Path: blob/main/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
35231 views
//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78// Windows on ARM uses a series of serialised data structures (RuntimeFunction)9// to create a table of information for unwinding. In order to conserve space,10// there are two different ways that this data is represented.11//12// For functions with canonical forms for the prologue and epilogue, the data13// can be stored in a "packed" form. In this case, the data is packed into the14// RuntimeFunction's remaining 30-bits and can fully describe the entire frame.15//16// +---------------------------------------+17// | Function Entry Address |18// +---------------------------------------+19// | Packed Form Data |20// +---------------------------------------+21//22// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is23// associated with such a frame as they can be derived from the provided data.24// The decoder does not synthesize this data as it is unnecessary for the25// purposes of validation, with the synthesis being required only by a proper26// unwinder.27//28// For functions that are large or do not match canonical forms, the data is29// split up into two portions, with the actual data residing in the "exception30// data" table (.xdata) with a reference to the entry from the "procedure data"31// (.pdata) entry.32//33// The exception data contains information about the frame setup, all of the34// epilogue scopes (for functions for which there are multiple exit points) and35// the associated exception handler. Additionally, the entry contains byte-code36// describing how to unwind the function (c.f. Decoder::decodeOpcodes).37//38// +---------------------------------------+39// | Function Entry Address |40// +---------------------------------------+41// | Exception Data Entry Address |42// +---------------------------------------+43//44// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must45// first resolve the exception data entry address. This structure46// (ExceptionDataRecord) has a variable sized header47// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as48// the packed form. However, because this information is insufficient to49// synthesize the unwinding, there are associated unwinding bytecode which make50// up the bulk of the Decoder.51//52// The decoder itself is table-driven, using the first byte to determine the53// opcode and dispatching to the associated printing routine. The bytecode54// itself is a variable length instruction encoding that can fully describe the55// state of the stack and the necessary operations for unwinding to the56// beginning of the frame.57//58// The byte-code maintains a 1-1 instruction mapping, indicating both the width59// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits60// wide) allowing the program to unwind from any point in the prologue, body, or61// epilogue of the function.6263#include "ARMWinEHPrinter.h"64#include "llvm/ADT/STLExtras.h"65#include "llvm/ADT/StringExtras.h"66#include "llvm/Support/ARMWinEH.h"67#include "llvm/Support/Format.h"6869using namespace llvm;70using namespace llvm::object;71using namespace llvm::support;7273namespace llvm {74raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {75switch (RT) {76case ARM::WinEH::ReturnType::RT_POP:77OS << "pop {pc}";78break;79case ARM::WinEH::ReturnType::RT_B:80OS << "bx <reg>";81break;82case ARM::WinEH::ReturnType::RT_BW:83OS << "b.w <target>";84break;85case ARM::WinEH::ReturnType::RT_NoEpilogue:86OS << "(no epilogue)";87break;88}89return OS;90}91}9293static std::string formatSymbol(StringRef Name, uint64_t Address,94uint64_t Offset = 0) {95std::string Buffer;96raw_string_ostream OS(Buffer);9798if (!Name.empty())99OS << Name << " ";100101if (Offset)102OS << format("+0x%" PRIX64 " (0x%" PRIX64 ")", Offset, Address);103else if (!Name.empty())104OS << format("(0x%" PRIX64 ")", Address);105else106OS << format("0x%" PRIX64, Address);107108return OS.str();109}110111namespace llvm {112namespace ARM {113namespace WinEH {114const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);115116// TODO name the uops more appropriately117const Decoder::RingEntry Decoder::Ring[] = {118{ 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit)119{ 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit)120{ 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit)121{ 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit)122{ 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit)123{ 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit)124{ 0xfc, 0xe8, 2, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit)125{ 0xfe, 0xec, 2, &Decoder::opcode_1110110L }, // UOP_POP (16-bit)126{ 0xff, 0xee, 2, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit)127// UOP_PUSH_MACHINE_FRAME128// UOP_PUSH_CONTEXT129// UOP_PUSH_TRAP_FRAME130// UOP_REDZONE_RESTORE_LR131{ 0xff, 0xef, 2, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit)132{ 0xff, 0xf5, 2, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit)133{ 0xff, 0xf6, 2, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit)134{ 0xff, 0xf7, 3, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit)135{ 0xff, 0xf8, 4, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit)136{ 0xff, 0xf9, 3, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit)137{ 0xff, 0xfa, 4, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit)138{ 0xff, 0xfb, 1, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit)139{ 0xff, 0xfc, 1, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit)140{ 0xff, 0xfd, 1, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END141{ 0xff, 0xfe, 1, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END142{ 0xff, 0xff, 1, &Decoder::opcode_11111111 }, // UOP_END143};144145// Unwind opcodes for ARM64.146// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling147const Decoder::RingEntry Decoder::Ring64[] = {148{0xe0, 0x00, 1, &Decoder::opcode_alloc_s},149{0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x},150{0xc0, 0x40, 1, &Decoder::opcode_save_fplr},151{0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x},152{0xf8, 0xc0, 2, &Decoder::opcode_alloc_m},153{0xfc, 0xc8, 2, &Decoder::opcode_save_regp},154{0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x},155{0xfc, 0xd0, 2, &Decoder::opcode_save_reg},156{0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x},157{0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair},158{0xfe, 0xd8, 2, &Decoder::opcode_save_fregp},159{0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x},160{0xfe, 0xdc, 2, &Decoder::opcode_save_freg},161{0xff, 0xde, 2, &Decoder::opcode_save_freg_x},162{0xff, 0xe0, 4, &Decoder::opcode_alloc_l},163{0xff, 0xe1, 1, &Decoder::opcode_setfp},164{0xff, 0xe2, 2, &Decoder::opcode_addfp},165{0xff, 0xe3, 1, &Decoder::opcode_nop},166{0xff, 0xe4, 1, &Decoder::opcode_end},167{0xff, 0xe5, 1, &Decoder::opcode_end_c},168{0xff, 0xe6, 1, &Decoder::opcode_save_next},169{0xff, 0xe7, 3, &Decoder::opcode_save_any_reg},170{0xff, 0xe8, 1, &Decoder::opcode_trap_frame},171{0xff, 0xe9, 1, &Decoder::opcode_machine_frame},172{0xff, 0xea, 1, &Decoder::opcode_context},173{0xff, 0xeb, 1, &Decoder::opcode_ec_context},174{0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call},175{0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr},176};177178static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First,179unsigned Last, char Letter) {180if (First == Last)181OS << LS << Letter << First;182else183OS << LS << Letter << First << "-" << Letter << Last;184}185186static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS,187unsigned Start, unsigned End, char Letter) {188int First = -1;189for (unsigned RI = Start; RI <= End; ++RI) {190if (Mask & (1 << RI)) {191if (First < 0)192First = RI;193} else {194if (First >= 0) {195printRange(OS, LS, First, RI - 1, Letter);196First = -1;197}198}199}200if (First >= 0)201printRange(OS, LS, First, End, Letter);202}203204void Decoder::printGPRMask(uint16_t GPRMask) {205OS << '{';206ListSeparator LS;207printRange(OS, GPRMask, LS, 0, 12, 'r');208if (GPRMask & (1 << 14))209OS << LS << "lr";210if (GPRMask & (1 << 15))211OS << LS << "pc";212OS << '}';213}214215void Decoder::printVFPMask(uint32_t VFPMask) {216OS << '{';217ListSeparator LS;218printRange(OS, VFPMask, LS, 0, 31, 'd');219OS << '}';220}221222ErrorOr<object::SectionRef>223Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {224for (const auto &Section : COFF.sections()) {225uint64_t Address = Section.getAddress();226uint64_t Size = Section.getSize();227228if (VA >= Address && (VA - Address) <= Size)229return Section;230}231return inconvertibleErrorCode();232}233234ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,235uint64_t VA, bool FunctionOnly) {236for (const auto &Symbol : COFF.symbols()) {237Expected<SymbolRef::Type> Type = Symbol.getType();238if (!Type)239return errorToErrorCode(Type.takeError());240if (FunctionOnly && *Type != SymbolRef::ST_Function)241continue;242243Expected<uint64_t> Address = Symbol.getAddress();244if (!Address)245return errorToErrorCode(Address.takeError());246if (*Address == VA)247return Symbol;248}249return inconvertibleErrorCode();250}251252ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,253const SectionRef &Section,254uint64_t Offset) {255for (const auto &Relocation : Section.relocations()) {256uint64_t RelocationOffset = Relocation.getOffset();257if (RelocationOffset == Offset)258return *Relocation.getSymbol();259}260return inconvertibleErrorCode();261}262263SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym,264uint64_t &SymbolOffset) {265// The symbol resolved by getRelocatedSymbol can be any internal266// nondescriptive symbol; try to resolve a more descriptive one.267COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym);268if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&269CoffSym.getSectionDefinition() == nullptr)270return Sym;271for (const auto &S : COFF.symbols()) {272COFFSymbolRef CS = COFF.getCOFFSymbol(S);273if (CS.getSectionNumber() == CoffSym.getSectionNumber() &&274CS.getValue() <= CoffSym.getValue() + SymbolOffset &&275CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&276CS.getSectionDefinition() == nullptr) {277uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue();278if (Offset <= SymbolOffset) {279SymbolOffset = Offset;280Sym = S;281CoffSym = CS;282if (CS.isExternal() && SymbolOffset == 0)283return Sym;284}285}286}287return Sym;288}289290ErrorOr<SymbolRef> Decoder::getSymbolForLocation(291const COFFObjectFile &COFF, const SectionRef &Section,292uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress,293uint64_t &SymbolOffset, bool FunctionOnly) {294// Try to locate a relocation that points at the offset in the section295ErrorOr<SymbolRef> SymOrErr =296getRelocatedSymbol(COFF, Section, OffsetInSection);297if (SymOrErr) {298// We found a relocation symbol; the immediate offset needs to be added299// to the symbol address.300SymbolOffset = ImmediateOffset;301302Expected<uint64_t> AddressOrErr = SymOrErr->getAddress();303if (!AddressOrErr) {304std::string Buf;305llvm::raw_string_ostream OS(Buf);306logAllUnhandledErrors(AddressOrErr.takeError(), OS);307report_fatal_error(Twine(OS.str()));308}309// We apply SymbolOffset here directly. We return it separately to allow310// the caller to print it as an offset on the symbol name.311SymbolAddress = *AddressOrErr + SymbolOffset;312313if (FunctionOnly) // Resolve label/section symbols into function names.314SymOrErr = getPreferredSymbol(COFF, *SymOrErr, SymbolOffset);315} else {316// No matching relocation found; operating on a linked image. Try to317// find a descriptive symbol if possible. The immediate offset contains318// the image relative address, and we shouldn't add any offset to the319// symbol.320SymbolAddress = COFF.getImageBase() + ImmediateOffset;321SymbolOffset = 0;322SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly);323}324return SymOrErr;325}326327bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,328unsigned Length, bool Prologue) {329uint8_t Imm = OC[Offset] & 0x7f;330SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n",331OC[Offset],332static_cast<const char *>(Prologue ? "sub" : "add"),333Imm);334++Offset;335return false;336}337338bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,339unsigned Length, bool Prologue) {340unsigned Link = (OC[Offset] & 0x20) >> 5;341uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))342| ((OC[Offset + 0] & 0x1f) << 8)343| ((OC[Offset + 1] & 0xff) << 0);344assert((~RegisterMask & (1 << 13)) && "sp must not be set");345assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set");346347SW.startLine() << format("0x%02x 0x%02x ; %s.w ",348OC[Offset + 0], OC[Offset + 1],349Prologue ? "push" : "pop");350printGPRMask(RegisterMask);351OS << '\n';352353Offset += 2;354return false;355}356357bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,358unsigned Length, bool Prologue) {359if (Prologue)360SW.startLine() << format("0x%02x ; mov r%u, sp\n",361OC[Offset], OC[Offset] & 0xf);362else363SW.startLine() << format("0x%02x ; mov sp, r%u\n",364OC[Offset], OC[Offset] & 0xf);365++Offset;366return false;367}368369bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,370unsigned Length, bool Prologue) {371unsigned Link = (OC[Offset] & 0x4) >> 2;372unsigned Count = (OC[Offset] & 0x3);373374uint16_t GPRMask = (Link << (Prologue ? 14 : 15))375| (((1 << (Count + 1)) - 1) << 4);376377SW.startLine() << format("0x%02x ; %s ", OC[Offset],378Prologue ? "push" : "pop");379printGPRMask(GPRMask);380OS << '\n';381382++Offset;383return false;384}385386bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,387unsigned Length, bool Prologue) {388unsigned Link = (OC[Offset] & 0x4) >> 2;389unsigned Count = (OC[Offset] & 0x3) + 4;390391uint16_t GPRMask = (Link << (Prologue ? 14 : 15))392| (((1 << (Count + 1)) - 1) << 4);393394SW.startLine() << format("0x%02x ; %s.w ", OC[Offset],395Prologue ? "push" : "pop");396printGPRMask(GPRMask);397OS << '\n';398399++Offset;400return false;401}402403bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,404unsigned Length, bool Prologue) {405unsigned High = (OC[Offset] & 0x7);406uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);407408SW.startLine() << format("0x%02x ; %s ", OC[Offset],409Prologue ? "vpush" : "vpop");410printVFPMask(VFPMask);411OS << '\n';412413++Offset;414return false;415}416417bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,418unsigned Length, bool Prologue) {419uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);420421SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n",422OC[Offset + 0], OC[Offset + 1],423static_cast<const char *>(Prologue ? "sub" : "add"),424Imm);425426Offset += 2;427return false;428}429430bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,431unsigned Length, bool Prologue) {432uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))433| ((OC[Offset + 1] & 0xff) << 0);434435SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],436OC[Offset + 1], Prologue ? "push" : "pop");437printGPRMask(GPRMask);438OS << '\n';439440Offset += 2;441return false;442}443444bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,445unsigned Length, bool Prologue) {446assert(!Prologue && "may not be used in prologue");447448if (OC[Offset + 1] & 0xf0)449SW.startLine() << format("0x%02x 0x%02x ; reserved\n",450OC[Offset + 0], OC[Offset + 1]);451else452SW.startLine()453<< format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n",454OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f);455456Offset += 2;457return false;458}459460bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,461unsigned Length, bool Prologue) {462if (OC[Offset + 1] & 0xf0)463SW.startLine() << format("0x%02x 0x%02x ; reserved\n",464OC[Offset + 0], OC[Offset + 1]);465else if (Prologue)466SW.startLine()467<< format("0x%02x 0x%02x ; str.w lr, [sp, #-%u]!\n",468OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);469else470SW.startLine()471<< format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n",472OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);473474Offset += 2;475return false;476}477478bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,479unsigned Length, bool Prologue) {480unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;481unsigned End = (OC[Offset + 1] & 0x0f) >> 0;482uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start;483484SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],485OC[Offset + 1], Prologue ? "vpush" : "vpop");486printVFPMask(VFPMask);487OS << '\n';488489Offset += 2;490return false;491}492493bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,494unsigned Length, bool Prologue) {495unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;496unsigned End = (OC[Offset + 1] & 0x0f) >> 0;497uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start);498499SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0],500OC[Offset + 1], Prologue ? "vpush" : "vpop");501printVFPMask(VFPMask);502OS << '\n';503504Offset += 2;505return false;506}507508bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,509unsigned Length, bool Prologue) {510uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);511512SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",513OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],514static_cast<const char *>(Prologue ? "sub" : "add"),515Imm);516517Offset += 3;518return false;519}520521bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,522unsigned Length, bool Prologue) {523uint32_t Imm = (OC[Offset + 1] << 16)524| (OC[Offset + 2] << 8)525| (OC[Offset + 3] << 0);526527SW.startLine()528<< format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",529OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],530static_cast<const char *>(Prologue ? "sub" : "add"), Imm);531532Offset += 4;533return false;534}535536bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,537unsigned Length, bool Prologue) {538uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);539540SW.startLine()541<< format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",542OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],543static_cast<const char *>(Prologue ? "sub" : "add"), Imm);544545Offset += 3;546return false;547}548549bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,550unsigned Length, bool Prologue) {551uint32_t Imm = (OC[Offset + 1] << 16)552| (OC[Offset + 2] << 8)553| (OC[Offset + 3] << 0);554555SW.startLine()556<< format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",557OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],558static_cast<const char *>(Prologue ? "sub" : "add"), Imm);559560Offset += 4;561return false;562}563564bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,565unsigned Length, bool Prologue) {566SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);567++Offset;568return false;569}570571bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,572unsigned Length, bool Prologue) {573SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]);574++Offset;575return false;576}577578bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,579unsigned Length, bool Prologue) {580SW.startLine() << format("0x%02x ; bx <reg>\n", OC[Offset]);581++Offset;582return true;583}584585bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,586unsigned Length, bool Prologue) {587SW.startLine() << format("0x%02x ; b.w <target>\n", OC[Offset]);588++Offset;589return true;590}591592bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,593unsigned Length, bool Prologue) {594++Offset;595return true;596}597598// ARM64 unwind codes start here.599bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset,600unsigned Length, bool Prologue) {601uint32_t NumBytes = (OC[Offset] & 0x1F) << 4;602SW.startLine() << format("0x%02x ; %s sp, #%u\n", OC[Offset],603static_cast<const char *>(Prologue ? "sub" : "add"),604NumBytes);605++Offset;606return false;607}608609bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset,610unsigned Length, bool Prologue) {611uint32_t Off = (OC[Offset] & 0x1F) << 3;612if (Prologue)613SW.startLine() << format(614"0x%02x ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off);615else616SW.startLine() << format(617"0x%02x ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off);618++Offset;619return false;620}621622bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset,623unsigned Length, bool Prologue) {624uint32_t Off = (OC[Offset] & 0x3F) << 3;625SW.startLine() << format(626"0x%02x ; %s x29, x30, [sp, #%u]\n", OC[Offset],627static_cast<const char *>(Prologue ? "stp" : "ldp"), Off);628++Offset;629return false;630}631632bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset,633unsigned Length, bool Prologue) {634uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3;635if (Prologue)636SW.startLine() << format(637"0x%02x ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off);638else639SW.startLine() << format(640"0x%02x ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off);641++Offset;642return false;643}644645bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset,646unsigned Length, bool Prologue) {647uint32_t NumBytes = ((OC[Offset] & 0x07) << 8);648NumBytes |= (OC[Offset + 1] & 0xFF);649NumBytes <<= 4;650SW.startLine() << format("0x%02x%02x ; %s sp, #%u\n",651OC[Offset], OC[Offset + 1],652static_cast<const char *>(Prologue ? "sub" : "add"),653NumBytes);654Offset += 2;655return false;656}657658bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset,659unsigned Length, bool Prologue) {660uint32_t Reg = ((OC[Offset] & 0x03) << 8);661Reg |= (OC[Offset + 1] & 0xC0);662Reg >>= 6;663Reg += 19;664uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;665SW.startLine() << format(666"0x%02x%02x ; %s x%u, x%u, [sp, #%u]\n",667OC[Offset], OC[Offset + 1],668static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off);669Offset += 2;670return false;671}672673bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset,674unsigned Length, bool Prologue) {675uint32_t Reg = ((OC[Offset] & 0x03) << 8);676Reg |= (OC[Offset + 1] & 0xC0);677Reg >>= 6;678Reg += 19;679uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;680if (Prologue)681SW.startLine() << format(682"0x%02x%02x ; stp x%u, x%u, [sp, #-%u]!\n",683OC[Offset], OC[Offset + 1], Reg,684Reg + 1, Off);685else686SW.startLine() << format(687"0x%02x%02x ; ldp x%u, x%u, [sp], #%u\n",688OC[Offset], OC[Offset + 1], Reg,689Reg + 1, Off);690Offset += 2;691return false;692}693694bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset,695unsigned Length, bool Prologue) {696uint32_t Reg = (OC[Offset] & 0x03) << 8;697Reg |= (OC[Offset + 1] & 0xC0);698Reg >>= 6;699Reg += 19;700uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;701SW.startLine() << format("0x%02x%02x ; %s x%u, [sp, #%u]\n",702OC[Offset], OC[Offset + 1],703static_cast<const char *>(Prologue ? "str" : "ldr"),704Reg, Off);705Offset += 2;706return false;707}708709bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset,710unsigned Length, bool Prologue) {711uint32_t Reg = (OC[Offset] & 0x01) << 8;712Reg |= (OC[Offset + 1] & 0xE0);713Reg >>= 5;714Reg += 19;715uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;716if (Prologue)717SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #-%u]!\n",718OC[Offset], OC[Offset + 1], Reg, Off);719else720SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n",721OC[Offset], OC[Offset + 1], Reg, Off);722Offset += 2;723return false;724}725726bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset,727unsigned Length, bool Prologue) {728uint32_t Reg = (OC[Offset] & 0x01) << 8;729Reg |= (OC[Offset + 1] & 0xC0);730Reg >>= 6;731Reg *= 2;732Reg += 19;733uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;734SW.startLine() << format("0x%02x%02x ; %s x%u, lr, [sp, #%u]\n",735OC[Offset], OC[Offset + 1],736static_cast<const char *>(Prologue ? "stp" : "ldp"),737Reg, Off);738Offset += 2;739return false;740}741742bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset,743unsigned Length, bool Prologue) {744uint32_t Reg = (OC[Offset] & 0x01) << 8;745Reg |= (OC[Offset + 1] & 0xC0);746Reg >>= 6;747Reg += 8;748uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;749SW.startLine() << format("0x%02x%02x ; %s d%u, d%u, [sp, #%u]\n",750OC[Offset], OC[Offset + 1],751static_cast<const char *>(Prologue ? "stp" : "ldp"),752Reg, Reg + 1, Off);753Offset += 2;754return false;755}756757bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset,758unsigned Length, bool Prologue) {759uint32_t Reg = (OC[Offset] & 0x01) << 8;760Reg |= (OC[Offset + 1] & 0xC0);761Reg >>= 6;762Reg += 8;763uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;764if (Prologue)765SW.startLine() << format(766"0x%02x%02x ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset],767OC[Offset + 1], Reg, Reg + 1, Off);768else769SW.startLine() << format(770"0x%02x%02x ; ldp d%u, d%u, [sp], #%u\n", OC[Offset],771OC[Offset + 1], Reg, Reg + 1, Off);772Offset += 2;773return false;774}775776bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset,777unsigned Length, bool Prologue) {778uint32_t Reg = (OC[Offset] & 0x01) << 8;779Reg |= (OC[Offset + 1] & 0xC0);780Reg >>= 6;781Reg += 8;782uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;783SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n",784OC[Offset], OC[Offset + 1],785static_cast<const char *>(Prologue ? "str" : "ldr"),786Reg, Off);787Offset += 2;788return false;789}790791bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset,792unsigned Length, bool Prologue) {793uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8;794uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;795if (Prologue)796SW.startLine() << format(797"0x%02x%02x ; str d%u, [sp, #-%u]!\n", OC[Offset],798OC[Offset + 1], Reg, Off);799else800SW.startLine() << format(801"0x%02x%02x ; ldr d%u, [sp], #%u\n", OC[Offset],802OC[Offset + 1], Reg, Off);803Offset += 2;804return false;805}806807bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset,808unsigned Length, bool Prologue) {809unsigned Off =810(OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0);811Off <<= 4;812SW.startLine() << format(813"0x%02x%02x%02x%02x ; %s sp, #%u\n", OC[Offset], OC[Offset + 1],814OC[Offset + 2], OC[Offset + 3],815static_cast<const char *>(Prologue ? "sub" : "add"), Off);816Offset += 4;817return false;818}819820bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length,821bool Prologue) {822SW.startLine() << format("0x%02x ; mov %s, %s\n", OC[Offset],823static_cast<const char *>(Prologue ? "fp" : "sp"),824static_cast<const char *>(Prologue ? "sp" : "fp"));825++Offset;826return false;827}828829bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length,830bool Prologue) {831unsigned NumBytes = OC[Offset + 1] << 3;832SW.startLine() << format(833"0x%02x%02x ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1],834static_cast<const char *>(Prologue ? "add" : "sub"),835static_cast<const char *>(Prologue ? "fp" : "sp"),836static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes);837Offset += 2;838return false;839}840841bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length,842bool Prologue) {843SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);844++Offset;845return false;846}847848bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length,849bool Prologue) {850SW.startLine() << format("0x%02x ; end\n", OC[Offset]);851++Offset;852return true;853}854855bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length,856bool Prologue) {857SW.startLine() << format("0x%02x ; end_c\n", OC[Offset]);858++Offset;859return false;860}861862bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset,863unsigned Length, bool Prologue) {864if (Prologue)865SW.startLine() << format("0x%02x ; save next\n", OC[Offset]);866else867SW.startLine() << format("0x%02x ; restore next\n",868OC[Offset]);869++Offset;870return false;871}872873bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,874unsigned Length, bool Prologue) {875// Whether the instruction has writeback876bool Writeback = (OC[Offset + 1] & 0x20) == 0x20;877// Whether the instruction is paired. (Paired instructions are required878// to save/restore adjacent registers.)879bool Paired = (OC[Offset + 1] & 0x40) == 0x40;880// The kind of register saved:881// - 0 is an x register882// - 1 is the low half of a q register883// - 2 is a whole q register884int RegKind = (OC[Offset + 2] & 0xC0) >> 6;885// Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.)886int Reg = OC[Offset + 1] & 0x1F;887// Encoded stack offset of load/store instruction; decoding varies by mode.888int StackOffset = OC[Offset + 2] & 0x3F;889if (Writeback)890StackOffset++;891if (!Writeback && !Paired && RegKind != 2)892StackOffset *= 8;893else894StackOffset *= 16;895896SW.startLine() << format("0x%02x%02x%02x ; ", OC[Offset],897OC[Offset + 1], OC[Offset + 2]);898899// Verify the encoding is in a form we understand. The high bit of the first900// byte, and mode 3 for the register kind are apparently reserved. The901// encoded register must refer to a valid register.902int MaxReg = 0x1F;903if (Paired)904--MaxReg;905if (RegKind == 0)906--MaxReg;907if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) {908SW.getOStream() << "invalid save_any_reg encoding\n";909Offset += 3;910return false;911}912913if (Paired) {914if (Prologue)915SW.getOStream() << "stp ";916else917SW.getOStream() << "ldp ";918} else {919if (Prologue)920SW.getOStream() << "str ";921else922SW.getOStream() << "ldr ";923}924925char RegChar = 'x';926if (RegKind == 1) {927RegChar = 'd';928} else if (RegKind == 2) {929RegChar = 'q';930}931932if (Paired)933SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1);934else935SW.getOStream() << format("%c%d, ", RegChar, Reg);936937if (Writeback) {938if (Prologue)939SW.getOStream() << format("[sp, #-%d]!\n", StackOffset);940else941SW.getOStream() << format("[sp], #%d\n", StackOffset);942} else {943SW.getOStream() << format("[sp, #%d]\n", StackOffset);944}945946Offset += 3;947return false;948}949950bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset,951unsigned Length, bool Prologue) {952SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]);953++Offset;954return false;955}956957bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset,958unsigned Length, bool Prologue) {959SW.startLine() << format("0x%02x ; machine frame\n",960OC[Offset]);961++Offset;962return false;963}964965bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset,966unsigned Length, bool Prologue) {967SW.startLine() << format("0x%02x ; context\n", OC[Offset]);968++Offset;969return false;970}971972bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset,973unsigned Length, bool Prologue) {974SW.startLine() << format("0x%02x ; EC context\n", OC[Offset]);975++Offset;976return false;977}978979bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset,980unsigned Length, bool Prologue) {981SW.startLine() << format("0x%02x ; clear unwound to call\n",982OC[Offset]);983++Offset;984return false;985}986987bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset,988unsigned Length, bool Prologue) {989if (Prologue)990SW.startLine() << format("0x%02x ; pacibsp\n", OC[Offset]);991else992SW.startLine() << format("0x%02x ; autibsp\n", OC[Offset]);993++Offset;994return false;995}996997void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,998bool Prologue) {999assert((!Prologue || Offset == 0) && "prologue should always use offset 0");1000const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring;1001bool Terminated = false;1002for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {1003for (unsigned DI = 0;; ++DI) {1004if ((isAArch64 && (DI >= std::size(Ring64))) ||1005(!isAArch64 && (DI >= std::size(Ring)))) {1006SW.startLine() << format("0x%02x ; Bad opcode!\n",1007Opcodes.data()[OI]);1008++OI;1009break;1010}10111012if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) {1013if (OI + DecodeRing[DI].Length > OE) {1014SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n",1015Opcodes[OI]);1016OI += DecodeRing[DI].Length;1017break;1018}1019Terminated =1020(this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue);1021break;1022}1023}1024}1025}10261027bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,1028const SectionRef &Section,1029uint64_t FunctionAddress, uint64_t VA) {1030ArrayRef<uint8_t> Contents;1031if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))1032return false;10331034uint64_t SectionVA = Section.getAddress();1035uint64_t Offset = VA - SectionVA;1036const ulittle32_t *Data =1037reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);10381039// Sanity check to ensure that the .xdata header is present.1040// A header is one or two words, followed by at least one word to describe1041// the unwind codes. Applicable to both ARM and AArch64.1042if (Contents.size() - Offset < 8)1043report_fatal_error(".xdata must be at least 8 bytes in size");10441045const ExceptionDataRecord XData(Data, isAArch64);1046DictScope XRS(SW, "ExceptionData");1047SW.printNumber("FunctionLength",1048isAArch64 ? XData.FunctionLengthInBytesAArch64() :1049XData.FunctionLengthInBytesARM());1050SW.printNumber("Version", XData.Vers());1051SW.printBoolean("ExceptionData", XData.X());1052SW.printBoolean("EpiloguePacked", XData.E());1053if (!isAArch64)1054SW.printBoolean("Fragment", XData.F());1055SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes",1056XData.EpilogueCount());1057uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t);1058SW.printNumber("ByteCodeLength", ByteCodeLength);10591060if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) -1061(XData.E() ? 0 : XData.EpilogueCount() * 4) -1062(XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) {1063SW.flush();1064report_fatal_error("Malformed unwind data");1065}10661067if (XData.E()) {1068ArrayRef<uint8_t> UC = XData.UnwindByteCode();1069{1070ListScope PS(SW, "Prologue");1071decodeOpcodes(UC, 0, /*Prologue=*/true);1072}1073if (XData.EpilogueCount()) {1074ListScope ES(SW, "Epilogue");1075decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);1076}1077} else {1078{1079ListScope PS(SW, "Prologue");1080decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true);1081}1082ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();1083ListScope ESS(SW, "EpilogueScopes");1084for (const EpilogueScope ES : EpilogueScopes) {1085DictScope ESES(SW, "EpilogueScope");1086SW.printNumber("StartOffset", ES.EpilogueStartOffset());1087if (!isAArch64)1088SW.printNumber("Condition", ES.Condition());1089SW.printNumber("EpilogueStartIndex",1090isAArch64 ? ES.EpilogueStartIndexAArch64()1091: ES.EpilogueStartIndexARM());1092unsigned ReservedMask = isAArch64 ? 0xF : 0x3;1093if ((ES.ES >> 18) & ReservedMask)1094SW.printNumber("ReservedBits", (ES.ES >> 18) & ReservedMask);10951096ListScope Opcodes(SW, "Opcodes");1097decodeOpcodes(XData.UnwindByteCode(),1098isAArch64 ? ES.EpilogueStartIndexAArch64()1099: ES.EpilogueStartIndexARM(),1100/*Prologue=*/false);1101}1102}11031104if (XData.X()) {1105const uint32_t Parameter = XData.ExceptionHandlerParameter();1106const size_t HandlerOffset = HeaderWords(XData) +1107(XData.E() ? 0 : XData.EpilogueCount()) +1108XData.CodeWords();11091110uint64_t Address, SymbolOffset;1111ErrorOr<SymbolRef> Symbol = getSymbolForLocation(1112COFF, Section, Offset + HandlerOffset * sizeof(uint32_t),1113XData.ExceptionHandlerRVA(), Address, SymbolOffset,1114/*FunctionOnly=*/true);1115if (!Symbol) {1116ListScope EHS(SW, "ExceptionHandler");1117SW.printHex("Routine", Address);1118SW.printHex("Parameter", Parameter);1119return true;1120}11211122Expected<StringRef> Name = Symbol->getName();1123if (!Name) {1124std::string Buf;1125llvm::raw_string_ostream OS(Buf);1126logAllUnhandledErrors(Name.takeError(), OS);1127report_fatal_error(Twine(OS.str()));1128}11291130ListScope EHS(SW, "ExceptionHandler");1131SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset));1132SW.printHex("Parameter", Parameter);1133}11341135return true;1136}11371138bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,1139const SectionRef Section, uint64_t Offset,1140unsigned Index, const RuntimeFunction &RF) {1141assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&1142"packed entry cannot be treated as an unpacked entry");11431144uint64_t FunctionAddress, FunctionOffset;1145ErrorOr<SymbolRef> Function = getSymbolForLocation(1146COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,1147/*FunctionOnly=*/true);11481149uint64_t XDataAddress, XDataOffset;1150ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation(1151COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress,1152XDataOffset);11531154if (!RF.BeginAddress && !Function)1155return false;1156if (!RF.UnwindData && !XDataRecord)1157return false;11581159StringRef FunctionName;1160if (Function) {1161Expected<StringRef> FunctionNameOrErr = Function->getName();1162if (!FunctionNameOrErr) {1163std::string Buf;1164llvm::raw_string_ostream OS(Buf);1165logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);1166report_fatal_error(Twine(OS.str()));1167}1168FunctionName = *FunctionNameOrErr;1169}11701171SW.printString("Function",1172formatSymbol(FunctionName, FunctionAddress, FunctionOffset));11731174if (XDataRecord) {1175Expected<StringRef> Name = XDataRecord->getName();1176if (!Name) {1177std::string Buf;1178llvm::raw_string_ostream OS(Buf);1179logAllUnhandledErrors(Name.takeError(), OS);1180report_fatal_error(Twine(OS.str()));1181}11821183SW.printString("ExceptionRecord",1184formatSymbol(*Name, XDataAddress, XDataOffset));11851186Expected<section_iterator> SIOrErr = XDataRecord->getSection();1187if (!SIOrErr) {1188// TODO: Actually report errors helpfully.1189consumeError(SIOrErr.takeError());1190return false;1191}1192section_iterator SI = *SIOrErr;11931194return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress);1195} else {1196SW.printString("ExceptionRecord", formatSymbol("", XDataAddress));11971198ErrorOr<SectionRef> Section = getSectionContaining(COFF, XDataAddress);1199if (!Section)1200return false;12011202return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress);1203}1204}12051206bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,1207const SectionRef Section, uint64_t Offset,1208unsigned Index, const RuntimeFunction &RF) {1209assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||1210RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&1211"unpacked entry cannot be treated as a packed entry");12121213uint64_t FunctionAddress, FunctionOffset;1214ErrorOr<SymbolRef> Function = getSymbolForLocation(1215COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,1216/*FunctionOnly=*/true);12171218StringRef FunctionName;1219if (Function) {1220Expected<StringRef> FunctionNameOrErr = Function->getName();1221if (!FunctionNameOrErr) {1222std::string Buf;1223llvm::raw_string_ostream OS(Buf);1224logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);1225report_fatal_error(Twine(OS.str()));1226}1227FunctionName = *FunctionNameOrErr;1228}12291230SW.printString("Function",1231formatSymbol(FunctionName, FunctionAddress, FunctionOffset));1232SW.printBoolean("Fragment",1233RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);1234SW.printNumber("FunctionLength", RF.FunctionLength());1235SW.startLine() << "ReturnType: " << RF.Ret() << '\n';1236SW.printBoolean("HomedParameters", RF.H());1237SW.printNumber("Reg", RF.Reg());1238SW.printNumber("R", RF.R());1239SW.printBoolean("LinkRegister", RF.L());1240SW.printBoolean("Chaining", RF.C());1241SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);12421243{1244ListScope PS(SW, "Prologue");12451246uint16_t GPRMask, VFPMask;1247std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true);12481249if (StackAdjustment(RF) && !PrologueFolding(RF))1250SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n";1251if (VFPMask) {1252SW.startLine() << "vpush ";1253printVFPMask(VFPMask);1254OS << "\n";1255}1256if (RF.C()) {1257// Count the number of registers pushed below R111258int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1));1259if (FpOffset)1260SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n";1261else1262SW.startLine() << "mov r11, sp\n";1263}1264if (GPRMask) {1265SW.startLine() << "push ";1266printGPRMask(GPRMask);1267OS << "\n";1268}1269if (RF.H())1270SW.startLine() << "push {r0-r3}\n";1271}12721273if (RF.Ret() != ReturnType::RT_NoEpilogue) {1274ListScope PS(SW, "Epilogue");12751276uint16_t GPRMask, VFPMask;1277std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false);12781279if (StackAdjustment(RF) && !EpilogueFolding(RF))1280SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n";1281if (VFPMask) {1282SW.startLine() << "vpop ";1283printVFPMask(VFPMask);1284OS << "\n";1285}1286if (GPRMask) {1287SW.startLine() << "pop ";1288printGPRMask(GPRMask);1289OS << "\n";1290}1291if (RF.H()) {1292if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP)1293SW.startLine() << "add sp, sp, #16\n";1294else1295SW.startLine() << "ldr pc, [sp], #20\n";1296}1297if (RF.Ret() != ReturnType::RT_POP)1298SW.startLine() << RF.Ret() << '\n';1299}13001301return true;1302}13031304bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF,1305const SectionRef Section, uint64_t Offset,1306unsigned Index,1307const RuntimeFunctionARM64 &RF) {1308assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||1309RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&1310"unpacked entry cannot be treated as a packed entry");13111312uint64_t FunctionAddress, FunctionOffset;1313ErrorOr<SymbolRef> Function = getSymbolForLocation(1314COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,1315/*FunctionOnly=*/true);13161317StringRef FunctionName;1318if (Function) {1319Expected<StringRef> FunctionNameOrErr = Function->getName();1320if (!FunctionNameOrErr) {1321std::string Buf;1322llvm::raw_string_ostream OS(Buf);1323logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);1324report_fatal_error(Twine(OS.str()));1325}1326FunctionName = *FunctionNameOrErr;1327}13281329SW.printString("Function",1330formatSymbol(FunctionName, FunctionAddress, FunctionOffset));1331SW.printBoolean("Fragment",1332RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);1333SW.printNumber("FunctionLength", RF.FunctionLength());1334SW.printNumber("RegF", RF.RegF());1335SW.printNumber("RegI", RF.RegI());1336SW.printBoolean("HomedParameters", RF.H());1337SW.printNumber("CR", RF.CR());1338SW.printNumber("FrameSize", RF.FrameSize() << 4);1339ListScope PS(SW, "Prologue");13401341// Synthesize the equivalent prologue according to the documentation1342// at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling,1343// printed in reverse order compared to the docs, to match how prologues1344// are printed for the non-packed case.1345int IntSZ = 8 * RF.RegI();1346if (RF.CR() == 1)1347IntSZ += 8;1348int FpSZ = 8 * RF.RegF();1349if (RF.RegF())1350FpSZ += 8;1351int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf;1352int LocSZ = (RF.FrameSize() << 4) - SavSZ;13531354if (RF.CR() == 2 || RF.CR() == 3) {1355SW.startLine() << "mov x29, sp\n";1356if (LocSZ <= 512) {1357SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ);1358} else {1359SW.startLine() << "stp x29, lr, [sp, #0]\n";1360}1361}1362if (LocSZ > 4080) {1363SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080);1364SW.startLine() << "sub sp, sp, #4080\n";1365} else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) {1366SW.startLine() << format("sub sp, sp, #%d\n", LocSZ);1367}1368if (RF.H()) {1369SW.startLine() << format("stp x6, x7, [sp, #%d]\n", SavSZ - 16);1370SW.startLine() << format("stp x4, x5, [sp, #%d]\n", SavSZ - 32);1371SW.startLine() << format("stp x2, x3, [sp, #%d]\n", SavSZ - 48);1372if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) {1373SW.startLine() << format("stp x0, x1, [sp, #%d]\n", SavSZ - 64);1374} else {1375// This case isn't documented; if neither RegI nor RegF nor CR=11376// have decremented the stack pointer by SavSZ, we need to do it here1377// (as the final stack adjustment of LocSZ excludes SavSZ).1378SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ);1379}1380}1381int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0;1382for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) {1383if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) {1384// The last register, an odd register without a pair1385SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I,1386IntSZ + 16 * I);1387} else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) {1388SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I,13898 + 2 * I + 1, SavSZ);1390} else {1391SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I,13928 + 2 * I + 1, IntSZ + 16 * I);1393}1394}1395if (RF.CR() == 1 && (RF.RegI() % 2) == 0) {1396if (RF.RegI() == 0)1397SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ);1398else1399SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8);1400}1401for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) {1402if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) {1403// The last register, an odd register without a pair1404if (RF.CR() == 1) {1405if (I == 0) { // If this is the only register pair1406// CR=1 combined with RegI=1 doesn't map to a documented case;1407// it doesn't map to any regular unwind info opcode, and the1408// actual unwinder doesn't support it.1409SW.startLine() << "INVALID!\n";1410} else1411SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I,141216 * I);1413} else {1414if (I == 0)1415SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ);1416else1417SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I);1418}1419} else if (I == 0) {1420// The first register pair1421SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ);1422} else {1423SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I,142419 + 2 * I + 1, 16 * I);1425}1426}1427// CR=2 is yet undocumented, see1428// https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream1429// progress on getting it documented.1430if (RF.CR() == 2)1431SW.startLine() << "pacibsp\n";1432SW.startLine() << "end\n";14331434return true;1435}14361437bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,1438const SectionRef Section, unsigned Index,1439ArrayRef<uint8_t> Contents) {1440uint64_t Offset = PDataEntrySize * Index;1441const ulittle32_t *Data =1442reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);14431444const RuntimeFunction Entry(Data);1445DictScope RFS(SW, "RuntimeFunction");1446if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)1447return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);1448if (isAArch64) {1449const RuntimeFunctionARM64 EntryARM64(Data);1450return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64);1451}1452return dumpPackedEntry(COFF, Section, Offset, Index, Entry);1453}14541455void Decoder::dumpProcedureData(const COFFObjectFile &COFF,1456const SectionRef Section) {1457ArrayRef<uint8_t> Contents;1458if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))1459return;14601461if (Contents.size() % PDataEntrySize) {1462errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";1463return;1464}14651466for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)1467if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))1468break;1469}14701471Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {1472for (const auto &Section : COFF.sections()) {1473Expected<StringRef> NameOrErr =1474COFF.getSectionName(COFF.getCOFFSection(Section));1475if (!NameOrErr)1476return NameOrErr.takeError();14771478if (NameOrErr->starts_with(".pdata"))1479dumpProcedureData(COFF, Section);1480}1481return Error::success();1482}1483}1484}1485}148614871488