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