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