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