blob: 1be1b0be1292c866c2e7a030f3072122bafea764 [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===-------------------------- 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
28namespace libunwind {
29
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +000030#if defined(_LIBUNWIND_TARGET_I386)
Saleem Abdulrasool17552662015-04-24 19:39:17 +000031/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
32/// unwind) by modifying a Registers_x86 register set
33template <typename A>
34class CompactUnwinder_x86 {
35public:
36
37 static int stepWithCompactEncoding(compact_unwind_encoding_t info,
38 uint32_t functionStart, A &addressSpace,
39 Registers_x86 &registers);
40
41private:
42 typename A::pint_t pint_t;
43
44 static void frameUnwind(A &addressSpace, Registers_x86 &registers);
45 static void framelessUnwind(A &addressSpace,
46 typename A::pint_t returnAddressLocation,
47 Registers_x86 &registers);
48 static int
49 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
50 uint32_t functionStart, A &addressSpace,
51 Registers_x86 &registers);
52 static int stepWithCompactEncodingFrameless(
53 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
54 A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
55};
56
57template <typename A>
58int CompactUnwinder_x86<A>::stepWithCompactEncoding(
59 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
60 A &addressSpace, Registers_x86 &registers) {
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
75template <typename A>
76int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
77 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
78 A &addressSpace, Registers_x86 &registers) {
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 "
Ed Maste41bc5a72016-08-30 15:38:10 +0000108 "function starting at 0x%X",
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000109 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
119template <typename A>
120int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
121 compact_unwind_encoding_t encoding, uint32_t functionStart,
122 A &addressSpace, Registers_x86 &registers, 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 "
Ed Maste41bc5a72016-08-30 15:38:10 +0000227 "function starting at 0x%X",
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000228 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
238template <typename A>
239void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
240 Registers_x86 &registers) {
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
250template <typename A>
251void CompactUnwinder_x86<A>::framelessUnwind(
252 A &addressSpace, typename A::pint_t returnAddressLocation,
253 Registers_x86 &registers) {
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}
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +0000259#endif // _LIBUNWIND_TARGET_I386
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000260
261
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +0000262#if defined(_LIBUNWIND_TARGET_X86_64)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000263/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
264/// unwind) by modifying a Registers_x86_64 register set
265template <typename A>
266class CompactUnwinder_x86_64 {
267public:
268
269 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
270 uint64_t functionStart, A &addressSpace,
271 Registers_x86_64 &registers);
272
273private:
274 typename A::pint_t pint_t;
275
276 static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
277 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
278 Registers_x86_64 &registers);
279 static int
280 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
281 uint64_t functionStart, A &addressSpace,
282 Registers_x86_64 &registers);
283 static int stepWithCompactEncodingFrameless(
284 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
285 A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
286};
287
288template <typename A>
289int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
290 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
291 A &addressSpace, Registers_x86_64 &registers) {
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
306template <typename A>
307int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
308 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
309 A &addressSpace, Registers_x86_64 &registers) {
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 "
Ed Maste41bc5a72016-08-30 15:38:10 +0000339 "function starting at 0x%llX",
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000340 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
350template <typename A>
351int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
352 compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
353 Registers_x86_64 &registers, 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 "
Ed Maste41bc5a72016-08-30 15:38:10 +0000458 "function starting at 0x%llX",
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000459 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
469template <typename A>
470void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
471 Registers_x86_64 &registers) {
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
481template <typename A>
482void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
483 uint64_t returnAddressLocation,
484 Registers_x86_64 &registers) {
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}
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +0000490#endif // _LIBUNWIND_TARGET_X86_64
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000491
492
493
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +0000494#if defined(_LIBUNWIND_TARGET_AARCH64)
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000495/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
496/// unwind) by modifying a Registers_arm64 register set
497template <typename A>
498class CompactUnwinder_arm64 {
499public:
500
501 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
502 uint64_t functionStart, A &addressSpace,
503 Registers_arm64 &registers);
504
505private:
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 &registers);
512 static int stepWithCompactEncodingFrameless(
513 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
514 A &addressSpace, Registers_arm64 &registers);
515};
516
517template <typename A>
518int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
519 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
520 A &addressSpace, Registers_arm64 &registers) {
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
532template <typename A>
533int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
534 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
535 Registers_arm64 &registers) {
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_ARM64_X19, addressSpace.get64(savedRegisterLoc));
543 savedRegisterLoc -= 8;
544 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
545 savedRegisterLoc -= 8;
546 }
547 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
548 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
549 savedRegisterLoc -= 8;
550 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
551 savedRegisterLoc -= 8;
552 }
553 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
554 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
555 savedRegisterLoc -= 8;
556 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
557 savedRegisterLoc -= 8;
558 }
559 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
560 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
561 savedRegisterLoc -= 8;
562 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
563 savedRegisterLoc -= 8;
564 }
565 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
566 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
567 savedRegisterLoc -= 8;
568 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
569 savedRegisterLoc -= 8;
570 }
571
572 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
573 registers.setFloatRegister(UNW_ARM64_D8,
574 addressSpace.getDouble(savedRegisterLoc));
575 savedRegisterLoc -= 8;
576 registers.setFloatRegister(UNW_ARM64_D9,
577 addressSpace.getDouble(savedRegisterLoc));
578 savedRegisterLoc -= 8;
579 }
580 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
581 registers.setFloatRegister(UNW_ARM64_D10,
582 addressSpace.getDouble(savedRegisterLoc));
583 savedRegisterLoc -= 8;
584 registers.setFloatRegister(UNW_ARM64_D11,
585 addressSpace.getDouble(savedRegisterLoc));
586 savedRegisterLoc -= 8;
587 }
588 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
589 registers.setFloatRegister(UNW_ARM64_D12,
590 addressSpace.getDouble(savedRegisterLoc));
591 savedRegisterLoc -= 8;
592 registers.setFloatRegister(UNW_ARM64_D13,
593 addressSpace.getDouble(savedRegisterLoc));
594 savedRegisterLoc -= 8;
595 }
596 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
597 registers.setFloatRegister(UNW_ARM64_D14,
598 addressSpace.getDouble(savedRegisterLoc));
599 savedRegisterLoc -= 8;
600 registers.setFloatRegister(UNW_ARM64_D15,
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_ARM64_LR));
610
611 return UNW_STEP_SUCCESS;
612}
613
614template <typename A>
615int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
616 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
617 Registers_arm64 &registers) {
618 uint64_t savedRegisterLoc = registers.getFP() - 8;
619
620 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
621 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
622 savedRegisterLoc -= 8;
623 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
624 savedRegisterLoc -= 8;
625 }
626 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
627 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
628 savedRegisterLoc -= 8;
629 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
630 savedRegisterLoc -= 8;
631 }
632 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
633 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
634 savedRegisterLoc -= 8;
635 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
636 savedRegisterLoc -= 8;
637 }
638 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
639 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
640 savedRegisterLoc -= 8;
641 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
642 savedRegisterLoc -= 8;
643 }
644 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
645 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
646 savedRegisterLoc -= 8;
647 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
648 savedRegisterLoc -= 8;
649 }
650
651 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
652 registers.setFloatRegister(UNW_ARM64_D8,
653 addressSpace.getDouble(savedRegisterLoc));
654 savedRegisterLoc -= 8;
655 registers.setFloatRegister(UNW_ARM64_D9,
656 addressSpace.getDouble(savedRegisterLoc));
657 savedRegisterLoc -= 8;
658 }
659 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
660 registers.setFloatRegister(UNW_ARM64_D10,
661 addressSpace.getDouble(savedRegisterLoc));
662 savedRegisterLoc -= 8;
663 registers.setFloatRegister(UNW_ARM64_D11,
664 addressSpace.getDouble(savedRegisterLoc));
665 savedRegisterLoc -= 8;
666 }
667 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
668 registers.setFloatRegister(UNW_ARM64_D12,
669 addressSpace.getDouble(savedRegisterLoc));
670 savedRegisterLoc -= 8;
671 registers.setFloatRegister(UNW_ARM64_D13,
672 addressSpace.getDouble(savedRegisterLoc));
673 savedRegisterLoc -= 8;
674 }
675 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
676 registers.setFloatRegister(UNW_ARM64_D14,
677 addressSpace.getDouble(savedRegisterLoc));
678 savedRegisterLoc -= 8;
679 registers.setFloatRegister(UNW_ARM64_D15,
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}
Asiri Rathnayakec00dcef2016-05-25 12:36:34 +0000694#endif // _LIBUNWIND_TARGET_AARCH64
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000695
696
697} // namespace libunwind
698
699#endif // __COMPACT_UNWINDER_HPP__