xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // Windows on ARM uses a series of serialised data structures (RuntimeFunction)
10 // to create a table of information for unwinding.  In order to conserve space,
11 // there are two different ways that this data is represented.
12 //
13 // For functions with canonical forms for the prologue and epilogue, the data
14 // can be stored in a "packed" form.  In this case, the data is packed into the
15 // RuntimeFunction's remaining 30-bits and can fully describe the entire frame.
16 //
17 //        +---------------------------------------+
18 //        |         Function Entry Address        |
19 //        +---------------------------------------+
20 //        |           Packed Form Data            |
21 //        +---------------------------------------+
22 //
23 // This layout is parsed by Decoder::dumpPackedEntry.  No unwind bytecode is
24 // associated with such a frame as they can be derived from the provided data.
25 // The decoder does not synthesize this data as it is unnecessary for the
26 // purposes of validation, with the synthesis being required only by a proper
27 // unwinder.
28 //
29 // For functions that are large or do not match canonical forms, the data is
30 // split up into two portions, with the actual data residing in the "exception
31 // data" table (.xdata) with a reference to the entry from the "procedure data"
32 // (.pdata) entry.
33 //
34 // The exception data contains information about the frame setup, all of the
35 // epilogue scopes (for functions for which there are multiple exit points) and
36 // the associated exception handler.  Additionally, the entry contains byte-code
37 // describing how to unwind the function (c.f. Decoder::decodeOpcodes).
38 //
39 //        +---------------------------------------+
40 //        |         Function Entry Address        |
41 //        +---------------------------------------+
42 //        |      Exception Data Entry Address     |
43 //        +---------------------------------------+
44 //
45 // This layout is parsed by Decoder::dumpUnpackedEntry.  Such an entry must
46 // first resolve the exception data entry address.  This structure
47 // (ExceptionDataRecord) has a variable sized header
48 // (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as
49 // the packed form.  However, because this information is insufficient to
50 // synthesize the unwinding, there are associated unwinding bytecode which make
51 // up the bulk of the Decoder.
52 //
53 // The decoder itself is table-driven, using the first byte to determine the
54 // opcode and dispatching to the associated printing routine.  The bytecode
55 // itself is a variable length instruction encoding that can fully describe the
56 // state of the stack and the necessary operations for unwinding to the
57 // beginning of the frame.
58 //
59 // The byte-code maintains a 1-1 instruction mapping, indicating both the width
60 // of the instruction (Thumb2 instructions are variable length, 16 or 32 bits
61 // wide) allowing the program to unwind from any point in the prologue, body, or
62 // epilogue of the function.
63 
64 #include "ARMWinEHPrinter.h"
65 #include "llvm/ADT/STLExtras.h"
66 #include "llvm/ADT/StringExtras.h"
67 #include "llvm/Support/ARMWinEH.h"
68 #include "llvm/Support/Format.h"
69 
70 using namespace llvm;
71 using namespace llvm::object;
72 using namespace llvm::support;
73 
74 namespace llvm {
operator <<(raw_ostream & OS,const ARM::WinEH::ReturnType & RT)75 raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {
76   switch (RT) {
77   case ARM::WinEH::ReturnType::RT_POP:
78     OS << "pop {pc}";
79     break;
80   case ARM::WinEH::ReturnType::RT_B:
81     OS << "bx <reg>";
82     break;
83   case ARM::WinEH::ReturnType::RT_BW:
84     OS << "b.w <target>";
85     break;
86   case ARM::WinEH::ReturnType::RT_NoEpilogue:
87     OS << "(no epilogue)";
88     break;
89   }
90   return OS;
91 }
92 }
93 
formatSymbol(StringRef Name,uint64_t Address,uint64_t Offset=0)94 static std::string formatSymbol(StringRef Name, uint64_t Address,
95                                 uint64_t Offset = 0) {
96   std::string Buffer;
97   raw_string_ostream OS(Buffer);
98 
99   if (!Name.empty())
100     OS << Name << " ";
101 
102   if (Offset)
103     OS << format("+0x%" PRIX64 " (0x%" PRIX64 ")", Offset, Address);
104   else if (!Name.empty())
105     OS << format("(0x%" PRIX64 ")", Address);
106   else
107     OS << format("0x%" PRIX64, Address);
108 
109   return Buffer;
110 }
111 
112 namespace llvm {
113 namespace ARM {
114 namespace WinEH {
115 const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);
116 
117 // TODO name the uops more appropriately
118 const Decoder::RingEntry Decoder::Ring[] = {
119   { 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx },  // UOP_STACK_FREE (16-bit)
120   { 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx },  // UOP_POP (32-bit)
121   { 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx },  // UOP_STACK_SAVE (16-bit)
122   { 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx },  // UOP_POP (16-bit)
123   { 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx },  // UOP_POP (32-bit)
124   { 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx },  // UOP_VPOP (32-bit)
125   { 0xfc, 0xe8, 2, &Decoder::opcode_111010xx },  // UOP_STACK_FREE (32-bit)
126   { 0xfe, 0xec, 2, &Decoder::opcode_1110110L },  // UOP_POP (16-bit)
127   { 0xff, 0xee, 2, &Decoder::opcode_11101110 },  // UOP_MICROSOFT_SPECIFIC (16-bit)
128                                               // UOP_PUSH_MACHINE_FRAME
129                                               // UOP_PUSH_CONTEXT
130                                               // UOP_PUSH_TRAP_FRAME
131                                               // UOP_REDZONE_RESTORE_LR
132   { 0xff, 0xef, 2, &Decoder::opcode_11101111 },  // UOP_LDRPC_POSTINC (32-bit)
133   { 0xff, 0xf5, 2, &Decoder::opcode_11110101 },  // UOP_VPOP (32-bit)
134   { 0xff, 0xf6, 2, &Decoder::opcode_11110110 },  // UOP_VPOP (32-bit)
135   { 0xff, 0xf7, 3, &Decoder::opcode_11110111 },  // UOP_STACK_RESTORE (16-bit)
136   { 0xff, 0xf8, 4, &Decoder::opcode_11111000 },  // UOP_STACK_RESTORE (16-bit)
137   { 0xff, 0xf9, 3, &Decoder::opcode_11111001 },  // UOP_STACK_RESTORE (32-bit)
138   { 0xff, 0xfa, 4, &Decoder::opcode_11111010 },  // UOP_STACK_RESTORE (32-bit)
139   { 0xff, 0xfb, 1, &Decoder::opcode_11111011 },  // UOP_NOP (16-bit)
140   { 0xff, 0xfc, 1, &Decoder::opcode_11111100 },  // UOP_NOP (32-bit)
141   { 0xff, 0xfd, 1, &Decoder::opcode_11111101 },  // UOP_NOP (16-bit) / END
142   { 0xff, 0xfe, 1, &Decoder::opcode_11111110 },  // UOP_NOP (32-bit) / END
143   { 0xff, 0xff, 1, &Decoder::opcode_11111111 },  // UOP_END
144 };
145 
146 // Unwind opcodes for ARM64.
147 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
148 const Decoder::RingEntry Decoder::Ring64[] = {
149     {0xe0, 0x00, 1, &Decoder::opcode_alloc_s},
150     {0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x},
151     {0xc0, 0x40, 1, &Decoder::opcode_save_fplr},
152     {0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x},
153     {0xf8, 0xc0, 2, &Decoder::opcode_alloc_m},
154     {0xfc, 0xc8, 2, &Decoder::opcode_save_regp},
155     {0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x},
156     {0xfc, 0xd0, 2, &Decoder::opcode_save_reg},
157     {0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x},
158     {0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair},
159     {0xfe, 0xd8, 2, &Decoder::opcode_save_fregp},
160     {0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x},
161     {0xfe, 0xdc, 2, &Decoder::opcode_save_freg},
162     {0xff, 0xde, 2, &Decoder::opcode_save_freg_x},
163     {0xff, 0xdf, 2, &Decoder::opcode_alloc_z},
164     {0xff, 0xe0, 4, &Decoder::opcode_alloc_l},
165     {0xff, 0xe1, 1, &Decoder::opcode_setfp},
166     {0xff, 0xe2, 2, &Decoder::opcode_addfp},
167     {0xff, 0xe3, 1, &Decoder::opcode_nop},
168     {0xff, 0xe4, 1, &Decoder::opcode_end},
169     {0xff, 0xe5, 1, &Decoder::opcode_end_c},
170     {0xff, 0xe6, 1, &Decoder::opcode_save_next},
171     {0xff, 0xe7, 3, &Decoder::opcode_e7},
172     {0xff, 0xe8, 1, &Decoder::opcode_trap_frame},
173     {0xff, 0xe9, 1, &Decoder::opcode_machine_frame},
174     {0xff, 0xea, 1, &Decoder::opcode_context},
175     {0xff, 0xeb, 1, &Decoder::opcode_ec_context},
176     {0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call},
177     {0xff, 0xfc, 1, &Decoder::opcode_pac_sign_lr},
178 };
179 
printRange(raw_ostream & OS,ListSeparator & LS,unsigned First,unsigned Last,char Letter)180 static void printRange(raw_ostream &OS, ListSeparator &LS, unsigned First,
181                        unsigned Last, char Letter) {
182   if (First == Last)
183     OS << LS << Letter << First;
184   else
185     OS << LS << Letter << First << "-" << Letter << Last;
186 }
187 
printRange(raw_ostream & OS,uint32_t Mask,ListSeparator & LS,unsigned Start,unsigned End,char Letter)188 static void printRange(raw_ostream &OS, uint32_t Mask, ListSeparator &LS,
189                        unsigned Start, unsigned End, char Letter) {
190   int First = -1;
191   for (unsigned RI = Start; RI <= End; ++RI) {
192     if (Mask & (1 << RI)) {
193       if (First < 0)
194         First = RI;
195     } else {
196       if (First >= 0) {
197         printRange(OS, LS, First, RI - 1, Letter);
198         First = -1;
199       }
200     }
201   }
202   if (First >= 0)
203     printRange(OS, LS, First, End, Letter);
204 }
205 
printGPRMask(uint16_t GPRMask)206 void Decoder::printGPRMask(uint16_t GPRMask) {
207   OS << '{';
208   ListSeparator LS;
209   printRange(OS, GPRMask, LS, 0, 12, 'r');
210   if (GPRMask & (1 << 14))
211     OS << LS << "lr";
212   if (GPRMask & (1 << 15))
213     OS << LS << "pc";
214   OS << '}';
215 }
216 
printVFPMask(uint32_t VFPMask)217 void Decoder::printVFPMask(uint32_t VFPMask) {
218   OS << '{';
219   ListSeparator LS;
220   printRange(OS, VFPMask, LS, 0, 31, 'd');
221   OS << '}';
222 }
223 
224 ErrorOr<object::SectionRef>
getSectionContaining(const COFFObjectFile & COFF,uint64_t VA)225 Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {
226   for (const auto &Section : COFF.sections()) {
227     uint64_t Address = Section.getAddress();
228     uint64_t Size = Section.getSize();
229 
230     if (VA >= Address && (VA - Address) <= Size)
231       return Section;
232   }
233   return inconvertibleErrorCode();
234 }
235 
getSymbol(const COFFObjectFile & COFF,uint64_t VA,bool FunctionOnly)236 ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,
237                                               uint64_t VA, bool FunctionOnly) {
238   for (const auto &Symbol : COFF.symbols()) {
239     Expected<SymbolRef::Type> Type = Symbol.getType();
240     if (!Type)
241       return errorToErrorCode(Type.takeError());
242     if (FunctionOnly && *Type != SymbolRef::ST_Function)
243       continue;
244 
245     Expected<uint64_t> Address = Symbol.getAddress();
246     if (!Address)
247       return errorToErrorCode(Address.takeError());
248     if (*Address == VA)
249       return Symbol;
250   }
251   return inconvertibleErrorCode();
252 }
253 
getRelocatedSymbol(const COFFObjectFile &,const SectionRef & Section,uint64_t Offset)254 ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,
255                                                const SectionRef &Section,
256                                                uint64_t Offset) {
257   for (const auto &Relocation : Section.relocations()) {
258     uint64_t RelocationOffset = Relocation.getOffset();
259     if (RelocationOffset == Offset)
260       return *Relocation.getSymbol();
261   }
262   return inconvertibleErrorCode();
263 }
264 
getPreferredSymbol(const COFFObjectFile & COFF,SymbolRef Sym,uint64_t & SymbolOffset)265 SymbolRef Decoder::getPreferredSymbol(const COFFObjectFile &COFF, SymbolRef Sym,
266                                       uint64_t &SymbolOffset) {
267   // The symbol resolved by getRelocatedSymbol can be any internal
268   // nondescriptive symbol; try to resolve a more descriptive one.
269   COFFSymbolRef CoffSym = COFF.getCOFFSymbol(Sym);
270   if (CoffSym.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&
271       CoffSym.getSectionDefinition() == nullptr)
272     return Sym;
273   for (const auto &S : COFF.symbols()) {
274     COFFSymbolRef CS = COFF.getCOFFSymbol(S);
275     if (CS.getSectionNumber() == CoffSym.getSectionNumber() &&
276         CS.getValue() <= CoffSym.getValue() + SymbolOffset &&
277         CS.getStorageClass() != COFF::IMAGE_SYM_CLASS_LABEL &&
278         CS.getSectionDefinition() == nullptr) {
279       uint32_t Offset = CoffSym.getValue() + SymbolOffset - CS.getValue();
280       if (Offset <= SymbolOffset) {
281         SymbolOffset = Offset;
282         Sym = S;
283         CoffSym = CS;
284         if (CS.isExternal() && SymbolOffset == 0)
285           return Sym;
286       }
287     }
288   }
289   return Sym;
290 }
291 
getSymbolForLocation(const COFFObjectFile & COFF,const SectionRef & Section,uint64_t OffsetInSection,uint64_t ImmediateOffset,uint64_t & SymbolAddress,uint64_t & SymbolOffset,bool FunctionOnly)292 ErrorOr<SymbolRef> Decoder::getSymbolForLocation(
293     const COFFObjectFile &COFF, const SectionRef &Section,
294     uint64_t OffsetInSection, uint64_t ImmediateOffset, uint64_t &SymbolAddress,
295     uint64_t &SymbolOffset, bool FunctionOnly) {
296   // Try to locate a relocation that points at the offset in the section
297   ErrorOr<SymbolRef> SymOrErr =
298       getRelocatedSymbol(COFF, Section, OffsetInSection);
299   if (SymOrErr) {
300     // We found a relocation symbol; the immediate offset needs to be added
301     // to the symbol address.
302     SymbolOffset = ImmediateOffset;
303 
304     Expected<uint64_t> AddressOrErr = SymOrErr->getAddress();
305     if (!AddressOrErr) {
306       std::string Buf;
307       llvm::raw_string_ostream OS(Buf);
308       logAllUnhandledErrors(AddressOrErr.takeError(), OS);
309       reportFatalUsageError(Twine(Buf));
310     }
311     // We apply SymbolOffset here directly. We return it separately to allow
312     // the caller to print it as an offset on the symbol name.
313     SymbolAddress = *AddressOrErr + SymbolOffset;
314 
315     if (FunctionOnly) // Resolve label/section symbols into function names.
316       SymOrErr = getPreferredSymbol(COFF, *SymOrErr, SymbolOffset);
317   } else {
318     // No matching relocation found; operating on a linked image. Try to
319     // find a descriptive symbol if possible. The immediate offset contains
320     // the image relative address, and we shouldn't add any offset to the
321     // symbol.
322     SymbolAddress = COFF.getImageBase() + ImmediateOffset;
323     SymbolOffset = 0;
324     SymOrErr = getSymbol(COFF, SymbolAddress, FunctionOnly);
325   }
326   return SymOrErr;
327 }
328 
opcode_0xxxxxxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)329 bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,
330                               unsigned Length, bool Prologue) {
331   uint8_t Imm = OC[Offset] & 0x7f;
332   SW.startLine() << format("0x%02x                ; %s sp, #(%u * 4)\n",
333                            OC[Offset],
334                            static_cast<const char *>(Prologue ? "sub" : "add"),
335                            Imm);
336   ++Offset;
337   return false;
338 }
339 
opcode_10Lxxxxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)340 bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,
341                               unsigned Length, bool Prologue) {
342   unsigned Link = (OC[Offset] & 0x20) >> 5;
343   uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))
344                         | ((OC[Offset + 0] & 0x1f) << 8)
345                         | ((OC[Offset + 1] & 0xff) << 0);
346   assert((~RegisterMask & (1 << 13)) && "sp must not be set");
347   assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set");
348 
349   SW.startLine() << format("0x%02x 0x%02x           ; %s.w ",
350                            OC[Offset + 0], OC[Offset + 1],
351                            Prologue ? "push" : "pop");
352   printGPRMask(RegisterMask);
353   OS << '\n';
354 
355   Offset += 2;
356   return false;
357 }
358 
opcode_1100xxxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)359 bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,
360                               unsigned Length, bool Prologue) {
361   if (Prologue)
362     SW.startLine() << format("0x%02x                ; mov r%u, sp\n",
363                              OC[Offset], OC[Offset] & 0xf);
364   else
365     SW.startLine() << format("0x%02x                ; mov sp, r%u\n",
366                              OC[Offset], OC[Offset] & 0xf);
367   ++Offset;
368   return false;
369 }
370 
opcode_11010Lxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)371 bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,
372                               unsigned Length, bool Prologue) {
373   unsigned Link = (OC[Offset] & 0x4) >> 2;
374   unsigned Count = (OC[Offset] & 0x3);
375 
376   uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
377                    | (((1 << (Count + 1)) - 1) << 4);
378 
379   SW.startLine() << format("0x%02x                ; %s ", OC[Offset],
380                            Prologue ? "push" : "pop");
381   printGPRMask(GPRMask);
382   OS << '\n';
383 
384   ++Offset;
385   return false;
386 }
387 
opcode_11011Lxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)388 bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,
389                               unsigned Length, bool Prologue) {
390   unsigned Link = (OC[Offset] & 0x4) >> 2;
391   unsigned Count = (OC[Offset] & 0x3) + 4;
392 
393   uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
394                    | (((1 << (Count + 1)) - 1) << 4);
395 
396   SW.startLine() << format("0x%02x                ; %s.w ", OC[Offset],
397                            Prologue ? "push" : "pop");
398   printGPRMask(GPRMask);
399   OS << '\n';
400 
401   ++Offset;
402   return false;
403 }
404 
opcode_11100xxx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)405 bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,
406                               unsigned Length, bool Prologue) {
407   unsigned High = (OC[Offset] & 0x7);
408   uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);
409 
410   SW.startLine() << format("0x%02x                ; %s ", OC[Offset],
411                            Prologue ? "vpush" : "vpop");
412   printVFPMask(VFPMask);
413   OS << '\n';
414 
415   ++Offset;
416   return false;
417 }
418 
opcode_111010xx(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)419 bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,
420                               unsigned Length, bool Prologue) {
421   uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);
422 
423   SW.startLine() << format("0x%02x 0x%02x           ; %s.w sp, #(%u * 4)\n",
424                            OC[Offset + 0], OC[Offset + 1],
425                            static_cast<const char *>(Prologue ? "sub" : "add"),
426                            Imm);
427 
428   Offset += 2;
429   return false;
430 }
431 
opcode_1110110L(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)432 bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,
433                               unsigned Length, bool Prologue) {
434   uint16_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))
435                    | ((OC[Offset + 1] & 0xff) << 0);
436 
437   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
438                            OC[Offset + 1], Prologue ? "push" : "pop");
439   printGPRMask(GPRMask);
440   OS << '\n';
441 
442   Offset += 2;
443   return false;
444 }
445 
opcode_11101110(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)446 bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,
447                               unsigned Length, bool Prologue) {
448   assert(!Prologue && "may not be used in prologue");
449 
450   if (OC[Offset + 1] & 0xf0)
451     SW.startLine() << format("0x%02x 0x%02x           ; reserved\n",
452                              OC[Offset + 0], OC[Offset +  1]);
453   else
454     SW.startLine()
455       << format("0x%02x 0x%02x           ; microsoft-specific (type: %u)\n",
456                 OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f);
457 
458   Offset += 2;
459   return false;
460 }
461 
opcode_11101111(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)462 bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,
463                               unsigned Length, bool Prologue) {
464   if (OC[Offset + 1] & 0xf0)
465     SW.startLine() << format("0x%02x 0x%02x           ; reserved\n",
466                              OC[Offset + 0], OC[Offset +  1]);
467   else if (Prologue)
468     SW.startLine()
469       << format("0x%02x 0x%02x           ; str.w lr, [sp, #-%u]!\n",
470                 OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
471   else
472     SW.startLine()
473       << format("0x%02x 0x%02x           ; ldr.w lr, [sp], #%u\n",
474                 OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
475 
476   Offset += 2;
477   return false;
478 }
479 
opcode_11110101(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)480 bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,
481                               unsigned Length, bool Prologue) {
482   unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
483   unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
484   uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << Start;
485 
486   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
487                            OC[Offset + 1], Prologue ? "vpush" : "vpop");
488   printVFPMask(VFPMask);
489   OS << '\n';
490 
491   Offset += 2;
492   return false;
493 }
494 
opcode_11110110(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)495 bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,
496                               unsigned Length, bool Prologue) {
497   unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
498   unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
499   uint32_t VFPMask = ((1 << (End + 1 - Start)) - 1) << (16 + Start);
500 
501   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
502                            OC[Offset + 1], Prologue ? "vpush" : "vpop");
503   printVFPMask(VFPMask);
504   OS << '\n';
505 
506   Offset += 2;
507   return false;
508 }
509 
opcode_11110111(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)510 bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,
511                               unsigned Length, bool Prologue) {
512   uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
513 
514   SW.startLine() << format("0x%02x 0x%02x 0x%02x      ; %s sp, sp, #(%u * 4)\n",
515                            OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
516                            static_cast<const char *>(Prologue ? "sub" : "add"),
517                            Imm);
518 
519   Offset += 3;
520   return false;
521 }
522 
opcode_11111000(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)523 bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,
524                               unsigned Length, bool Prologue) {
525   uint32_t Imm = (OC[Offset + 1] << 16)
526                | (OC[Offset + 2] << 8)
527                | (OC[Offset + 3] << 0);
528 
529   SW.startLine()
530     << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
531               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
532               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
533 
534   Offset += 4;
535   return false;
536 }
537 
opcode_11111001(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)538 bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,
539                               unsigned Length, bool Prologue) {
540   uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
541 
542   SW.startLine()
543     << format("0x%02x 0x%02x 0x%02x      ; %s.w sp, sp, #(%u * 4)\n",
544               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
545               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
546 
547   Offset += 3;
548   return false;
549 }
550 
opcode_11111010(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)551 bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,
552                               unsigned Length, bool Prologue) {
553   uint32_t Imm = (OC[Offset + 1] << 16)
554                | (OC[Offset + 2] << 8)
555                | (OC[Offset + 3] << 0);
556 
557   SW.startLine()
558     << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
559               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
560               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
561 
562   Offset += 4;
563   return false;
564 }
565 
opcode_11111011(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)566 bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,
567                               unsigned Length, bool Prologue) {
568   SW.startLine() << format("0x%02x                ; nop\n", OC[Offset]);
569   ++Offset;
570   return false;
571 }
572 
opcode_11111100(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)573 bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,
574                               unsigned Length, bool Prologue) {
575   SW.startLine() << format("0x%02x                ; nop.w\n", OC[Offset]);
576   ++Offset;
577   return false;
578 }
579 
opcode_11111101(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)580 bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,
581                               unsigned Length, bool Prologue) {
582   SW.startLine() << format("0x%02x                ; bx <reg>\n", OC[Offset]);
583   ++Offset;
584   return true;
585 }
586 
opcode_11111110(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)587 bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,
588                               unsigned Length, bool Prologue) {
589   SW.startLine() << format("0x%02x                ; b.w <target>\n", OC[Offset]);
590   ++Offset;
591   return true;
592 }
593 
opcode_11111111(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)594 bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,
595                               unsigned Length, bool Prologue) {
596   ++Offset;
597   return true;
598 }
599 
600 // ARM64 unwind codes start here.
opcode_alloc_s(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)601 bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset,
602                              unsigned Length, bool Prologue) {
603   uint32_t NumBytes = (OC[Offset] & 0x1F) << 4;
604   SW.startLine() << format("0x%02x                ; %s sp, #%u\n", OC[Offset],
605                            static_cast<const char *>(Prologue ? "sub" : "add"),
606                            NumBytes);
607   ++Offset;
608   return false;
609 }
610 
opcode_save_r19r20_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)611 bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset,
612                                    unsigned Length, bool Prologue) {
613   uint32_t Off = (OC[Offset] & 0x1F) << 3;
614   if (Prologue)
615     SW.startLine() << format(
616         "0x%02x                ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off);
617   else
618     SW.startLine() << format(
619         "0x%02x                ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off);
620   ++Offset;
621   return false;
622 }
623 
opcode_save_fplr(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)624 bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset,
625                                unsigned Length, bool Prologue) {
626   uint32_t Off = (OC[Offset] & 0x3F) << 3;
627   SW.startLine() << format(
628       "0x%02x                ; %s x29, x30, [sp, #%u]\n", OC[Offset],
629       static_cast<const char *>(Prologue ? "stp" : "ldp"), Off);
630   ++Offset;
631   return false;
632 }
633 
opcode_save_fplr_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)634 bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset,
635                                  unsigned Length, bool Prologue) {
636   uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3;
637   if (Prologue)
638     SW.startLine() << format(
639         "0x%02x                ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off);
640   else
641     SW.startLine() << format(
642         "0x%02x                ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off);
643   ++Offset;
644   return false;
645 }
646 
opcode_alloc_m(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)647 bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset,
648                              unsigned Length, bool Prologue) {
649   uint32_t NumBytes = ((OC[Offset] & 0x07) << 8);
650   NumBytes |= (OC[Offset + 1] & 0xFF);
651   NumBytes <<= 4;
652   SW.startLine() << format("0x%02x%02x              ; %s sp, #%u\n",
653                            OC[Offset], OC[Offset + 1],
654                            static_cast<const char *>(Prologue ? "sub" : "add"),
655                            NumBytes);
656   Offset += 2;
657   return false;
658 }
659 
opcode_save_regp(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)660 bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset,
661                                unsigned Length, bool Prologue) {
662   uint32_t Reg = ((OC[Offset] & 0x03) << 8);
663   Reg |= (OC[Offset + 1] & 0xC0);
664   Reg >>= 6;
665   Reg += 19;
666   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
667   SW.startLine() << format(
668       "0x%02x%02x              ; %s x%u, x%u, [sp, #%u]\n",
669       OC[Offset], OC[Offset + 1],
670       static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off);
671   Offset += 2;
672   return false;
673 }
674 
opcode_save_regp_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)675 bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset,
676                                  unsigned Length, bool Prologue) {
677   uint32_t Reg = ((OC[Offset] & 0x03) << 8);
678   Reg |= (OC[Offset + 1] & 0xC0);
679   Reg >>= 6;
680   Reg += 19;
681   uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
682   if (Prologue)
683     SW.startLine() << format(
684         "0x%02x%02x              ; stp x%u, x%u, [sp, #-%u]!\n",
685         OC[Offset], OC[Offset + 1], Reg,
686         Reg + 1, Off);
687   else
688     SW.startLine() << format(
689         "0x%02x%02x              ; ldp x%u, x%u, [sp], #%u\n",
690         OC[Offset], OC[Offset + 1], Reg,
691         Reg + 1, Off);
692   Offset += 2;
693   return false;
694 }
695 
opcode_save_reg(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)696 bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset,
697                               unsigned Length, bool Prologue) {
698   uint32_t Reg = (OC[Offset] & 0x03) << 8;
699   Reg |= (OC[Offset + 1] & 0xC0);
700   Reg >>= 6;
701   Reg += 19;
702   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
703   SW.startLine() << format("0x%02x%02x              ; %s x%u, [sp, #%u]\n",
704                            OC[Offset], OC[Offset + 1],
705                            static_cast<const char *>(Prologue ? "str" : "ldr"),
706                            Reg, Off);
707   Offset += 2;
708   return false;
709 }
710 
opcode_save_reg_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)711 bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset,
712                                 unsigned Length, bool Prologue) {
713   uint32_t Reg = (OC[Offset] & 0x01) << 8;
714   Reg |= (OC[Offset + 1] & 0xE0);
715   Reg >>= 5;
716   Reg += 19;
717   uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
718   if (Prologue)
719     SW.startLine() << format("0x%02x%02x              ; str x%u, [sp, #-%u]!\n",
720                              OC[Offset], OC[Offset + 1], Reg, Off);
721   else
722     SW.startLine() << format("0x%02x%02x              ; ldr x%u, [sp], #%u\n",
723                              OC[Offset], OC[Offset + 1], Reg, Off);
724   Offset += 2;
725   return false;
726 }
727 
opcode_save_lrpair(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)728 bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset,
729                                  unsigned Length, bool Prologue) {
730   uint32_t Reg = (OC[Offset] & 0x01) << 8;
731   Reg |= (OC[Offset + 1] & 0xC0);
732   Reg >>= 6;
733   Reg *= 2;
734   Reg += 19;
735   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
736   SW.startLine() << format("0x%02x%02x              ; %s x%u, lr, [sp, #%u]\n",
737                            OC[Offset], OC[Offset + 1],
738                            static_cast<const char *>(Prologue ? "stp" : "ldp"),
739                            Reg, Off);
740   Offset += 2;
741   return false;
742 }
743 
opcode_save_fregp(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)744 bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset,
745                                 unsigned Length, bool Prologue) {
746   uint32_t Reg = (OC[Offset] & 0x01) << 8;
747   Reg |= (OC[Offset + 1] & 0xC0);
748   Reg >>= 6;
749   Reg += 8;
750   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
751   SW.startLine() << format("0x%02x%02x              ; %s d%u, d%u, [sp, #%u]\n",
752                            OC[Offset], OC[Offset + 1],
753                            static_cast<const char *>(Prologue ? "stp" : "ldp"),
754                            Reg, Reg + 1, Off);
755   Offset += 2;
756   return false;
757 }
758 
opcode_save_fregp_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)759 bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset,
760                                   unsigned Length, bool Prologue) {
761   uint32_t Reg = (OC[Offset] & 0x01) << 8;
762   Reg |= (OC[Offset + 1] & 0xC0);
763   Reg >>= 6;
764   Reg += 8;
765   uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
766   if (Prologue)
767     SW.startLine() << format(
768         "0x%02x%02x              ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset],
769         OC[Offset + 1], Reg, Reg + 1, Off);
770   else
771     SW.startLine() << format(
772         "0x%02x%02x              ; ldp d%u, d%u, [sp], #%u\n", OC[Offset],
773         OC[Offset + 1], Reg, Reg + 1, Off);
774   Offset += 2;
775   return false;
776 }
777 
opcode_save_freg(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)778 bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset,
779                                unsigned Length, bool Prologue) {
780   uint32_t Reg = (OC[Offset] & 0x01) << 8;
781   Reg |= (OC[Offset + 1] & 0xC0);
782   Reg >>= 6;
783   Reg += 8;
784   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
785   SW.startLine() << format("0x%02x%02x              ; %s d%u, [sp, #%u]\n",
786                            OC[Offset], OC[Offset + 1],
787                            static_cast<const char *>(Prologue ? "str" : "ldr"),
788                            Reg, Off);
789   Offset += 2;
790   return false;
791 }
792 
opcode_save_freg_x(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)793 bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset,
794                                  unsigned Length, bool Prologue) {
795   uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8;
796   uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
797   if (Prologue)
798     SW.startLine() << format(
799         "0x%02x%02x              ; str d%u, [sp, #-%u]!\n", OC[Offset],
800         OC[Offset + 1], Reg, Off);
801   else
802     SW.startLine() << format(
803         "0x%02x%02x              ; ldr d%u, [sp], #%u\n", OC[Offset],
804         OC[Offset + 1], Reg, Off);
805   Offset += 2;
806   return false;
807 }
808 
opcode_alloc_z(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)809 bool Decoder::opcode_alloc_z(const uint8_t *OC, unsigned &Offset,
810                              unsigned Length, bool Prologue) {
811   unsigned Off = OC[Offset + 1];
812   SW.startLine() << format("0x%02x%02x              ; addvl sp, #%d\n",
813                            OC[Offset], OC[Offset + 1],
814                            Prologue ? -(int)Off : (int)Off);
815   Offset += 2;
816   return false;
817 }
818 
opcode_alloc_l(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)819 bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset,
820                              unsigned Length, bool Prologue) {
821   unsigned Off =
822       (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0);
823   Off <<= 4;
824   SW.startLine() << format(
825       "0x%02x%02x%02x%02x          ; %s sp, #%u\n", OC[Offset], OC[Offset + 1],
826       OC[Offset + 2], OC[Offset + 3],
827       static_cast<const char *>(Prologue ? "sub" : "add"), Off);
828   Offset += 4;
829   return false;
830 }
831 
opcode_setfp(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)832 bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
833                            bool Prologue) {
834   SW.startLine() << format("0x%02x                ; mov %s, %s\n", OC[Offset],
835                            static_cast<const char *>(Prologue ? "fp" : "sp"),
836                            static_cast<const char *>(Prologue ? "sp" : "fp"));
837   ++Offset;
838   return false;
839 }
840 
opcode_addfp(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)841 bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
842                            bool Prologue) {
843   unsigned NumBytes = OC[Offset + 1] << 3;
844   SW.startLine() << format(
845       "0x%02x%02x              ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1],
846       static_cast<const char *>(Prologue ? "add" : "sub"),
847       static_cast<const char *>(Prologue ? "fp" : "sp"),
848       static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes);
849   Offset += 2;
850   return false;
851 }
852 
opcode_nop(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)853 bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length,
854                          bool Prologue) {
855   SW.startLine() << format("0x%02x                ; nop\n", OC[Offset]);
856   ++Offset;
857   return false;
858 }
859 
opcode_end(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)860 bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length,
861                          bool Prologue) {
862   SW.startLine() << format("0x%02x                ; end\n", OC[Offset]);
863   ++Offset;
864   return true;
865 }
866 
opcode_end_c(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)867 bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length,
868                            bool Prologue) {
869   SW.startLine() << format("0x%02x                ; end_c\n", OC[Offset]);
870   ++Offset;
871   return false;
872 }
873 
opcode_save_next(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)874 bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset,
875                                unsigned Length, bool Prologue) {
876   if (Prologue)
877     SW.startLine() << format("0x%02x                ; save next\n", OC[Offset]);
878   else
879     SW.startLine() << format("0x%02x                ; restore next\n",
880                              OC[Offset]);
881   ++Offset;
882   return false;
883 }
884 
opcode_e7(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)885 bool Decoder::opcode_e7(const uint8_t *OC, unsigned &Offset, unsigned Length,
886                         bool Prologue) {
887   // The e7 opcode has unusual decoding rules; write out the logic.
888   if ((OC[Offset + 1] & 0x80) == 0x80) {
889     SW.getOStream() << "reserved encoding\n";
890     Offset += 3;
891     return false;
892   }
893 
894   if ((OC[Offset + 2] & 0xC0) == 0xC0) {
895     if ((OC[Offset + 1] & 0x10) == 0)
896       return opcode_save_zreg(OC, Offset, Length, Prologue);
897     return opcode_save_preg(OC, Offset, Length, Prologue);
898   }
899 
900   return opcode_save_any_reg(OC, Offset, Length, Prologue);
901 }
902 
opcode_save_any_reg(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)903 bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,
904                                   unsigned Length, bool Prologue) {
905   // Whether the instruction has writeback
906   bool Writeback = (OC[Offset + 1] & 0x20) == 0x20;
907   // Whether the instruction is paired.  (Paired instructions are required
908   // to save/restore adjacent registers.)
909   bool Paired = (OC[Offset + 1] & 0x40) == 0x40;
910   // The kind of register saved:
911   // - 0 is an x register
912   // - 1 is the low half of a q register
913   // - 2 is a whole q register
914   int RegKind = (OC[Offset + 2] & 0xC0) >> 6;
915   // Encoded register name (0 -> x0/q0, 1 -> x1/q1, etc.)
916   int Reg = OC[Offset + 1] & 0x1F;
917   // Encoded stack offset of load/store instruction; decoding varies by mode.
918   int StackOffset = OC[Offset + 2] & 0x3F;
919   if (Writeback)
920     StackOffset++;
921   if (!Writeback && !Paired && RegKind != 2)
922     StackOffset *= 8;
923   else
924     StackOffset *= 16;
925 
926   SW.startLine() << format("0x%02x%02x%02x            ; ", OC[Offset],
927                            OC[Offset + 1], OC[Offset + 2]);
928 
929   // Verify the encoding is in a form we understand.  The high bit of the first
930   // byte, and mode 3 for the register kind are apparently reserved.  The
931   // encoded register must refer to a valid register.
932   int MaxReg = 0x1F;
933   if (Paired)
934     --MaxReg;
935   if (RegKind == 0)
936     --MaxReg;
937   if ((OC[Offset + 1] & 0x80) == 0x80 || RegKind == 3 || Reg > MaxReg) {
938     SW.getOStream() << "invalid save_any_reg encoding\n";
939     Offset += 3;
940     return false;
941   }
942 
943   if (Paired) {
944     if (Prologue)
945       SW.getOStream() << "stp ";
946     else
947       SW.getOStream() << "ldp ";
948   } else {
949     if (Prologue)
950       SW.getOStream() << "str ";
951     else
952       SW.getOStream() << "ldr ";
953   }
954 
955   char RegChar = 'x';
956   if (RegKind == 1) {
957     RegChar = 'd';
958   } else if (RegKind == 2) {
959     RegChar = 'q';
960   }
961 
962   if (Paired)
963     SW.getOStream() << format("%c%d, %c%d, ", RegChar, Reg, RegChar, Reg + 1);
964   else
965     SW.getOStream() << format("%c%d, ", RegChar, Reg);
966 
967   if (Writeback) {
968     if (Prologue)
969       SW.getOStream() << format("[sp, #-%d]!\n", StackOffset);
970     else
971       SW.getOStream() << format("[sp], #%d\n", StackOffset);
972   } else {
973     SW.getOStream() << format("[sp, #%d]\n", StackOffset);
974   }
975 
976   Offset += 3;
977   return false;
978 }
979 
opcode_save_zreg(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)980 bool Decoder::opcode_save_zreg(const uint8_t *OC, unsigned &Offset,
981                                unsigned Length, bool Prologue) {
982   uint32_t Reg = (OC[Offset + 1] & 0x0F) + 8;
983   uint32_t Off = ((OC[Offset + 1] & 0x60) << 1) | (OC[Offset + 2] & 0x3F);
984   SW.startLine() << format(
985       "0x%02x%02x%02x            ; %s z%u, [sp, #%u, mul vl]\n", OC[Offset],
986       OC[Offset + 1], OC[Offset + 2],
987       static_cast<const char *>(Prologue ? "str" : "ldr"), Reg, Off);
988   Offset += 3;
989   return false;
990 }
991 
opcode_save_preg(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)992 bool Decoder::opcode_save_preg(const uint8_t *OC, unsigned &Offset,
993                                unsigned Length, bool Prologue) {
994   uint32_t Reg = (OC[Offset + 1] & 0x0F);
995   uint32_t Off = ((OC[Offset + 1] & 0x60) << 1) | (OC[Offset + 2] & 0x3F);
996   SW.startLine() << format(
997       "0x%02x%02x%02x            ; %s p%u, [sp, #%u, mul vl]\n", OC[Offset],
998       OC[Offset + 1], OC[Offset + 2],
999       static_cast<const char *>(Prologue ? "str" : "ldr"), Reg, Off);
1000   Offset += 3;
1001   return false;
1002 }
1003 
opcode_trap_frame(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1004 bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset,
1005                                 unsigned Length, bool Prologue) {
1006   SW.startLine() << format("0x%02x                ; trap frame\n", OC[Offset]);
1007   ++Offset;
1008   return false;
1009 }
1010 
opcode_machine_frame(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1011 bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset,
1012                                    unsigned Length, bool Prologue) {
1013   SW.startLine() << format("0x%02x                ; machine frame\n",
1014                            OC[Offset]);
1015   ++Offset;
1016   return false;
1017 }
1018 
opcode_context(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1019 bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset,
1020                              unsigned Length, bool Prologue) {
1021   SW.startLine() << format("0x%02x                ; context\n", OC[Offset]);
1022   ++Offset;
1023   return false;
1024 }
1025 
opcode_ec_context(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1026 bool Decoder::opcode_ec_context(const uint8_t *OC, unsigned &Offset,
1027                                 unsigned Length, bool Prologue) {
1028   SW.startLine() << format("0x%02x                ; EC context\n", OC[Offset]);
1029   ++Offset;
1030   return false;
1031 }
1032 
opcode_clear_unwound_to_call(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1033 bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset,
1034                                            unsigned Length, bool Prologue) {
1035   SW.startLine() << format("0x%02x                ; clear unwound to call\n",
1036                            OC[Offset]);
1037   ++Offset;
1038   return false;
1039 }
1040 
opcode_pac_sign_lr(const uint8_t * OC,unsigned & Offset,unsigned Length,bool Prologue)1041 bool Decoder::opcode_pac_sign_lr(const uint8_t *OC, unsigned &Offset,
1042                                  unsigned Length, bool Prologue) {
1043   if (Prologue)
1044     SW.startLine() << format("0x%02x                ; pacibsp\n", OC[Offset]);
1045   else
1046     SW.startLine() << format("0x%02x                ; autibsp\n", OC[Offset]);
1047   ++Offset;
1048   return false;
1049 }
1050 
decodeOpcodes(ArrayRef<uint8_t> Opcodes,unsigned Offset,bool Prologue)1051 void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
1052                             bool Prologue) {
1053   assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
1054   const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring;
1055   bool Terminated = false;
1056   for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {
1057     for (unsigned DI = 0;; ++DI) {
1058       if ((isAArch64 && (DI >= std::size(Ring64))) ||
1059           (!isAArch64 && (DI >= std::size(Ring)))) {
1060         SW.startLine() << format("0x%02x                ; Bad opcode!\n",
1061                                  Opcodes.data()[OI]);
1062         ++OI;
1063         break;
1064       }
1065 
1066       if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) {
1067         if (OI + DecodeRing[DI].Length > OE) {
1068           SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n",
1069                                     Opcodes[OI]);
1070           OI += DecodeRing[DI].Length;
1071           break;
1072         }
1073         Terminated =
1074             (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue);
1075         break;
1076       }
1077     }
1078   }
1079 }
1080 
dumpXDataRecord(const COFFObjectFile & COFF,const SectionRef & Section,uint64_t FunctionAddress,uint64_t VA)1081 bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
1082                               const SectionRef &Section,
1083                               uint64_t FunctionAddress, uint64_t VA) {
1084   ArrayRef<uint8_t> Contents;
1085   if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
1086     return false;
1087 
1088   uint64_t SectionVA = Section.getAddress();
1089   uint64_t Offset = VA - SectionVA;
1090   const ulittle32_t *Data =
1091     reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
1092 
1093   // Sanity check to ensure that the .xdata header is present.
1094   // A header is one or two words, followed by at least one word to describe
1095   // the unwind codes. Applicable to both ARM and AArch64.
1096   if (Contents.size() - Offset < 8)
1097     reportFatalUsageError(".xdata must be at least 8 bytes in size");
1098 
1099   const ExceptionDataRecord XData(Data, isAArch64);
1100   DictScope XRS(SW, "ExceptionData");
1101   SW.printNumber("FunctionLength",
1102                  isAArch64 ? XData.FunctionLengthInBytesAArch64() :
1103                  XData.FunctionLengthInBytesARM());
1104   SW.printNumber("Version", XData.Vers());
1105   SW.printBoolean("ExceptionData", XData.X());
1106   SW.printBoolean("EpiloguePacked", XData.E());
1107   if (!isAArch64)
1108     SW.printBoolean("Fragment", XData.F());
1109   SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes",
1110                  XData.EpilogueCount());
1111   uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t);
1112   SW.printNumber("ByteCodeLength", ByteCodeLength);
1113 
1114   if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) -
1115                 (XData.E() ? 0 : XData.EpilogueCount() * 4) -
1116                 (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) {
1117     SW.flush();
1118     reportFatalUsageError("Malformed unwind data");
1119   }
1120 
1121   if (XData.E()) {
1122     ArrayRef<uint8_t> UC = XData.UnwindByteCode();
1123     {
1124       ListScope PS(SW, "Prologue");
1125       decodeOpcodes(UC, 0, /*Prologue=*/true);
1126     }
1127     if (XData.EpilogueCount()) {
1128       ListScope ES(SW, "Epilogue");
1129       decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);
1130     }
1131   } else {
1132     {
1133       ListScope PS(SW, "Prologue");
1134       decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true);
1135     }
1136     ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();
1137     ListScope ESS(SW, "EpilogueScopes");
1138     for (const EpilogueScope ES : EpilogueScopes) {
1139       DictScope ESES(SW, "EpilogueScope");
1140       SW.printNumber("StartOffset", ES.EpilogueStartOffset());
1141       if (!isAArch64)
1142         SW.printNumber("Condition", ES.Condition());
1143       SW.printNumber("EpilogueStartIndex",
1144                      isAArch64 ? ES.EpilogueStartIndexAArch64()
1145                                : ES.EpilogueStartIndexARM());
1146       unsigned ReservedMask = isAArch64 ? 0xF : 0x3;
1147       if ((ES.ES >> 18) & ReservedMask)
1148         SW.printNumber("ReservedBits", (ES.ES >> 18) & ReservedMask);
1149 
1150       ListScope Opcodes(SW, "Opcodes");
1151       decodeOpcodes(XData.UnwindByteCode(),
1152                     isAArch64 ? ES.EpilogueStartIndexAArch64()
1153                               : ES.EpilogueStartIndexARM(),
1154                     /*Prologue=*/false);
1155     }
1156   }
1157 
1158   if (XData.X()) {
1159     const uint32_t Parameter = XData.ExceptionHandlerParameter();
1160     const size_t HandlerOffset = HeaderWords(XData) +
1161                                  (XData.E() ? 0 : XData.EpilogueCount()) +
1162                                  XData.CodeWords();
1163 
1164     uint64_t Address, SymbolOffset;
1165     ErrorOr<SymbolRef> Symbol = getSymbolForLocation(
1166         COFF, Section, Offset + HandlerOffset * sizeof(uint32_t),
1167         XData.ExceptionHandlerRVA(), Address, SymbolOffset,
1168         /*FunctionOnly=*/true);
1169     if (!Symbol) {
1170       ListScope EHS(SW, "ExceptionHandler");
1171       SW.printHex("Routine", Address);
1172       SW.printHex("Parameter", Parameter);
1173       return true;
1174     }
1175 
1176     Expected<StringRef> Name = Symbol->getName();
1177     if (!Name) {
1178       std::string Buf;
1179       llvm::raw_string_ostream OS(Buf);
1180       logAllUnhandledErrors(Name.takeError(), OS);
1181       reportFatalUsageError(Twine(Buf));
1182     }
1183 
1184     ListScope EHS(SW, "ExceptionHandler");
1185     SW.printString("Routine", formatSymbol(*Name, Address, SymbolOffset));
1186     SW.printHex("Parameter", Parameter);
1187   }
1188 
1189   return true;
1190 }
1191 
dumpUnpackedEntry(const COFFObjectFile & COFF,const SectionRef Section,uint64_t Offset,unsigned Index,const RuntimeFunction & RF)1192 bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
1193                                 const SectionRef Section, uint64_t Offset,
1194                                 unsigned Index, const RuntimeFunction &RF) {
1195   assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
1196          "packed entry cannot be treated as an unpacked entry");
1197 
1198   uint64_t FunctionAddress, FunctionOffset;
1199   ErrorOr<SymbolRef> Function = getSymbolForLocation(
1200       COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
1201       /*FunctionOnly=*/true);
1202 
1203   uint64_t XDataAddress, XDataOffset;
1204   ErrorOr<SymbolRef> XDataRecord = getSymbolForLocation(
1205       COFF, Section, Offset + 4, RF.ExceptionInformationRVA(), XDataAddress,
1206       XDataOffset);
1207 
1208   if (!RF.BeginAddress && !Function)
1209     return false;
1210   if (!RF.UnwindData && !XDataRecord)
1211     return false;
1212 
1213   StringRef FunctionName;
1214   if (Function) {
1215     Expected<StringRef> FunctionNameOrErr = Function->getName();
1216     if (!FunctionNameOrErr) {
1217       std::string Buf;
1218       llvm::raw_string_ostream OS(Buf);
1219       logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
1220       reportFatalUsageError(Twine(Buf));
1221     }
1222     FunctionName = *FunctionNameOrErr;
1223   }
1224 
1225   SW.printString("Function",
1226                  formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
1227 
1228   if (XDataRecord) {
1229     Expected<StringRef> Name = XDataRecord->getName();
1230     if (!Name) {
1231       std::string Buf;
1232       llvm::raw_string_ostream OS(Buf);
1233       logAllUnhandledErrors(Name.takeError(), OS);
1234       reportFatalUsageError(Twine(Buf));
1235     }
1236 
1237     SW.printString("ExceptionRecord",
1238                    formatSymbol(*Name, XDataAddress, XDataOffset));
1239 
1240     Expected<section_iterator> SIOrErr = XDataRecord->getSection();
1241     if (!SIOrErr) {
1242       // TODO: Actually report errors helpfully.
1243       consumeError(SIOrErr.takeError());
1244       return false;
1245     }
1246     section_iterator SI = *SIOrErr;
1247 
1248     return dumpXDataRecord(COFF, *SI, FunctionAddress, XDataAddress);
1249   } else {
1250     SW.printString("ExceptionRecord", formatSymbol("", XDataAddress));
1251 
1252     ErrorOr<SectionRef> Section = getSectionContaining(COFF, XDataAddress);
1253     if (!Section)
1254       return false;
1255 
1256     return dumpXDataRecord(COFF, *Section, FunctionAddress, XDataAddress);
1257   }
1258 }
1259 
dumpPackedEntry(const object::COFFObjectFile & COFF,const SectionRef Section,uint64_t Offset,unsigned Index,const RuntimeFunction & RF)1260 bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
1261                               const SectionRef Section, uint64_t Offset,
1262                               unsigned Index, const RuntimeFunction &RF) {
1263   assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
1264           RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
1265          "unpacked entry cannot be treated as a packed entry");
1266 
1267   uint64_t FunctionAddress, FunctionOffset;
1268   ErrorOr<SymbolRef> Function = getSymbolForLocation(
1269       COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
1270       /*FunctionOnly=*/true);
1271 
1272   StringRef FunctionName;
1273   if (Function) {
1274     Expected<StringRef> FunctionNameOrErr = Function->getName();
1275     if (!FunctionNameOrErr) {
1276       std::string Buf;
1277       llvm::raw_string_ostream OS(Buf);
1278       logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
1279       reportFatalUsageError(Twine(Buf));
1280     }
1281     FunctionName = *FunctionNameOrErr;
1282   }
1283 
1284   SW.printString("Function",
1285                  formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
1286   SW.printBoolean("Fragment",
1287                   RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
1288   SW.printNumber("FunctionLength", RF.FunctionLength());
1289   SW.startLine() << "ReturnType: " << RF.Ret() << '\n';
1290   SW.printBoolean("HomedParameters", RF.H());
1291   SW.printNumber("Reg", RF.Reg());
1292   SW.printNumber("R", RF.R());
1293   SW.printBoolean("LinkRegister", RF.L());
1294   SW.printBoolean("Chaining", RF.C());
1295   SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);
1296 
1297   {
1298     ListScope PS(SW, "Prologue");
1299 
1300     uint16_t GPRMask, VFPMask;
1301     std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true);
1302 
1303     if (StackAdjustment(RF) && !PrologueFolding(RF))
1304       SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n";
1305     if (VFPMask) {
1306       SW.startLine() << "vpush ";
1307       printVFPMask(VFPMask);
1308       OS << "\n";
1309     }
1310     if (RF.C()) {
1311       // Count the number of registers pushed below R11
1312       int FpOffset = 4 * llvm::popcount(GPRMask & ((1U << 11) - 1));
1313       if (FpOffset)
1314         SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n";
1315       else
1316         SW.startLine() << "mov r11, sp\n";
1317     }
1318     if (GPRMask) {
1319       SW.startLine() << "push ";
1320       printGPRMask(GPRMask);
1321       OS << "\n";
1322     }
1323     if (RF.H())
1324       SW.startLine() << "push {r0-r3}\n";
1325   }
1326 
1327   if (RF.Ret() != ReturnType::RT_NoEpilogue) {
1328     ListScope PS(SW, "Epilogue");
1329 
1330     uint16_t GPRMask, VFPMask;
1331     std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false);
1332 
1333     if (StackAdjustment(RF) && !EpilogueFolding(RF))
1334       SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n";
1335     if (VFPMask) {
1336       SW.startLine() << "vpop ";
1337       printVFPMask(VFPMask);
1338       OS << "\n";
1339     }
1340     if (GPRMask) {
1341       SW.startLine() << "pop ";
1342       printGPRMask(GPRMask);
1343       OS << "\n";
1344     }
1345     if (RF.H()) {
1346       if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP)
1347         SW.startLine() << "add sp, sp, #16\n";
1348       else
1349         SW.startLine() << "ldr pc, [sp], #20\n";
1350     }
1351     if (RF.Ret() != ReturnType::RT_POP)
1352       SW.startLine() << RF.Ret() << '\n';
1353   }
1354 
1355   return true;
1356 }
1357 
dumpPackedARM64Entry(const object::COFFObjectFile & COFF,const SectionRef Section,uint64_t Offset,unsigned Index,const RuntimeFunctionARM64 & RF)1358 bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF,
1359                                    const SectionRef Section, uint64_t Offset,
1360                                    unsigned Index,
1361                                    const RuntimeFunctionARM64 &RF) {
1362   assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
1363           RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
1364          "unpacked entry cannot be treated as a packed entry");
1365 
1366   uint64_t FunctionAddress, FunctionOffset;
1367   ErrorOr<SymbolRef> Function = getSymbolForLocation(
1368       COFF, Section, Offset, RF.BeginAddress, FunctionAddress, FunctionOffset,
1369       /*FunctionOnly=*/true);
1370 
1371   StringRef FunctionName;
1372   if (Function) {
1373     Expected<StringRef> FunctionNameOrErr = Function->getName();
1374     if (!FunctionNameOrErr) {
1375       std::string Buf;
1376       llvm::raw_string_ostream OS(Buf);
1377       logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
1378       reportFatalUsageError(Twine(Buf));
1379     }
1380     FunctionName = *FunctionNameOrErr;
1381   }
1382 
1383   SW.printString("Function",
1384                  formatSymbol(FunctionName, FunctionAddress, FunctionOffset));
1385   SW.printBoolean("Fragment",
1386                   RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
1387   SW.printNumber("FunctionLength", RF.FunctionLength());
1388   SW.printNumber("RegF", RF.RegF());
1389   SW.printNumber("RegI", RF.RegI());
1390   SW.printBoolean("HomedParameters", RF.H());
1391   SW.printNumber("CR", RF.CR());
1392   SW.printNumber("FrameSize", RF.FrameSize() << 4);
1393   ListScope PS(SW, "Prologue");
1394 
1395   // Synthesize the equivalent prologue according to the documentation
1396   // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling,
1397   // printed in reverse order compared to the docs, to match how prologues
1398   // are printed for the non-packed case.
1399   int IntSZ = 8 * RF.RegI();
1400   if (RF.CR() == 1)
1401     IntSZ += 8;
1402   int FpSZ = 8 * RF.RegF();
1403   if (RF.RegF())
1404     FpSZ += 8;
1405   int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf;
1406   int LocSZ = (RF.FrameSize() << 4) - SavSZ;
1407 
1408   if (RF.CR() == 2 || RF.CR() == 3) {
1409     SW.startLine() << "mov x29, sp\n";
1410     if (LocSZ <= 512) {
1411       SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ);
1412     } else {
1413       SW.startLine() << "stp x29, lr, [sp, #0]\n";
1414     }
1415   }
1416   if (LocSZ > 4080) {
1417     SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080);
1418     SW.startLine() << "sub sp, sp, #4080\n";
1419   } else if ((RF.CR() != 3 && RF.CR() != 2 && LocSZ > 0) || LocSZ > 512) {
1420     SW.startLine() << format("sub sp, sp, #%d\n", LocSZ);
1421   }
1422   if (RF.H()) {
1423     SW.startLine() << format("stp x6, x7, [sp, #%d]\n", SavSZ - 16);
1424     SW.startLine() << format("stp x4, x5, [sp, #%d]\n", SavSZ - 32);
1425     SW.startLine() << format("stp x2, x3, [sp, #%d]\n", SavSZ - 48);
1426     if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) {
1427       SW.startLine() << format("stp x0, x1, [sp, #%d]\n", SavSZ - 64);
1428     } else {
1429       // This case isn't documented; if neither RegI nor RegF nor CR=1
1430       // have decremented the stack pointer by SavSZ, we need to do it here
1431       // (as the final stack adjustment of LocSZ excludes SavSZ).
1432       SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ);
1433     }
1434   }
1435   int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0;
1436   for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) {
1437     if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) {
1438       // The last register, an odd register without a pair
1439       SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I,
1440                                IntSZ + 16 * I);
1441     } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) {
1442       SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I,
1443                                8 + 2 * I + 1, SavSZ);
1444     } else {
1445       SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I,
1446                                8 + 2 * I + 1, IntSZ + 16 * I);
1447     }
1448   }
1449   if (RF.CR() == 1 && (RF.RegI() % 2) == 0) {
1450     if (RF.RegI() == 0)
1451       SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ);
1452     else
1453       SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8);
1454   }
1455   for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) {
1456     if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) {
1457       // The last register, an odd register without a pair
1458       if (RF.CR() == 1) {
1459         if (I == 0) { // If this is the only register pair
1460           // CR=1 combined with RegI=1 doesn't map to a documented case;
1461           // it doesn't map to any regular unwind info opcode, and the
1462           // actual unwinder doesn't support it.
1463           SW.startLine() << "INVALID!\n";
1464         } else
1465           SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I,
1466                                    16 * I);
1467       } else {
1468         if (I == 0)
1469           SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ);
1470         else
1471           SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I);
1472       }
1473     } else if (I == 0) {
1474       // The first register pair
1475       SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ);
1476     } else {
1477       SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I,
1478                                19 + 2 * I + 1, 16 * I);
1479     }
1480   }
1481   // CR=2 is yet undocumented, see
1482   // https://github.com/MicrosoftDocs/cpp-docs/pull/4202 for upstream
1483   // progress on getting it documented.
1484   if (RF.CR() == 2)
1485     SW.startLine() << "pacibsp\n";
1486   SW.startLine() << "end\n";
1487 
1488   return true;
1489 }
1490 
dumpProcedureDataEntry(const COFFObjectFile & COFF,const SectionRef Section,unsigned Index,ArrayRef<uint8_t> Contents)1491 bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
1492                                      const SectionRef Section, unsigned Index,
1493                                      ArrayRef<uint8_t> Contents) {
1494   uint64_t Offset = PDataEntrySize * Index;
1495   const ulittle32_t *Data =
1496     reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
1497 
1498   const RuntimeFunction Entry(Data);
1499   DictScope RFS(SW, "RuntimeFunction");
1500   if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
1501     return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
1502   if (isAArch64) {
1503     const RuntimeFunctionARM64 EntryARM64(Data);
1504     return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64);
1505   }
1506   return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
1507 }
1508 
dumpProcedureData(const COFFObjectFile & COFF,const SectionRef Section)1509 void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
1510                                 const SectionRef Section) {
1511   ArrayRef<uint8_t> Contents;
1512   if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
1513     return;
1514 
1515   if (Contents.size() % PDataEntrySize) {
1516     errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";
1517     return;
1518   }
1519 
1520   for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)
1521     if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))
1522       break;
1523 }
1524 
dumpProcedureData(const COFFObjectFile & COFF)1525 Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
1526   for (const auto &Section : COFF.sections()) {
1527     Expected<StringRef> NameOrErr =
1528         COFF.getSectionName(COFF.getCOFFSection(Section));
1529     if (!NameOrErr)
1530       return NameOrErr.takeError();
1531 
1532     if (NameOrErr->starts_with(".pdata"))
1533       dumpProcedureData(COFF, Section);
1534   }
1535   return Error::success();
1536 }
1537 }
1538 }
1539 }
1540