static void get_action_description_for (_Unwind_Ptr ip, _Unwind_Exception *uw_exception, _Unwind_Action uw_phase, region_descriptor *region, action_descriptor *action) { _GNAT_Exception *gnat_exception = (_GNAT_Exception *) uw_exception; /* Search the call site table first, which may get us a landing pad as well as the head of an action record list. */ get_call_site_action_for (ip, region, action); db_action_for (action, ip); /* If there is not even a call_site entry, we are done. */ if (action->kind == nothing) return; /* Otherwise, check what we have at the place of the call site. */ /* No landing pad => no cleanups or handlers. */ if (action->landing_pad == 0) { action->kind = nothing; return; } /* Landing pad + null table entry => only cleanups. */ else if (action->table_entry == 0) { action->kind = cleanup; action->ttype_filter = cleanup_filter; /* The filter initialization is not strictly necessary, as cleanup-only landing pads don't look at the filter value. It is there to ensure we don't pass random values and so trigger potential confusion when installing the context later on. */ return; } /* Landing pad + Table entry => handlers + possible cleanups. */ else { const unsigned char * p = action->table_entry; _sleb128_t ar_filter, ar_disp; action->kind = nothing; while (1) { p = read_sleb128 (p, &ar_filter); read_sleb128 (p, &ar_disp); /* Don't assign p here, as it will be incremented by ar_disp below. */ /* Null filters are for cleanups. */ if (ar_filter == cleanup_filter) { action->kind = cleanup; action->ttype_filter = cleanup_filter; /* The filter initialization is required here, to ensure the target landing pad branches to the cleanup code if we happen not to find a matching handler. */ } /* Positive filters are for regular handlers. */ else if (ar_filter > 0) { /* Do not catch an exception if the _UA_FORCE_UNWIND flag is passed (to follow the ABI). */ if (!(uw_phase & _UA_FORCE_UNWIND)) { enum action_kind act; /* See if the filter we have is for an exception which matches the one we are propagating. */ _Unwind_Ptr choice = get_ttype_entry_for (region, ar_filter); act = is_handled_by (choice, gnat_exception); if (act != nothing) { action->kind = act; action->ttype_filter = ar_filter; return; } } } /* Negative filter values are for C++ exception specifications. Should not be there for Ada :/ */ else db (DB_ERR, "========> Err, filter < 0 for Ada/dwarf\n"); if (ar_disp == 0) return; p += ar_disp; } } }
_Unwind_Reason_Code __gnat_eh_personality (int uw_version, _Unwind_Action uw_phases, _Unwind_Exception_Class uw_exception_class, _Unwind_Exception *uw_exception, _Unwind_Context *uw_context) { _GNAT_Exception * gnat_exception = (_GNAT_Exception *) uw_exception; region_descriptor region; action_descriptor action; if (uw_version != 1) return _URC_FATAL_PHASE1_ERROR; db_indent (DB_INDENT_RESET); db_phases (uw_phases); db_indent (DB_INDENT_INCREASE); /* Get the region description for the context we were provided with. This will tell us if there is some lsda, call_site, action and/or ttype data for the associated ip. */ get_region_description_for (uw_context, ®ion); db_region_for (®ion, uw_context); /* No LSDA => no handlers or cleanups => we shall unwind further up. */ if (! region.lsda) return _URC_CONTINUE_UNWIND; /* Search the call-site and action-record tables for the action associated with this IP. */ get_action_description_for (uw_context, uw_exception, ®ion, &action); db_action_for (&action, uw_context); /* Whatever the phase, if there is nothing relevant in this frame, unwinding should just go on. */ if (action.kind == nothing) return _URC_CONTINUE_UNWIND; /* If we found something in search phase, we should return a code indicating what to do next depending on what we found. If we only have cleanups around, we shall try to unwind further up to find a handler, otherwise, tell we have a handler, which will trigger the second phase. */ if (uw_phases & _UA_SEARCH_PHASE) { if (action.kind == cleanup) { gnat_exception->n_cleanups_to_trigger ++; return _URC_CONTINUE_UNWIND; } else { /* Trigger the appropriate notification routines before the second phase starts, which ensures the stack is still intact. */ __gnat_notify_handled_exception (); return _URC_HANDLER_FOUND; } } /* We found something in cleanup/handler phase, which might be the handler or a cleanup for a handled occurrence, or a cleanup for an unhandled occurrence (we are in a FORCED_UNWIND phase in this case). Install the context to get there. */ /* If we are going to install a cleanup context, decrement the cleanup count. This is required in a FORCED_UNWINDing phase (for an unhandled exception), as this is used from the forced unwinding handler in Ada.Exceptions.Exception_Propagation to decide wether unwinding should proceed further or Unhandled_Exception_Terminate should be called. */ if (action.kind == cleanup) gnat_exception->n_cleanups_to_trigger --; setup_to_install (uw_context, uw_exception, action.landing_pad, action.ttype_filter); return _URC_INSTALL_CONTEXT; }
_Unwind_Reason_Code PERSONALITY_FUNCTION (version_arg_t version_arg, phases_arg_t phases_arg, _Unwind_Exception_Class uw_exception_class ATTRIBUTE_UNUSED, _Unwind_Exception *uw_exception, _Unwind_Context *uw_context) { /* Fetch the version and phases args with their nominal ABI types for later use. This is a noop everywhere except on ia64-vms when called from the Condition Handling Facility. */ int uw_version = (int) version_arg; _Unwind_Action uw_phases = (_Unwind_Action) phases_arg; region_descriptor region; action_descriptor action; _Unwind_Ptr ip; /* Check that we're called from the ABI context we expect, with a major possible variation on VMS for IA64. */ if (uw_version != 1) { #if defined (VMS) && defined (__IA64) /* Assume we're called with sigargs/mechargs arguments if really unexpected bits are set in our first two formals. Redirect to the GNAT condition handling code in this case. */ extern long __gnat_handle_vms_condition (void *, void *); unsigned int version_unexpected_bits_mask = 0xffffff00U; unsigned int phases_unexpected_bits_mask = 0xffffff00U; if ((unsigned int)uw_version & version_unexpected_bits_mask && (unsigned int)uw_phases & phases_unexpected_bits_mask) return __gnat_handle_vms_condition (version_arg, phases_arg); #endif return _URC_FATAL_PHASE1_ERROR; } db_indent (DB_INDENT_RESET); db_phases (uw_phases); db_indent (DB_INDENT_INCREASE); /* Get the region description for the context we were provided with. This will tell us if there is some lsda, call_site, action and/or ttype data for the associated ip. */ get_region_description_for (uw_context, ®ion); ip = get_ip_from_context (uw_context); db_region_for (®ion, ip); /* No LSDA => no handlers or cleanups => we shall unwind further up. */ if (! region.lsda) return _URC_CONTINUE_UNWIND; /* Search the call-site and action-record tables for the action associated with this IP. */ get_action_description_for (ip, uw_exception, uw_phases, ®ion, &action); db_action_for (&action, ip); /* Whatever the phase, if there is nothing relevant in this frame, unwinding should just go on. */ if (action.kind == nothing) return _URC_CONTINUE_UNWIND; /* If we found something in search phase, we should return a code indicating what to do next depending on what we found. If we only have cleanups around, we shall try to unwind further up to find a handler, otherwise, tell we have a handler, which will trigger the second phase. */ if (uw_phases & _UA_SEARCH_PHASE) { if (action.kind == cleanup) { return _URC_CONTINUE_UNWIND; } else { struct Exception_Occurrence *excep; /* Trigger the appropriate notification routines before the second phase starts, which ensures the stack is still intact. First, setup the Ada occurrence. */ excep = __gnat_setup_current_excep (uw_exception); if (action.kind == unhandler) __gnat_notify_unhandled_exception (excep); else __gnat_notify_handled_exception (excep); return _URC_HANDLER_FOUND; } } /* We found something in cleanup/handler phase, which might be the handler or a cleanup for a handled occurrence, or a cleanup for an unhandled occurrence (we are in a FORCED_UNWIND phase in this case). Install the context to get there. */ setup_to_install (uw_context, uw_exception, action.landing_pad, action.ttype_filter); /* Write current exception, so that it can be retrieved from Ada. */ __gnat_setup_current_excep (uw_exception); return _URC_INSTALL_CONTEXT; }
static void get_action_description_for (_Unwind_Context *uw_context, _Unwind_Exception *uw_exception, region_descriptor *region, action_descriptor *action) { _GNAT_Exception * gnat_exception = (_GNAT_Exception *) uw_exception; /* Search the call site table first, which may get us a landing pad as well as the head of an action record list. */ get_call_site_action_for (uw_context, region, action); db_action_for (action, uw_context); /* If there is not even a call_site entry, we are done. */ if (action->kind == nothing) return; /* Otherwise, check what we have at the place of the call site */ /* No landing pad => no cleanups or handlers. */ if (action->landing_pad == 0) { action->kind = nothing; return; } /* Landing pad + null table entry => only cleanups. */ else if (action->table_entry == 0) { action->kind = cleanup; return; } /* Landing pad + Table entry => handlers + possible cleanups. */ else { const unsigned char * p = action->table_entry; _Unwind_Sword ar_filter, ar_disp; action->kind = nothing; while (1) { p = read_sleb128 (p, &ar_filter); read_sleb128 (p, &ar_disp); /* Don't assign p here, as it will be incremented by ar_disp below. */ /* Null filters are for cleanups. */ if (ar_filter == 0) action->kind = cleanup; /* Positive filters are for regular handlers. */ else if (ar_filter > 0) { /* See if the filter we have is for an exception which matches the one we are propagating. */ _Unwind_Ptr eid = get_ttype_entry_for (region, ar_filter); if (eid == gnat_exception->id || eid == GNAT_ALL_OTHERS || (eid == GNAT_OTHERS && gnat_exception->handled_by_others)) { action->ttype_filter = ar_filter; action->ttype_entry = eid; action->kind = handler; return; } } /* Negative filter values are for C++ exception specifications. Should not be there for Ada :/ */ else db (DB_ERR, "========> Err, filter < 0 for Ada/dwarf\n"); if (ar_disp == 0) return; p += ar_disp; } } }