/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, _Unwind_Context *ctx) { void *cf = (void *)_Unwind_GetGR(ctx, 13); lua_State *L = cframe_L(cf); int errcode; switch ((state & _US_ACTION_MASK)) { case _US_VIRTUAL_UNWIND_FRAME: if ((state & _US_FORCE_UNWIND)) break; return _URC_HANDLER_FOUND; case _US_UNWIND_FRAME_STARTING: if (LJ_UEXCLASS_CHECK(ucb->exclass)) { errcode = LJ_UEXCLASS_ERRCODE(ucb->exclass); } else { errcode = LUA_ERRRUN; setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); } cf = err_unwind(L, cf, errcode); if ((state & _US_FORCE_UNWIND) || cf == NULL) break; _Unwind_SetGR(ctx, 15, (uint32_t)lj_vm_unwind_ext); _Unwind_SetGR(ctx, 0, (uint32_t)ucb); _Unwind_SetGR(ctx, 1, (uint32_t)errcode); _Unwind_SetGR(ctx, 2, cframe_unwind_ff(cf) ? (uint32_t)lj_vm_unwind_ff_eh : (uint32_t)lj_vm_unwind_c_eh); return _URC_INSTALL_CONTEXT; default: return _URC_FAILURE; } if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) return _URC_FAILURE; return _URC_CONTINUE_UNWIND; }
/* DWARF2 personality handler referenced from interpreter .eh_frame. */ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions, uint64_t uexclass, struct _Unwind_Exception *uex, struct _Unwind_Context *ctx) { void *cf; lua_State *L; if (version != 1) return _URC_FATAL_PHASE1_ERROR; UNUSED(uexclass); cf = (void *)_Unwind_GetCFA(ctx); L = cframe_L(cf); if ((actions & _UA_SEARCH_PHASE)) { #if LJ_UNWIND_EXT if (err_unwind(L, cf, 0) == NULL) return _URC_CONTINUE_UNWIND; #endif if (!LJ_UEXCLASS_CHECK(uexclass)) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); } return _URC_HANDLER_FOUND; } if ((actions & _UA_CLEANUP_PHASE)) { int errcode; if (LJ_UEXCLASS_CHECK(uexclass)) { errcode = LJ_UEXCLASS_ERRCODE(uexclass); } else { if ((actions & _UA_HANDLER_FRAME)) _Unwind_DeleteException(uex); errcode = LUA_ERRRUN; } #if LJ_UNWIND_EXT cf = err_unwind(L, cf, errcode); if ((actions & _UA_FORCE_UNWIND)) { return _URC_CONTINUE_UNWIND; } else if (cf) { _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ? lj_vm_unwind_ff_eh : lj_vm_unwind_c_eh)); return _URC_INSTALL_CONTEXT; } #if LJ_TARGET_X86ORX64 else if ((actions & _UA_HANDLER_FRAME)) { /* Workaround for ancient libgcc bug. Still present in RHEL 5.5. :-/ ** Real fix: http://gcc.gnu.org/viewcvs/trunk/gcc/unwind-dw2.c?r1=121165&r2=124837&pathrev=153877&diff_format=h */ _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)lj_vm_unwind_rethrow); return _URC_INSTALL_CONTEXT; } #endif #else /* This is not the proper way to escape from the unwinder. We get away with ** it on x86/PPC because the interpreter restores all callee-saved regs. */ lj_err_throw(L, errcode); #endif } return _URC_CONTINUE_UNWIND; }
static void setup_to_install (_Unwind_Context *uw_context, _Unwind_Exception *uw_exception, _Unwind_Ptr uw_landing_pad, int uw_filter) { #ifndef EH_RETURN_DATA_REGNO /* We should not be called if the appropriate underlying support is not there. */ abort (); #else /* 1/ exception object pointer, which might be provided back to _Unwind_Resume (and thus to this personality routine) if we are jumping to a cleanup. */ _Unwind_SetGR (uw_context, __builtin_eh_return_data_regno (0), (_Unwind_Word)uw_exception); /* 2/ handler switch value register, which will also be used by the target landing pad to decide what action it shall take. */ _Unwind_SetGR (uw_context, __builtin_eh_return_data_regno (1), (_Unwind_Word)uw_filter); /* Setup the address we should jump at to reach the code where there is the "something" we found. */ _Unwind_SetIP (uw_context, uw_landing_pad); #endif }
COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, struct _Unwind_Context *context) #endif { /* Since C does not have catch clauses, there is nothing to do during */ /* phase 1 (the search phase). */ if ( actions & _UA_SEARCH_PHASE ) return _URC_CONTINUE_UNWIND; /* There is nothing to do if there is no LSDA for this frame. */ const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context); if ( lsda == (uint8_t*) 0 ) return _URC_CONTINUE_UNWIND; uintptr_t pc = _Unwind_GetIP(context)-1; uintptr_t funcStart = _Unwind_GetRegionStart(context); uintptr_t pcOffset = pc - funcStart; /* Parse LSDA header. */ uint8_t lpStartEncoding = *lsda++; if (lpStartEncoding != DW_EH_PE_omit) { readEncodedPointer(&lsda, lpStartEncoding); } uint8_t ttypeEncoding = *lsda++; if (ttypeEncoding != DW_EH_PE_omit) { readULEB128(&lsda); } /* Walk call-site table looking for range that includes current PC. */ uint8_t callSiteEncoding = *lsda++; uint32_t callSiteTableLength = readULEB128(&lsda); const uint8_t* callSiteTableStart = lsda; const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; const uint8_t* p=callSiteTableStart; while (p < callSiteTableEnd) { uintptr_t start = readEncodedPointer(&p, callSiteEncoding); uintptr_t length = readEncodedPointer(&p, callSiteEncoding); uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding); readULEB128(&p); /* action value not used for C code */ if ( landingPad == 0 ) continue; /* no landing pad for this entry */ if ( (start <= pcOffset) && (pcOffset < (start+length)) ) { /* Found landing pad for the PC. * Set Instruction Pointer to so we re-enter function * at landing pad. The landing pad is created by the compiler * to take two parameters in registers. */ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)exceptionObject); _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); _Unwind_SetIP(context, (funcStart + landingPad)); return _URC_INSTALL_CONTEXT; } } /* No landing pad found, continue unwinding. */ return _URC_CONTINUE_UNWIND; }
_Unwind_Reason_Code __gxx_personality_v0 ( int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception* unwind_exception, _Unwind_Context* context) { if (actions & _UA_SEARCH_PHASE) { printf("Personality function, lookup phase\n"); return _URC_HANDLER_FOUND; } else if (actions & _UA_CLEANUP_PHASE) { printf("Personality function, cleanup\n"); // Pointer to the beginning of the raw LSDA LSDA_ptr lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context); // Read LSDA headerfor the LSDA LSDA_Header header(&lsda); // Read the LSDA CS header LSDA_CS_Header cs_header(&lsda); // Calculate where the end of the LSDA CS table is const LSDA_ptr lsda_cs_table_end = lsda + cs_header.length; // Loop through each entry in the CS table while (lsda < lsda_cs_table_end) { LSDA_CS cs(&lsda); if (cs.lp) { int r0 = __builtin_eh_return_data_regno(0); int r1 = __builtin_eh_return_data_regno(1); _Unwind_SetGR(context, r0, (uintptr_t)(unwind_exception)); // Note the following code hardcodes the exception type; // we'll fix that later on _Unwind_SetGR(context, r1, (uintptr_t)(1)); uintptr_t func_start = _Unwind_GetRegionStart(context); _Unwind_SetIP(context, func_start + cs.lp); break; } } return _URC_INSTALL_CONTEXT; } else { printf("Personality function, error\n"); return _URC_FATAL_PHASE1_ERROR; } }
static void set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, const scan_results& results) { #if __arm__ _Unwind_SetGR(context, 0, reinterpret_cast<uintptr_t>(unwind_exception)); _Unwind_SetGR(context, 1, static_cast<uintptr_t>(results.ttypeIndex)); #else _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), reinterpret_cast<uintptr_t>(unwind_exception)); _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), static_cast<uintptr_t>(results.ttypeIndex)); #endif _Unwind_SetIP(context, results.landingPad); }
/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ LJ_FUNCA int lj_err_unwind_arm(int state, void *ucb, _Unwind_Context *ctx) { void *cf = (void *)_Unwind_GetGR(ctx, 13); lua_State *L = cframe_L(cf); if ((state & _US_ACTION_MASK) == _US_VIRTUAL_UNWIND_FRAME) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); return _URC_HANDLER_FOUND; } if ((state&(_US_ACTION_MASK|_US_FORCE_UNWIND)) == _US_UNWIND_FRAME_STARTING) { _Unwind_DeleteException(ucb); _Unwind_SetGR(ctx, 15, (uint32_t)(void *)lj_err_throw); _Unwind_SetGR(ctx, 0, (uint32_t)L); _Unwind_SetGR(ctx, 1, (uint32_t)LUA_ERRRUN); return _URC_INSTALL_CONTEXT; } if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) return _URC_FAILURE; return _URC_CONTINUE_UNWIND; }
_Unwind_Reason_Code PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) /* APPLE LOCAL begin LLVM */ #endif /* APPLE LOCAL end LLVM */ { lsda_header_info info; const unsigned char *language_specific_data, *p, *action_record; _Unwind_Ptr landing_pad, ip; /* APPLE LOCAL begin LLVM */ #ifdef __ARM_EABI_UNWINDER__ if (state != _US_UNWIND_FRAME_STARTING) CONTINUE_UNWINDING; /* The dwarf unwinder assumes the context structure holds things like the function and LSDA pointers. The ARM implementation caches these in the exception header (UCB). To avoid rewriting everything we make the virtual IP register point at the UCB. */ ip = (_Unwind_Ptr) ue_header; _Unwind_SetGR (context, 12, ip); #else /* APPLE LOCAL end LLVM */ if (version != 1) return _URC_FATAL_PHASE1_ERROR; /* Currently we only support cleanups for C. */ if ((actions & _UA_CLEANUP_PHASE) == 0) /* APPLE LOCAL begin LLVM */ CONTINUE_UNWINDING; #endif /* APPLE LOCAL end LLVM */ language_specific_data = (const unsigned char *) _Unwind_GetLanguageSpecificData (context); /* If no LSDA, then there are no handlers or cleanups. */ if (! language_specific_data) /* APPLE LOCAL begin LLVM */ CONTINUE_UNWINDING; /* APPLE LOCAL end LLVM */ /* Parse the LSDA header. */ p = parse_lsda_header (context, language_specific_data, &info); ip = _Unwind_GetIP (context) - 1; landing_pad = 0; #ifdef __USING_SJLJ_EXCEPTIONS__ /* The given "IP" is an index into the call-site table, with two exceptions -- -1 means no-action, and 0 means terminate. But since we're using uleb128 values, we've not got random access to the array. */ if ((int) ip <= 0) return _URC_CONTINUE_UNWIND; else { _Unwind_Word cs_lp, cs_action; do { p = read_uleb128 (p, &cs_lp); p = read_uleb128 (p, &cs_action); } while (--ip); /* Can never have null landing pad for sjlj -- that would have been indicated by a -1 call site index. */ landing_pad = cs_lp + 1; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } #else /* Search the call-site table for the action associated with this IP. */ while (p < info.action_table) { _Unwind_Ptr cs_start, cs_len, cs_lp; _Unwind_Word cs_action; /* Note that all call-site encodings are "absolute" displacements. */ p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); p = read_uleb128 (p, &cs_action); /* The table is sorted, so if we've passed the ip, stop. */ if (ip < info.Start + cs_start) p = info.action_table; else if (ip < info.Start + cs_start + cs_len) { if (cs_lp) landing_pad = info.LPStart + cs_lp; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } } #endif /* IP is not in table. No associated cleanups. */ /* ??? This is where C++ calls std::terminate to catch throw from a destructor. */ /* APPLE LOCAL begin LLVM */ CONTINUE_UNWINDING; /* APPLE LOCAL end LLVM */ found_something: if (landing_pad == 0) { /* IP is present, but has a null landing pad. No handler to be run. */ /* APPLE LOCAL begin LLVM */ CONTINUE_UNWINDING; /* APPLE LOCAL end LLVM */ } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), (_Unwind_Ptr) ue_header); _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); _Unwind_SetIP (context, landing_pad); return _URC_INSTALL_CONTEXT; }
PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) #endif { struct ObjcException *xh = (struct ObjcException *) ue_header; struct lsda_header_info info; const unsigned char *language_specific_data; const unsigned char *action_record; const unsigned char *p; _Unwind_Ptr landing_pad, ip; int handler_switch_value; int saw_cleanup = 0, saw_handler; void *return_object; int foreign_exception; int ip_before_insn = 0; #ifdef __ARM_EABI_UNWINDER__ _Unwind_Action actions; switch (state & _US_ACTION_MASK) { case _US_VIRTUAL_UNWIND_FRAME: actions = _UA_SEARCH_PHASE; break; case _US_UNWIND_FRAME_STARTING: actions = _UA_CLEANUP_PHASE; if (!(state & _US_FORCE_UNWIND) && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) actions |= _UA_HANDLER_FRAME; break; case _US_UNWIND_FRAME_RESUME: CONTINUE_UNWINDING; break; default: abort(); } actions |= state & _US_FORCE_UNWIND; foreign_exception = 0; ip = (_Unwind_Ptr) ue_header; _Unwind_SetGR(context, 12, ip); #else /* Interface version check. */ if (version != 1) return _URC_FATAL_PHASE1_ERROR; foreign_exception = !(exception_class == __objc_exception_class); #endif /* Shortcut for phase 2 found handler for domestic exception. */ if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) && !foreign_exception) { #ifdef __ARM_EABI_UNWINDER__ handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; #else handler_switch_value = xh->handlerSwitchValue; landing_pad = xh->landingPad; #endif goto install_context; } language_specific_data = (const unsigned char *) _Unwind_GetLanguageSpecificData (context); /* If no LSDA, then there are no handlers or cleanups. */ if (! language_specific_data) CONTINUE_UNWINDING; /* Parse the LSDA header. */ p = parse_lsda_header (context, language_specific_data, &info); info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); #ifdef HAVE_GETIPINFO ip = _Unwind_GetIPInfo (context, &ip_before_insn); #else ip = _Unwind_GetIP (context); #endif if (! ip_before_insn) --ip; landing_pad = 0; action_record = 0; handler_switch_value = 0; #ifdef SJLJ_EXCEPTIONS /* The given "IP" is an index into the call-site table, with two exceptions -- -1 means no-action, and 0 means terminate. But since we're using uleb128 values, we've not got random access to the array. */ if ((int) ip < 0) return _URC_CONTINUE_UNWIND; else { _Unwind_Word cs_lp, cs_action; do { p = read_uleb128 (p, &cs_lp); p = read_uleb128 (p, &cs_action); } while (--ip); /* Can never have null landing pad for sjlj -- that would have been indicated by a -1 call site index. */ landing_pad = cs_lp + 1; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } #else /* Search the call-site table for the action associated with this IP. */ while (p < info.action_table) { _Unwind_Ptr cs_start, cs_len, cs_lp; _Unwind_Word cs_action; /* Note that all call-site encodings are "absolute" displacements. */ p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); p = read_uleb128 (p, &cs_action); /* The table is sorted, so if we've passed the ip, stop. */ if (ip < info.Start + cs_start) p = info.action_table; else if (ip < info.Start + cs_start + cs_len) { if (cs_lp) landing_pad = info.LPStart + cs_lp; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } } #endif /* SJLJ_EXCEPTIONS */ /* If ip is not present in the table, C++ would call terminate. */ /* ??? As with Java, it's perhaps better to tweek the LSDA to that no-action is mapped to no-entry. */ return _URC_CONTINUE_UNWIND; found_something: saw_cleanup = 0; saw_handler = 0; if (landing_pad == 0) { /* If ip is present, and has a null landing pad, there are no cleanups or handlers to be run. */ } else if (action_record == 0) { /* If ip is present, has a non-null landing pad, and a null action table offset, then there are only cleanups present. Cleanups use a zero switch value, as set above. */ saw_cleanup = 1; } else { /* Otherwise we have a catch handler. */ _Unwind_Sword ar_filter, ar_disp; while (1) { p = action_record; p = read_sleb128 (p, &ar_filter); read_sleb128 (p, &ar_disp); if (ar_filter == 0) { /* Zero filter values are cleanups. */ saw_cleanup = 1; } /* During forced unwinding, we only run cleanups. With a foreign exception class, we have no class info to match. */ else if ((actions & _UA_FORCE_UNWIND) || foreign_exception) ; else if (ar_filter > 0) { /* Positive filter values are handlers. */ Class catch_type = get_ttype_entry (&info, ar_filter); if (isKindOf (xh->value, catch_type)) { handler_switch_value = ar_filter; saw_handler = 1; break; } } else { /* Negative filter values are exception specifications, which Objective-C does not use. */ abort (); } if (ar_disp == 0) break; action_record = p + ar_disp; } } if (! saw_handler && ! saw_cleanup) CONTINUE_UNWINDING; if (actions & _UA_SEARCH_PHASE) { if (!saw_handler) CONTINUE_UNWINDING; /* For domestic exceptions, we cache data from phase 1 for phase 2. */ if (!foreign_exception) { #ifdef __ARM_EABI_UNWIDER__ ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13); ue_header->barrier_cache.bitpattern[1] = (_uw) handler_switch_value; ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; #else xh->handlerSwitchValue = handler_switch_value; xh->landingPad = landing_pad; #endif } return _URC_HANDLER_FOUND; } install_context: if (saw_cleanup == 0) { return_object = xh->value; if (!(actions & _UA_SEARCH_PHASE)) _Unwind_DeleteException(&xh->base); } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), __builtin_extend_pointer (saw_cleanup ? xh : return_object)); _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), handler_switch_value); _Unwind_SetIP (context, landing_pad); return _URC_INSTALL_CONTEXT; }
_Unwind_Reason_Code PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) #endif { lsda_header_info info; const unsigned char *language_specific_data, *p, *action_record; _Unwind_Ptr landing_pad, ip; int ip_before_insn = 0; _Bool is_foreign; G *g; #ifdef __ARM_EABI_UNWINDER__ _Unwind_Action actions; switch (state & _US_ACTION_MASK) { case _US_VIRTUAL_UNWIND_FRAME: actions = _UA_SEARCH_PHASE; break; case _US_UNWIND_FRAME_STARTING: actions = _UA_CLEANUP_PHASE; if (!(state & _US_FORCE_UNWIND) && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) actions |= _UA_HANDLER_FRAME; break; case _US_UNWIND_FRAME_RESUME: CONTINUE_UNWINDING; break; default: abort(); } actions |= state & _US_FORCE_UNWIND; is_foreign = 0; /* The dwarf unwinder assumes the context structure holds things like the function and LSDA pointers. The ARM implementation caches these in the exception header (UCB). To avoid rewriting everything we make the virtual IP register point at the UCB. */ ip = (_Unwind_Ptr) ue_header; _Unwind_SetGR (context, 12, ip); #else if (version != 1) return _URC_FATAL_PHASE1_ERROR; is_foreign = exception_class != __go_exception_class; #endif language_specific_data = (const unsigned char *) _Unwind_GetLanguageSpecificData (context); /* If no LSDA, then there are no handlers or cleanups. */ if (! language_specific_data) CONTINUE_UNWINDING; /* Parse the LSDA header. */ p = parse_lsda_header (context, language_specific_data, &info); #ifdef HAVE_GETIPINFO ip = _Unwind_GetIPInfo (context, &ip_before_insn); #else ip = _Unwind_GetIP (context); #endif if (! ip_before_insn) --ip; landing_pad = 0; action_record = NULL; #ifdef __USING_SJLJ_EXCEPTIONS__ /* The given "IP" is an index into the call-site table, with two exceptions -- -1 means no-action, and 0 means terminate. But since we're using uleb128 values, we've not got random access to the array. */ if ((int) ip <= 0) return _URC_CONTINUE_UNWIND; else { _uleb128_t cs_lp, cs_action; do { p = read_uleb128 (p, &cs_lp); p = read_uleb128 (p, &cs_action); } while (--ip); /* Can never have null landing pad for sjlj -- that would have been indicated by a -1 call site index. */ landing_pad = (_Unwind_Ptr)cs_lp + 1; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } #else /* Search the call-site table for the action associated with this IP. */ while (p < info.action_table) { _Unwind_Ptr cs_start, cs_len, cs_lp; _uleb128_t cs_action; /* Note that all call-site encodings are "absolute" displacements. */ p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); p = read_uleb128 (p, &cs_action); /* The table is sorted, so if we've passed the ip, stop. */ if (ip < info.Start + cs_start) p = info.action_table; else if (ip < info.Start + cs_start + cs_len) { if (cs_lp) landing_pad = info.LPStart + cs_lp; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } } #endif /* IP is not in table. No associated cleanups. */ CONTINUE_UNWINDING; found_something: if (landing_pad == 0) { /* IP is present, but has a null landing pad. No handler to be run. */ CONTINUE_UNWINDING; } if (actions & _UA_SEARCH_PHASE) { if (action_record == 0) { /* This indicates a cleanup rather than an exception handler. */ CONTINUE_UNWINDING; } return _URC_HANDLER_FOUND; } /* It's possible for g to be NULL here for an exception thrown by a language other than Go. */ g = runtime_g (); if (g == NULL) { if (!is_foreign) abort (); } else { g->exception = ue_header; g->isforeign = is_foreign; } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), (_Unwind_Ptr) ue_header); _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); _Unwind_SetIP (context, landing_pad); return _URC_INSTALL_CONTEXT; }
_Unwind_Reason_Code __runa_personality(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) { enum found_handler_type { found_nothing, found_terminate, found_cleanup, found_handler } found_type; struct lsda_header_info info; const unsigned char *language_specific_data; const unsigned char *action_record; const unsigned char *p; _Unwind_Ptr landing_pad, ip; int handler_switch_value; void* thrown_ptr = 0; bool foreign_exception; int ip_before_insn = 0; //__cxa_exception* xh = __get_exception_header_from_ue(ue_header); // Interface version check. if (version != 1) return _URC_FATAL_PHASE1_ERROR; foreign_exception = exception_class != RUNA_CLASS; // Shortcut for phase 2 found handler for domestic exception. if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) && !foreign_exception) { restore_caught_exception(ue_header, &handler_switch_value, &language_specific_data, &landing_pad); found_type = (landing_pad == 0 ? found_terminate : found_handler); goto install_context; } language_specific_data = (const unsigned char *) _Unwind_GetLanguageSpecificData(context); // If no LSDA, then there are no handlers or cleanups. if (!language_specific_data) return _URC_CONTINUE_UNWIND; // Parse the LSDA header. p = parse_lsda_header(context, language_specific_data, &info); info.ttype_base = base_of_encoded_value(info.ttype_encoding, context); ip = _Unwind_GetIPInfo(context, &ip_before_insn); //ip = _Unwind_GetIP(context); if (!ip_before_insn) --ip; landing_pad = 0; action_record = 0; handler_switch_value = 0; // Search the call-site table for the action associated with this IP. while (p < info.action_table) { _Unwind_Ptr cs_start, cs_len, cs_lp; _uleb128_t cs_action; // Note that all call-site encodings are "absolute" displacements. p = read_encoded_value(0, info.call_site_encoding, p, &cs_start); p = read_encoded_value(0, info.call_site_encoding, p, &cs_len); p = read_encoded_value(0, info.call_site_encoding, p, &cs_lp); p = read_uleb128(p, &cs_action); // The table is sorted, so if we've passed the ip, stop. if (ip < info.Start + cs_start) { p = info.action_table; } else if (ip < info.Start + cs_start + cs_len) { if (cs_lp) landing_pad = info.LPStart + cs_lp; if (cs_action) action_record = info.action_table + cs_action - 1; goto found_something; } } // If ip is not present in the table, call terminate. This is for // a destructor inside a cleanup, or a library routine the compiler // was not expecting to throw. found_type = found_terminate; goto do_something; found_something: if (landing_pad == 0) { // If ip is present, and has a null landing pad, there are // no cleanups or handlers to be run. found_type = found_nothing; } else if (action_record == 0) { // If ip is present, has a non-null landing pad, and a null // action table offset, then there are only cleanups present. // Cleanups use a zero switch value, as set above. found_type = found_cleanup; } else { // Otherwise we have a catch handler or exception specification. _sleb128_t ar_filter, ar_disp; //const std::type_info* catch_type; //_throw_typet* throw_type; bool saw_cleanup = false; bool saw_handler = false; { //thrown_ptr = __get_object_from_ue(ue_header); //throw_type = __get_exception_header_from_obj(thrown_ptr)->exceptionType; } while (1) { p = action_record; p = read_sleb128(p, &ar_filter); read_sleb128(p, &ar_disp); if (ar_filter == 0) { // Zero filter values are cleanups. saw_cleanup = true; } else if (ar_filter > 0) { // Positive filter values are handlers. //catch_type = get_ttype_entry(&info, ar_filter); //printf("positive filter value -- handler found\n"); saw_handler = true; break; // Null catch type is a catch-all handler; we can catch foreign // exceptions with this. Otherwise we must match types. //if (!catch_type || (throw_type && // get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))) { // saw_handler = true; // break; //} } else { printf("negative filter value -- exception spec\n"); // Negative filter values are exception specifications. // ??? How do foreign exceptions fit in? As far as I can // see we can't match because there's no __cxa_exception // object to stuff bits in for __cxa_call_unexpected to use. // Allow them iff the exception spec is non-empty. I.e. // a throw() specification results in __unexpected. //if ((throw_type && !(actions & _UA_FORCE_UNWIND) && !foreign_exception) ? // !check_exception_spec(&info, throw_type, thrown_ptr, ar_filter) : // empty_exception_spec(&info, ar_filter)) { // saw_handler = true; // break; //} } if (ar_disp == 0) break; action_record = p + ar_disp; } if (saw_handler) { handler_switch_value = ar_filter; found_type = found_handler; } else { found_type = (saw_cleanup ? found_cleanup : found_nothing); } } do_something: if (found_type == found_nothing) return _URC_CONTINUE_UNWIND; if (actions & _UA_SEARCH_PHASE) { if (found_type == found_cleanup) return _URC_CONTINUE_UNWIND; // For domestic exceptions, we cache data from phase 1 for phase 2. if (!foreign_exception) { save_caught_exception(ue_header, handler_switch_value, language_specific_data, landing_pad); } return _URC_HANDLER_FOUND; } install_context: // We can't use any of the cxa routines with foreign exceptions, // because they all expect ue_header to be a struct __cxa_exception. // So in that case, call terminate or unexpected directly. if ((actions & _UA_FORCE_UNWIND) || foreign_exception) { if (found_type == found_terminate) abort(); // std::terminate(); else if (handler_switch_value < 0) { printf("WTF\n"); //__try // { std::unexpected (); } //__catch(...) // { std::terminate (); } } } else { if (found_type == found_terminate) abort(); //__cxa_call_terminate(ue_header); // Cache the TType base value for __cxa_call_unexpected, as we won't // have an _Unwind_Context then. if (handler_switch_value < 0) { parse_lsda_header(context, language_specific_data, &info); info.ttype_base = base_of_encoded_value(info.ttype_encoding, context); //xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); } } /* For targets with pointers smaller than the word size, we must extend the pointer, and this extension is target dependent. */ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), __builtin_extend_pointer(ue_header)); _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), handler_switch_value); _Unwind_SetIP(context, landing_pad); return _URC_INSTALL_CONTEXT; }
_Unwind_Reason_Code __gxx_personality_v0 ( int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception* unwind_exception, _Unwind_Context* context) { if (actions & _UA_SEARCH_PHASE) { printf("Personality function, lookup phase\n"); return _URC_HANDLER_FOUND; } else if (actions & _UA_CLEANUP_PHASE) { printf("Personality function, cleanup\n"); // Calculate what the instruction pointer was just before the // exception was thrown for this stack frame uintptr_t throw_ip = _Unwind_GetIP(context) - 1; // Pointer to the beginning of the raw LSDA LSDA_ptr lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context); // Read LSDA headerfor the LSDA LSDA_Header header(&lsda); // Read the LSDA CS header LSDA_CS_Header cs_header(&lsda); // Calculate where the end of the LSDA CS table is const LSDA_ptr lsda_cs_table_end = lsda + cs_header.length; // Loop through each entry in the CS table while (lsda < lsda_cs_table_end) { LSDA_CS cs(&lsda); // If there's no LP we can't handle this exception; move on if (not cs.lp) continue; uintptr_t func_start = _Unwind_GetRegionStart(context); // Calculate the range of the instruction pointer valid for this // landing pad; if this LP can handle the current exception then // the IP for this stack frame must be in this range uintptr_t try_start = func_start + cs.start; uintptr_t try_end = func_start + cs.start + cs.len; // Check if this is the correct LP for the current try block if (throw_ip < try_start) continue; if (throw_ip > try_end) continue; // We found a landing pad for this exception; resume execution int r0 = __builtin_eh_return_data_regno(0); int r1 = __builtin_eh_return_data_regno(1); _Unwind_SetGR(context, r0, (uintptr_t)(unwind_exception)); // Note the following code hardcodes the exception type; // we'll fix that later on _Unwind_SetGR(context, r1, (uintptr_t)(1)); _Unwind_SetIP(context, func_start + cs.lp); break; } return _URC_INSTALL_CONTEXT; } else { printf("Personality function, error\n"); return _URC_FATAL_PHASE1_ERROR; } }
_Unwind_Reason_Code __gxx_personality_v0 ( int version, _Unwind_Action actions, uint64_t exceptionClass, _Unwind_Exception* unwind_exception, _Unwind_Context* context) { if (actions & _UA_SEARCH_PHASE) { printf("Personality function, lookup phase\n"); return _URC_HANDLER_FOUND; } else if (actions & _UA_CLEANUP_PHASE) { printf("Personality function, cleanup\n"); // Calculate what the instruction pointer was just before the // exception was thrown for this stack frame uintptr_t throw_ip = _Unwind_GetIP(context) - 1; // Get a pointer to the raw memory address of the LSDA LSDA_ptr raw_lsda = (LSDA_ptr) _Unwind_GetLanguageSpecificData(context); // Create an object to hide some part of the LSDA processing LSDA lsda(raw_lsda); // Go through each call site in this stack frame to check whether // the current exception can be handled here for(const LSDA_CS *cs = lsda.next_call_site_entry(true); cs != NULL; cs = lsda.next_call_site_entry()) { // If there's no landing pad we can't handle this exception if (not cs->lp) continue; uintptr_t func_start = _Unwind_GetRegionStart(context); // Calculate the range of the instruction pointer valid for this // landing pad; if this LP can handle the current exception then // the IP for this stack frame must be in this range uintptr_t try_start = func_start + cs->start; uintptr_t try_end = func_start + cs->start + cs->len; // Check if this is the correct LP for the current try block if (throw_ip < try_start) continue; if (throw_ip > try_end) continue; // Get the offset into the action table for this LP if (cs->action > 0) { // cs->action is the offset + 1; that way cs->action == 0 // means there is no associated entry in the action table const size_t action_offset = cs->action - 1; const LSDA_ptr action = lsda.action_tbl_start + action_offset; // For a landing pad with a catch the action table will // hold an index to a list of types int type_index = action[0]; const void* catch_type_info = lsda.types_table_start[ -1 * type_index ]; const std::type_info *catch_ti = (const std::type_info *) catch_type_info; printf("%s\n", catch_ti->name()); } // We found a landing pad for this exception; resume execution int r0 = __builtin_eh_return_data_regno(0); int r1 = __builtin_eh_return_data_regno(1); _Unwind_SetGR(context, r0, (uintptr_t)(unwind_exception)); // Note the following code hardcodes the exception type; // we'll fix that later on _Unwind_SetGR(context, r1, (uintptr_t)(1)); _Unwind_SetIP(context, func_start + cs->lp); break; } return _URC_INSTALL_CONTEXT; } else { printf("Personality function, error\n"); return _URC_FATAL_PHASE1_ERROR; } }