Esempio n. 1
0
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;
	}
    }
}
Esempio n. 2
0
_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, &region);
  db_region_for (&region, 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, &region, &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;
}
Esempio n. 3
0
_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, &region);
  ip = get_ip_from_context (uw_context);
  db_region_for (&region, 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, &region, &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;
}
Esempio n. 4
0
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;
	}
    }
}