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
27namespace 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
32template <typename A>
33class CompactUnwinder_x86 {
34public:
35
36 static int stepWithCompactEncoding(compact_unwind_encoding_t info,
37 uint32_t functionStart, A &addressSpace,
38 Registers_x86 &registers);
39
40private:
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
56template <typename A>
57int 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
74template <typename A>
75int 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
118template <typename A>
119int 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
237template <typename A>
238void 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
249template <typename A>
250void 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
264template <typename A>
265class CompactUnwinder_x86_64 {
266public:
267
268 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
269 uint64_t functionStart, A &addressSpace,
270 Registers_x86_64 &registers);
271
272private:
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
287template <typename A>
288int 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, indirectStackSize: false);
298 case UNWIND_X86_64_MODE_STACK_IND:
299 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
300 addressSpace, registers, indirectStackSize: true);
301 }
302 _LIBUNWIND_ABORT("invalid compact unwind encoding");
303}
304
305template <typename A>
306int 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
349template <typename A>
350int 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, returnAddressLocation: savedRegisters, registers);
464 return UNW_STEP_SUCCESS;
465}
466
467
468template <typename A>
469void 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
480template <typename A>
481void 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
496template <typename A>
497class CompactUnwinder_arm64 {
498public:
499
500 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
501 uint64_t functionStart, A &addressSpace,
502 Registers_arm64 &registers);
503
504private:
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
516template <typename A>
517int 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
531template <typename A>
532int 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
613template <typename A>
614int 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