Path: blob/main/contrib/llvm-project/libunwind/src/UnwindLevel1.c
35148 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//7// Implements C++ ABI Exception Handling Level 1 as documented at:8// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html9// using libunwind10//11//===----------------------------------------------------------------------===//1213// ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}(). Thus, we are14// defining inline functions to delegate the function calls to15// _Unwind_VRS_{Get,Set}(). However, some applications might declare the16// function protetype directly (instead of including <unwind.h>), thus we need17// to export these functions from libunwind.so as well.18#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 11920#include <inttypes.h>21#include <stdint.h>22#include <stdbool.h>23#include <stdlib.h>24#include <stdio.h>25#include <string.h>2627#include "cet_unwind.h"28#include "config.h"29#include "libunwind.h"30#include "libunwind_ext.h"31#include "unwind.h"3233#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) && \34!defined(__wasm__)3536#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND3738// When CET is enabled, each "call" instruction will push return address to39// CET shadow stack, each "ret" instruction will pop current CET shadow stack40// top and compare it with target address which program will return.41// In exception handing, some stack frames will be skipped before jumping to42// landing pad and we must adjust CET shadow stack accordingly.43// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we44// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using45// a regular function call to avoid pushing to CET shadow stack again.46#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)47#define __unw_phase2_resume(cursor, fn) \48do { \49(void)fn; \50__unw_resume((cursor)); \51} while (0)52#elif defined(_LIBUNWIND_TARGET_I386)53#define __cet_ss_step_size 454#define __unw_phase2_resume(cursor, fn) \55do { \56_LIBUNWIND_POP_CET_SSP((fn)); \57void *cetRegContext = __libunwind_cet_get_registers((cursor)); \58void *cetJumpAddress = __libunwind_cet_get_jump_target(); \59__asm__ volatile("push %%edi\n\t" \60"sub $4, %%esp\n\t" \61"jmp *%%edx\n\t" :: "D"(cetRegContext), \62"d"(cetJumpAddress)); \63} while (0)64#elif defined(_LIBUNWIND_TARGET_X86_64)65#define __cet_ss_step_size 866#define __unw_phase2_resume(cursor, fn) \67do { \68_LIBUNWIND_POP_CET_SSP((fn)); \69void *cetRegContext = __libunwind_cet_get_registers((cursor)); \70void *cetJumpAddress = __libunwind_cet_get_jump_target(); \71__asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \72"d"(cetJumpAddress)); \73} while (0)74#elif defined(_LIBUNWIND_TARGET_AARCH64)75#define __cet_ss_step_size 876#define __unw_phase2_resume(cursor, fn) \77do { \78_LIBUNWIND_POP_CET_SSP((fn)); \79void *cetRegContext = __libunwind_cet_get_registers((cursor)); \80void *cetJumpAddress = __libunwind_cet_get_jump_target(); \81__asm__ volatile("mov x0, %0\n\t" \82"br %1\n\t" \83: \84: "r"(cetRegContext), "r"(cetJumpAddress) \85: "x0"); \86} while (0)87#endif8889static _Unwind_Reason_Code90unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {91__unw_init_local(cursor, uc);9293// Walk each frame looking for a place to stop.94while (true) {95// Ask libunwind to get next frame (skip over first which is96// _Unwind_RaiseException).97int stepResult = __unw_step(cursor);98if (stepResult == 0) {99_LIBUNWIND_TRACE_UNWINDING(100"unwind_phase1(ex_obj=%p): __unw_step() reached "101"bottom => _URC_END_OF_STACK",102(void *)exception_object);103return _URC_END_OF_STACK;104} else if (stepResult < 0) {105_LIBUNWIND_TRACE_UNWINDING(106"unwind_phase1(ex_obj=%p): __unw_step failed => "107"_URC_FATAL_PHASE1_ERROR",108(void *)exception_object);109return _URC_FATAL_PHASE1_ERROR;110}111112// See if frame has code to run (has personality routine).113unw_proc_info_t frameInfo;114unw_word_t sp;115if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {116_LIBUNWIND_TRACE_UNWINDING(117"unwind_phase1(ex_obj=%p): __unw_get_proc_info "118"failed => _URC_FATAL_PHASE1_ERROR",119(void *)exception_object);120return _URC_FATAL_PHASE1_ERROR;121}122123#ifndef NDEBUG124// When tracing, print state information.125if (_LIBUNWIND_TRACING_UNWINDING) {126char functionBuf[512];127const char *functionName = functionBuf;128unw_word_t offset;129if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),130&offset) != UNW_ESUCCESS) ||131(frameInfo.start_ip + offset > frameInfo.end_ip))132functionName = ".anonymous.";133unw_word_t pc;134__unw_get_reg(cursor, UNW_REG_IP, &pc);135_LIBUNWIND_TRACE_UNWINDING(136"unwind_phase1(ex_obj=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR137", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",138(void *)exception_object, pc, frameInfo.start_ip, functionName,139frameInfo.lsda, frameInfo.handler);140}141#endif142143// If there is a personality routine, ask it if it will want to stop at144// this frame.145if (frameInfo.handler != 0) {146_Unwind_Personality_Fn p =147(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);148_LIBUNWIND_TRACE_UNWINDING(149"unwind_phase1(ex_obj=%p): calling personality function %p",150(void *)exception_object, (void *)(uintptr_t)p);151_Unwind_Reason_Code personalityResult =152(*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,153exception_object, (struct _Unwind_Context *)(cursor));154switch (personalityResult) {155case _URC_HANDLER_FOUND:156// found a catch clause or locals that need destructing in this frame157// stop search and remember stack pointer at the frame158__unw_get_reg(cursor, UNW_REG_SP, &sp);159exception_object->private_2 = (uintptr_t)sp;160_LIBUNWIND_TRACE_UNWINDING(161"unwind_phase1(ex_obj=%p): _URC_HANDLER_FOUND",162(void *)exception_object);163return _URC_NO_REASON;164165case _URC_CONTINUE_UNWIND:166_LIBUNWIND_TRACE_UNWINDING(167"unwind_phase1(ex_obj=%p): _URC_CONTINUE_UNWIND",168(void *)exception_object);169// continue unwinding170break;171172default:173// something went wrong174_LIBUNWIND_TRACE_UNWINDING(175"unwind_phase1(ex_obj=%p): _URC_FATAL_PHASE1_ERROR",176(void *)exception_object);177return _URC_FATAL_PHASE1_ERROR;178}179}180}181return _URC_NO_REASON;182}183extern int __unw_step_stage2(unw_cursor_t *);184185#if defined(_LIBUNWIND_USE_GCS)186// Enable the GCS target feature to permit gcspop instructions to be used.187__attribute__((target("gcs")))188#endif189static _Unwind_Reason_Code190unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {191__unw_init_local(cursor, uc);192193_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p)",194(void *)exception_object);195196// uc is initialized by __unw_getcontext in the parent frame. The first stack197// frame walked is unwind_phase2.198unsigned framesWalked = 1;199#if defined(_LIBUNWIND_USE_CET)200unsigned long shadowStackTop = _get_ssp();201#elif defined(_LIBUNWIND_USE_GCS)202unsigned long shadowStackTop = 0;203if (__chkfeat(_CHKFEAT_GCS))204shadowStackTop = (unsigned long)__gcspr();205#endif206// Walk each frame until we reach where search phase said to stop.207while (true) {208209// Ask libunwind to get next frame (skip over first which is210// _Unwind_RaiseException).211int stepResult = __unw_step_stage2(cursor);212if (stepResult == 0) {213_LIBUNWIND_TRACE_UNWINDING(214"unwind_phase2(ex_obj=%p): __unw_step_stage2() reached "215"bottom => _URC_END_OF_STACK",216(void *)exception_object);217return _URC_END_OF_STACK;218} else if (stepResult < 0) {219_LIBUNWIND_TRACE_UNWINDING(220"unwind_phase2(ex_obj=%p): __unw_step_stage2 failed => "221"_URC_FATAL_PHASE1_ERROR",222(void *)exception_object);223return _URC_FATAL_PHASE2_ERROR;224}225226// Get info about this frame.227unw_word_t sp;228unw_proc_info_t frameInfo;229__unw_get_reg(cursor, UNW_REG_SP, &sp);230if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {231_LIBUNWIND_TRACE_UNWINDING(232"unwind_phase2(ex_obj=%p): __unw_get_proc_info "233"failed => _URC_FATAL_PHASE1_ERROR",234(void *)exception_object);235return _URC_FATAL_PHASE2_ERROR;236}237238#ifndef NDEBUG239// When tracing, print state information.240if (_LIBUNWIND_TRACING_UNWINDING) {241char functionBuf[512];242const char *functionName = functionBuf;243unw_word_t offset;244if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),245&offset) != UNW_ESUCCESS) ||246(frameInfo.start_ip + offset > frameInfo.end_ip))247functionName = ".anonymous.";248_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): start_ip=0x%" PRIxPTR249", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR250", personality=0x%" PRIxPTR,251(void *)exception_object, frameInfo.start_ip,252functionName, sp, frameInfo.lsda,253frameInfo.handler);254}255#endif256257// In CET enabled environment, we check return address stored in normal stack258// against return address stored in CET shadow stack, if the 2 addresses don't259// match, it means return address in normal stack has been corrupted, we return260// _URC_FATAL_PHASE2_ERROR.261#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)262if (shadowStackTop != 0) {263unw_word_t retInNormalStack;264__unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);265unsigned long retInShadowStack = *(266unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);267if (retInNormalStack != retInShadowStack)268return _URC_FATAL_PHASE2_ERROR;269}270#endif271++framesWalked;272// If there is a personality routine, tell it we are unwinding.273if (frameInfo.handler != 0) {274_Unwind_Personality_Fn p =275(_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);276_Unwind_Action action = _UA_CLEANUP_PHASE;277if (sp == exception_object->private_2) {278// Tell personality this was the frame it marked in phase 1.279action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);280}281_Unwind_Reason_Code personalityResult =282(*p)(1, action, exception_object->exception_class, exception_object,283(struct _Unwind_Context *)(cursor));284switch (personalityResult) {285case _URC_CONTINUE_UNWIND:286// Continue unwinding287_LIBUNWIND_TRACE_UNWINDING(288"unwind_phase2(ex_obj=%p): _URC_CONTINUE_UNWIND",289(void *)exception_object);290if (sp == exception_object->private_2) {291// Phase 1 said we would stop at this frame, but we did not...292_LIBUNWIND_ABORT("during phase1 personality function said it would "293"stop here, but now in phase2 it did not stop here");294}295break;296case _URC_INSTALL_CONTEXT:297_LIBUNWIND_TRACE_UNWINDING(298"unwind_phase2(ex_obj=%p): _URC_INSTALL_CONTEXT",299(void *)exception_object);300// Personality routine says to transfer control to landing pad.301// We may get control back if landing pad calls _Unwind_Resume().302if (_LIBUNWIND_TRACING_UNWINDING) {303unw_word_t pc;304__unw_get_reg(cursor, UNW_REG_IP, &pc);305__unw_get_reg(cursor, UNW_REG_SP, &sp);306_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): re-entering "307"user code with ip=0x%" PRIxPTR308", sp=0x%" PRIxPTR,309(void *)exception_object, pc, sp);310}311312__unw_phase2_resume(cursor, framesWalked);313// __unw_phase2_resume() only returns if there was an error.314return _URC_FATAL_PHASE2_ERROR;315default:316// Personality routine returned an unknown result code.317_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",318personalityResult);319return _URC_FATAL_PHASE2_ERROR;320}321}322}323324// Clean up phase did not resume at the frame that the search phase325// said it would...326return _URC_FATAL_PHASE2_ERROR;327}328329#if defined(_LIBUNWIND_USE_GCS)330// Enable the GCS target feature to permit gcspop instructions to be used.331__attribute__((target("gcs")))332#endif333static _Unwind_Reason_Code334unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,335_Unwind_Exception *exception_object,336_Unwind_Stop_Fn stop, void *stop_parameter) {337__unw_init_local(cursor, uc);338339// uc is initialized by __unw_getcontext in the parent frame. The first stack340// frame walked is unwind_phase2_forced.341unsigned framesWalked = 1;342// Walk each frame until we reach where search phase said to stop343while (__unw_step_stage2(cursor) > 0) {344345// Update info about this frame.346unw_proc_info_t frameInfo;347if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {348_LIBUNWIND_TRACE_UNWINDING(349"unwind_phase2_forced(ex_obj=%p): __unw_get_proc_info "350"failed => _URC_END_OF_STACK",351(void *)exception_object);352return _URC_FATAL_PHASE2_ERROR;353}354355#ifndef NDEBUG356// When tracing, print state information.357if (_LIBUNWIND_TRACING_UNWINDING) {358char functionBuf[512];359const char *functionName = functionBuf;360unw_word_t offset;361if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),362&offset) != UNW_ESUCCESS) ||363(frameInfo.start_ip + offset > frameInfo.end_ip))364functionName = ".anonymous.";365_LIBUNWIND_TRACE_UNWINDING(366"unwind_phase2_forced(ex_obj=%p): start_ip=0x%" PRIxPTR367", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,368(void *)exception_object, frameInfo.start_ip, functionName,369frameInfo.lsda, frameInfo.handler);370}371#endif372373// Call stop function at each frame.374_Unwind_Action action =375(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);376_Unwind_Reason_Code stopResult =377(*stop)(1, action, exception_object->exception_class, exception_object,378(struct _Unwind_Context *)(cursor), stop_parameter);379_LIBUNWIND_TRACE_UNWINDING(380"unwind_phase2_forced(ex_obj=%p): stop function returned %d",381(void *)exception_object, stopResult);382if (stopResult != _URC_NO_REASON) {383_LIBUNWIND_TRACE_UNWINDING(384"unwind_phase2_forced(ex_obj=%p): stopped by stop function",385(void *)exception_object);386return _URC_FATAL_PHASE2_ERROR;387}388389++framesWalked;390// If there is a personality routine, tell it we are unwinding.391if (frameInfo.handler != 0) {392_Unwind_Personality_Fn p =393(_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);394_LIBUNWIND_TRACE_UNWINDING(395"unwind_phase2_forced(ex_obj=%p): calling personality function %p",396(void *)exception_object, (void *)(uintptr_t)p);397_Unwind_Reason_Code personalityResult =398(*p)(1, action, exception_object->exception_class, exception_object,399(struct _Unwind_Context *)(cursor));400switch (personalityResult) {401case _URC_CONTINUE_UNWIND:402_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "403"personality returned "404"_URC_CONTINUE_UNWIND",405(void *)exception_object);406// Destructors called, continue unwinding407break;408case _URC_INSTALL_CONTEXT:409_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "410"personality returned "411"_URC_INSTALL_CONTEXT",412(void *)exception_object);413// We may get control back if landing pad calls _Unwind_Resume().414__unw_phase2_resume(cursor, framesWalked);415break;416default:417// Personality routine returned an unknown result code.418_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "419"personality returned %d, "420"_URC_FATAL_PHASE2_ERROR",421(void *)exception_object, personalityResult);422return _URC_FATAL_PHASE2_ERROR;423}424}425}426427// Call stop function one last time and tell it we've reached the end428// of the stack.429_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): calling stop "430"function with _UA_END_OF_STACK",431(void *)exception_object);432_Unwind_Action lastAction =433(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);434(*stop)(1, lastAction, exception_object->exception_class, exception_object,435(struct _Unwind_Context *)(cursor), stop_parameter);436437// Clean up phase did not resume at the frame that the search phase said it438// would.439return _URC_FATAL_PHASE2_ERROR;440}441442443/// Called by __cxa_throw. Only returns if there is a fatal error.444_LIBUNWIND_EXPORT _Unwind_Reason_Code445_Unwind_RaiseException(_Unwind_Exception *exception_object) {446_LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",447(void *)exception_object);448unw_context_t uc;449unw_cursor_t cursor;450__unw_getcontext(&uc);451452// Mark that this is a non-forced unwind, so _Unwind_Resume()453// can do the right thing.454exception_object->private_1 = 0;455exception_object->private_2 = 0;456457// phase 1: the search phase458_Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);459if (phase1 != _URC_NO_REASON)460return phase1;461462// phase 2: the clean up phase463return unwind_phase2(&uc, &cursor, exception_object);464}465466467468/// When _Unwind_RaiseException() is in phase2, it hands control469/// to the personality function at each frame. The personality470/// may force a jump to a landing pad in that function, the landing471/// pad code may then call _Unwind_Resume() to continue with the472/// unwinding. Note: the call to _Unwind_Resume() is from compiler473/// generated user code. All other _Unwind_* routines are called474/// by the C++ runtime __cxa_* routines.475///476/// Note: re-throwing an exception (as opposed to continuing the unwind)477/// is implemented by having the code call __cxa_rethrow() which478/// in turn calls _Unwind_Resume_or_Rethrow().479_LIBUNWIND_EXPORT void480_Unwind_Resume(_Unwind_Exception *exception_object) {481_LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);482unw_context_t uc;483unw_cursor_t cursor;484__unw_getcontext(&uc);485486if (exception_object->private_1 != 0)487unwind_phase2_forced(&uc, &cursor, exception_object,488(_Unwind_Stop_Fn) exception_object->private_1,489(void *)exception_object->private_2);490else491unwind_phase2(&uc, &cursor, exception_object);492493// Clients assume _Unwind_Resume() does not return, so all we can do is abort.494_LIBUNWIND_ABORT("_Unwind_Resume() can't return");495}496497498499/// Not used by C++.500/// Unwinds stack, calling "stop" function at each frame.501/// Could be used to implement longjmp().502_LIBUNWIND_EXPORT _Unwind_Reason_Code503_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,504_Unwind_Stop_Fn stop, void *stop_parameter) {505_LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",506(void *)exception_object, (void *)(uintptr_t)stop);507unw_context_t uc;508unw_cursor_t cursor;509__unw_getcontext(&uc);510511// Mark that this is a forced unwind, so _Unwind_Resume() can do512// the right thing.513exception_object->private_1 = (uintptr_t) stop;514exception_object->private_2 = (uintptr_t) stop_parameter;515516// do it517return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter);518}519520521/// Called by personality handler during phase 2 to get LSDA for current frame.522_LIBUNWIND_EXPORT uintptr_t523_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {524unw_cursor_t *cursor = (unw_cursor_t *)context;525unw_proc_info_t frameInfo;526uintptr_t result = 0;527if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)528result = (uintptr_t)frameInfo.lsda;529_LIBUNWIND_TRACE_API(530"_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,531(void *)context, result);532#if !defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)533if (result != 0) {534if (*((uint8_t *)result) != 0xFF)535_LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",536result);537}538#endif539return result;540}541542543/// Called by personality handler during phase 2 to find the start of the544/// function.545_LIBUNWIND_EXPORT uintptr_t546_Unwind_GetRegionStart(struct _Unwind_Context *context) {547unw_cursor_t *cursor = (unw_cursor_t *)context;548unw_proc_info_t frameInfo;549uintptr_t result = 0;550if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)551result = (uintptr_t)frameInfo.start_ip;552_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,553(void *)context, result);554return result;555}556557#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND558559/// Called by personality handler during phase 2 if a foreign exception560// is caught.561_LIBUNWIND_EXPORT void562_Unwind_DeleteException(_Unwind_Exception *exception_object) {563_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",564(void *)exception_object);565if (exception_object->exception_cleanup != NULL)566(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,567exception_object);568}569570/// Called by personality handler during phase 2 to get register values.571_LIBUNWIND_EXPORT uintptr_t572_Unwind_GetGR(struct _Unwind_Context *context, int index) {573unw_cursor_t *cursor = (unw_cursor_t *)context;574unw_word_t result;575__unw_get_reg(cursor, index, &result);576_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,577(void *)context, index, result);578return (uintptr_t)result;579}580581/// Called by personality handler during phase 2 to alter register values.582_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,583uintptr_t value) {584_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR585")",586(void *)context, index, value);587unw_cursor_t *cursor = (unw_cursor_t *)context;588__unw_set_reg(cursor, index, value);589}590591/// Called by personality handler during phase 2 to get instruction pointer.592_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {593unw_cursor_t *cursor = (unw_cursor_t *)context;594unw_word_t result;595__unw_get_reg(cursor, UNW_REG_IP, &result);596_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,597(void *)context, result);598return (uintptr_t)result;599}600601/// Called by personality handler during phase 2 to alter instruction pointer,602/// such as setting where the landing pad is, so _Unwind_Resume() will603/// start executing in the landing pad.604_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,605uintptr_t value) {606_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",607(void *)context, value);608unw_cursor_t *cursor = (unw_cursor_t *)context;609__unw_set_reg(cursor, UNW_REG_IP, value);610}611612#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)613614615