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/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka 31/// unwind) by modifying a Registers_x86 register set 32template <typename A> 33class CompactUnwinder_x86 { 34public: 35 36 static int stepWithCompactEncoding(compact_unwind_encoding_t info, 37 uint32_t functionStart, A &addressSpace, 38 Registers_x86 ®isters); 39 40private: 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 56template <typename A> 57int 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 74template <typename A> 75int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame( 76 compact_unwind_encoding_t compactEncoding, uint32_t functionStart, 77 A &addressSpace, Registers_x86 ®isters) { 78 uint32_t savedRegistersOffset = 79 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); 80 uint32_t savedRegistersLocations = 81 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); 82 83 uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; 84 for (int i = 0; i < 5; ++i) { 85 switch (savedRegistersLocations & 0x7) { 86 case UNWIND_X86_REG_NONE: 87 // no register saved in this slot 88 break; 89 case UNWIND_X86_REG_EBX: 90 registers.setEBX(addressSpace.get32(savedRegisters)); 91 break; 92 case UNWIND_X86_REG_ECX: 93 registers.setECX(addressSpace.get32(savedRegisters)); 94 break; 95 case UNWIND_X86_REG_EDX: 96 registers.setEDX(addressSpace.get32(savedRegisters)); 97 break; 98 case UNWIND_X86_REG_EDI: 99 registers.setEDI(addressSpace.get32(savedRegisters)); 100 break; 101 case UNWIND_X86_REG_ESI: 102 registers.setESI(addressSpace.get32(savedRegisters)); 103 break; 104 default: 105 (void)functionStart; 106 _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " 107 "function starting at 0x%X\n", 108 compactEncoding, functionStart); 109 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 110 } 111 savedRegisters += 4; 112 savedRegistersLocations = (savedRegistersLocations >> 3); 113 } 114 frameUnwind(addressSpace, registers); 115 return UNW_STEP_SUCCESS; 116} 117 118template <typename A> 119int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless( 120 compact_unwind_encoding_t encoding, uint32_t functionStart, 121 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { 122 uint32_t stackSizeEncoded = 123 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 124 uint32_t stackAdjust = 125 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); 126 uint32_t regCount = 127 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 128 uint32_t permutation = 129 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 130 uint32_t stackSize = stackSizeEncoded * 4; 131 if (indirectStackSize) { 132 // stack size is encoded in subl $xxx,%esp instruction 133 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); 134 stackSize = subl + 4 * stackAdjust; 135 } 136 // decompress permutation 137 uint32_t permunreg[6]; 138 switch (regCount) { 139 case 6: 140 permunreg[0] = permutation / 120; 141 permutation -= (permunreg[0] * 120); 142 permunreg[1] = permutation / 24; 143 permutation -= (permunreg[1] * 24); 144 permunreg[2] = permutation / 6; 145 permutation -= (permunreg[2] * 6); 146 permunreg[3] = permutation / 2; 147 permutation -= (permunreg[3] * 2); 148 permunreg[4] = permutation; 149 permunreg[5] = 0; 150 break; 151 case 5: 152 permunreg[0] = permutation / 120; 153 permutation -= (permunreg[0] * 120); 154 permunreg[1] = permutation / 24; 155 permutation -= (permunreg[1] * 24); 156 permunreg[2] = permutation / 6; 157 permutation -= (permunreg[2] * 6); 158 permunreg[3] = permutation / 2; 159 permutation -= (permunreg[3] * 2); 160 permunreg[4] = permutation; 161 break; 162 case 4: 163 permunreg[0] = permutation / 60; 164 permutation -= (permunreg[0] * 60); 165 permunreg[1] = permutation / 12; 166 permutation -= (permunreg[1] * 12); 167 permunreg[2] = permutation / 3; 168 permutation -= (permunreg[2] * 3); 169 permunreg[3] = permutation; 170 break; 171 case 3: 172 permunreg[0] = permutation / 20; 173 permutation -= (permunreg[0] * 20); 174 permunreg[1] = permutation / 4; 175 permutation -= (permunreg[1] * 4); 176 permunreg[2] = permutation; 177 break; 178 case 2: 179 permunreg[0] = permutation / 5; 180 permutation -= (permunreg[0] * 5); 181 permunreg[1] = permutation; 182 break; 183 case 1: 184 permunreg[0] = permutation; 185 break; 186 } 187 // re-number registers back to standard numbers 188 int registersSaved[6]; 189 bool used[7] = { false, false, false, false, false, false, false }; 190 for (uint32_t i = 0; i < regCount; ++i) { 191 uint32_t renum = 0; 192 for (int u = 1; u < 7; ++u) { 193 if (!used[u]) { 194 if (renum == permunreg[i]) { 195 registersSaved[i] = u; 196 used[u] = true; 197 break; 198 } 199 ++renum; 200 } 201 } 202 } 203 uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; 204 for (uint32_t i = 0; i < regCount; ++i) { 205 switch (registersSaved[i]) { 206 case UNWIND_X86_REG_EBX: 207 registers.setEBX(addressSpace.get32(savedRegisters)); 208 break; 209 case UNWIND_X86_REG_ECX: 210 registers.setECX(addressSpace.get32(savedRegisters)); 211 break; 212 case UNWIND_X86_REG_EDX: 213 registers.setEDX(addressSpace.get32(savedRegisters)); 214 break; 215 case UNWIND_X86_REG_EDI: 216 registers.setEDI(addressSpace.get32(savedRegisters)); 217 break; 218 case UNWIND_X86_REG_ESI: 219 registers.setESI(addressSpace.get32(savedRegisters)); 220 break; 221 case UNWIND_X86_REG_EBP: 222 registers.setEBP(addressSpace.get32(savedRegisters)); 223 break; 224 default: 225 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " 226 "function starting at 0x%X\n", 227 encoding, functionStart); 228 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 229 } 230 savedRegisters += 4; 231 } 232 framelessUnwind(addressSpace, savedRegisters, registers); 233 return UNW_STEP_SUCCESS; 234} 235 236 237template <typename A> 238void 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 249template <typename A> 250void CompactUnwinder_x86<A>::framelessUnwind( 251 A &addressSpace, typename A::pint_t returnAddressLocation, 252 Registers_x86 ®isters) { 253 // return address is on stack after last saved register 254 registers.setIP(addressSpace.get32(returnAddressLocation)); 255 // old esp is before return address 256 registers.setSP((uint32_t)returnAddressLocation + 4); 257} 258 259 260/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka 261/// unwind) by modifying a Registers_x86_64 register set 262template <typename A> 263class CompactUnwinder_x86_64 { 264public: 265 266 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, 267 uint64_t functionStart, A &addressSpace, 268 Registers_x86_64 ®isters); 269 270private: 271 typename A::pint_t pint_t; 272 273 static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); 274 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, 275 Registers_x86_64 ®isters); 276 static int 277 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, 278 uint64_t functionStart, A &addressSpace, 279 Registers_x86_64 ®isters); 280 static int stepWithCompactEncodingFrameless( 281 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 282 A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); 283}; 284 285template <typename A> 286int CompactUnwinder_x86_64<A>::stepWithCompactEncoding( 287 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 288 A &addressSpace, Registers_x86_64 ®isters) { 289 switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { 290 case UNWIND_X86_64_MODE_RBP_FRAME: 291 return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, 292 addressSpace, registers); 293 case UNWIND_X86_64_MODE_STACK_IMMD: 294 return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 295 addressSpace, registers, false); 296 case UNWIND_X86_64_MODE_STACK_IND: 297 return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 298 addressSpace, registers, true); 299 } 300 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 301} 302 303template <typename A> 304int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame( 305 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 306 A &addressSpace, Registers_x86_64 ®isters) { 307 uint32_t savedRegistersOffset = 308 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 309 uint32_t savedRegistersLocations = 310 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 311 312 uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; 313 for (int i = 0; i < 5; ++i) { 314 switch (savedRegistersLocations & 0x7) { 315 case UNWIND_X86_64_REG_NONE: 316 // no register saved in this slot 317 break; 318 case UNWIND_X86_64_REG_RBX: 319 registers.setRBX(addressSpace.get64(savedRegisters)); 320 break; 321 case UNWIND_X86_64_REG_R12: 322 registers.setR12(addressSpace.get64(savedRegisters)); 323 break; 324 case UNWIND_X86_64_REG_R13: 325 registers.setR13(addressSpace.get64(savedRegisters)); 326 break; 327 case UNWIND_X86_64_REG_R14: 328 registers.setR14(addressSpace.get64(savedRegisters)); 329 break; 330 case UNWIND_X86_64_REG_R15: 331 registers.setR15(addressSpace.get64(savedRegisters)); 332 break; 333 default: 334 (void)functionStart; 335 _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " 336 "function starting at 0x%llX\n", 337 compactEncoding, functionStart); 338 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 339 } 340 savedRegisters += 8; 341 savedRegistersLocations = (savedRegistersLocations >> 3); 342 } 343 frameUnwind(addressSpace, registers); 344 return UNW_STEP_SUCCESS; 345} 346 347template <typename A> 348int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless( 349 compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, 350 Registers_x86_64 ®isters, bool indirectStackSize) { 351 uint32_t stackSizeEncoded = 352 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 353 uint32_t stackAdjust = 354 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 355 uint32_t regCount = 356 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 357 uint32_t permutation = 358 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 359 uint32_t stackSize = stackSizeEncoded * 8; 360 if (indirectStackSize) { 361 // stack size is encoded in subl $xxx,%esp instruction 362 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); 363 stackSize = subl + 8 * stackAdjust; 364 } 365 // decompress permutation 366 uint32_t permunreg[6]; 367 switch (regCount) { 368 case 6: 369 permunreg[0] = permutation / 120; 370 permutation -= (permunreg[0] * 120); 371 permunreg[1] = permutation / 24; 372 permutation -= (permunreg[1] * 24); 373 permunreg[2] = permutation / 6; 374 permutation -= (permunreg[2] * 6); 375 permunreg[3] = permutation / 2; 376 permutation -= (permunreg[3] * 2); 377 permunreg[4] = permutation; 378 permunreg[5] = 0; 379 break; 380 case 5: 381 permunreg[0] = permutation / 120; 382 permutation -= (permunreg[0] * 120); 383 permunreg[1] = permutation / 24; 384 permutation -= (permunreg[1] * 24); 385 permunreg[2] = permutation / 6; 386 permutation -= (permunreg[2] * 6); 387 permunreg[3] = permutation / 2; 388 permutation -= (permunreg[3] * 2); 389 permunreg[4] = permutation; 390 break; 391 case 4: 392 permunreg[0] = permutation / 60; 393 permutation -= (permunreg[0] * 60); 394 permunreg[1] = permutation / 12; 395 permutation -= (permunreg[1] * 12); 396 permunreg[2] = permutation / 3; 397 permutation -= (permunreg[2] * 3); 398 permunreg[3] = permutation; 399 break; 400 case 3: 401 permunreg[0] = permutation / 20; 402 permutation -= (permunreg[0] * 20); 403 permunreg[1] = permutation / 4; 404 permutation -= (permunreg[1] * 4); 405 permunreg[2] = permutation; 406 break; 407 case 2: 408 permunreg[0] = permutation / 5; 409 permutation -= (permunreg[0] * 5); 410 permunreg[1] = permutation; 411 break; 412 case 1: 413 permunreg[0] = permutation; 414 break; 415 } 416 // re-number registers back to standard numbers 417 int registersSaved[6]; 418 bool used[7] = { false, false, false, false, false, false, false }; 419 for (uint32_t i = 0; i < regCount; ++i) { 420 uint32_t renum = 0; 421 for (int u = 1; u < 7; ++u) { 422 if (!used[u]) { 423 if (renum == permunreg[i]) { 424 registersSaved[i] = u; 425 used[u] = true; 426 break; 427 } 428 ++renum; 429 } 430 } 431 } 432 uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; 433 for (uint32_t i = 0; i < regCount; ++i) { 434 switch (registersSaved[i]) { 435 case UNWIND_X86_64_REG_RBX: 436 registers.setRBX(addressSpace.get64(savedRegisters)); 437 break; 438 case UNWIND_X86_64_REG_R12: 439 registers.setR12(addressSpace.get64(savedRegisters)); 440 break; 441 case UNWIND_X86_64_REG_R13: 442 registers.setR13(addressSpace.get64(savedRegisters)); 443 break; 444 case UNWIND_X86_64_REG_R14: 445 registers.setR14(addressSpace.get64(savedRegisters)); 446 break; 447 case UNWIND_X86_64_REG_R15: 448 registers.setR15(addressSpace.get64(savedRegisters)); 449 break; 450 case UNWIND_X86_64_REG_RBP: 451 registers.setRBP(addressSpace.get64(savedRegisters)); 452 break; 453 default: 454 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " 455 "function starting at 0x%llX\n", 456 encoding, functionStart); 457 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 458 } 459 savedRegisters += 8; 460 } 461 framelessUnwind(addressSpace, savedRegisters, registers); 462 return UNW_STEP_SUCCESS; 463} 464 465 466template <typename A> 467void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace, 468 Registers_x86_64 ®isters) { 469 uint64_t rbp = registers.getRBP(); 470 // ebp points to old ebp 471 registers.setRBP(addressSpace.get64(rbp)); 472 // old esp is ebp less saved ebp and return address 473 registers.setSP(rbp + 16); 474 // pop return address into eip 475 registers.setIP(addressSpace.get64(rbp + 8)); 476} 477 478template <typename A> 479void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace, 480 uint64_t returnAddressLocation, 481 Registers_x86_64 ®isters) { 482 // return address is on stack after last saved register 483 registers.setIP(addressSpace.get64(returnAddressLocation)); 484 // old esp is before return address 485 registers.setSP(returnAddressLocation + 8); 486} 487 488 489 490/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka 491/// unwind) by modifying a Registers_arm64 register set 492template <typename A> 493class CompactUnwinder_arm64 { 494public: 495 496 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, 497 uint64_t functionStart, A &addressSpace, 498 Registers_arm64 ®isters); 499 500private: 501 typename A::pint_t pint_t; 502 503 static int 504 stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, 505 uint64_t functionStart, A &addressSpace, 506 Registers_arm64 ®isters); 507 static int stepWithCompactEncodingFrameless( 508 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 509 A &addressSpace, Registers_arm64 ®isters); 510}; 511 512template <typename A> 513int CompactUnwinder_arm64<A>::stepWithCompactEncoding( 514 compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 515 A &addressSpace, Registers_arm64 ®isters) { 516 switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { 517 case UNWIND_ARM64_MODE_FRAME: 518 return stepWithCompactEncodingFrame(compactEncoding, functionStart, 519 addressSpace, registers); 520 case UNWIND_ARM64_MODE_FRAMELESS: 521 return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 522 addressSpace, registers); 523 } 524 _LIBUNWIND_ABORT("invalid compact unwind encoding"); 525} 526 527template <typename A> 528int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless( 529 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, 530 Registers_arm64 ®isters) { 531 uint32_t stackSize = 532 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); 533 534 uint64_t savedRegisterLoc = registers.getSP() + stackSize; 535 536 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 537 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); 538 savedRegisterLoc -= 8; 539 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); 540 savedRegisterLoc -= 8; 541 } 542 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 543 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); 544 savedRegisterLoc -= 8; 545 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); 546 savedRegisterLoc -= 8; 547 } 548 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 549 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); 550 savedRegisterLoc -= 8; 551 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); 552 savedRegisterLoc -= 8; 553 } 554 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 555 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); 556 savedRegisterLoc -= 8; 557 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); 558 savedRegisterLoc -= 8; 559 } 560 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 561 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); 562 savedRegisterLoc -= 8; 563 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); 564 savedRegisterLoc -= 8; 565 } 566 567 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 568 registers.setFloatRegister(UNW_ARM64_D8, 569 addressSpace.getDouble(savedRegisterLoc)); 570 savedRegisterLoc -= 8; 571 registers.setFloatRegister(UNW_ARM64_D9, 572 addressSpace.getDouble(savedRegisterLoc)); 573 savedRegisterLoc -= 8; 574 } 575 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 576 registers.setFloatRegister(UNW_ARM64_D10, 577 addressSpace.getDouble(savedRegisterLoc)); 578 savedRegisterLoc -= 8; 579 registers.setFloatRegister(UNW_ARM64_D11, 580 addressSpace.getDouble(savedRegisterLoc)); 581 savedRegisterLoc -= 8; 582 } 583 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 584 registers.setFloatRegister(UNW_ARM64_D12, 585 addressSpace.getDouble(savedRegisterLoc)); 586 savedRegisterLoc -= 8; 587 registers.setFloatRegister(UNW_ARM64_D13, 588 addressSpace.getDouble(savedRegisterLoc)); 589 savedRegisterLoc -= 8; 590 } 591 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 592 registers.setFloatRegister(UNW_ARM64_D14, 593 addressSpace.getDouble(savedRegisterLoc)); 594 savedRegisterLoc -= 8; 595 registers.setFloatRegister(UNW_ARM64_D15, 596 addressSpace.getDouble(savedRegisterLoc)); 597 savedRegisterLoc -= 8; 598 } 599 600 // subtract stack size off of sp 601 registers.setSP(savedRegisterLoc); 602 603 // set pc to be value in lr 604 registers.setIP(registers.getRegister(UNW_ARM64_LR)); 605 606 return UNW_STEP_SUCCESS; 607} 608 609template <typename A> 610int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame( 611 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, 612 Registers_arm64 ®isters) { 613 uint64_t savedRegisterLoc = registers.getFP() - 8; 614 615 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 616 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); 617 savedRegisterLoc -= 8; 618 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); 619 savedRegisterLoc -= 8; 620 } 621 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 622 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); 623 savedRegisterLoc -= 8; 624 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); 625 savedRegisterLoc -= 8; 626 } 627 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 628 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); 629 savedRegisterLoc -= 8; 630 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); 631 savedRegisterLoc -= 8; 632 } 633 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 634 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); 635 savedRegisterLoc -= 8; 636 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); 637 savedRegisterLoc -= 8; 638 } 639 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 640 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); 641 savedRegisterLoc -= 8; 642 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); 643 savedRegisterLoc -= 8; 644 } 645 646 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 647 registers.setFloatRegister(UNW_ARM64_D8, 648 addressSpace.getDouble(savedRegisterLoc)); 649 savedRegisterLoc -= 8; 650 registers.setFloatRegister(UNW_ARM64_D9, 651 addressSpace.getDouble(savedRegisterLoc)); 652 savedRegisterLoc -= 8; 653 } 654 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 655 registers.setFloatRegister(UNW_ARM64_D10, 656 addressSpace.getDouble(savedRegisterLoc)); 657 savedRegisterLoc -= 8; 658 registers.setFloatRegister(UNW_ARM64_D11, 659 addressSpace.getDouble(savedRegisterLoc)); 660 savedRegisterLoc -= 8; 661 } 662 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 663 registers.setFloatRegister(UNW_ARM64_D12, 664 addressSpace.getDouble(savedRegisterLoc)); 665 savedRegisterLoc -= 8; 666 registers.setFloatRegister(UNW_ARM64_D13, 667 addressSpace.getDouble(savedRegisterLoc)); 668 savedRegisterLoc -= 8; 669 } 670 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 671 registers.setFloatRegister(UNW_ARM64_D14, 672 addressSpace.getDouble(savedRegisterLoc)); 673 savedRegisterLoc -= 8; 674 registers.setFloatRegister(UNW_ARM64_D15, 675 addressSpace.getDouble(savedRegisterLoc)); 676 savedRegisterLoc -= 8; 677 } 678 679 uint64_t fp = registers.getFP(); 680 // fp points to old fp 681 registers.setFP(addressSpace.get64(fp)); 682 // old sp is fp less saved fp and lr 683 registers.setSP(fp + 16); 684 // pop return address into pc 685 registers.setIP(addressSpace.get64(fp + 8)); 686 687 return UNW_STEP_SUCCESS; 688} 689 690 691} // namespace libunwind 692 693#endif // __COMPACT_UNWINDER_HPP__ 694