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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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