static inline NORETURN void resume(unw_cursor_t* cursor, const uint8_t* landing_pad, int64_t switch_value, const ExcInfo* exc_data) { checkExcInfo(exc_data); assert(landing_pad); if (VERBOSITY("cxx_unwind") >= 4) printf(" * RESUMED: ip %p switch_value %ld\n", (const void*)landing_pad, (long)switch_value); if (0 != switch_value) { // The exception handler will call __cxa_begin_catch, which stops this timer and logs it. per_thread_resume_catch_timer.restart("resume_catch", 20); } else { // The cleanup code will call _Unwind_Resume, which will stop this timer and log it. // TODO: am I sure cleanup code can't raise exceptions? maybe have an assert! per_thread_cleanup_timer.restart("cleanup", 20); #ifndef NDEBUG in_cleanup_code = true; #endif } // set rax to pointer to exception object // set rdx to the switch_value (0 for cleanup, otherwise an index indicating which exception handler to use) // // NB. assumes x86-64. maybe I should use __builtin_eh_return_data_regno() here? // but then, need to translate into UNW_* values somehow. not clear how. check(unw_set_reg(cursor, UNW_X86_64_RAX, (unw_word_t)exc_data)); check(unw_set_reg(cursor, UNW_X86_64_RDX, switch_value)); // resume! check(unw_set_reg(cursor, UNW_REG_IP, (unw_word_t)landing_pad)); unw_resume(cursor); RELEASE_ASSERT(0, "unw_resume returned!"); }
void jffi_longjmp (jmp_buf env, int val) { extern int _jffi_longjmp_cont; unw_context_t uc; unw_cursor_t c; unw_word_t sp, ip, bp = 0; uintptr_t *wp = (uintptr_t *) env; int i, setjmp_frame; if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) { debug("failed to get context"); abort (); } #ifdef __x86_86__ # define UNW_REG_BP UNW_X86_64_RBP #else # define UNW_REG_BP UNW_X86_EBP #endif setjmp_frame = 0; do { char name[256]; unw_proc_info_t pi; unw_word_t off; if (unw_get_reg (&c, UNW_REG_BP, &bp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) { abort(); } if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0) { abort(); } unw_get_proc_name(&c, name, sizeof(name), &off); unw_get_proc_info(&c, &pi); // debug("frame %s ip=%llx sp=%llx bp=%llx wp[RP]=%p wp[SP]=%p, pi.start_ip=%llx, pi.end_ip=%llx", // name, (long long) ip, (long long) sp, (long long) bp, (void *) wp[JB_RP], (void *) wp[JB_SP], // pi.start_ip, pi.end_ip); if (wp[JB_SP] > sp || wp[JB_RP] < pi.start_ip || wp[JB_RP] > pi.end_ip) continue; /* found the right frame: */ // debug("found frame to jump back to"); assert (UNW_NUM_EH_REGS >= 2); if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) &_jffi_longjmp_cont)) abort (); unw_resume (&c); // should not reach here abort (); } while (unw_step (&c) > 0); // debug("failed to find correct frame to jmp to"); }
/// Called by personality handler during phase 2 to alter instruction pointer, /// such as setting where the landing pad is, so _Unwind_Resume() will /// start executing in the landing pad. _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t new_value) { _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", context, (uint64_t) new_value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, UNW_REG_IP, new_value); }
/// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t value) { _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64 ")\n", (void *)context, index, (uint64_t)value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, index, value); }
/// Called by personality handler during phase 2 to alter register values. _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t new_value) { _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, " "value=0x%0llX)\n", context, index, (uint64_t) new_value); unw_cursor_t *cursor = (unw_cursor_t *)context; unw_set_reg(cursor, index, new_value); }
void _longjmp (jmp_buf env, int val) { extern int _UI_longjmp_cont; unw_context_t uc; unw_cursor_t c; unw_word_t sp; unw_word_t *wp = (unw_word_t *) env; if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) abort (); do { if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) abort (); #ifdef __FreeBSD__ if (sp != wp[JB_SP] + sizeof(unw_word_t)) #else if (sp != wp[JB_SP]) #endif continue; if (!bsp_match (&c, wp)) continue; /* found the right frame: */ assert (UNW_NUM_EH_REGS >= 2); if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) &_UI_longjmp_cont)) abort (); unw_resume (&c); abort (); } while (unw_step (&c) > 0); abort (); }
_Unwind_VRS_Result _Unwind_VRS_Set( _Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, regclass=%d reg=%d, rep=%d, " "value=0x%0llX)\n", context, regclass, regno, representation, 0LL /* FIXME */); unw_cursor_t *cursor = (unw_cursor_t *)context; switch (regclass) { case _UVRSC_CORE: { if (representation != _UVRSD_UINT32) _LIBUNWIND_ABORT("Core register representation must be _UVRSD_UINT32."); return unw_set_reg(cursor, regno, *((unw_word_t*)valuep)) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; } // FIXME: Are these right? See 4.7 on lazy-saving case _UVRSC_WMMXD: case _UVRSC_WMMXC: case _UVRSC_VFP: { unw_fpreg_t value; switch (representation) { case _UVRSD_VFPX: // TODO(ajwong): What does this mean? break; case _UVRSD_UINT64: { uint64_t tmp = *(uint64_t*)valuep; memcpy(&value, &tmp, sizeof(tmp)); break; } case _UVRSD_FLOAT: { float tmp = *(float*)valuep; memcpy(&value, &tmp, sizeof(tmp)); break; } case _UVRSD_DOUBLE: { double tmp = *(double*)valuep; memcpy(&value, &tmp, sizeof(tmp)); break; } case _UVRSD_UINT32: { uint32_t tmp = *(uint32_t*)valuep; memcpy(&value, &tmp, sizeof(tmp)); break; } default: _LIBUNWIND_ABORT("Invalid VFP data representation."); } return unw_set_fpreg(cursor, regno, value) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; } } return _UVRSR_NOT_IMPLEMENTED; }
static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor) { #if defined(_AMD64_) unw_set_reg(cursor, UNW_REG_IP, winContext->Rip); unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp); unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp); unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx); unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12); unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13); unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14); unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15); #endif }
static int unwind_and_resume (long iteration, int (*next_func[])()) { unw_context_t uc; unw_cursor_t c; unw_word_t ip; int i, ret; if (verbose) printf (" %s(iteration=%ld, next_func=%p)\n", __FUNCTION__, iteration, next_func); unw_getcontext (&uc); if ((ret = unw_init_local (&c, &uc)) < 0) panic ("unw_init_local (ret=%d)", ret); for (i = 0; i < unwind_count; ++i) if ((ret = unw_step (&c)) < 0) panic ("unw_step (ret=%d)", ret); if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) &resumption_point_label) < 0 || unw_set_reg (&c, UNW_REG_EH + 0, 0) /* ret val */ || unw_set_reg (&c, UNW_REG_EH + 1, ip)) panic ("failed to redirect to resumption_point\n"); if (verbose) { unw_word_t bsp; if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0) panic ("unw_get_reg() failed\n"); printf (" bsp=%lx, old ip=%lx, new ip=%p\n", bsp, ip, &resumption_point_label); } ret = unw_resume (&c); panic ("unw_resume() returned (ret=%d)!!\n", ret); return 0; }
/// Scans unwind information to find the function that contains the /// specified code address "pc". _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc); // This is slow, but works. // We create an unwind cursor then alter the IP to be pc unw_cursor_t cursor; unw_context_t uc; unw_proc_info_t info; unw_getcontext(&uc); unw_init_local(&cursor, &uc); unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) return (void *)(long) info.start_ip; else return NULL; }
static void restore_context (MonoContext *ctx) { int res; unw_word_t ip; res = unw_get_reg (&ctx->cursor, UNW_IA64_IP, &ip); g_assert (res == 0); /* Set this to 0 to tell OP_START_HANDLER that it doesn't have to set the frame pointer */ res = unw_set_reg (&ctx->cursor, UNW_IA64_GR + 15, 0); g_assert (res == 0); unw_resume (&ctx->cursor); }
void unwindExc(Box* exc_obj) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip, sp; unw_getcontext(&uc); unw_init_local(&cursor, &uc); int code; unw_proc_info_t pip; while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_get_reg(&cursor, UNW_REG_SP, &sp); printf("ip = %lx, sp = %lx\n", (long)ip, (long)sp); code = unw_get_proc_info(&cursor, &pip); RELEASE_ASSERT(code == 0, ""); // printf("%lx %lx %lx %lx %lx %lx %d %d %p\n", pip.start_ip, pip.end_ip, pip.lsda, pip.handler, pip.gp, // pip.flags, pip.format, pip.unwind_info_size, pip.unwind_info); assert((pip.lsda == 0) == (pip.handler == 0)); assert(pip.flags == 0); if (pip.handler == 0) { if (VERBOSITY()) printf("Skipping frame without handler\n"); continue; } printf("%lx %lx %lx\n", pip.lsda, pip.handler, pip.flags); // assert(pip.handler == (uintptr_t)__gxx_personality_v0 || pip.handler == (uintptr_t)__py_personality_v0); // auto handler_fn = (int (*)(int, int, uint64_t, void*, void*))pip.handler; ////handler_fn(1, 1 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL); // handler_fn(2, 2 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL); unw_set_reg(&cursor, UNW_REG_IP, 1); // TODO testing: // unw_resume(&cursor); } abort(); }
/// Find dwarf unwind info for an address 'pc' in some function. _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *bases) { // This is slow, but works. // We create an unwind cursor then alter the IP to be pc unw_cursor_t cursor; unw_context_t uc; unw_proc_info_t info; unw_getcontext(&uc); unw_init_local(&cursor, &uc); unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); unw_get_proc_info(&cursor, &info); bases->tbase = (uintptr_t)info.extra; bases->dbase = 0; // dbase not used on Mac OS X bases->func = (uintptr_t)info.start_ip; _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, (void *)(long) info.unwind_info); return (void *)(long) info.unwind_info; }
static void sighandler (int signal) { unw_cursor_t cursor, cursor2; unw_word_t ip; unw_context_t uc; if (verbose) printf ("caught signal %d\n", signal); unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init() failed!\n"); /* get cursor for caller of sighandler: */ if (unw_step (&cursor) < 0) panic ("unw_step() failed!\n"); cursor2 = cursor; while (!unw_is_signal_frame (&cursor2)) if (unw_step (&cursor2) < 0) panic ("failed to find signal frame!\n"); if (unw_step (&cursor2) < 0) panic ("unw_step() failed!\n"); if (unw_get_reg (&cursor2, UNW_REG_IP, &ip) < 0) panic ("failed to get IP!\n"); /* skip faulting instruction (doesn't handle MLX template) */ ++ip; if ((ip & 0x3) == 0x3) ip += 13; if (unw_set_reg (&cursor2, UNW_REG_IP, ip) < 0) panic ("failed to set IP!\n"); unw_resume (&cursor); /* update context & return to caller of sighandler() */ panic ("unexpected return from unw_resume()!\n"); }
static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, struct _Unwind_Exception *exception_object, bool resume) { // See comment at the start of unwind_phase1 regarding VRS integrity. unw_cursor_t cursor2; unw_init_local(&cursor2, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); int frame_count = 0; // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException or _Unwind_Resume). // // Resume only ever makes sense for 1 frame. _Unwind_State state = resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; if (resume && frame_count == 1) { // On a resume, first unwind the _Unwind_Resume() frame. The next frame // is now the landing pad for the cleanup from a previous execution of // phase2. To continue unwindingly correctly, replace VRS[15] with the // IP of the frame that the previous run of phase2 installed the context // for. After this, continue unwinding as if normal. // // See #7.4.6 for details. unw_set_reg(&cursor2, UNW_REG_IP, exception_object->unwinder_cache.reserved2); resume = false; } int stepResult = unw_step(&cursor2); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " "_URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // Get info about this frame. unw_word_t sp; unw_proc_info_t frameInfo; unw_get_reg(&cursor2, UNW_REG_SP, &sp); if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionName[512]; unw_word_t offset; if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) strcpy(functionName, ".anonymous."); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " "lsda=0x%llX, personality=0x%llX\n", exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2); #ifdef __arm__ exception_object->pr_cache.fnstart = frameInfo.start_ip; exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; exception_object->pr_cache.additional = frameInfo.flags; _Unwind_Reason_Code personalityResult = (*p)(state, exception_object, context); #else _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); } _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, context); #endif switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); #ifdef __arm__ if (sp == exception_object->barrier_cache.sp) { #else if (sp == exception_object->private_2) { #endif // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). if (_LIBUNWIND_TRACING_UNWINDING) { unw_word_t pc; unw_get_reg(&cursor2, UNW_REG_IP, &pc); unw_get_reg(&cursor2, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " "user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp); } #ifdef __arm__ // #7.4.1 says we need to preserve pc for when _Unwind_Resume is called // back, to find this same frame. unw_word_t pc; unw_get_reg(&cursor2, UNW_REG_IP, &pc); exception_object->unwinder_cache.reserved2 = (uint32_t)pc; #endif unw_resume(&cursor2); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; #ifdef __arm__ // # 7.4.3 case _URC_FAILURE: abort(); #endif default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } frame_count++; } // Clean up phase did not resume at the frame that the search phase // said it would... return _URC_FATAL_PHASE2_ERROR; } #ifndef __arm__ static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t *uc, struct _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter) { unw_cursor_t cursor2; unw_init_local(&cursor2, uc); // Walk each frame until we reach where search phase said to stop while (unw_step(&cursor2) > 0) { // Update info about this frame. unw_proc_info_t frameInfo; if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " "failed => _URC_END_OF_STACK\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionName[512]; unw_word_t offset; if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) strcpy(functionName, ".anonymous."); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "start_ip=0x%llX, func=%s, lsda=0x%llX, " " personality=0x%llX\n", exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } // Call stop function at each frame. _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); _Unwind_Reason_Code stopResult = (*stop)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2), stop_parameter); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult); if (stopResult != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p); _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned _URC_CONTINUE_UNWIND\n", exception_object); // Destructors called, continue unwinding break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned _URC_INSTALL_CONTEXT\n", exception_object); // We may get control back if landing pad calls _Unwind_Resume(). unw_resume(&cursor2); break; default: // Personality routine returned an unknown result code. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned %d, " "_URC_FATAL_PHASE2_ERROR\n", exception_object, personalityResult); return _URC_FATAL_PHASE2_ERROR; } } } // Call stop function one last time and tell it we've reached the end // of the stack. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " "function with _UA_END_OF_STACK\n", exception_object); _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2), stop_parameter); // Clean up phase did not resume at the frame that the search phase said it // would. return _URC_FATAL_PHASE2_ERROR; }
static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor) { #if defined(_AMD64_) unw_set_reg(cursor, UNW_REG_IP, winContext->Rip); unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp); unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp); unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx); unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12); unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13); unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14); unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15); #elif defined(_ARM_) unw_set_reg(cursor, UNW_ARM_R13, winContext->Sp); unw_set_reg(cursor, UNW_ARM_R14, winContext->Lr); unw_set_reg(cursor, UNW_ARM_R15, winContext->Pc); unw_set_reg(cursor, UNW_ARM_R4, winContext->R4); unw_set_reg(cursor, UNW_ARM_R5, winContext->R5); unw_set_reg(cursor, UNW_ARM_R6, winContext->R6); unw_set_reg(cursor, UNW_ARM_R7, winContext->R7); unw_set_reg(cursor, UNW_ARM_R8, winContext->R8); unw_set_reg(cursor, UNW_ARM_R9, winContext->R9); unw_set_reg(cursor, UNW_ARM_R10, winContext->R10); unw_set_reg(cursor, UNW_ARM_R11, winContext->R11); #endif }
PROTECTED void _Unwind_SetIP (struct _Unwind_Context *context, unsigned long new_value) { unw_set_reg (&context->cursor, UNW_REG_IP, new_value); }
int backtrace(void **trace, int size) { unw_cursor_t cursor; unw_context_t uc; unw_word_t ip; int n = 0; unw_getcontext(&uc); unw_init_local(&cursor, &uc); while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); trace[n++] = (void *)ip; { char buf[256]; unw_get_proc_name(&cursor, buf, 256, &ip); if (strncmp("_sigtramp", buf, sizeof("_sigtramp")) == 0) { goto darwin_sigtramp; } } } return n; darwin_sigtramp: /* darwin's bundled libunwind doesn't support signal trampoline */ { ucontext_t *uctx; /* get _sigtramp's ucontext_t and set values to cursor * http://www.opensource.apple.com/source/Libc/Libc-825.25/i386/sys/_sigtramp.s * http://www.opensource.apple.com/source/libunwind/libunwind-35.1/src/unw_getcontext.s */ unw_get_reg(&cursor, UNW_X86_64_RBX, &ip); uctx = (ucontext_t *)ip; unw_set_reg(&cursor, UNW_X86_64_RAX, uctx->uc_mcontext->__ss.__rax); unw_set_reg(&cursor, UNW_X86_64_RBX, uctx->uc_mcontext->__ss.__rbx); unw_set_reg(&cursor, UNW_X86_64_RCX, uctx->uc_mcontext->__ss.__rcx); unw_set_reg(&cursor, UNW_X86_64_RDX, uctx->uc_mcontext->__ss.__rdx); unw_set_reg(&cursor, UNW_X86_64_RDI, uctx->uc_mcontext->__ss.__rdi); unw_set_reg(&cursor, UNW_X86_64_RSI, uctx->uc_mcontext->__ss.__rsi); unw_set_reg(&cursor, UNW_X86_64_RBP, uctx->uc_mcontext->__ss.__rbp); unw_set_reg(&cursor, UNW_X86_64_RSP, 8+(uctx->uc_mcontext->__ss.__rsp)); unw_set_reg(&cursor, UNW_X86_64_R8, uctx->uc_mcontext->__ss.__r8); unw_set_reg(&cursor, UNW_X86_64_R9, uctx->uc_mcontext->__ss.__r9); unw_set_reg(&cursor, UNW_X86_64_R10, uctx->uc_mcontext->__ss.__r10); unw_set_reg(&cursor, UNW_X86_64_R11, uctx->uc_mcontext->__ss.__r11); unw_set_reg(&cursor, UNW_X86_64_R12, uctx->uc_mcontext->__ss.__r12); unw_set_reg(&cursor, UNW_X86_64_R13, uctx->uc_mcontext->__ss.__r13); unw_set_reg(&cursor, UNW_X86_64_R14, uctx->uc_mcontext->__ss.__r14); unw_set_reg(&cursor, UNW_X86_64_R15, uctx->uc_mcontext->__ss.__r15); ip = uctx->uc_mcontext->__ss.__rip; if (((char*)ip)[-2] == 0x0f && ((char*)ip)[-1] == 5) { /* signal received in syscall */ trace[n++] = (void *)ip; ip = *(unw_word_t*)uctx->uc_mcontext->__ss.__rsp; } trace[n++] = (void *)ip; unw_set_reg(&cursor, UNW_REG_IP, ip); } while (unw_step(&cursor) > 0) { unw_get_reg(&cursor, UNW_REG_IP, &ip); trace[n++] = (void *)ip; } return n; }
void siglongjmp (sigjmp_buf env, int val) { unw_word_t *wp = (unw_word_t *) env; extern int _UI_siglongjmp_cont; extern int _UI_longjmp_cont; unw_context_t uc; unw_cursor_t c; unw_word_t sp; int *cont; if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0) abort (); do { if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0) abort (); #ifdef __FreeBSD__ if (sp != wp[JB_SP] + sizeof(unw_word_t)) #else if (sp != wp[JB_SP]) #endif continue; if (!bsp_match (&c, wp)) continue; /* found the right frame: */ /* default to resuming without restoring signal-mask */ cont = &_UI_longjmp_cont; /* Order of evaluation is important here: if unw_resume() restores signal mask, we must set it up appropriately, even if wp[JB_MASK_SAVED] is FALSE. */ if (!resume_restores_sigmask (&c, wp) && wp[JB_MASK_SAVED]) { /* sigmask was saved */ if (UNW_NUM_EH_REGS < 4 || _NSIG >= 16 * sizeof (unw_word_t)) /* signal mask doesn't fit into EH arguments and we can't put it on the stack without overwriting something else... */ abort (); else if (unw_set_reg (&c, UNW_REG_EH + 2, wp[JB_MASK]) < 0 || (_NSIG > 8 * sizeof (unw_word_t) && unw_set_reg (&c, UNW_REG_EH + 3, wp[JB_MASK + 1]) < 0)) abort (); cont = &_UI_siglongjmp_cont; } if (unw_set_reg (&c, UNW_REG_EH + 0, wp[JB_RP]) < 0 || unw_set_reg (&c, UNW_REG_EH + 1, val) < 0 || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) (uintptr_t) cont)) abort (); unw_resume (&c); abort (); } while (unw_step (&c) > 0); abort (); }
bool SetFrameRegisterCallback::execute_real() { ret = unw_set_reg(cp_, reg_, val_); return true; }
// // Called by personality handler during phase 2 to alter register values // EXPORT void _Unwind_SetGR(struct _Unwind_Context* context, int index, uintptr_t new_value) { DEBUG_PRINT_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0llX)\n", context, index, (uint64_t)new_value); unw_cursor_t* cursor = (unw_cursor_t*)context; unw_set_reg(cursor, index, new_value); }