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