CompactUnwinder.hpp revision 303975
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 28namespace libunwind { 29 30#if defined(_LIBUNWIND_TARGET_I386) 31/// 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 ®isters); 40 41private: 42 typename A::pint_t pint_t; 43 44 static void frameUnwind(A &addressSpace, Registers_x86 ®isters); 45 static void framelessUnwind(A &addressSpace, 46 typename A::pint_t returnAddressLocation, 47 Registers_x86 ®isters); 48 static int 49 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, 50 uint32_t functionStart, A &addressSpace, 51 Registers_x86 ®isters); 52 static int stepWithCompactEncodingFrameless( 53 compact_unwind_encoding_t compactEncoding, uint32_t functionStart, 54 A &addressSpace, Registers_x86 ®isters, 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 ®isters) { 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 ®isters) { 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 " 108 "function starting at 0x%X\n", 109 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 ®isters, 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 " 227 "function starting at 0x%X\n", 228 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 ®isters) { 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 ®isters) { 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} 259#endif // _LIBUNWIND_TARGET_I386 260 261 262#if defined(_LIBUNWIND_TARGET_X86_64) 263/// 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 ®isters); 272 273private: 274 typename A::pint_t pint_t; 275 276 static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); 277 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, 278 Registers_x86_64 ®isters); 279 static int 280 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, 281 uint64_t functionStart, A &addressSpace, 282 Registers_x86_64 ®isters); 283 static int stepWithCompactEncodingFrameless( 284 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 285 A &addressSpace, Registers_x86_64 ®isters, 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 ®isters) { 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 ®isters) { 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 " 339 "function starting at 0x%llX\n", 340 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 ®isters, 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 " 458 "function starting at 0x%llX\n", 459 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 ®isters) { 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 ®isters) { 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} 490#endif // _LIBUNWIND_TARGET_X86_64 491 492 493 494#if defined(_LIBUNWIND_TARGET_AARCH64) 495/// 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 ®isters); 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 ®isters); 512 static int stepWithCompactEncodingFrameless( 513 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 514 A &addressSpace, Registers_arm64 ®isters); 515}; 516 517template <typename A> 518int CompactUnwinder_arm64<A>::stepWithCompactEncoding( 519 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 520 A &addressSpace, Registers_arm64 ®isters) { 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 ®isters) { 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 ®isters) { 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} 694#endif // _LIBUNWIND_TARGET_AARCH64 695 696 697} // namespace libunwind 698 699#endif // __COMPACT_UNWINDER_HPP__ 700