ARMWinEHPrinter.cpp revision 360784
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
71using namespace llvm;
72using namespace llvm::object;
73using namespace llvm::support;
74
75namespace llvm {
76raw_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
95static 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
113namespace llvm {
114namespace ARM {
115namespace WinEH {
116const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction);
117
118// TODO name the uops more appropriately
119const 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
150const 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
173void 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
211ErrorOr<object::SectionRef>
212Decoder::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
223ErrorOr<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
241ErrorOr<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
252bool 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
263bool 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
282bool 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
294bool 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
311bool 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
328bool 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
342bool 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
355bool 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
369bool 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
385bool 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
401bool 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
416bool 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
431bool 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
444bool 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
459bool 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
472bool 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
487bool 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
494bool 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
501bool 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
508bool 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
515bool 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.
522bool 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
532bool 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
545bool 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
555bool 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
568bool 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
581bool 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
596bool 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
617bool 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
632bool 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
649bool 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
665bool 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
680bool 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
699bool 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
714bool 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
730bool 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
743bool 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
750bool 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
759bool 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
766bool 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
773bool 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
780void 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
810bool 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    SW.flush();
847    report_fatal_error("Malformed unwind data");
848  }
849
850  if (XData.E()) {
851    ArrayRef<uint8_t> UC = XData.UnwindByteCode();
852    if (isAArch64 || !XData.F()) {
853      ListScope PS(SW, "Prologue");
854      decodeOpcodes(UC, 0, /*Prologue=*/true);
855    }
856    if (XData.EpilogueCount()) {
857      ListScope ES(SW, "Epilogue");
858      decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false);
859    }
860  } else {
861    {
862      ListScope PS(SW, "Prologue");
863      decodeOpcodes(XData.UnwindByteCode(), 0, /*Prologue=*/true);
864    }
865    ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes();
866    ListScope ESS(SW, "EpilogueScopes");
867    for (const EpilogueScope ES : EpilogueScopes) {
868      DictScope ESES(SW, "EpilogueScope");
869      SW.printNumber("StartOffset", ES.EpilogueStartOffset());
870      if (!isAArch64)
871        SW.printNumber("Condition", ES.Condition());
872      SW.printNumber("EpilogueStartIndex",
873                     isAArch64 ? ES.EpilogueStartIndexAArch64()
874                               : ES.EpilogueStartIndexARM());
875      if (ES.ES & ~0xffc3ffff)
876        SW.printNumber("ReservedBits", (ES.ES >> 18) & 0xF);
877
878      ListScope Opcodes(SW, "Opcodes");
879      decodeOpcodes(XData.UnwindByteCode(),
880                    isAArch64 ? ES.EpilogueStartIndexAArch64()
881                              : ES.EpilogueStartIndexARM(),
882                    /*Prologue=*/false);
883    }
884  }
885
886  if (XData.X()) {
887    const uint64_t Address = COFF.getImageBase() + XData.ExceptionHandlerRVA();
888    const uint32_t Parameter = XData.ExceptionHandlerParameter();
889    const size_t HandlerOffset = HeaderWords(XData)
890                               + (XData.E() ? 0 : XData.EpilogueCount())
891                               + XData.CodeWords();
892
893    ErrorOr<SymbolRef> Symbol = getRelocatedSymbol(
894        COFF, Section, Offset + HandlerOffset * sizeof(uint32_t));
895    if (!Symbol)
896      Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true);
897    if (!Symbol) {
898      ListScope EHS(SW, "ExceptionHandler");
899      SW.printHex("Routine", Address);
900      SW.printHex("Parameter", Parameter);
901      return true;
902    }
903
904    Expected<StringRef> Name = Symbol->getName();
905    if (!Name) {
906      std::string Buf;
907      llvm::raw_string_ostream OS(Buf);
908      logAllUnhandledErrors(Name.takeError(), OS);
909      OS.flush();
910      report_fatal_error(Buf);
911    }
912
913    ListScope EHS(SW, "ExceptionHandler");
914    SW.printString("Routine", formatSymbol(*Name, Address));
915    SW.printHex("Parameter", Parameter);
916  }
917
918  return true;
919}
920
921bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
922                                const SectionRef Section, uint64_t Offset,
923                                unsigned Index, const RuntimeFunction &RF) {
924  assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
925         "packed entry cannot be treated as an unpacked entry");
926
927  ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
928  if (!Function)
929    Function = getSymbol(COFF, COFF.getImageBase() + RF.BeginAddress,
930                         /*FunctionOnly=*/true);
931
932  ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4);
933  if (!XDataRecord)
934    XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA());
935
936  if (!RF.BeginAddress && !Function)
937    return false;
938  if (!RF.UnwindData && !XDataRecord)
939    return false;
940
941  StringRef FunctionName;
942  uint64_t FunctionAddress;
943  if (Function) {
944    Expected<StringRef> FunctionNameOrErr = Function->getName();
945    if (!FunctionNameOrErr) {
946      std::string Buf;
947      llvm::raw_string_ostream OS(Buf);
948      logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
949      OS.flush();
950      report_fatal_error(Buf);
951    }
952    FunctionName = *FunctionNameOrErr;
953    Expected<uint64_t> FunctionAddressOrErr = Function->getAddress();
954    if (!FunctionAddressOrErr) {
955      std::string Buf;
956      llvm::raw_string_ostream OS(Buf);
957      logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS);
958      OS.flush();
959      report_fatal_error(Buf);
960    }
961    FunctionAddress = *FunctionAddressOrErr;
962  } else {
963    FunctionAddress = COFF.getImageBase() + RF.BeginAddress;
964  }
965
966  SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
967
968  if (XDataRecord) {
969    Expected<StringRef> Name = XDataRecord->getName();
970    if (!Name) {
971      std::string Buf;
972      llvm::raw_string_ostream OS(Buf);
973      logAllUnhandledErrors(Name.takeError(), OS);
974      OS.flush();
975      report_fatal_error(Buf);
976    }
977
978    Expected<uint64_t> AddressOrErr = XDataRecord->getAddress();
979    if (!AddressOrErr) {
980      std::string Buf;
981      llvm::raw_string_ostream OS(Buf);
982      logAllUnhandledErrors(AddressOrErr.takeError(), OS);
983      OS.flush();
984      report_fatal_error(Buf);
985    }
986    uint64_t Address = *AddressOrErr;
987
988    SW.printString("ExceptionRecord", formatSymbol(*Name, Address));
989
990    Expected<section_iterator> SIOrErr = XDataRecord->getSection();
991    if (!SIOrErr) {
992      // TODO: Actually report errors helpfully.
993      consumeError(SIOrErr.takeError());
994      return false;
995    }
996    section_iterator SI = *SIOrErr;
997
998    // FIXME: Do we need to add an offset from the relocation?
999    return dumpXDataRecord(COFF, *SI, FunctionAddress,
1000                           RF.ExceptionInformationRVA());
1001  } else {
1002    uint64_t Address = COFF.getImageBase() + RF.ExceptionInformationRVA();
1003    SW.printString("ExceptionRecord", formatSymbol("", Address));
1004
1005    ErrorOr<SectionRef> Section = getSectionContaining(COFF, Address);
1006    if (!Section)
1007      return false;
1008
1009    return dumpXDataRecord(COFF, *Section, FunctionAddress, Address);
1010  }
1011}
1012
1013bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
1014                              const SectionRef Section, uint64_t Offset,
1015                              unsigned Index, const RuntimeFunction &RF) {
1016  assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
1017          RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
1018         "unpacked entry cannot be treated as a packed entry");
1019
1020  ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
1021  if (!Function)
1022    Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
1023
1024  StringRef FunctionName;
1025  uint64_t FunctionAddress;
1026  if (Function) {
1027    Expected<StringRef> FunctionNameOrErr = Function->getName();
1028    if (!FunctionNameOrErr) {
1029      std::string Buf;
1030      llvm::raw_string_ostream OS(Buf);
1031      logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
1032      OS.flush();
1033      report_fatal_error(Buf);
1034    }
1035    FunctionName = *FunctionNameOrErr;
1036    Expected<uint64_t> FunctionAddressOrErr = Function->getAddress();
1037    if (!FunctionAddressOrErr) {
1038      std::string Buf;
1039      llvm::raw_string_ostream OS(Buf);
1040      logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS);
1041      OS.flush();
1042      report_fatal_error(Buf);
1043    }
1044    FunctionAddress = *FunctionAddressOrErr;
1045  } else {
1046    FunctionAddress = COFF.getPE32Header()->ImageBase + RF.BeginAddress;
1047  }
1048
1049  SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
1050  if (!isAArch64)
1051    SW.printBoolean("Fragment",
1052                    RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
1053  SW.printNumber("FunctionLength", RF.FunctionLength());
1054  SW.startLine() << "ReturnType: " << RF.Ret() << '\n';
1055  SW.printBoolean("HomedParameters", RF.H());
1056  SW.startLine() << "SavedRegisters: ";
1057                 printRegisters(SavedRegisterMask(RF));
1058  OS << '\n';
1059  SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2);
1060
1061  return true;
1062}
1063
1064bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
1065                                     const SectionRef Section, unsigned Index,
1066                                     ArrayRef<uint8_t> Contents) {
1067  uint64_t Offset = PDataEntrySize * Index;
1068  const ulittle32_t *Data =
1069    reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
1070
1071  const RuntimeFunction Entry(Data);
1072  DictScope RFS(SW, "RuntimeFunction");
1073  if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
1074    return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
1075  if (isAArch64) {
1076    SW.startLine() << "Packed unwind data not yet supported for ARM64\n";
1077    return true;
1078  }
1079  return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
1080}
1081
1082void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
1083                                const SectionRef Section) {
1084  ArrayRef<uint8_t> Contents;
1085  if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
1086    return;
1087
1088  if (Contents.size() % PDataEntrySize) {
1089    errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n";
1090    return;
1091  }
1092
1093  for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI)
1094    if (!dumpProcedureDataEntry(COFF, Section, EI, Contents))
1095      break;
1096}
1097
1098Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
1099  for (const auto &Section : COFF.sections()) {
1100    Expected<StringRef> NameOrErr =
1101        COFF.getSectionName(COFF.getCOFFSection(Section));
1102    if (!NameOrErr)
1103      return NameOrErr.takeError();
1104
1105    if (NameOrErr->startswith(".pdata"))
1106      dumpProcedureData(COFF, Section);
1107  }
1108  return Error::success();
1109}
1110}
1111}
1112}
1113