1288149Semaste//===-------------------------- CompactUnwinder.hpp -----------------------===// 2288149Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6288149Semaste// 7288149Semaste// 8288149Semaste// Does runtime stack unwinding using compact unwind encodings. 9288149Semaste// 10288149Semaste//===----------------------------------------------------------------------===// 11288149Semaste 12288149Semaste#ifndef __COMPACT_UNWINDER_HPP__ 13288149Semaste#define __COMPACT_UNWINDER_HPP__ 14288149Semaste 15288149Semaste#include <stdint.h> 16288149Semaste#include <stdlib.h> 17288149Semaste 18288149Semaste#include <libunwind.h> 19288149Semaste#include <mach-o/compact_unwind_encoding.h> 20288149Semaste 21288149Semaste#include "Registers.hpp" 22288149Semaste 23288149Semaste#define EXTRACT_BITS(value, mask) \ 24288149Semaste ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) 25288149Semaste 26288149Semastenamespace libunwind { 27288149Semaste 28302450Semaste#if defined(_LIBUNWIND_TARGET_I386) 29288149Semaste/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka 30288149Semaste/// unwind) by modifying a Registers_x86 register set 31288149Semastetemplate <typename A> 32288149Semasteclass CompactUnwinder_x86 { 33288149Semastepublic: 34288149Semaste 35288149Semaste static int stepWithCompactEncoding(compact_unwind_encoding_t info, 36288149Semaste uint32_t functionStart, A &addressSpace, 37288149Semaste Registers_x86 ®isters); 38288149Semaste 39288149Semasteprivate: 40288149Semaste typename A::pint_t pint_t; 41288149Semaste 42288149Semaste static void frameUnwind(A &addressSpace, Registers_x86 ®isters); 43288149Semaste static void framelessUnwind(A &addressSpace, 44288149Semaste typename A::pint_t returnAddressLocation, 45288149Semaste Registers_x86 ®isters); 46288149Semaste static int 47288149Semaste stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, 48288149Semaste uint32_t functionStart, A &addressSpace, 49288149Semaste Registers_x86 ®isters); 50288149Semaste static int stepWithCompactEncodingFrameless( 51288149Semaste compact_unwind_encoding_t compactEncoding, uint32_t functionStart, 52288149Semaste A &addressSpace, Registers_x86 ®isters, bool indirectStackSize); 53288149Semaste}; 54288149Semaste 55288149Semastetemplate <typename A> 56288149Semasteint CompactUnwinder_x86<A>::stepWithCompactEncoding( 57288149Semaste compact_unwind_encoding_t compactEncoding, uint32_t functionStart, 58288149Semaste A &addressSpace, Registers_x86 ®isters) { 59288149Semaste switch (compactEncoding & UNWIND_X86_MODE_MASK) { 60288149Semaste case UNWIND_X86_MODE_EBP_FRAME: 61288149Semaste return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, 62288149Semaste addressSpace, registers); 63288149Semaste case UNWIND_X86_MODE_STACK_IMMD: 64288149Semaste return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 65288149Semaste addressSpace, registers, false); 66288149Semaste case UNWIND_X86_MODE_STACK_IND: 67288149Semaste return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 68288149Semaste addressSpace, registers, true); 69288149Semaste } 70288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 71288149Semaste} 72288149Semaste 73288149Semastetemplate <typename A> 74288149Semasteint CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame( 75288149Semaste compact_unwind_encoding_t compactEncoding, uint32_t functionStart, 76288149Semaste A &addressSpace, Registers_x86 ®isters) { 77288149Semaste uint32_t savedRegistersOffset = 78288149Semaste EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); 79288149Semaste uint32_t savedRegistersLocations = 80288149Semaste EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); 81288149Semaste 82288149Semaste uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; 83288149Semaste for (int i = 0; i < 5; ++i) { 84288149Semaste switch (savedRegistersLocations & 0x7) { 85288149Semaste case UNWIND_X86_REG_NONE: 86288149Semaste // no register saved in this slot 87288149Semaste break; 88288149Semaste case UNWIND_X86_REG_EBX: 89288149Semaste registers.setEBX(addressSpace.get32(savedRegisters)); 90288149Semaste break; 91288149Semaste case UNWIND_X86_REG_ECX: 92288149Semaste registers.setECX(addressSpace.get32(savedRegisters)); 93288149Semaste break; 94288149Semaste case UNWIND_X86_REG_EDX: 95288149Semaste registers.setEDX(addressSpace.get32(savedRegisters)); 96288149Semaste break; 97288149Semaste case UNWIND_X86_REG_EDI: 98288149Semaste registers.setEDI(addressSpace.get32(savedRegisters)); 99288149Semaste break; 100288149Semaste case UNWIND_X86_REG_ESI: 101288149Semaste registers.setESI(addressSpace.get32(savedRegisters)); 102288149Semaste break; 103288149Semaste default: 104288149Semaste (void)functionStart; 105288149Semaste _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " 106308006Semaste "function starting at 0x%X", 107288149Semaste compactEncoding, functionStart); 108288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 109288149Semaste } 110288149Semaste savedRegisters += 4; 111288149Semaste savedRegistersLocations = (savedRegistersLocations >> 3); 112288149Semaste } 113288149Semaste frameUnwind(addressSpace, registers); 114288149Semaste return UNW_STEP_SUCCESS; 115288149Semaste} 116288149Semaste 117288149Semastetemplate <typename A> 118288149Semasteint CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless( 119288149Semaste compact_unwind_encoding_t encoding, uint32_t functionStart, 120288149Semaste A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { 121288149Semaste uint32_t stackSizeEncoded = 122288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 123288149Semaste uint32_t stackAdjust = 124288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); 125288149Semaste uint32_t regCount = 126288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 127288149Semaste uint32_t permutation = 128288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 129288149Semaste uint32_t stackSize = stackSizeEncoded * 4; 130288149Semaste if (indirectStackSize) { 131288149Semaste // stack size is encoded in subl $xxx,%esp instruction 132288149Semaste uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); 133288149Semaste stackSize = subl + 4 * stackAdjust; 134288149Semaste } 135288149Semaste // decompress permutation 136288149Semaste uint32_t permunreg[6]; 137288149Semaste switch (regCount) { 138288149Semaste case 6: 139288149Semaste permunreg[0] = permutation / 120; 140288149Semaste permutation -= (permunreg[0] * 120); 141288149Semaste permunreg[1] = permutation / 24; 142288149Semaste permutation -= (permunreg[1] * 24); 143288149Semaste permunreg[2] = permutation / 6; 144288149Semaste permutation -= (permunreg[2] * 6); 145288149Semaste permunreg[3] = permutation / 2; 146288149Semaste permutation -= (permunreg[3] * 2); 147288149Semaste permunreg[4] = permutation; 148288149Semaste permunreg[5] = 0; 149288149Semaste break; 150288149Semaste case 5: 151288149Semaste permunreg[0] = permutation / 120; 152288149Semaste permutation -= (permunreg[0] * 120); 153288149Semaste permunreg[1] = permutation / 24; 154288149Semaste permutation -= (permunreg[1] * 24); 155288149Semaste permunreg[2] = permutation / 6; 156288149Semaste permutation -= (permunreg[2] * 6); 157288149Semaste permunreg[3] = permutation / 2; 158288149Semaste permutation -= (permunreg[3] * 2); 159288149Semaste permunreg[4] = permutation; 160288149Semaste break; 161288149Semaste case 4: 162288149Semaste permunreg[0] = permutation / 60; 163288149Semaste permutation -= (permunreg[0] * 60); 164288149Semaste permunreg[1] = permutation / 12; 165288149Semaste permutation -= (permunreg[1] * 12); 166288149Semaste permunreg[2] = permutation / 3; 167288149Semaste permutation -= (permunreg[2] * 3); 168288149Semaste permunreg[3] = permutation; 169288149Semaste break; 170288149Semaste case 3: 171288149Semaste permunreg[0] = permutation / 20; 172288149Semaste permutation -= (permunreg[0] * 20); 173288149Semaste permunreg[1] = permutation / 4; 174288149Semaste permutation -= (permunreg[1] * 4); 175288149Semaste permunreg[2] = permutation; 176288149Semaste break; 177288149Semaste case 2: 178288149Semaste permunreg[0] = permutation / 5; 179288149Semaste permutation -= (permunreg[0] * 5); 180288149Semaste permunreg[1] = permutation; 181288149Semaste break; 182288149Semaste case 1: 183288149Semaste permunreg[0] = permutation; 184288149Semaste break; 185288149Semaste } 186288149Semaste // re-number registers back to standard numbers 187288149Semaste int registersSaved[6]; 188288149Semaste bool used[7] = { false, false, false, false, false, false, false }; 189288149Semaste for (uint32_t i = 0; i < regCount; ++i) { 190288149Semaste uint32_t renum = 0; 191288149Semaste for (int u = 1; u < 7; ++u) { 192288149Semaste if (!used[u]) { 193288149Semaste if (renum == permunreg[i]) { 194288149Semaste registersSaved[i] = u; 195288149Semaste used[u] = true; 196288149Semaste break; 197288149Semaste } 198288149Semaste ++renum; 199288149Semaste } 200288149Semaste } 201288149Semaste } 202288149Semaste uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; 203288149Semaste for (uint32_t i = 0; i < regCount; ++i) { 204288149Semaste switch (registersSaved[i]) { 205288149Semaste case UNWIND_X86_REG_EBX: 206288149Semaste registers.setEBX(addressSpace.get32(savedRegisters)); 207288149Semaste break; 208288149Semaste case UNWIND_X86_REG_ECX: 209288149Semaste registers.setECX(addressSpace.get32(savedRegisters)); 210288149Semaste break; 211288149Semaste case UNWIND_X86_REG_EDX: 212288149Semaste registers.setEDX(addressSpace.get32(savedRegisters)); 213288149Semaste break; 214288149Semaste case UNWIND_X86_REG_EDI: 215288149Semaste registers.setEDI(addressSpace.get32(savedRegisters)); 216288149Semaste break; 217288149Semaste case UNWIND_X86_REG_ESI: 218288149Semaste registers.setESI(addressSpace.get32(savedRegisters)); 219288149Semaste break; 220288149Semaste case UNWIND_X86_REG_EBP: 221288149Semaste registers.setEBP(addressSpace.get32(savedRegisters)); 222288149Semaste break; 223288149Semaste default: 224288149Semaste _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " 225308006Semaste "function starting at 0x%X", 226288149Semaste encoding, functionStart); 227288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 228288149Semaste } 229288149Semaste savedRegisters += 4; 230288149Semaste } 231288149Semaste framelessUnwind(addressSpace, savedRegisters, registers); 232288149Semaste return UNW_STEP_SUCCESS; 233288149Semaste} 234288149Semaste 235288149Semaste 236288149Semastetemplate <typename A> 237288149Semastevoid CompactUnwinder_x86<A>::frameUnwind(A &addressSpace, 238288149Semaste Registers_x86 ®isters) { 239288149Semaste typename A::pint_t bp = registers.getEBP(); 240288149Semaste // ebp points to old ebp 241288149Semaste registers.setEBP(addressSpace.get32(bp)); 242288149Semaste // old esp is ebp less saved ebp and return address 243288149Semaste registers.setSP((uint32_t)bp + 8); 244288149Semaste // pop return address into eip 245288149Semaste registers.setIP(addressSpace.get32(bp + 4)); 246288149Semaste} 247288149Semaste 248288149Semastetemplate <typename A> 249288149Semastevoid CompactUnwinder_x86<A>::framelessUnwind( 250288149Semaste A &addressSpace, typename A::pint_t returnAddressLocation, 251288149Semaste Registers_x86 ®isters) { 252288149Semaste // return address is on stack after last saved register 253288149Semaste registers.setIP(addressSpace.get32(returnAddressLocation)); 254288149Semaste // old esp is before return address 255288149Semaste registers.setSP((uint32_t)returnAddressLocation + 4); 256288149Semaste} 257302450Semaste#endif // _LIBUNWIND_TARGET_I386 258288149Semaste 259288149Semaste 260302450Semaste#if defined(_LIBUNWIND_TARGET_X86_64) 261288149Semaste/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka 262288149Semaste/// unwind) by modifying a Registers_x86_64 register set 263288149Semastetemplate <typename A> 264288149Semasteclass CompactUnwinder_x86_64 { 265288149Semastepublic: 266288149Semaste 267288149Semaste static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, 268288149Semaste uint64_t functionStart, A &addressSpace, 269288149Semaste Registers_x86_64 ®isters); 270288149Semaste 271288149Semasteprivate: 272288149Semaste typename A::pint_t pint_t; 273288149Semaste 274288149Semaste static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); 275288149Semaste static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, 276288149Semaste Registers_x86_64 ®isters); 277288149Semaste static int 278288149Semaste stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, 279288149Semaste uint64_t functionStart, A &addressSpace, 280288149Semaste Registers_x86_64 ®isters); 281288149Semaste static int stepWithCompactEncodingFrameless( 282288149Semaste compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 283288149Semaste A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); 284288149Semaste}; 285288149Semaste 286288149Semastetemplate <typename A> 287288149Semasteint CompactUnwinder_x86_64<A>::stepWithCompactEncoding( 288288149Semaste compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 289288149Semaste A &addressSpace, Registers_x86_64 ®isters) { 290288149Semaste switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { 291288149Semaste case UNWIND_X86_64_MODE_RBP_FRAME: 292288149Semaste return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, 293288149Semaste addressSpace, registers); 294288149Semaste case UNWIND_X86_64_MODE_STACK_IMMD: 295288149Semaste return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 296288149Semaste addressSpace, registers, false); 297288149Semaste case UNWIND_X86_64_MODE_STACK_IND: 298288149Semaste return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 299288149Semaste addressSpace, registers, true); 300288149Semaste } 301288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 302288149Semaste} 303288149Semaste 304288149Semastetemplate <typename A> 305288149Semasteint CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame( 306288149Semaste compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 307288149Semaste A &addressSpace, Registers_x86_64 ®isters) { 308288149Semaste uint32_t savedRegistersOffset = 309288149Semaste EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 310288149Semaste uint32_t savedRegistersLocations = 311288149Semaste EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 312288149Semaste 313288149Semaste uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; 314288149Semaste for (int i = 0; i < 5; ++i) { 315288149Semaste switch (savedRegistersLocations & 0x7) { 316288149Semaste case UNWIND_X86_64_REG_NONE: 317288149Semaste // no register saved in this slot 318288149Semaste break; 319288149Semaste case UNWIND_X86_64_REG_RBX: 320288149Semaste registers.setRBX(addressSpace.get64(savedRegisters)); 321288149Semaste break; 322288149Semaste case UNWIND_X86_64_REG_R12: 323288149Semaste registers.setR12(addressSpace.get64(savedRegisters)); 324288149Semaste break; 325288149Semaste case UNWIND_X86_64_REG_R13: 326288149Semaste registers.setR13(addressSpace.get64(savedRegisters)); 327288149Semaste break; 328288149Semaste case UNWIND_X86_64_REG_R14: 329288149Semaste registers.setR14(addressSpace.get64(savedRegisters)); 330288149Semaste break; 331288149Semaste case UNWIND_X86_64_REG_R15: 332288149Semaste registers.setR15(addressSpace.get64(savedRegisters)); 333288149Semaste break; 334288149Semaste default: 335288149Semaste (void)functionStart; 336288149Semaste _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " 337308006Semaste "function starting at 0x%llX", 338288149Semaste compactEncoding, functionStart); 339288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 340288149Semaste } 341288149Semaste savedRegisters += 8; 342288149Semaste savedRegistersLocations = (savedRegistersLocations >> 3); 343288149Semaste } 344288149Semaste frameUnwind(addressSpace, registers); 345288149Semaste return UNW_STEP_SUCCESS; 346288149Semaste} 347288149Semaste 348288149Semastetemplate <typename A> 349288149Semasteint CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless( 350288149Semaste compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, 351288149Semaste Registers_x86_64 ®isters, bool indirectStackSize) { 352288149Semaste uint32_t stackSizeEncoded = 353288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 354288149Semaste uint32_t stackAdjust = 355288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 356288149Semaste uint32_t regCount = 357288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 358288149Semaste uint32_t permutation = 359288149Semaste EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 360288149Semaste uint32_t stackSize = stackSizeEncoded * 8; 361288149Semaste if (indirectStackSize) { 362288149Semaste // stack size is encoded in subl $xxx,%esp instruction 363288149Semaste uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); 364288149Semaste stackSize = subl + 8 * stackAdjust; 365288149Semaste } 366288149Semaste // decompress permutation 367288149Semaste uint32_t permunreg[6]; 368288149Semaste switch (regCount) { 369288149Semaste case 6: 370288149Semaste permunreg[0] = permutation / 120; 371288149Semaste permutation -= (permunreg[0] * 120); 372288149Semaste permunreg[1] = permutation / 24; 373288149Semaste permutation -= (permunreg[1] * 24); 374288149Semaste permunreg[2] = permutation / 6; 375288149Semaste permutation -= (permunreg[2] * 6); 376288149Semaste permunreg[3] = permutation / 2; 377288149Semaste permutation -= (permunreg[3] * 2); 378288149Semaste permunreg[4] = permutation; 379288149Semaste permunreg[5] = 0; 380288149Semaste break; 381288149Semaste case 5: 382288149Semaste permunreg[0] = permutation / 120; 383288149Semaste permutation -= (permunreg[0] * 120); 384288149Semaste permunreg[1] = permutation / 24; 385288149Semaste permutation -= (permunreg[1] * 24); 386288149Semaste permunreg[2] = permutation / 6; 387288149Semaste permutation -= (permunreg[2] * 6); 388288149Semaste permunreg[3] = permutation / 2; 389288149Semaste permutation -= (permunreg[3] * 2); 390288149Semaste permunreg[4] = permutation; 391288149Semaste break; 392288149Semaste case 4: 393288149Semaste permunreg[0] = permutation / 60; 394288149Semaste permutation -= (permunreg[0] * 60); 395288149Semaste permunreg[1] = permutation / 12; 396288149Semaste permutation -= (permunreg[1] * 12); 397288149Semaste permunreg[2] = permutation / 3; 398288149Semaste permutation -= (permunreg[2] * 3); 399288149Semaste permunreg[3] = permutation; 400288149Semaste break; 401288149Semaste case 3: 402288149Semaste permunreg[0] = permutation / 20; 403288149Semaste permutation -= (permunreg[0] * 20); 404288149Semaste permunreg[1] = permutation / 4; 405288149Semaste permutation -= (permunreg[1] * 4); 406288149Semaste permunreg[2] = permutation; 407288149Semaste break; 408288149Semaste case 2: 409288149Semaste permunreg[0] = permutation / 5; 410288149Semaste permutation -= (permunreg[0] * 5); 411288149Semaste permunreg[1] = permutation; 412288149Semaste break; 413288149Semaste case 1: 414288149Semaste permunreg[0] = permutation; 415288149Semaste break; 416288149Semaste } 417288149Semaste // re-number registers back to standard numbers 418288149Semaste int registersSaved[6]; 419288149Semaste bool used[7] = { false, false, false, false, false, false, false }; 420288149Semaste for (uint32_t i = 0; i < regCount; ++i) { 421288149Semaste uint32_t renum = 0; 422288149Semaste for (int u = 1; u < 7; ++u) { 423288149Semaste if (!used[u]) { 424288149Semaste if (renum == permunreg[i]) { 425288149Semaste registersSaved[i] = u; 426288149Semaste used[u] = true; 427288149Semaste break; 428288149Semaste } 429288149Semaste ++renum; 430288149Semaste } 431288149Semaste } 432288149Semaste } 433288149Semaste uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; 434288149Semaste for (uint32_t i = 0; i < regCount; ++i) { 435288149Semaste switch (registersSaved[i]) { 436288149Semaste case UNWIND_X86_64_REG_RBX: 437288149Semaste registers.setRBX(addressSpace.get64(savedRegisters)); 438288149Semaste break; 439288149Semaste case UNWIND_X86_64_REG_R12: 440288149Semaste registers.setR12(addressSpace.get64(savedRegisters)); 441288149Semaste break; 442288149Semaste case UNWIND_X86_64_REG_R13: 443288149Semaste registers.setR13(addressSpace.get64(savedRegisters)); 444288149Semaste break; 445288149Semaste case UNWIND_X86_64_REG_R14: 446288149Semaste registers.setR14(addressSpace.get64(savedRegisters)); 447288149Semaste break; 448288149Semaste case UNWIND_X86_64_REG_R15: 449288149Semaste registers.setR15(addressSpace.get64(savedRegisters)); 450288149Semaste break; 451288149Semaste case UNWIND_X86_64_REG_RBP: 452288149Semaste registers.setRBP(addressSpace.get64(savedRegisters)); 453288149Semaste break; 454288149Semaste default: 455288149Semaste _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " 456308006Semaste "function starting at 0x%llX", 457288149Semaste encoding, functionStart); 458288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 459288149Semaste } 460288149Semaste savedRegisters += 8; 461288149Semaste } 462288149Semaste framelessUnwind(addressSpace, savedRegisters, registers); 463288149Semaste return UNW_STEP_SUCCESS; 464288149Semaste} 465288149Semaste 466288149Semaste 467288149Semastetemplate <typename A> 468288149Semastevoid CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace, 469288149Semaste Registers_x86_64 ®isters) { 470288149Semaste uint64_t rbp = registers.getRBP(); 471288149Semaste // ebp points to old ebp 472288149Semaste registers.setRBP(addressSpace.get64(rbp)); 473288149Semaste // old esp is ebp less saved ebp and return address 474288149Semaste registers.setSP(rbp + 16); 475288149Semaste // pop return address into eip 476288149Semaste registers.setIP(addressSpace.get64(rbp + 8)); 477288149Semaste} 478288149Semaste 479288149Semastetemplate <typename A> 480288149Semastevoid CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace, 481288149Semaste uint64_t returnAddressLocation, 482288149Semaste Registers_x86_64 ®isters) { 483288149Semaste // return address is on stack after last saved register 484288149Semaste registers.setIP(addressSpace.get64(returnAddressLocation)); 485288149Semaste // old esp is before return address 486288149Semaste registers.setSP(returnAddressLocation + 8); 487288149Semaste} 488302450Semaste#endif // _LIBUNWIND_TARGET_X86_64 489288149Semaste 490288149Semaste 491288149Semaste 492302450Semaste#if defined(_LIBUNWIND_TARGET_AARCH64) 493288149Semaste/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka 494288149Semaste/// unwind) by modifying a Registers_arm64 register set 495288149Semastetemplate <typename A> 496288149Semasteclass CompactUnwinder_arm64 { 497288149Semastepublic: 498288149Semaste 499288149Semaste static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, 500288149Semaste uint64_t functionStart, A &addressSpace, 501288149Semaste Registers_arm64 ®isters); 502288149Semaste 503288149Semasteprivate: 504288149Semaste typename A::pint_t pint_t; 505288149Semaste 506288149Semaste static int 507288149Semaste stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, 508288149Semaste uint64_t functionStart, A &addressSpace, 509288149Semaste Registers_arm64 ®isters); 510288149Semaste static int stepWithCompactEncodingFrameless( 511288149Semaste compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 512288149Semaste A &addressSpace, Registers_arm64 ®isters); 513288149Semaste}; 514288149Semaste 515288149Semastetemplate <typename A> 516288149Semasteint CompactUnwinder_arm64<A>::stepWithCompactEncoding( 517288149Semaste compact_unwind_encoding_t compactEncoding, uint64_t functionStart, 518288149Semaste A &addressSpace, Registers_arm64 ®isters) { 519288149Semaste switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { 520288149Semaste case UNWIND_ARM64_MODE_FRAME: 521288149Semaste return stepWithCompactEncodingFrame(compactEncoding, functionStart, 522288149Semaste addressSpace, registers); 523288149Semaste case UNWIND_ARM64_MODE_FRAMELESS: 524288149Semaste return stepWithCompactEncodingFrameless(compactEncoding, functionStart, 525288149Semaste addressSpace, registers); 526288149Semaste } 527288149Semaste _LIBUNWIND_ABORT("invalid compact unwind encoding"); 528288149Semaste} 529288149Semaste 530288149Semastetemplate <typename A> 531288149Semasteint CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless( 532288149Semaste compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, 533288149Semaste Registers_arm64 ®isters) { 534288149Semaste uint32_t stackSize = 535288149Semaste 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); 536288149Semaste 537288149Semaste uint64_t savedRegisterLoc = registers.getSP() + stackSize; 538288149Semaste 539288149Semaste if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 540288149Semaste registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); 541288149Semaste savedRegisterLoc -= 8; 542288149Semaste registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); 543288149Semaste savedRegisterLoc -= 8; 544288149Semaste } 545288149Semaste if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 546288149Semaste registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); 547288149Semaste savedRegisterLoc -= 8; 548288149Semaste registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); 549288149Semaste savedRegisterLoc -= 8; 550288149Semaste } 551288149Semaste if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 552288149Semaste registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); 553288149Semaste savedRegisterLoc -= 8; 554288149Semaste registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); 555288149Semaste savedRegisterLoc -= 8; 556288149Semaste } 557288149Semaste if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 558288149Semaste registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); 559288149Semaste savedRegisterLoc -= 8; 560288149Semaste registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); 561288149Semaste savedRegisterLoc -= 8; 562288149Semaste } 563288149Semaste if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 564288149Semaste registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); 565288149Semaste savedRegisterLoc -= 8; 566288149Semaste registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); 567288149Semaste savedRegisterLoc -= 8; 568288149Semaste } 569288149Semaste 570288149Semaste if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 571288149Semaste registers.setFloatRegister(UNW_ARM64_D8, 572288149Semaste addressSpace.getDouble(savedRegisterLoc)); 573288149Semaste savedRegisterLoc -= 8; 574288149Semaste registers.setFloatRegister(UNW_ARM64_D9, 575288149Semaste addressSpace.getDouble(savedRegisterLoc)); 576288149Semaste savedRegisterLoc -= 8; 577288149Semaste } 578288149Semaste if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 579288149Semaste registers.setFloatRegister(UNW_ARM64_D10, 580288149Semaste addressSpace.getDouble(savedRegisterLoc)); 581288149Semaste savedRegisterLoc -= 8; 582288149Semaste registers.setFloatRegister(UNW_ARM64_D11, 583288149Semaste addressSpace.getDouble(savedRegisterLoc)); 584288149Semaste savedRegisterLoc -= 8; 585288149Semaste } 586288149Semaste if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 587288149Semaste registers.setFloatRegister(UNW_ARM64_D12, 588288149Semaste addressSpace.getDouble(savedRegisterLoc)); 589288149Semaste savedRegisterLoc -= 8; 590288149Semaste registers.setFloatRegister(UNW_ARM64_D13, 591288149Semaste addressSpace.getDouble(savedRegisterLoc)); 592288149Semaste savedRegisterLoc -= 8; 593288149Semaste } 594288149Semaste if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 595288149Semaste registers.setFloatRegister(UNW_ARM64_D14, 596288149Semaste addressSpace.getDouble(savedRegisterLoc)); 597288149Semaste savedRegisterLoc -= 8; 598288149Semaste registers.setFloatRegister(UNW_ARM64_D15, 599288149Semaste addressSpace.getDouble(savedRegisterLoc)); 600288149Semaste savedRegisterLoc -= 8; 601288149Semaste } 602288149Semaste 603288149Semaste // subtract stack size off of sp 604288149Semaste registers.setSP(savedRegisterLoc); 605288149Semaste 606288149Semaste // set pc to be value in lr 607288149Semaste registers.setIP(registers.getRegister(UNW_ARM64_LR)); 608288149Semaste 609288149Semaste return UNW_STEP_SUCCESS; 610288149Semaste} 611288149Semaste 612288149Semastetemplate <typename A> 613288149Semasteint CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame( 614288149Semaste compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, 615288149Semaste Registers_arm64 ®isters) { 616288149Semaste uint64_t savedRegisterLoc = registers.getFP() - 8; 617288149Semaste 618288149Semaste if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 619288149Semaste registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); 620288149Semaste savedRegisterLoc -= 8; 621288149Semaste registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); 622288149Semaste savedRegisterLoc -= 8; 623288149Semaste } 624288149Semaste if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 625288149Semaste registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); 626288149Semaste savedRegisterLoc -= 8; 627288149Semaste registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); 628288149Semaste savedRegisterLoc -= 8; 629288149Semaste } 630288149Semaste if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 631288149Semaste registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); 632288149Semaste savedRegisterLoc -= 8; 633288149Semaste registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); 634288149Semaste savedRegisterLoc -= 8; 635288149Semaste } 636288149Semaste if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 637288149Semaste registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); 638288149Semaste savedRegisterLoc -= 8; 639288149Semaste registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); 640288149Semaste savedRegisterLoc -= 8; 641288149Semaste } 642288149Semaste if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 643288149Semaste registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); 644288149Semaste savedRegisterLoc -= 8; 645288149Semaste registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); 646288149Semaste savedRegisterLoc -= 8; 647288149Semaste } 648288149Semaste 649288149Semaste if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 650288149Semaste registers.setFloatRegister(UNW_ARM64_D8, 651288149Semaste addressSpace.getDouble(savedRegisterLoc)); 652288149Semaste savedRegisterLoc -= 8; 653288149Semaste registers.setFloatRegister(UNW_ARM64_D9, 654288149Semaste addressSpace.getDouble(savedRegisterLoc)); 655288149Semaste savedRegisterLoc -= 8; 656288149Semaste } 657288149Semaste if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 658288149Semaste registers.setFloatRegister(UNW_ARM64_D10, 659288149Semaste addressSpace.getDouble(savedRegisterLoc)); 660288149Semaste savedRegisterLoc -= 8; 661288149Semaste registers.setFloatRegister(UNW_ARM64_D11, 662288149Semaste addressSpace.getDouble(savedRegisterLoc)); 663288149Semaste savedRegisterLoc -= 8; 664288149Semaste } 665288149Semaste if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 666288149Semaste registers.setFloatRegister(UNW_ARM64_D12, 667288149Semaste addressSpace.getDouble(savedRegisterLoc)); 668288149Semaste savedRegisterLoc -= 8; 669288149Semaste registers.setFloatRegister(UNW_ARM64_D13, 670288149Semaste addressSpace.getDouble(savedRegisterLoc)); 671288149Semaste savedRegisterLoc -= 8; 672288149Semaste } 673288149Semaste if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 674288149Semaste registers.setFloatRegister(UNW_ARM64_D14, 675288149Semaste addressSpace.getDouble(savedRegisterLoc)); 676288149Semaste savedRegisterLoc -= 8; 677288149Semaste registers.setFloatRegister(UNW_ARM64_D15, 678288149Semaste addressSpace.getDouble(savedRegisterLoc)); 679288149Semaste savedRegisterLoc -= 8; 680288149Semaste } 681288149Semaste 682288149Semaste uint64_t fp = registers.getFP(); 683288149Semaste // fp points to old fp 684288149Semaste registers.setFP(addressSpace.get64(fp)); 685288149Semaste // old sp is fp less saved fp and lr 686288149Semaste registers.setSP(fp + 16); 687288149Semaste // pop return address into pc 688288149Semaste registers.setIP(addressSpace.get64(fp + 8)); 689288149Semaste 690288149Semaste return UNW_STEP_SUCCESS; 691288149Semaste} 692302450Semaste#endif // _LIBUNWIND_TARGET_AARCH64 693288149Semaste 694288149Semaste 695288149Semaste} // namespace libunwind 696288149Semaste 697288149Semaste#endif // __COMPACT_UNWINDER_HPP__ 698