Patchwork [Ada] Report unhandled exceptions as unhandled

login
register
mail settings
Submitter Arnaud Charlet
Date July 12, 2012, 10:24 a.m.
Message ID <20120712102451.GA25305@adacore.com>
Download mbox | patch
Permalink /patch/170630/
State New
Headers show

Comments

Arnaud Charlet - July 12, 2012, 10:24 a.m.
On some targets, there is a catch-all handler to catch unhandled exceptions.
This patch adjust the personality routine to report them as unhandled.
Behavior not changed.

Tested on x86_64-pc-linux-gnu, committed on trunk

2012-07-12  Tristan Gingold  <gingold@adacore.com>

	* raise-gcc.c: Do not include unwind-dw2-fde.h. Adjust comments.
	(db_region_for): Second argument is ip.  Do not recompute ip.
	(action_kind): Remove typedef, add unhandler enum const.
	(action_descriptor): Adjust type of kind field.
	(db_action_for): Second argument is ip, do not recompute it.
	(get_call_site_action_for): First argument is call_site, do not
	recompute it.  Remove useless return.
	(is_handled_by): Now return enum action_kind.
	Handle GNAT_ALL_OTHERS first.
	Return unhandler for GNAT_UNHANDLED_OTHERS.
	(get_action_description_for): First argument is now ip, do not
	recompute it.  Adjust code for call to is_handled_by.
	(__gnat_notify_unhandled_exception): Add prototype.
	(PERSONALITY_FUNCTION): Call get_ip_from_context.  Adjust calls.
	Handle unhandler case.
	(__gnat_cleanupunwind_handler): Add comments, add
	ATTRIBUTE_UNUSED on arguments.
	(__gnat_Unwind_RaiseException, __gnat_Unwind_ForcedUnwind): Define
	only once.
	* raise.h: Makes struct Exception_Data opaque.

Patch

Index: raise-gcc.c
===================================================================
--- raise-gcc.c	(revision 189431)
+++ raise-gcc.c	(working copy)
@@ -81,7 +81,6 @@ 
 extern void __gnat_unhandled_except_handler (_Unwind_Exception *);
 
 #include "dwarf2.h"
-#include "unwind-dw2-fde.h"
 #include "unwind-pe.h"
 
 /* The known and handled exception classes.  */
@@ -426,7 +425,7 @@ 
 	   |
 	   +--> get_region_description_for (context)
 	   |
-	   +--> get_action_description_for (context, exception, region)
+	   +--> get_action_description_for (ip, exception, region)
 	   |       |
 	   |       +--> get_call_site_action_for (context, region)
 	   |            (one version for each underlying scheme)
@@ -514,15 +513,11 @@ 
 }
 
 static void
-db_region_for (region_descriptor *region, _Unwind_Context *uw_context)
+db_region_for (region_descriptor *region, _Unwind_Ptr ip)
 {
-  _Unwind_Ptr ip;
-
   if (! (db_accepted_codes () & DB_REGIONS))
     return;
 
-  ip = get_ip_from_context (uw_context);
-
   db (DB_REGIONS, "For ip @ %p => ", (void *)ip);
 
   if (region->lsda)
@@ -607,7 +602,7 @@ 
 /* Describe an action to be taken when propagating an exception up to
    some context.  */
 
-typedef enum
+enum action_kind
 {
   /* Found some call site base data, but need to analyze further
      before being able to decide.  */
@@ -620,16 +615,20 @@ 
   cleanup,
 
   /* There is a handler for the exception in this context.  */
-  handler
-} action_kind;
+  handler,
 
+  /* There is a handler for the exception, but it is only for catching
+     unhandled exceptions.  */
+  unhandler
+};
+
 /* filter value for cleanup actions.  */
 static const int cleanup_filter = 0;
 
 typedef struct
 {
   /* The kind of action to be taken.  */
-  action_kind kind;
+  enum action_kind kind;
 
   /* A pointer to the action record entry.  */
   const unsigned char *table_entry;
@@ -645,10 +644,8 @@ 
 } action_descriptor;
 
 static void
-db_action_for (action_descriptor *action, _Unwind_Context *uw_context)
+db_action_for (action_descriptor *action, _Unwind_Ptr ip)
 {
-  _Unwind_Ptr ip = get_ip_from_context (uw_context);
-
   db (DB_ACTIONS, "For ip @ %p => ", (void *)ip);
 
   switch (action->kind)
@@ -691,12 +688,10 @@ 
 #define __builtin_eh_return_data_regno(x) x
 
 static void
-get_call_site_action_for (_Unwind_Context *uw_context,
+get_call_site_action_for (_Unwind_Ptr call_site,
                           region_descriptor *region,
                           action_descriptor *action)
 {
-  _Unwind_Ptr call_site = get_ip_from_context (uw_context);
-
   /* call_site is a direct index into the call-site table, with two special
      values : -1 for no-action and 0 for "terminate".  The latter should never
      show up for Ada.  To test for the former, beware that _Unwind_Ptr might
@@ -705,17 +700,16 @@ 
   if ((int)call_site < 0)
     {
       action->kind = nothing;
-      return;
     }
   else if (call_site == 0)
     {
       db (DB_ERR, "========> Err, null call_site for Ada/sjlj\n");
       action->kind = nothing;
-      return;
     }
   else
     {
       _uleb128_t cs_lp, cs_action;
+      const unsigned char *p = region->call_site_table;
 
       /* Let the caller know there may be an action to take, but let it
 	 determine the kind.  */
@@ -725,34 +719,31 @@ 
 	 made of leb128 values, the encoding length of which is variable.  We
 	 can't merely compute an offset from the index, then, but have to read
 	 all the entries before the one of interest.  */
+      p = region->call_site_table;
+      do
+	{
+	  p = read_uleb128 (p, &cs_lp);
+	  p = read_uleb128 (p, &cs_action);
+	}
+      while (--call_site);
 
-      const unsigned char *p = region->call_site_table;
-
-      do {
-	p = read_uleb128 (p, &cs_lp);
-	p = read_uleb128 (p, &cs_action);
-      } while (--call_site);
-
       action->landing_pad = cs_lp + 1;
 
       if (cs_action)
 	action->table_entry = region->action_table + cs_action - 1;
       else
 	action->table_entry = 0;
-
-      return;
     }
 }
 
 #else /* !__USING_SJLJ_EXCEPTIONS__  */
 
 static void
-get_call_site_action_for (_Unwind_Context *uw_context,
+get_call_site_action_for (_Unwind_Ptr ip,
                           region_descriptor *region,
                           action_descriptor *action)
 {
   const unsigned char *p = region->call_site_table;
-  _Unwind_Ptr ip = get_ip_from_context (uw_context);
 
   /* Unless we are able to determine otherwise...  */
   action->kind = nothing;
@@ -824,25 +815,29 @@ 
 
 extern Exception_Id EID_For (_GNAT_Exception * e);
 
-static int
+static enum action_kind
 is_handled_by (_Unwind_Ptr choice, _GNAT_Exception * propagated_exception)
 {
+  if (choice == GNAT_ALL_OTHERS)
+    return handler;
+
   if (propagated_exception->common.exception_class == GNAT_EXCEPTION_CLASS)
     {
       /* Pointer to the GNAT exception data corresponding to the propagated
          occurrence.  */
       _Unwind_Ptr E = (_Unwind_Ptr) EID_For (propagated_exception);
 
+      if (choice == GNAT_UNHANDLED_OTHERS)
+	return unhandler;
+
+      E = (_Unwind_Ptr) EID_For (propagated_exception);
+
       /* Base matching rules: An exception data (id) matches itself, "when
          all_others" matches anything and "when others" matches anything
          unless explicitly stated otherwise in the propagated occurrence.  */
+      if (choice == E || (choice == GNAT_OTHERS && Is_Handled_By_Others (E)))
+	return handler;
 
-      bool is_handled =
-        choice == E
-        || (choice == GNAT_OTHERS && Is_Handled_By_Others (E))
-        || choice == GNAT_ALL_OTHERS
-        || choice == GNAT_UNHANDLED_OTHERS;
-
       /* In addition, on OpenVMS, Non_Ada_Error matches VMS exceptions, and we
          may have different exception data pointers that should match for the
          same condition code, if both an export and an import have been
@@ -854,43 +849,44 @@ 
 #     define Non_Ada_Error system__aux_dec__non_ada_error
       extern struct Exception_Data Non_Ada_Error;
 
-      is_handled |=
-        (Language_For (E) == 'V'
-         && choice != GNAT_OTHERS && choice != GNAT_ALL_OTHERS
-         && ((Language_For (choice) == 'V' && Import_Code_For (choice) != 0
-              && Import_Code_For (choice) == Import_Code_For (E))
-             || choice == (_Unwind_Ptr)&Non_Ada_Error));
+      if ((Language_For (E) == 'V'
+	   && choice != GNAT_OTHERS
+	   && ((Language_For (choice) == 'V'
+		&& Import_Code_For (choice) != 0
+		&& Import_Code_For (choice) == Import_Code_For (E))
+	       || choice == (_Unwind_Ptr)&Non_Ada_Error)))
+	return handler;
 #endif
-
-      return is_handled;
     }
   else
     {
-#     define Foreign_Exception system__exceptions__foreign_exception;
+#     define Foreign_Exception system__exceptions__foreign_exception
       extern struct Exception_Data Foreign_Exception;
 
-      return choice == GNAT_ALL_OTHERS
-        || choice == GNAT_OTHERS
-        || choice == (_Unwind_Ptr)&Foreign_Exception;
+      if (choice == GNAT_ALL_OTHERS
+	  || choice == GNAT_OTHERS
+	  || choice == (_Unwind_Ptr) &Foreign_Exception)
+	return handler;
     }
+  return nothing;
 }
 
 /* Fill out the ACTION to be taken from propagating UW_EXCEPTION up to
    UW_CONTEXT in REGION.  */
 
 static void
-get_action_description_for (_Unwind_Context *uw_context,
+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;
+  _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);
+  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)
@@ -954,9 +950,9 @@ 
                      matches the one we are propagating.  */
                   _Unwind_Ptr choice = get_ttype_entry_for (region, ar_filter);
 
-                  if (is_handled_by (choice, gnat_exception))
+		  action->kind = is_handled_by (choice, gnat_exception);
+                  if (action->kind != nothing)
                     {
-                      action->kind = handler;
                       action->ttype_filter = ar_filter;
                       return;
                     }
@@ -1006,6 +1002,7 @@ 
    automatic backtraces upon exception raise, as provided through the
    GNAT.Traceback facilities.  */
 extern void __gnat_notify_handled_exception (void);
+extern void __gnat_notify_unhandled_exception (void);
 
 /* Below is the eh personality routine per se. We currently assume that only
    GNU-Ada exceptions are met.  */
@@ -1072,6 +1069,7 @@ 
   _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.  */
@@ -1104,7 +1102,8 @@ 
      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);
+  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)
@@ -1112,9 +1111,8 @@ 
 
   /* Search the call-site and action-record tables for the action associated
      with this IP.  */
-  get_action_description_for (uw_context, uw_exception, uw_phases,
-                              &region, &action);
-  db_action_for (&action, uw_context);
+  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.  */
@@ -1137,7 +1135,10 @@ 
 	     phase starts, which ensures the stack is still intact.
              First, setup the Ada occurrence.  */
           __gnat_setup_current_excep (uw_exception);
-	  __gnat_notify_handled_exception ();
+	  if (action.kind == unhandler)
+	    __gnat_notify_unhandled_exception ();
+	  else
+	    __gnat_notify_handled_exception ();
 
 	  return _URC_HANDLER_FOUND;
 	}
@@ -1157,13 +1158,16 @@ 
   return _URC_INSTALL_CONTEXT;
 }
 
+/* Callback routine called by Unwind_ForcedUnwind to execute all the cleanup
+   before exiting the task.  */
+
 _Unwind_Reason_Code
-__gnat_cleanupunwind_handler (int version,
+__gnat_cleanupunwind_handler (int version ATTRIBUTE_UNUSED,
 			      _Unwind_Action phases,
-			      _Unwind_Exception_Class eclass,
+			      _Unwind_Exception_Class eclass ATTRIBUTE_UNUSED,
 			      struct _Unwind_Exception *exception,
-			      struct _Unwind_Context *context,
-			      void *arg)
+			      struct _Unwind_Context *context ATTRIBUTE_UNUSED,
+			      void *arg ATTRIBUTE_UNUSED)
 {
   /* Terminate when the end of the stack is reached.  */
   if ((phases & _UA_END_OF_STACK) != 0
@@ -1184,46 +1188,28 @@ 
 
 /* Define the consistently named wrappers imported by Propagate_Exception.  */
 
-#ifdef __USING_SJLJ_EXCEPTIONS__
-
-#undef _Unwind_RaiseException
-
 _Unwind_Reason_Code
 __gnat_Unwind_RaiseException (_Unwind_Exception *e)
 {
+#ifdef __USING_SJLJ_EXCEPTIONS__
   return _Unwind_SjLj_RaiseException (e);
-}
-
-
-#undef _Unwind_ForcedUnwind
-
-_Unwind_Reason_Code
-__gnat_Unwind_ForcedUnwind (_Unwind_Exception *e,
-                            void * handler,
-                            void * argument)
-{
-  return _Unwind_SjLj_ForcedUnwind (e, handler, argument);
-}
-
-
-#else /* __USING_SJLJ_EXCEPTIONS__ */
-
-_Unwind_Reason_Code
-__gnat_Unwind_RaiseException (_Unwind_Exception *e)
-{
+#else
   return _Unwind_RaiseException (e);
+#endif
 }
 
 _Unwind_Reason_Code
 __gnat_Unwind_ForcedUnwind (_Unwind_Exception *e,
-                            void * handler,
-                            void * argument)
+			    void *handler,
+			    void *argument)
 {
+#ifdef __USING_SJLJ_EXCEPTIONS__
+  return _Unwind_SjLj_ForcedUnwind (e, handler, argument);
+#else
   return _Unwind_ForcedUnwind (e, handler, argument);
+#endif
 }
 
-#endif /* __USING_SJLJ_EXCEPTIONS__ */
-
 #ifdef __SEH__
 
 #define STATUS_USER_DEFINED		(1U << 29)
Index: raise.h
===================================================================
--- raise.h	(revision 189431)
+++ raise.h	(working copy)
@@ -6,7 +6,7 @@ 
  *                                                                          *
  *                              C Header File                               *
  *                                                                          *
- *          Copyright (C) 1992-2011, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2012, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -37,16 +37,7 @@ 
 
 typedef unsigned Exception_Code;
 
-struct Exception_Data
-{
-  char Not_Handled_By_Others;
-  char Lang;
-  int Name_Length;
-  char *Full_Name, *Htable_Ptr;
-  Exception_Code Import_Code;
-  void (*Raise_Hook)(void);
-};
-
+struct Exception_Data;
 typedef struct Exception_Data *Exception_Id;
 
 extern void _gnat_builtin_longjmp	(void *, int);