xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp (revision f976241773df2260e6170317080761d1c5814fe5)
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 "Error.h"
66 #include "llvm/ADT/STLExtras.h"
67 #include "llvm/ADT/StringExtras.h"
68 #include "llvm/Support/ARMWinEH.h"
69 #include "llvm/Support/Format.h"
70 
71 using namespace llvm;
72 using namespace llvm::object;
73 using namespace llvm::support;
74 
75 namespace llvm {
76 raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) {
77   switch (RT) {
78   case ARM::WinEH::ReturnType::RT_POP:
79     OS << "pop {pc}";
80     break;
81   case ARM::WinEH::ReturnType::RT_B:
82     OS << "b target";
83     break;
84   case ARM::WinEH::ReturnType::RT_BW:
85     OS << "b.w target";
86     break;
87   case ARM::WinEH::ReturnType::RT_NoEpilogue:
88     OS << "(no epilogue)";
89     break;
90   }
91   return OS;
92 }
93 }
94 
95 static std::string formatSymbol(StringRef Name, uint64_t Address,
96                                 uint64_t Offset = 0) {
97   std::string Buffer;
98   raw_string_ostream OS(Buffer);
99 
100   if (!Name.empty())
101     OS << Name << " ";
102 
103   if (Offset)
104     OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address);
105   else if (!Name.empty())
106     OS << format("(0x%" PRIX64 ")", Address);
107   else
108     OS << format("0x%" PRIX64, Address);
109 
110   return OS.str();
111 }
112 
113 namespace llvm {
114 namespace ARM {
115 namespace WinEH {
116 const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);
117 
118 // TODO name the uops more appropriately
119 const Decoder::RingEntry Decoder::Ring[] = {
120   { 0x80, 0x00, 1, &Decoder::opcode_0xxxxxxx },  // UOP_STACK_FREE (16-bit)
121   { 0xc0, 0x80, 2, &Decoder::opcode_10Lxxxxx },  // UOP_POP (32-bit)
122   { 0xf0, 0xc0, 1, &Decoder::opcode_1100xxxx },  // UOP_STACK_SAVE (16-bit)
123   { 0xf8, 0xd0, 1, &Decoder::opcode_11010Lxx },  // UOP_POP (16-bit)
124   { 0xf8, 0xd8, 1, &Decoder::opcode_11011Lxx },  // UOP_POP (32-bit)
125   { 0xf8, 0xe0, 1, &Decoder::opcode_11100xxx },  // UOP_VPOP (32-bit)
126   { 0xfc, 0xe8, 2, &Decoder::opcode_111010xx },  // UOP_STACK_FREE (32-bit)
127   { 0xfe, 0xec, 2, &Decoder::opcode_1110110L },  // UOP_POP (16-bit)
128   { 0xff, 0xee, 2, &Decoder::opcode_11101110 },  // UOP_MICROSOFT_SPECIFIC (16-bit)
129                                               // UOP_PUSH_MACHINE_FRAME
130                                               // UOP_PUSH_CONTEXT
131                                               // UOP_PUSH_TRAP_FRAME
132                                               // UOP_REDZONE_RESTORE_LR
133   { 0xff, 0xef, 2, &Decoder::opcode_11101111 },  // UOP_LDRPC_POSTINC (32-bit)
134   { 0xff, 0xf5, 2, &Decoder::opcode_11110101 },  // UOP_VPOP (32-bit)
135   { 0xff, 0xf6, 2, &Decoder::opcode_11110110 },  // UOP_VPOP (32-bit)
136   { 0xff, 0xf7, 3, &Decoder::opcode_11110111 },  // UOP_STACK_RESTORE (16-bit)
137   { 0xff, 0xf8, 4, &Decoder::opcode_11111000 },  // UOP_STACK_RESTORE (16-bit)
138   { 0xff, 0xf9, 3, &Decoder::opcode_11111001 },  // UOP_STACK_RESTORE (32-bit)
139   { 0xff, 0xfa, 4, &Decoder::opcode_11111010 },  // UOP_STACK_RESTORE (32-bit)
140   { 0xff, 0xfb, 1, &Decoder::opcode_11111011 },  // UOP_NOP (16-bit)
141   { 0xff, 0xfc, 1, &Decoder::opcode_11111100 },  // UOP_NOP (32-bit)
142   { 0xff, 0xfd, 1, &Decoder::opcode_11111101 },  // UOP_NOP (16-bit) / END
143   { 0xff, 0xfe, 1, &Decoder::opcode_11111110 },  // UOP_NOP (32-bit) / END
144   { 0xff, 0xff, 1, &Decoder::opcode_11111111 },  // UOP_END
145 };
146 
147 
148 // Unwind opcodes for ARM64.
149 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
150 const Decoder::RingEntry Decoder::Ring64[] = {
151   { 0xe0, 0x00, 1, &Decoder::opcode_alloc_s },
152   { 0xe0, 0x20, 1, &Decoder::opcode_save_r19r20_x },
153   { 0xc0, 0x40, 1, &Decoder::opcode_save_fplr },
154   { 0xc0, 0x80, 1, &Decoder::opcode_save_fplr_x },
155   { 0xf8, 0xc0, 2, &Decoder::opcode_alloc_m },
156   { 0xfc, 0xc8, 2, &Decoder::opcode_save_regp },
157   { 0xfc, 0xcc, 2, &Decoder::opcode_save_regp_x },
158   { 0xfc, 0xd0, 2, &Decoder::opcode_save_reg },
159   { 0xfe, 0xd4, 2, &Decoder::opcode_save_reg_x },
160   { 0xfe, 0xd6, 2, &Decoder::opcode_save_lrpair },
161   { 0xfe, 0xd8, 2, &Decoder::opcode_save_fregp },
162   { 0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x },
163   { 0xfe, 0xdc, 2, &Decoder::opcode_save_freg },
164   { 0xff, 0xde, 2, &Decoder::opcode_save_freg_x },
165   { 0xff, 0xe0, 4, &Decoder::opcode_alloc_l },
166   { 0xff, 0xe1, 1, &Decoder::opcode_setfp },
167   { 0xff, 0xe2, 2, &Decoder::opcode_addfp },
168   { 0xff, 0xe3, 1, &Decoder::opcode_nop },
169   { 0xff, 0xe4, 1, &Decoder::opcode_end },
170   { 0xff, 0xe5, 1, &Decoder::opcode_end_c },
171 };
172 
173 void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) {
174   static const char * const GPRRegisterNames[16] = {
175     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
176     "r11", "ip", "sp", "lr", "pc",
177   };
178 
179   const uint16_t GPRMask = std::get<0>(RegisterMask);
180   const uint16_t VFPMask = std::get<1>(RegisterMask);
181 
182   OS << '{';
183   bool Comma = false;
184   for (unsigned RI = 0, RE = 11; RI < RE; ++RI) {
185     if (GPRMask & (1 << RI)) {
186       if (Comma)
187         OS << ", ";
188       OS << GPRRegisterNames[RI];
189       Comma = true;
190     }
191   }
192   for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {
193     if (VFPMask & (1 << RI)) {
194       if (Comma)
195         OS << ", ";
196       OS << "d" << unsigned(RI);
197       Comma = true;
198     }
199   }
200   for (unsigned RI = 11, RE = 16; RI < RE; ++RI) {
201     if (GPRMask & (1 << RI)) {
202       if (Comma)
203         OS << ", ";
204       OS << GPRRegisterNames[RI];
205       Comma = true;
206     }
207   }
208   OS << '}';
209 }
210 
211 ErrorOr<object::SectionRef>
212 Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {
213   for (const auto &Section : COFF.sections()) {
214     uint64_t Address = Section.getAddress();
215     uint64_t Size = Section.getSize();
216 
217     if (VA >= Address && (VA - Address) <= Size)
218       return Section;
219   }
220   return readobj_error::unknown_symbol;
221 }
222 
223 ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,
224                                               uint64_t VA, bool FunctionOnly) {
225   for (const auto &Symbol : COFF.symbols()) {
226     Expected<SymbolRef::Type> Type = Symbol.getType();
227     if (!Type)
228       return errorToErrorCode(Type.takeError());
229     if (FunctionOnly && *Type != SymbolRef::ST_Function)
230       continue;
231 
232     Expected<uint64_t> Address = Symbol.getAddress();
233     if (!Address)
234       return errorToErrorCode(Address.takeError());
235     if (*Address == VA)
236       return Symbol;
237   }
238   return readobj_error::unknown_symbol;
239 }
240 
241 ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,
242                                                const SectionRef &Section,
243                                                uint64_t Offset) {
244   for (const auto &Relocation : Section.relocations()) {
245     uint64_t RelocationOffset = Relocation.getOffset();
246     if (RelocationOffset == Offset)
247       return *Relocation.getSymbol();
248   }
249   return readobj_error::unknown_symbol;
250 }
251 
252 bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,
253                               unsigned Length, bool Prologue) {
254   uint8_t Imm = OC[Offset] & 0x7f;
255   SW.startLine() << format("0x%02x                ; %s sp, #(%u * 4)\n",
256                            OC[Offset],
257                            static_cast<const char *>(Prologue ? "sub" : "add"),
258                            Imm);
259   ++Offset;
260   return false;
261 }
262 
263 bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,
264                               unsigned Length, bool Prologue) {
265   unsigned Link = (OC[Offset] & 0x20) >> 5;
266   uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))
267                         | ((OC[Offset + 0] & 0x1f) << 8)
268                         | ((OC[Offset + 1] & 0xff) << 0);
269   assert((~RegisterMask & (1 << 13)) && "sp must not be set");
270   assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set");
271 
272   SW.startLine() << format("0x%02x 0x%02x           ; %s.w ",
273                            OC[Offset + 0], OC[Offset + 1],
274                            Prologue ? "push" : "pop");
275   printRegisters(std::make_pair(RegisterMask, 0));
276   OS << '\n';
277 
278   Offset += 2;
279   return false;
280 }
281 
282 bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,
283                               unsigned Length, bool Prologue) {
284   if (Prologue)
285     SW.startLine() << format("0x%02x                ; mov r%u, sp\n",
286                              OC[Offset], OC[Offset] & 0xf);
287   else
288     SW.startLine() << format("0x%02x                ; mov sp, r%u\n",
289                              OC[Offset], OC[Offset] & 0xf);
290   ++Offset;
291   return false;
292 }
293 
294 bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,
295                               unsigned Length, bool Prologue) {
296   unsigned Link = (OC[Offset] & 0x4) >> 3;
297   unsigned Count = (OC[Offset] & 0x3);
298 
299   uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
300                    | (((1 << (Count + 1)) - 1) << 4);
301 
302   SW.startLine() << format("0x%02x                ; %s ", OC[Offset],
303                            Prologue ? "push" : "pop");
304   printRegisters(std::make_pair(GPRMask, 0));
305   OS << '\n';
306 
307   ++Offset;
308   return false;
309 }
310 
311 bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,
312                               unsigned Length, bool Prologue) {
313   unsigned Link = (OC[Offset] & 0x4) >> 2;
314   unsigned Count = (OC[Offset] & 0x3) + 4;
315 
316   uint16_t GPRMask = (Link << (Prologue ? 14 : 15))
317                    | (((1 << (Count + 1)) - 1) << 4);
318 
319   SW.startLine() << format("0x%02x                ; %s.w ", OC[Offset],
320                            Prologue ? "push" : "pop");
321   printRegisters(std::make_pair(GPRMask, 0));
322   OS << '\n';
323 
324   ++Offset;
325   return false;
326 }
327 
328 bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,
329                               unsigned Length, bool Prologue) {
330   unsigned High = (OC[Offset] & 0x7);
331   uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);
332 
333   SW.startLine() << format("0x%02x                ; %s ", OC[Offset],
334                            Prologue ? "vpush" : "vpop");
335   printRegisters(std::make_pair(0, VFPMask));
336   OS << '\n';
337 
338   ++Offset;
339   return false;
340 }
341 
342 bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,
343                               unsigned Length, bool Prologue) {
344   uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);
345 
346   SW.startLine() << format("0x%02x 0x%02x           ; %s.w sp, #(%u * 4)\n",
347                            OC[Offset + 0], OC[Offset + 1],
348                            static_cast<const char *>(Prologue ? "sub" : "add"),
349                            Imm);
350 
351   Offset += 2;
352   return false;
353 }
354 
355 bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,
356                               unsigned Length, bool Prologue) {
357   uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))
358                   | ((OC[Offset + 1] & 0xff) << 0);
359 
360   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
361                            OC[Offset + 1], Prologue ? "push" : "pop");
362   printRegisters(std::make_pair(GPRMask, 0));
363   OS << '\n';
364 
365   Offset += 2;
366   return false;
367 }
368 
369 bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,
370                               unsigned Length, bool Prologue) {
371   assert(!Prologue && "may not be used in prologue");
372 
373   if (OC[Offset + 1] & 0xf0)
374     SW.startLine() << format("0x%02x 0x%02x           ; reserved\n",
375                              OC[Offset + 0], OC[Offset +  1]);
376   else
377     SW.startLine()
378       << format("0x%02x 0x%02x           ; microsoft-specific (type: %u)\n",
379                 OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f);
380 
381   Offset += 2;
382   return false;
383 }
384 
385 bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,
386                               unsigned Length, bool Prologue) {
387   assert(!Prologue && "may not be used in prologue");
388 
389   if (OC[Offset + 1] & 0xf0)
390     SW.startLine() << format("0x%02x 0x%02x           ; reserved\n",
391                              OC[Offset + 0], OC[Offset +  1]);
392   else
393     SW.startLine()
394       << format("0x%02x 0x%02x           ; ldr.w lr, [sp], #%u\n",
395                 OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2);
396 
397   Offset += 2;
398   return false;
399 }
400 
401 bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,
402                               unsigned Length, bool Prologue) {
403   unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
404   unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
405   uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start;
406 
407   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
408                            OC[Offset + 1], Prologue ? "vpush" : "vpop");
409   printRegisters(std::make_pair(0, VFPMask));
410   OS << '\n';
411 
412   Offset += 2;
413   return false;
414 }
415 
416 bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,
417                               unsigned Length, bool Prologue) {
418   unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
419   unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
420   uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16;
421 
422   SW.startLine() << format("0x%02x 0x%02x           ; %s ", OC[Offset + 0],
423                            OC[Offset + 1], Prologue ? "vpush" : "vpop");
424   printRegisters(std::make_pair(0, VFPMask));
425   OS << '\n';
426 
427   Offset += 2;
428   return false;
429 }
430 
431 bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,
432                               unsigned Length, bool Prologue) {
433   uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
434 
435   SW.startLine() << format("0x%02x 0x%02x 0x%02x      ; %s sp, sp, #(%u * 4)\n",
436                            OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
437                            static_cast<const char *>(Prologue ? "sub" : "add"),
438                            Imm);
439 
440   Offset += 3;
441   return false;
442 }
443 
444 bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,
445                               unsigned Length, bool Prologue) {
446   uint32_t Imm = (OC[Offset + 1] << 16)
447                | (OC[Offset + 2] << 8)
448                | (OC[Offset + 3] << 0);
449 
450   SW.startLine()
451     << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n",
452               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
453               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
454 
455   Offset += 4;
456   return false;
457 }
458 
459 bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,
460                               unsigned Length, bool Prologue) {
461   uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
462 
463   SW.startLine()
464     << format("0x%02x 0x%02x 0x%02x      ; %s.w sp, sp, #(%u * 4)\n",
465               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2],
466               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
467 
468   Offset += 3;
469   return false;
470 }
471 
472 bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,
473                               unsigned Length, bool Prologue) {
474   uint32_t Imm = (OC[Offset + 1] << 16)
475                | (OC[Offset + 2] << 8)
476                | (OC[Offset + 3] << 0);
477 
478   SW.startLine()
479     << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n",
480               OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3],
481               static_cast<const char *>(Prologue ? "sub" : "add"), Imm);
482 
483   Offset += 4;
484   return false;
485 }
486 
487 bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,
488                               unsigned Length, bool Prologue) {
489   SW.startLine() << format("0x%02x                ; nop\n", OC[Offset]);
490   ++Offset;
491   return false;
492 }
493 
494 bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,
495                               unsigned Length, bool Prologue) {
496   SW.startLine() << format("0x%02x                ; nop.w\n", OC[Offset]);
497   ++Offset;
498   return false;
499 }
500 
501 bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,
502                               unsigned Length, bool Prologue) {
503   SW.startLine() << format("0x%02x                ; b\n", OC[Offset]);
504   ++Offset;
505   return true;
506 }
507 
508 bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,
509                               unsigned Length, bool Prologue) {
510   SW.startLine() << format("0x%02x                ; b.w\n", OC[Offset]);
511   ++Offset;
512   return true;
513 }
514 
515 bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,
516                               unsigned Length, bool Prologue) {
517   ++Offset;
518   return true;
519 }
520 
521 // ARM64 unwind codes start here.
522 bool Decoder::opcode_alloc_s(const uint8_t *OC, unsigned &Offset,
523                              unsigned Length, bool Prologue) {
524   uint32_t NumBytes = (OC[Offset] & 0x1F) << 4;
525   SW.startLine() << format("0x%02x                ; %s sp, #%u\n", OC[Offset],
526                            static_cast<const char *>(Prologue ? "sub" : "add"),
527                            NumBytes);
528   ++Offset;
529   return false;
530 }
531 
532 bool Decoder::opcode_save_r19r20_x(const uint8_t *OC, unsigned &Offset,
533                                    unsigned Length, bool Prologue) {
534   uint32_t Off = (OC[Offset] & 0x1F) << 3;
535   if (Prologue)
536     SW.startLine() << format(
537         "0x%02x                ; stp x19, x20, [sp, #-%u]!\n", OC[Offset], Off);
538   else
539     SW.startLine() << format(
540         "0x%02x                ; ldp x19, x20, [sp], #%u\n", OC[Offset], Off);
541   ++Offset;
542   return false;
543 }
544 
545 bool Decoder::opcode_save_fplr(const uint8_t *OC, unsigned &Offset,
546                                unsigned Length, bool Prologue) {
547   uint32_t Off = (OC[Offset] & 0x3F) << 3;
548   SW.startLine() << format(
549       "0x%02x                ; %s x29, x30, [sp, #%u]\n", OC[Offset],
550       static_cast<const char *>(Prologue ? "stp" : "ldp"), Off);
551   ++Offset;
552   return false;
553 }
554 
555 bool Decoder::opcode_save_fplr_x(const uint8_t *OC, unsigned &Offset,
556                                  unsigned Length, bool Prologue) {
557   uint32_t Off = ((OC[Offset] & 0x3F) + 1) << 3;
558   if (Prologue)
559     SW.startLine() << format(
560         "0x%02x                ; stp x29, x30, [sp, #-%u]!\n", OC[Offset], Off);
561   else
562     SW.startLine() << format(
563         "0x%02x                ; ldp x29, x30, [sp], #%u\n", OC[Offset], Off);
564   ++Offset;
565   return false;
566 }
567 
568 bool Decoder::opcode_alloc_m(const uint8_t *OC, unsigned &Offset,
569                              unsigned Length, bool Prologue) {
570   uint32_t NumBytes = ((OC[Offset] & 0x07) << 8);
571   NumBytes |= (OC[Offset + 1] & 0xFF);
572   NumBytes <<= 4;
573   SW.startLine() << format("0x%02x%02x              ; %s sp, #%u\n",
574                            OC[Offset], OC[Offset + 1],
575                            static_cast<const char *>(Prologue ? "sub" : "add"),
576                            NumBytes);
577   Offset += 2;
578   return false;
579 }
580 
581 bool Decoder::opcode_save_regp(const uint8_t *OC, unsigned &Offset,
582                                unsigned Length, bool Prologue) {
583   uint32_t Reg = ((OC[Offset] & 0x03) << 8);
584   Reg |= (OC[Offset + 1] & 0xC0);
585   Reg >>= 6;
586   Reg += 19;
587   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
588   SW.startLine() << format(
589       "0x%02x%02x              ; %s x%u, x%u, [sp, #%u]\n",
590       OC[Offset], OC[Offset + 1],
591       static_cast<const char *>(Prologue ? "stp" : "ldp"), Reg, Reg + 1, Off);
592   Offset += 2;
593   return false;
594 }
595 
596 bool Decoder::opcode_save_regp_x(const uint8_t *OC, unsigned &Offset,
597                                  unsigned Length, bool Prologue) {
598   uint32_t Reg = ((OC[Offset] & 0x03) << 8);
599   Reg |= (OC[Offset + 1] & 0xC0);
600   Reg >>= 6;
601   Reg += 19;
602   uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
603   if (Prologue)
604     SW.startLine() << format(
605         "0x%02x%02x              ; stp x%u, x%u, [sp, #-%u]!\n",
606         OC[Offset], OC[Offset + 1], Reg,
607         Reg + 1, Off);
608   else
609     SW.startLine() << format(
610         "0x%02x%02x              ; ldp x%u, x%u, [sp], #%u\n",
611         OC[Offset], OC[Offset + 1], Reg,
612         Reg + 1, Off);
613   Offset += 2;
614   return false;
615 }
616 
617 bool Decoder::opcode_save_reg(const uint8_t *OC, unsigned &Offset,
618                               unsigned Length, bool Prologue) {
619   uint32_t Reg = (OC[Offset] & 0x03) << 8;
620   Reg |= (OC[Offset + 1] & 0xC0);
621   Reg >>= 6;
622   Reg += 19;
623   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
624   SW.startLine() << format("0x%02x%02x              ; %s x%u, [sp, #%u]\n",
625                            OC[Offset], OC[Offset + 1],
626                            static_cast<const char *>(Prologue ? "str" : "ldr"),
627                            Reg, Off);
628   Offset += 2;
629   return false;
630 }
631 
632 bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset,
633                                 unsigned Length, bool Prologue) {
634   uint32_t Reg = (OC[Offset] & 0x01) << 8;
635   Reg |= (OC[Offset + 1] & 0xE0);
636   Reg >>= 5;
637   Reg += 19;
638   uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
639   if (Prologue)
640     SW.startLine() << format("0x%02x%02x              ; str x%u, [sp, #%u]!\n",
641                              OC[Offset], OC[Offset + 1], Reg, Off);
642   else
643     SW.startLine() << format("0x%02x%02x              ; ldr x%u, [sp], #%u\n",
644                              OC[Offset], OC[Offset + 1], Reg, Off);
645   Offset += 2;
646   return false;
647 }
648 
649 bool Decoder::opcode_save_lrpair(const uint8_t *OC, unsigned &Offset,
650                                  unsigned Length, bool Prologue) {
651   uint32_t Reg = (OC[Offset] & 0x01) << 8;
652   Reg |= (OC[Offset + 1] & 0xC0);
653   Reg >>= 6;
654   Reg *= 2;
655   Reg += 19;
656   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
657   SW.startLine() << format("0x%02x%02x              ; %s x%u, lr, [sp, #%u]\n",
658                            OC[Offset], OC[Offset + 1],
659                            static_cast<const char *>(Prologue ? "stp" : "ldp"),
660                            Reg, Off);
661   Offset += 2;
662   return false;
663 }
664 
665 bool Decoder::opcode_save_fregp(const uint8_t *OC, unsigned &Offset,
666                                 unsigned Length, bool Prologue) {
667   uint32_t Reg = (OC[Offset] & 0x01) << 8;
668   Reg |= (OC[Offset + 1] & 0xC0);
669   Reg >>= 6;
670   Reg += 8;
671   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
672   SW.startLine() << format("0x%02x%02x              ; %s d%u, d%u, [sp, #%u]\n",
673                            OC[Offset], OC[Offset + 1],
674                            static_cast<const char *>(Prologue ? "stp" : "ldp"),
675                            Reg, Reg + 1, Off);
676   Offset += 2;
677   return false;
678 }
679 
680 bool Decoder::opcode_save_fregp_x(const uint8_t *OC, unsigned &Offset,
681                                   unsigned Length, bool Prologue) {
682   uint32_t Reg = (OC[Offset] & 0x01) << 8;
683   Reg |= (OC[Offset + 1] & 0xC0);
684   Reg >>= 6;
685   Reg += 8;
686   uint32_t Off = ((OC[Offset + 1] & 0x3F) + 1) << 3;
687   if (Prologue)
688     SW.startLine() << format(
689         "0x%02x%02x              ; stp d%u, d%u, [sp, #-%u]!\n", OC[Offset],
690         OC[Offset + 1], Reg, Reg + 1, Off);
691   else
692     SW.startLine() << format(
693         "0x%02x%02x              ; ldp d%u, d%u, [sp], #%u\n", OC[Offset],
694         OC[Offset + 1], Reg, Reg + 1, Off);
695   Offset += 2;
696   return false;
697 }
698 
699 bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset,
700                                unsigned Length, bool Prologue) {
701   uint32_t Reg = (OC[Offset] & 0x01) << 8;
702   Reg |= (OC[Offset + 1] & 0xC0);
703   Reg >>= 6;
704   Reg += 8;
705   uint32_t Off = (OC[Offset + 1] & 0x3F) << 3;
706   SW.startLine() << format("0x%02x%02x                ; %s d%u, [sp, #%u]\n",
707                            OC[Offset], OC[Offset + 1],
708                            static_cast<const char *>(Prologue ? "str" : "ldr"),
709                            Reg, Off);
710   Offset += 2;
711   return false;
712 }
713 
714 bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset,
715                                  unsigned Length, bool Prologue) {
716   uint32_t Reg = ((OC[Offset + 1] & 0xE0) >> 5) + 8;
717   uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3;
718   if (Prologue)
719     SW.startLine() << format(
720         "0x%02x%02x              ; str d%u, [sp, #-%u]!\n", OC[Offset],
721         OC[Offset + 1], Reg, Off);
722   else
723     SW.startLine() << format(
724         "0x%02x%02x              ; ldr d%u, [sp], #%u\n", OC[Offset],
725         OC[Offset + 1], Reg, Off);
726   Offset += 2;
727   return false;
728 }
729 
730 bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset,
731                              unsigned Length, bool Prologue) {
732   unsigned Off =
733       (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) | (OC[Offset + 3] << 0);
734   Off <<= 4;
735   SW.startLine() << format(
736       "0x%02x%02x%02x%02x          ; %s sp, #%u\n", OC[Offset], OC[Offset + 1],
737       OC[Offset + 2], OC[Offset + 3],
738       static_cast<const char *>(Prologue ? "sub" : "add"), Off);
739   Offset += 4;
740   return false;
741 }
742 
743 bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
744                            bool Prologue) {
745   SW.startLine() << format("0x%02x                ; mov fp, sp\n", OC[Offset]);
746   ++Offset;
747   return false;
748 }
749 
750 bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length,
751                            bool Prologue) {
752   unsigned NumBytes = OC[Offset + 1] << 3;
753   SW.startLine() << format("0x%02x%02x              ; add fp, sp, #%u\n",
754                            OC[Offset], OC[Offset + 1], NumBytes);
755   Offset += 2;
756   return false;
757 }
758 
759 bool Decoder::opcode_nop(const uint8_t *OC, unsigned &Offset, unsigned Length,
760                          bool Prologue) {
761   SW.startLine() << format("0x%02x                ; nop\n", OC[Offset]);
762   ++Offset;
763   return false;
764 }
765 
766 bool Decoder::opcode_end(const uint8_t *OC, unsigned &Offset, unsigned Length,
767                          bool Prologue) {
768   SW.startLine() << format("0x%02x                ; end\n", OC[Offset]);
769   ++Offset;
770   return true;
771 }
772 
773 bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length,
774                            bool Prologue) {
775   SW.startLine() << format("0x%02x                ; end_c\n", OC[Offset]);
776   ++Offset;
777   return true;
778 }
779 
780 void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
781                             bool Prologue) {
782   assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
783   const RingEntry* DecodeRing = isAArch64 ? Ring64 : Ring;
784   bool Terminated = false;
785   for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) {
786     for (unsigned DI = 0;; ++DI) {
787       if ((isAArch64 && (DI >= array_lengthof(Ring64))) ||
788           (!isAArch64 && (DI >= array_lengthof(Ring)))) {
789         SW.startLine() << format("0x%02x                ; Bad opcode!\n",
790                                  Opcodes.data()[OI]);
791         ++OI;
792         break;
793       }
794 
795       if ((Opcodes[OI] & DecodeRing[DI].Mask) == DecodeRing[DI].Value) {
796         if (OI + DecodeRing[DI].Length > OE) {
797           SW.startLine() << format("Opcode 0x%02x goes past the unwind data\n",
798                                     Opcodes[OI]);
799           OI += DecodeRing[DI].Length;
800           break;
801         }
802         Terminated =
803             (this->*DecodeRing[DI].Routine)(Opcodes.data(), OI, 0, Prologue);
804         break;
805       }
806     }
807   }
808 }
809 
810 bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
811                               const SectionRef &Section,
812                               uint64_t FunctionAddress, uint64_t VA) {
813   ArrayRef<uint8_t> Contents;
814   if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
815     return false;
816 
817   uint64_t SectionVA = Section.getAddress();
818   uint64_t Offset = VA - SectionVA;
819   const ulittle32_t *Data =
820     reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
821 
822   // Sanity check to ensure that the .xdata header is present.
823   // A header is one or two words, followed by at least one word to describe
824   // the unwind codes. Applicable to both ARM and AArch64.
825   if (Contents.size() - Offset < 8)
826     report_fatal_error(".xdata must be at least 8 bytes in size");
827 
828   const ExceptionDataRecord XData(Data, isAArch64);
829   DictScope XRS(SW, "ExceptionData");
830   SW.printNumber("FunctionLength",
831                  isAArch64 ? XData.FunctionLengthInBytesAArch64() :
832                  XData.FunctionLengthInBytesARM());
833   SW.printNumber("Version", XData.Vers());
834   SW.printBoolean("ExceptionData", XData.X());
835   SW.printBoolean("EpiloguePacked", XData.E());
836   if (!isAArch64)
837     SW.printBoolean("Fragment", XData.F());
838   SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes",
839                  XData.EpilogueCount());
840   uint64_t ByteCodeLength = XData.CodeWords() * sizeof(uint32_t);
841   SW.printNumber("ByteCodeLength", ByteCodeLength);
842 
843   if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) -
844                 (XData.E() ? 0 : XData.EpilogueCount() * 4) -
845                 (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength)
846     report_fatal_error("Malformed unwind data");
847 
848   if (XData.E()) {
849     ArrayRef<uint8_t> UC = XData.UnwindByteCode();
850     if (isAArch64 || !XData.F()) {
851       ListScope PS(SW, "Prologue");
852       decodeOpcodes(UC, 0, /*Prologue=*/true);
853     }
854     if (XData.EpilogueCount()) {
855       ListScope ES(SW, "Epilogue");
856       decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);
857     }
858   } else {
859     {
860       ListScope PS(SW, "Prologue");
861       decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true);
862     }
863     ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();
864     ListScope ESS(SW, "EpilogueScopes");
865     for (const EpilogueScope ES : EpilogueScopes) {
866       DictScope ESES(SW, "EpilogueScope");
867       SW.printNumber("StartOffset", ES.EpilogueStartOffset());
868       if (!isAArch64)
869         SW.printNumber("Condition", ES.Condition());
870       SW.printNumber("EpilogueStartIndex",
871                      isAArch64 ? ES.EpilogueStartIndexAArch64()
872                                : ES.EpilogueStartIndexARM());
873       if (ES.ES & ~0xffc3ffff)
874         SW.printNumber("ReservedBits", (ES.ES >> 18) & 0xF);
875 
876       ListScope Opcodes(SW, "Opcodes");
877       decodeOpcodes(XData.UnwindByteCode(),
878                     isAArch64 ? ES.EpilogueStartIndexAArch64()
879                               : ES.EpilogueStartIndexARM(),
880                     /*Prologue=*/false);
881     }
882   }
883 
884   if (XData.X()) {
885     const uint32_t Address = XData.ExceptionHandlerRVA();
886     const uint32_t Parameter = XData.ExceptionHandlerParameter();
887     const size_t HandlerOffset = HeaderWords(XData)
888                                + (XData.E() ? 0 : XData.EpilogueCount())
889                                + XData.CodeWords();
890 
891     ErrorOr<SymbolRef> Symbol = getRelocatedSymbol(
892         COFF, Section, Offset + HandlerOffset * sizeof(uint32_t));
893     if (!Symbol)
894       Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true);
895     if (!Symbol) {
896       ListScope EHS(SW, "ExceptionHandler");
897       SW.printString("Routine", "(null)");
898       return true;
899     }
900 
901     Expected<StringRef> Name = Symbol->getName();
902     if (!Name) {
903       std::string Buf;
904       llvm::raw_string_ostream OS(Buf);
905       logAllUnhandledErrors(Name.takeError(), OS);
906       OS.flush();
907       report_fatal_error(Buf);
908     }
909 
910     ListScope EHS(SW, "ExceptionHandler");
911     SW.printString("Routine", formatSymbol(*Name, Address));
912     SW.printHex("Parameter", Parameter);
913   }
914 
915   return true;
916 }
917 
918 bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
919                                 const SectionRef Section, uint64_t Offset,
920                                 unsigned Index, const RuntimeFunction &RF) {
921   assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
922          "packed entry cannot be treated as an unpacked entry");
923 
924   ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
925   if (!Function)
926     Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
927 
928   ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4);
929   if (!XDataRecord)
930     XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA());
931 
932   if (!RF.BeginAddress && !Function)
933     return false;
934   if (!RF.UnwindData && !XDataRecord)
935     return false;
936 
937   StringRef FunctionName;
938   uint64_t FunctionAddress;
939   if (Function) {
940     Expected<StringRef> FunctionNameOrErr = Function->getName();
941     if (!FunctionNameOrErr) {
942       std::string Buf;
943       llvm::raw_string_ostream OS(Buf);
944       logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
945       OS.flush();
946       report_fatal_error(Buf);
947     }
948     FunctionName = *FunctionNameOrErr;
949     Expected<uint64_t> FunctionAddressOrErr = Function->getAddress();
950     if (!FunctionAddressOrErr) {
951       std::string Buf;
952       llvm::raw_string_ostream OS(Buf);
953       logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS);
954       OS.flush();
955       report_fatal_error(Buf);
956     }
957     FunctionAddress = *FunctionAddressOrErr;
958   } else {
959     FunctionAddress = COFF.getImageBase() + RF.BeginAddress;
960   }
961 
962   SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
963 
964   if (XDataRecord) {
965     Expected<StringRef> Name = XDataRecord->getName();
966     if (!Name) {
967       std::string Buf;
968       llvm::raw_string_ostream OS(Buf);
969       logAllUnhandledErrors(Name.takeError(), OS);
970       OS.flush();
971       report_fatal_error(Buf);
972     }
973 
974     Expected<uint64_t> AddressOrErr = XDataRecord->getAddress();
975     if (!AddressOrErr) {
976       std::string Buf;
977       llvm::raw_string_ostream OS(Buf);
978       logAllUnhandledErrors(AddressOrErr.takeError(), OS);
979       OS.flush();
980       report_fatal_error(Buf);
981     }
982     uint64_t Address = *AddressOrErr;
983 
984     SW.printString("ExceptionRecord", formatSymbol(*Name, Address));
985 
986     Expected<section_iterator> SIOrErr = XDataRecord->getSection();
987     if (!SIOrErr) {
988       // TODO: Actually report errors helpfully.
989       consumeError(SIOrErr.takeError());
990       return false;
991     }
992     section_iterator SI = *SIOrErr;
993 
994     // FIXME: Do we need to add an offset from the relocation?
995     return dumpXDataRecord(COFF, *SI, FunctionAddress,
996                            RF.ExceptionInformationRVA());
997   } else {
998     uint64_t Address = COFF.getImageBase() + RF.ExceptionInformationRVA();
999     SW.printString("ExceptionRecord", formatSymbol("", Address));
1000 
1001     ErrorOr<SectionRef> Section = getSectionContaining(COFF, Address);
1002     if (!Section)
1003       return false;
1004 
1005     return dumpXDataRecord(COFF, *Section, FunctionAddress, Address);
1006   }
1007 }
1008 
1009 bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
1010                               const SectionRef Section, uint64_t Offset,
1011                               unsigned Index, const RuntimeFunction &RF) {
1012   assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
1013           RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
1014          "unpacked entry cannot be treated as a packed entry");
1015 
1016   ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
1017   if (!Function)
1018     Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
1019 
1020   StringRef FunctionName;
1021   uint64_t FunctionAddress;
1022   if (Function) {
1023     Expected<StringRef> FunctionNameOrErr = Function->getName();
1024     if (!FunctionNameOrErr) {
1025       std::string Buf;
1026       llvm::raw_string_ostream OS(Buf);
1027       logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
1028       OS.flush();
1029       report_fatal_error(Buf);
1030     }
1031     FunctionName = *FunctionNameOrErr;
1032     Expected<uint64_t> FunctionAddressOrErr = Function->getAddress();
1033     if (!FunctionAddressOrErr) {
1034       std::string Buf;
1035       llvm::raw_string_ostream OS(Buf);
1036       logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS);
1037       OS.flush();
1038       report_fatal_error(Buf);
1039     }
1040     FunctionAddress = *FunctionAddressOrErr;
1041   } else {
1042     const pe32_header *PEHeader;
1043     if (COFF.getPE32Header(PEHeader))
1044       return false;
1045     FunctionAddress = PEHeader->ImageBase + RF.BeginAddress;
1046   }
1047 
1048   SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
1049   if (!isAArch64)
1050     SW.printBoolean("Fragment",
1051                     RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
1052   SW.printNumber("FunctionLength", RF.FunctionLength());
1053   SW.startLine() << "ReturnType: " << RF.Ret() << '\n';
1054   SW.printBoolean("HomedParameters", RF.H());
1055   SW.startLine() << "SavedRegisters: ";
1056                  printRegisters(SavedRegisterMask(RF));
1057   OS << '\n';
1058   SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);
1059 
1060   return true;
1061 }
1062 
1063 bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
1064                                      const SectionRef Section, unsigned Index,
1065                                      ArrayRef<uint8_t> Contents) {
1066   uint64_t Offset = PDataEntrySize * Index;
1067   const ulittle32_t *Data =
1068     reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
1069 
1070   const RuntimeFunction Entry(Data);
1071   DictScope RFS(SW, "RuntimeFunction");
1072   if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
1073     return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
1074   if (isAArch64) {
1075     SW.startLine() << "Packed unwind data not yet supported for ARM64\n";
1076     return true;
1077   }
1078   return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
1079 }
1080 
1081 void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
1082                                 const SectionRef Section) {
1083   ArrayRef<uint8_t> Contents;
1084   if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
1085     return;
1086 
1087   if (Contents.size() % PDataEntrySize) {
1088     errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";
1089     return;
1090   }
1091 
1092   for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)
1093     if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))
1094       break;
1095 }
1096 
1097 Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
1098   for (const auto &Section : COFF.sections()) {
1099     Expected<StringRef> NameOrErr =
1100         COFF.getSectionName(COFF.getCOFFSection(Section));
1101     if (!NameOrErr)
1102       return NameOrErr.takeError();
1103 
1104     if (NameOrErr->startswith(".pdata"))
1105       dumpProcedureData(COFF, Section);
1106   }
1107   return Error::success();
1108 }
1109 }
1110 }
1111 }
1112