Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libunwind/src/CompactUnwinder.hpp
35154 views
1
//===----------------------------------------------------------------------===//
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
// Does runtime stack unwinding using compact unwind encodings.
9
//
10
//===----------------------------------------------------------------------===//
11
12
#ifndef __COMPACT_UNWINDER_HPP__
13
#define __COMPACT_UNWINDER_HPP__
14
15
#include <stdint.h>
16
#include <stdlib.h>
17
18
#include <libunwind.h>
19
#include <mach-o/compact_unwind_encoding.h>
20
21
#include "Registers.hpp"
22
#include "libunwind_ext.h"
23
24
#define EXTRACT_BITS(value, mask) \
25
((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
26
27
namespace libunwind {
28
29
#if defined(_LIBUNWIND_TARGET_I386)
30
/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
31
/// unwind) by modifying a Registers_x86 register set
32
template <typename A>
33
class CompactUnwinder_x86 {
34
public:
35
36
static int stepWithCompactEncoding(compact_unwind_encoding_t info,
37
uint32_t functionStart, A &addressSpace,
38
Registers_x86 &registers);
39
40
private:
41
typename A::pint_t pint_t;
42
43
static void frameUnwind(A &addressSpace, Registers_x86 &registers);
44
static void framelessUnwind(A &addressSpace,
45
typename A::pint_t returnAddressLocation,
46
Registers_x86 &registers);
47
static int
48
stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
49
uint32_t functionStart, A &addressSpace,
50
Registers_x86 &registers);
51
static int stepWithCompactEncodingFrameless(
52
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
53
A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
54
};
55
56
template <typename A>
57
int CompactUnwinder_x86<A>::stepWithCompactEncoding(
58
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
59
A &addressSpace, Registers_x86 &registers) {
60
switch (compactEncoding & UNWIND_X86_MODE_MASK) {
61
case UNWIND_X86_MODE_EBP_FRAME:
62
return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
63
addressSpace, registers);
64
case UNWIND_X86_MODE_STACK_IMMD:
65
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
66
addressSpace, registers, false);
67
case UNWIND_X86_MODE_STACK_IND:
68
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
69
addressSpace, registers, true);
70
}
71
_LIBUNWIND_ABORT("invalid compact unwind encoding");
72
}
73
74
template <typename A>
75
int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
76
compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
77
A &addressSpace, Registers_x86 &registers) {
78
uint32_t savedRegistersOffset =
79
EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
80
uint32_t savedRegistersLocations =
81
EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
82
83
uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
84
for (int i = 0; i < 5; ++i) {
85
switch (savedRegistersLocations & 0x7) {
86
case UNWIND_X86_REG_NONE:
87
// no register saved in this slot
88
break;
89
case UNWIND_X86_REG_EBX:
90
registers.setEBX(addressSpace.get32(savedRegisters));
91
break;
92
case UNWIND_X86_REG_ECX:
93
registers.setECX(addressSpace.get32(savedRegisters));
94
break;
95
case UNWIND_X86_REG_EDX:
96
registers.setEDX(addressSpace.get32(savedRegisters));
97
break;
98
case UNWIND_X86_REG_EDI:
99
registers.setEDI(addressSpace.get32(savedRegisters));
100
break;
101
case UNWIND_X86_REG_ESI:
102
registers.setESI(addressSpace.get32(savedRegisters));
103
break;
104
default:
105
(void)functionStart;
106
_LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
107
"function starting at 0x%X",
108
compactEncoding, functionStart);
109
_LIBUNWIND_ABORT("invalid compact unwind encoding");
110
}
111
savedRegisters += 4;
112
savedRegistersLocations = (savedRegistersLocations >> 3);
113
}
114
frameUnwind(addressSpace, registers);
115
return UNW_STEP_SUCCESS;
116
}
117
118
template <typename A>
119
int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
120
compact_unwind_encoding_t encoding, uint32_t functionStart,
121
A &addressSpace, Registers_x86 &registers, bool indirectStackSize) {
122
uint32_t stackSizeEncoded =
123
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
124
uint32_t stackAdjust =
125
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
126
uint32_t regCount =
127
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
128
uint32_t permutation =
129
EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
130
uint32_t stackSize = stackSizeEncoded * 4;
131
if (indirectStackSize) {
132
// stack size is encoded in subl $xxx,%esp instruction
133
uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
134
stackSize = subl + 4 * stackAdjust;
135
}
136
// decompress permutation
137
uint32_t permunreg[6];
138
switch (regCount) {
139
case 6:
140
permunreg[0] = permutation / 120;
141
permutation -= (permunreg[0] * 120);
142
permunreg[1] = permutation / 24;
143
permutation -= (permunreg[1] * 24);
144
permunreg[2] = permutation / 6;
145
permutation -= (permunreg[2] * 6);
146
permunreg[3] = permutation / 2;
147
permutation -= (permunreg[3] * 2);
148
permunreg[4] = permutation;
149
permunreg[5] = 0;
150
break;
151
case 5:
152
permunreg[0] = permutation / 120;
153
permutation -= (permunreg[0] * 120);
154
permunreg[1] = permutation / 24;
155
permutation -= (permunreg[1] * 24);
156
permunreg[2] = permutation / 6;
157
permutation -= (permunreg[2] * 6);
158
permunreg[3] = permutation / 2;
159
permutation -= (permunreg[3] * 2);
160
permunreg[4] = permutation;
161
break;
162
case 4:
163
permunreg[0] = permutation / 60;
164
permutation -= (permunreg[0] * 60);
165
permunreg[1] = permutation / 12;
166
permutation -= (permunreg[1] * 12);
167
permunreg[2] = permutation / 3;
168
permutation -= (permunreg[2] * 3);
169
permunreg[3] = permutation;
170
break;
171
case 3:
172
permunreg[0] = permutation / 20;
173
permutation -= (permunreg[0] * 20);
174
permunreg[1] = permutation / 4;
175
permutation -= (permunreg[1] * 4);
176
permunreg[2] = permutation;
177
break;
178
case 2:
179
permunreg[0] = permutation / 5;
180
permutation -= (permunreg[0] * 5);
181
permunreg[1] = permutation;
182
break;
183
case 1:
184
permunreg[0] = permutation;
185
break;
186
}
187
// re-number registers back to standard numbers
188
int registersSaved[6];
189
bool used[7] = { false, false, false, false, false, false, false };
190
for (uint32_t i = 0; i < regCount; ++i) {
191
uint32_t renum = 0;
192
for (int u = 1; u < 7; ++u) {
193
if (!used[u]) {
194
if (renum == permunreg[i]) {
195
registersSaved[i] = u;
196
used[u] = true;
197
break;
198
}
199
++renum;
200
}
201
}
202
}
203
uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
204
for (uint32_t i = 0; i < regCount; ++i) {
205
switch (registersSaved[i]) {
206
case UNWIND_X86_REG_EBX:
207
registers.setEBX(addressSpace.get32(savedRegisters));
208
break;
209
case UNWIND_X86_REG_ECX:
210
registers.setECX(addressSpace.get32(savedRegisters));
211
break;
212
case UNWIND_X86_REG_EDX:
213
registers.setEDX(addressSpace.get32(savedRegisters));
214
break;
215
case UNWIND_X86_REG_EDI:
216
registers.setEDI(addressSpace.get32(savedRegisters));
217
break;
218
case UNWIND_X86_REG_ESI:
219
registers.setESI(addressSpace.get32(savedRegisters));
220
break;
221
case UNWIND_X86_REG_EBP:
222
registers.setEBP(addressSpace.get32(savedRegisters));
223
break;
224
default:
225
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
226
"function starting at 0x%X",
227
encoding, functionStart);
228
_LIBUNWIND_ABORT("invalid compact unwind encoding");
229
}
230
savedRegisters += 4;
231
}
232
framelessUnwind(addressSpace, savedRegisters, registers);
233
return UNW_STEP_SUCCESS;
234
}
235
236
237
template <typename A>
238
void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
239
Registers_x86 &registers) {
240
typename A::pint_t bp = registers.getEBP();
241
// ebp points to old ebp
242
registers.setEBP(addressSpace.get32(bp));
243
// old esp is ebp less saved ebp and return address
244
registers.setSP((uint32_t)bp + 8);
245
// pop return address into eip
246
registers.setIP(addressSpace.get32(bp + 4));
247
}
248
249
template <typename A>
250
void CompactUnwinder_x86<A>::framelessUnwind(
251
A &addressSpace, typename A::pint_t returnAddressLocation,
252
Registers_x86 &registers) {
253
// return address is on stack after last saved register
254
registers.setIP(addressSpace.get32(returnAddressLocation));
255
// old esp is before return address
256
registers.setSP((uint32_t)returnAddressLocation + 4);
257
}
258
#endif // _LIBUNWIND_TARGET_I386
259
260
261
#if defined(_LIBUNWIND_TARGET_X86_64)
262
/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
263
/// unwind) by modifying a Registers_x86_64 register set
264
template <typename A>
265
class CompactUnwinder_x86_64 {
266
public:
267
268
static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
269
uint64_t functionStart, A &addressSpace,
270
Registers_x86_64 &registers);
271
272
private:
273
typename A::pint_t pint_t;
274
275
static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
276
static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
277
Registers_x86_64 &registers);
278
static int
279
stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
280
uint64_t functionStart, A &addressSpace,
281
Registers_x86_64 &registers);
282
static int stepWithCompactEncodingFrameless(
283
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
284
A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
285
};
286
287
template <typename A>
288
int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
289
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
290
A &addressSpace, Registers_x86_64 &registers) {
291
switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
292
case UNWIND_X86_64_MODE_RBP_FRAME:
293
return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
294
addressSpace, registers);
295
case UNWIND_X86_64_MODE_STACK_IMMD:
296
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
297
addressSpace, registers, false);
298
case UNWIND_X86_64_MODE_STACK_IND:
299
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
300
addressSpace, registers, true);
301
}
302
_LIBUNWIND_ABORT("invalid compact unwind encoding");
303
}
304
305
template <typename A>
306
int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
307
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
308
A &addressSpace, Registers_x86_64 &registers) {
309
uint32_t savedRegistersOffset =
310
EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
311
uint32_t savedRegistersLocations =
312
EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
313
314
uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
315
for (int i = 0; i < 5; ++i) {
316
switch (savedRegistersLocations & 0x7) {
317
case UNWIND_X86_64_REG_NONE:
318
// no register saved in this slot
319
break;
320
case UNWIND_X86_64_REG_RBX:
321
registers.setRBX(addressSpace.get64(savedRegisters));
322
break;
323
case UNWIND_X86_64_REG_R12:
324
registers.setR12(addressSpace.get64(savedRegisters));
325
break;
326
case UNWIND_X86_64_REG_R13:
327
registers.setR13(addressSpace.get64(savedRegisters));
328
break;
329
case UNWIND_X86_64_REG_R14:
330
registers.setR14(addressSpace.get64(savedRegisters));
331
break;
332
case UNWIND_X86_64_REG_R15:
333
registers.setR15(addressSpace.get64(savedRegisters));
334
break;
335
default:
336
(void)functionStart;
337
_LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
338
"function starting at 0x%llX",
339
compactEncoding, functionStart);
340
_LIBUNWIND_ABORT("invalid compact unwind encoding");
341
}
342
savedRegisters += 8;
343
savedRegistersLocations = (savedRegistersLocations >> 3);
344
}
345
frameUnwind(addressSpace, registers);
346
return UNW_STEP_SUCCESS;
347
}
348
349
template <typename A>
350
int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
351
compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
352
Registers_x86_64 &registers, bool indirectStackSize) {
353
uint32_t stackSizeEncoded =
354
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
355
uint32_t stackAdjust =
356
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
357
uint32_t regCount =
358
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
359
uint32_t permutation =
360
EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
361
uint32_t stackSize = stackSizeEncoded * 8;
362
if (indirectStackSize) {
363
// stack size is encoded in subl $xxx,%esp instruction
364
uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
365
stackSize = subl + 8 * stackAdjust;
366
}
367
// decompress permutation
368
uint32_t permunreg[6];
369
switch (regCount) {
370
case 6:
371
permunreg[0] = permutation / 120;
372
permutation -= (permunreg[0] * 120);
373
permunreg[1] = permutation / 24;
374
permutation -= (permunreg[1] * 24);
375
permunreg[2] = permutation / 6;
376
permutation -= (permunreg[2] * 6);
377
permunreg[3] = permutation / 2;
378
permutation -= (permunreg[3] * 2);
379
permunreg[4] = permutation;
380
permunreg[5] = 0;
381
break;
382
case 5:
383
permunreg[0] = permutation / 120;
384
permutation -= (permunreg[0] * 120);
385
permunreg[1] = permutation / 24;
386
permutation -= (permunreg[1] * 24);
387
permunreg[2] = permutation / 6;
388
permutation -= (permunreg[2] * 6);
389
permunreg[3] = permutation / 2;
390
permutation -= (permunreg[3] * 2);
391
permunreg[4] = permutation;
392
break;
393
case 4:
394
permunreg[0] = permutation / 60;
395
permutation -= (permunreg[0] * 60);
396
permunreg[1] = permutation / 12;
397
permutation -= (permunreg[1] * 12);
398
permunreg[2] = permutation / 3;
399
permutation -= (permunreg[2] * 3);
400
permunreg[3] = permutation;
401
break;
402
case 3:
403
permunreg[0] = permutation / 20;
404
permutation -= (permunreg[0] * 20);
405
permunreg[1] = permutation / 4;
406
permutation -= (permunreg[1] * 4);
407
permunreg[2] = permutation;
408
break;
409
case 2:
410
permunreg[0] = permutation / 5;
411
permutation -= (permunreg[0] * 5);
412
permunreg[1] = permutation;
413
break;
414
case 1:
415
permunreg[0] = permutation;
416
break;
417
}
418
// re-number registers back to standard numbers
419
int registersSaved[6];
420
bool used[7] = { false, false, false, false, false, false, false };
421
for (uint32_t i = 0; i < regCount; ++i) {
422
uint32_t renum = 0;
423
for (int u = 1; u < 7; ++u) {
424
if (!used[u]) {
425
if (renum == permunreg[i]) {
426
registersSaved[i] = u;
427
used[u] = true;
428
break;
429
}
430
++renum;
431
}
432
}
433
}
434
uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
435
for (uint32_t i = 0; i < regCount; ++i) {
436
switch (registersSaved[i]) {
437
case UNWIND_X86_64_REG_RBX:
438
registers.setRBX(addressSpace.get64(savedRegisters));
439
break;
440
case UNWIND_X86_64_REG_R12:
441
registers.setR12(addressSpace.get64(savedRegisters));
442
break;
443
case UNWIND_X86_64_REG_R13:
444
registers.setR13(addressSpace.get64(savedRegisters));
445
break;
446
case UNWIND_X86_64_REG_R14:
447
registers.setR14(addressSpace.get64(savedRegisters));
448
break;
449
case UNWIND_X86_64_REG_R15:
450
registers.setR15(addressSpace.get64(savedRegisters));
451
break;
452
case UNWIND_X86_64_REG_RBP:
453
registers.setRBP(addressSpace.get64(savedRegisters));
454
break;
455
default:
456
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
457
"function starting at 0x%llX",
458
encoding, functionStart);
459
_LIBUNWIND_ABORT("invalid compact unwind encoding");
460
}
461
savedRegisters += 8;
462
}
463
framelessUnwind(addressSpace, savedRegisters, registers);
464
return UNW_STEP_SUCCESS;
465
}
466
467
468
template <typename A>
469
void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
470
Registers_x86_64 &registers) {
471
uint64_t rbp = registers.getRBP();
472
// ebp points to old ebp
473
registers.setRBP(addressSpace.get64(rbp));
474
// old esp is ebp less saved ebp and return address
475
registers.setSP(rbp + 16);
476
// pop return address into eip
477
registers.setIP(addressSpace.get64(rbp + 8));
478
}
479
480
template <typename A>
481
void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
482
uint64_t returnAddressLocation,
483
Registers_x86_64 &registers) {
484
// return address is on stack after last saved register
485
registers.setIP(addressSpace.get64(returnAddressLocation));
486
// old esp is before return address
487
registers.setSP(returnAddressLocation + 8);
488
}
489
#endif // _LIBUNWIND_TARGET_X86_64
490
491
492
493
#if defined(_LIBUNWIND_TARGET_AARCH64)
494
/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
495
/// unwind) by modifying a Registers_arm64 register set
496
template <typename A>
497
class CompactUnwinder_arm64 {
498
public:
499
500
static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
501
uint64_t functionStart, A &addressSpace,
502
Registers_arm64 &registers);
503
504
private:
505
typename A::pint_t pint_t;
506
507
static int
508
stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
509
uint64_t functionStart, A &addressSpace,
510
Registers_arm64 &registers);
511
static int stepWithCompactEncodingFrameless(
512
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
513
A &addressSpace, Registers_arm64 &registers);
514
};
515
516
template <typename A>
517
int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
518
compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
519
A &addressSpace, Registers_arm64 &registers) {
520
switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
521
case UNWIND_ARM64_MODE_FRAME:
522
return stepWithCompactEncodingFrame(compactEncoding, functionStart,
523
addressSpace, registers);
524
case UNWIND_ARM64_MODE_FRAMELESS:
525
return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
526
addressSpace, registers);
527
}
528
_LIBUNWIND_ABORT("invalid compact unwind encoding");
529
}
530
531
template <typename A>
532
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
533
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
534
Registers_arm64 &registers) {
535
uint32_t stackSize =
536
16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
537
538
uint64_t savedRegisterLoc = registers.getSP() + stackSize;
539
540
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
541
registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
542
savedRegisterLoc -= 8;
543
registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));
544
savedRegisterLoc -= 8;
545
}
546
if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
547
registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));
548
savedRegisterLoc -= 8;
549
registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));
550
savedRegisterLoc -= 8;
551
}
552
if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
553
registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));
554
savedRegisterLoc -= 8;
555
registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));
556
savedRegisterLoc -= 8;
557
}
558
if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
559
registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));
560
savedRegisterLoc -= 8;
561
registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));
562
savedRegisterLoc -= 8;
563
}
564
if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
565
registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));
566
savedRegisterLoc -= 8;
567
registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));
568
savedRegisterLoc -= 8;
569
}
570
571
if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
572
registers.setFloatRegister(UNW_AARCH64_V8,
573
addressSpace.getDouble(savedRegisterLoc));
574
savedRegisterLoc -= 8;
575
registers.setFloatRegister(UNW_AARCH64_V9,
576
addressSpace.getDouble(savedRegisterLoc));
577
savedRegisterLoc -= 8;
578
}
579
if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
580
registers.setFloatRegister(UNW_AARCH64_V10,
581
addressSpace.getDouble(savedRegisterLoc));
582
savedRegisterLoc -= 8;
583
registers.setFloatRegister(UNW_AARCH64_V11,
584
addressSpace.getDouble(savedRegisterLoc));
585
savedRegisterLoc -= 8;
586
}
587
if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
588
registers.setFloatRegister(UNW_AARCH64_V12,
589
addressSpace.getDouble(savedRegisterLoc));
590
savedRegisterLoc -= 8;
591
registers.setFloatRegister(UNW_AARCH64_V13,
592
addressSpace.getDouble(savedRegisterLoc));
593
savedRegisterLoc -= 8;
594
}
595
if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
596
registers.setFloatRegister(UNW_AARCH64_V14,
597
addressSpace.getDouble(savedRegisterLoc));
598
savedRegisterLoc -= 8;
599
registers.setFloatRegister(UNW_AARCH64_V15,
600
addressSpace.getDouble(savedRegisterLoc));
601
savedRegisterLoc -= 8;
602
}
603
604
// subtract stack size off of sp
605
registers.setSP(savedRegisterLoc);
606
607
// set pc to be value in lr
608
registers.setIP(registers.getRegister(UNW_AARCH64_LR));
609
610
return UNW_STEP_SUCCESS;
611
}
612
613
template <typename A>
614
int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
615
compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
616
Registers_arm64 &registers) {
617
uint64_t savedRegisterLoc = registers.getFP() - 8;
618
619
if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
620
registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
621
savedRegisterLoc -= 8;
622
registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));
623
savedRegisterLoc -= 8;
624
}
625
if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
626
registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));
627
savedRegisterLoc -= 8;
628
registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));
629
savedRegisterLoc -= 8;
630
}
631
if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
632
registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));
633
savedRegisterLoc -= 8;
634
registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));
635
savedRegisterLoc -= 8;
636
}
637
if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
638
registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));
639
savedRegisterLoc -= 8;
640
registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));
641
savedRegisterLoc -= 8;
642
}
643
if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
644
registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));
645
savedRegisterLoc -= 8;
646
registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));
647
savedRegisterLoc -= 8;
648
}
649
650
if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
651
registers.setFloatRegister(UNW_AARCH64_V8,
652
addressSpace.getDouble(savedRegisterLoc));
653
savedRegisterLoc -= 8;
654
registers.setFloatRegister(UNW_AARCH64_V9,
655
addressSpace.getDouble(savedRegisterLoc));
656
savedRegisterLoc -= 8;
657
}
658
if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
659
registers.setFloatRegister(UNW_AARCH64_V10,
660
addressSpace.getDouble(savedRegisterLoc));
661
savedRegisterLoc -= 8;
662
registers.setFloatRegister(UNW_AARCH64_V11,
663
addressSpace.getDouble(savedRegisterLoc));
664
savedRegisterLoc -= 8;
665
}
666
if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
667
registers.setFloatRegister(UNW_AARCH64_V12,
668
addressSpace.getDouble(savedRegisterLoc));
669
savedRegisterLoc -= 8;
670
registers.setFloatRegister(UNW_AARCH64_V13,
671
addressSpace.getDouble(savedRegisterLoc));
672
savedRegisterLoc -= 8;
673
}
674
if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
675
registers.setFloatRegister(UNW_AARCH64_V14,
676
addressSpace.getDouble(savedRegisterLoc));
677
savedRegisterLoc -= 8;
678
registers.setFloatRegister(UNW_AARCH64_V15,
679
addressSpace.getDouble(savedRegisterLoc));
680
savedRegisterLoc -= 8;
681
}
682
683
uint64_t fp = registers.getFP();
684
// fp points to old fp
685
registers.setFP(addressSpace.get64(fp));
686
// old sp is fp less saved fp and lr
687
registers.setSP(fp + 16);
688
// pop return address into pc
689
registers.setIP(addressSpace.get64(fp + 8));
690
691
return UNW_STEP_SUCCESS;
692
}
693
#endif // _LIBUNWIND_TARGET_AARCH64
694
695
696
} // namespace libunwind
697
698
#endif // __COMPACT_UNWINDER_HPP__
699
700