1 //===-------------------------- CompactUnwinder.hpp -----------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 // Does runtime stack unwinding using compact unwind encodings.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef __COMPACT_UNWINDER_HPP__
14 #define __COMPACT_UNWINDER_HPP__
15
16 #include <stdint.h>
17 #include <stdlib.h>
18
19 #include <libunwind.h>
20 #include <mach-o/compact_unwind_encoding.h>
21
22 #include "AddressSpace.hpp"
23 #include "Registers.hpp"
24
25 #define EXTRACT_BITS(value, mask) \
26 ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
27
28 namespace libunwind {
29
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 ®isters);
39
40 private:
41 typename A::pint_t pint_t;
42
43 static void frameUnwind(A &addressSpace, Registers_x86 ®isters);
44 static void framelessUnwind(A &addressSpace,
45 typename A::pint_t returnAddressLocation,
46 Registers_x86 ®isters);
47 static int
48 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
49 uint32_t functionStart, A &addressSpace,
50 Registers_x86 ®isters);
51 static int stepWithCompactEncodingFrameless(
52 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
53 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);
54 };
55
56 template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers)57 int CompactUnwinder_x86<A>::stepWithCompactEncoding(
58 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
59 A &addressSpace, Registers_x86 ®isters) {
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>
stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers)75 int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
76 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
77 A &addressSpace, Registers_x86 ®isters) {
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\n",
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>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers,bool indirectStackSize)119 int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
120 compact_unwind_encoding_t encoding, uint32_t functionStart,
121 A &addressSpace, Registers_x86 ®isters, 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\n",
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>
frameUnwind(A & addressSpace,Registers_x86 & registers)238 void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
239 Registers_x86 ®isters) {
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>
framelessUnwind(A & addressSpace,typename A::pint_t returnAddressLocation,Registers_x86 & registers)250 void CompactUnwinder_x86<A>::framelessUnwind(
251 A &addressSpace, typename A::pint_t returnAddressLocation,
252 Registers_x86 ®isters) {
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
259
260 /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
261 /// unwind) by modifying a Registers_x86_64 register set
262 template <typename A>
263 class CompactUnwinder_x86_64 {
264 public:
265
266 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
267 uint64_t functionStart, A &addressSpace,
268 Registers_x86_64 ®isters);
269
270 private:
271 typename A::pint_t pint_t;
272
273 static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);
274 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
275 Registers_x86_64 ®isters);
276 static int
277 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
278 uint64_t functionStart, A &addressSpace,
279 Registers_x86_64 ®isters);
280 static int stepWithCompactEncodingFrameless(
281 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
282 A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);
283 };
284
285 template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers)286 int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
287 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
288 A &addressSpace, Registers_x86_64 ®isters) {
289 switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
290 case UNWIND_X86_64_MODE_RBP_FRAME:
291 return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
292 addressSpace, registers);
293 case UNWIND_X86_64_MODE_STACK_IMMD:
294 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
295 addressSpace, registers, false);
296 case UNWIND_X86_64_MODE_STACK_IND:
297 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
298 addressSpace, registers, true);
299 }
300 _LIBUNWIND_ABORT("invalid compact unwind encoding");
301 }
302
303 template <typename A>
stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers)304 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
305 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
306 A &addressSpace, Registers_x86_64 ®isters) {
307 uint32_t savedRegistersOffset =
308 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
309 uint32_t savedRegistersLocations =
310 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
311
312 uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
313 for (int i = 0; i < 5; ++i) {
314 switch (savedRegistersLocations & 0x7) {
315 case UNWIND_X86_64_REG_NONE:
316 // no register saved in this slot
317 break;
318 case UNWIND_X86_64_REG_RBX:
319 registers.setRBX(addressSpace.get64(savedRegisters));
320 break;
321 case UNWIND_X86_64_REG_R12:
322 registers.setR12(addressSpace.get64(savedRegisters));
323 break;
324 case UNWIND_X86_64_REG_R13:
325 registers.setR13(addressSpace.get64(savedRegisters));
326 break;
327 case UNWIND_X86_64_REG_R14:
328 registers.setR14(addressSpace.get64(savedRegisters));
329 break;
330 case UNWIND_X86_64_REG_R15:
331 registers.setR15(addressSpace.get64(savedRegisters));
332 break;
333 default:
334 (void)functionStart;
335 _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
336 "function starting at 0x%llX\n",
337 compactEncoding, functionStart);
338 _LIBUNWIND_ABORT("invalid compact unwind encoding");
339 }
340 savedRegisters += 8;
341 savedRegistersLocations = (savedRegistersLocations >> 3);
342 }
343 frameUnwind(addressSpace, registers);
344 return UNW_STEP_SUCCESS;
345 }
346
347 template <typename A>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers,bool indirectStackSize)348 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
349 compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
350 Registers_x86_64 ®isters, bool indirectStackSize) {
351 uint32_t stackSizeEncoded =
352 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
353 uint32_t stackAdjust =
354 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
355 uint32_t regCount =
356 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
357 uint32_t permutation =
358 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
359 uint32_t stackSize = stackSizeEncoded * 8;
360 if (indirectStackSize) {
361 // stack size is encoded in subl $xxx,%esp instruction
362 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
363 stackSize = subl + 8 * stackAdjust;
364 }
365 // decompress permutation
366 uint32_t permunreg[6];
367 switch (regCount) {
368 case 6:
369 permunreg[0] = permutation / 120;
370 permutation -= (permunreg[0] * 120);
371 permunreg[1] = permutation / 24;
372 permutation -= (permunreg[1] * 24);
373 permunreg[2] = permutation / 6;
374 permutation -= (permunreg[2] * 6);
375 permunreg[3] = permutation / 2;
376 permutation -= (permunreg[3] * 2);
377 permunreg[4] = permutation;
378 permunreg[5] = 0;
379 break;
380 case 5:
381 permunreg[0] = permutation / 120;
382 permutation -= (permunreg[0] * 120);
383 permunreg[1] = permutation / 24;
384 permutation -= (permunreg[1] * 24);
385 permunreg[2] = permutation / 6;
386 permutation -= (permunreg[2] * 6);
387 permunreg[3] = permutation / 2;
388 permutation -= (permunreg[3] * 2);
389 permunreg[4] = permutation;
390 break;
391 case 4:
392 permunreg[0] = permutation / 60;
393 permutation -= (permunreg[0] * 60);
394 permunreg[1] = permutation / 12;
395 permutation -= (permunreg[1] * 12);
396 permunreg[2] = permutation / 3;
397 permutation -= (permunreg[2] * 3);
398 permunreg[3] = permutation;
399 break;
400 case 3:
401 permunreg[0] = permutation / 20;
402 permutation -= (permunreg[0] * 20);
403 permunreg[1] = permutation / 4;
404 permutation -= (permunreg[1] * 4);
405 permunreg[2] = permutation;
406 break;
407 case 2:
408 permunreg[0] = permutation / 5;
409 permutation -= (permunreg[0] * 5);
410 permunreg[1] = permutation;
411 break;
412 case 1:
413 permunreg[0] = permutation;
414 break;
415 }
416 // re-number registers back to standard numbers
417 int registersSaved[6];
418 bool used[7] = { false, false, false, false, false, false, false };
419 for (uint32_t i = 0; i < regCount; ++i) {
420 uint32_t renum = 0;
421 for (int u = 1; u < 7; ++u) {
422 if (!used[u]) {
423 if (renum == permunreg[i]) {
424 registersSaved[i] = u;
425 used[u] = true;
426 break;
427 }
428 ++renum;
429 }
430 }
431 }
432 uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
433 for (uint32_t i = 0; i < regCount; ++i) {
434 switch (registersSaved[i]) {
435 case UNWIND_X86_64_REG_RBX:
436 registers.setRBX(addressSpace.get64(savedRegisters));
437 break;
438 case UNWIND_X86_64_REG_R12:
439 registers.setR12(addressSpace.get64(savedRegisters));
440 break;
441 case UNWIND_X86_64_REG_R13:
442 registers.setR13(addressSpace.get64(savedRegisters));
443 break;
444 case UNWIND_X86_64_REG_R14:
445 registers.setR14(addressSpace.get64(savedRegisters));
446 break;
447 case UNWIND_X86_64_REG_R15:
448 registers.setR15(addressSpace.get64(savedRegisters));
449 break;
450 case UNWIND_X86_64_REG_RBP:
451 registers.setRBP(addressSpace.get64(savedRegisters));
452 break;
453 default:
454 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
455 "function starting at 0x%llX\n",
456 encoding, functionStart);
457 _LIBUNWIND_ABORT("invalid compact unwind encoding");
458 }
459 savedRegisters += 8;
460 }
461 framelessUnwind(addressSpace, savedRegisters, registers);
462 return UNW_STEP_SUCCESS;
463 }
464
465
466 template <typename A>
frameUnwind(A & addressSpace,Registers_x86_64 & registers)467 void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
468 Registers_x86_64 ®isters) {
469 uint64_t rbp = registers.getRBP();
470 // ebp points to old ebp
471 registers.setRBP(addressSpace.get64(rbp));
472 // old esp is ebp less saved ebp and return address
473 registers.setSP(rbp + 16);
474 // pop return address into eip
475 registers.setIP(addressSpace.get64(rbp + 8));
476 }
477
478 template <typename A>
framelessUnwind(A & addressSpace,uint64_t returnAddressLocation,Registers_x86_64 & registers)479 void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
480 uint64_t returnAddressLocation,
481 Registers_x86_64 ®isters) {
482 // return address is on stack after last saved register
483 registers.setIP(addressSpace.get64(returnAddressLocation));
484 // old esp is before return address
485 registers.setSP(returnAddressLocation + 8);
486 }
487
488
489
490 /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
491 /// unwind) by modifying a Registers_arm64 register set
492 template <typename A>
493 class CompactUnwinder_arm64 {
494 public:
495
496 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
497 uint64_t functionStart, A &addressSpace,
498 Registers_arm64 ®isters);
499
500 private:
501 typename A::pint_t pint_t;
502
503 static int
504 stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
505 uint64_t functionStart, A &addressSpace,
506 Registers_arm64 ®isters);
507 static int stepWithCompactEncodingFrameless(
508 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
509 A &addressSpace, Registers_arm64 ®isters);
510 };
511
512 template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_arm64 & registers)513 int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
514 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
515 A &addressSpace, Registers_arm64 ®isters) {
516 switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
517 case UNWIND_ARM64_MODE_FRAME:
518 return stepWithCompactEncodingFrame(compactEncoding, functionStart,
519 addressSpace, registers);
520 case UNWIND_ARM64_MODE_FRAMELESS:
521 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
522 addressSpace, registers);
523 }
524 _LIBUNWIND_ABORT("invalid compact unwind encoding");
525 }
526
527 template <typename A>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint64_t,A & addressSpace,Registers_arm64 & registers)528 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
529 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
530 Registers_arm64 ®isters) {
531 uint32_t stackSize =
532 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
533
534 uint64_t savedRegisterLoc = registers.getSP() + stackSize;
535
536 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
537 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
538 savedRegisterLoc -= 8;
539 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
540 savedRegisterLoc -= 8;
541 }
542 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
543 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
544 savedRegisterLoc -= 8;
545 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
546 savedRegisterLoc -= 8;
547 }
548 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
549 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
550 savedRegisterLoc -= 8;
551 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
552 savedRegisterLoc -= 8;
553 }
554 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
555 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
556 savedRegisterLoc -= 8;
557 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
558 savedRegisterLoc -= 8;
559 }
560 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
561 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
562 savedRegisterLoc -= 8;
563 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
564 savedRegisterLoc -= 8;
565 }
566
567 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
568 registers.setFloatRegister(UNW_ARM64_D8,
569 addressSpace.getDouble(savedRegisterLoc));
570 savedRegisterLoc -= 8;
571 registers.setFloatRegister(UNW_ARM64_D9,
572 addressSpace.getDouble(savedRegisterLoc));
573 savedRegisterLoc -= 8;
574 }
575 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
576 registers.setFloatRegister(UNW_ARM64_D10,
577 addressSpace.getDouble(savedRegisterLoc));
578 savedRegisterLoc -= 8;
579 registers.setFloatRegister(UNW_ARM64_D11,
580 addressSpace.getDouble(savedRegisterLoc));
581 savedRegisterLoc -= 8;
582 }
583 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
584 registers.setFloatRegister(UNW_ARM64_D12,
585 addressSpace.getDouble(savedRegisterLoc));
586 savedRegisterLoc -= 8;
587 registers.setFloatRegister(UNW_ARM64_D13,
588 addressSpace.getDouble(savedRegisterLoc));
589 savedRegisterLoc -= 8;
590 }
591 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
592 registers.setFloatRegister(UNW_ARM64_D14,
593 addressSpace.getDouble(savedRegisterLoc));
594 savedRegisterLoc -= 8;
595 registers.setFloatRegister(UNW_ARM64_D15,
596 addressSpace.getDouble(savedRegisterLoc));
597 savedRegisterLoc -= 8;
598 }
599
600 // subtract stack size off of sp
601 registers.setSP(savedRegisterLoc);
602
603 // set pc to be value in lr
604 registers.setIP(registers.getRegister(UNW_ARM64_LR));
605
606 return UNW_STEP_SUCCESS;
607 }
608
609 template <typename A>
stepWithCompactEncodingFrame(compact_unwind_encoding_t encoding,uint64_t,A & addressSpace,Registers_arm64 & registers)610 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
611 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
612 Registers_arm64 ®isters) {
613 uint64_t savedRegisterLoc = registers.getFP() - 8;
614
615 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
616 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
617 savedRegisterLoc -= 8;
618 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
619 savedRegisterLoc -= 8;
620 }
621 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
622 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
623 savedRegisterLoc -= 8;
624 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
625 savedRegisterLoc -= 8;
626 }
627 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
628 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
629 savedRegisterLoc -= 8;
630 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
631 savedRegisterLoc -= 8;
632 }
633 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
634 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
635 savedRegisterLoc -= 8;
636 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
637 savedRegisterLoc -= 8;
638 }
639 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
640 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
641 savedRegisterLoc -= 8;
642 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
643 savedRegisterLoc -= 8;
644 }
645
646 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
647 registers.setFloatRegister(UNW_ARM64_D8,
648 addressSpace.getDouble(savedRegisterLoc));
649 savedRegisterLoc -= 8;
650 registers.setFloatRegister(UNW_ARM64_D9,
651 addressSpace.getDouble(savedRegisterLoc));
652 savedRegisterLoc -= 8;
653 }
654 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
655 registers.setFloatRegister(UNW_ARM64_D10,
656 addressSpace.getDouble(savedRegisterLoc));
657 savedRegisterLoc -= 8;
658 registers.setFloatRegister(UNW_ARM64_D11,
659 addressSpace.getDouble(savedRegisterLoc));
660 savedRegisterLoc -= 8;
661 }
662 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
663 registers.setFloatRegister(UNW_ARM64_D12,
664 addressSpace.getDouble(savedRegisterLoc));
665 savedRegisterLoc -= 8;
666 registers.setFloatRegister(UNW_ARM64_D13,
667 addressSpace.getDouble(savedRegisterLoc));
668 savedRegisterLoc -= 8;
669 }
670 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
671 registers.setFloatRegister(UNW_ARM64_D14,
672 addressSpace.getDouble(savedRegisterLoc));
673 savedRegisterLoc -= 8;
674 registers.setFloatRegister(UNW_ARM64_D15,
675 addressSpace.getDouble(savedRegisterLoc));
676 savedRegisterLoc -= 8;
677 }
678
679 uint64_t fp = registers.getFP();
680 // fp points to old fp
681 registers.setFP(addressSpace.get64(fp));
682 // old sp is fp less saved fp and lr
683 registers.setSP(fp + 16);
684 // pop return address into pc
685 registers.setIP(addressSpace.get64(fp + 8));
686
687 return UNW_STEP_SUCCESS;
688 }
689
690
691 } // namespace libunwind
692
693 #endif // __COMPACT_UNWINDER_HPP__
694