This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] libunwind-based exception-handling for gcc


Here is a patch to add libunwind support to GCC.  At the moment,
libunwind is supported on ia64 linux only.  Even there, you have to
use "configure --enable-libunwind-exceptions" to get libunwind-based
exception handling.  I ran the full GCC testsuite (for C, C++, F77,
Java, and ObjC) as well as the libstdc++-v3 and libjava testsuites and
the behavior appears unchanged.  I think most of the patch is either
harmless to other platforms or rather obvious.  There was one
non-trivial change to gccspec.c, however.  Basically, the new logic
mirrors what's found in g++spec.c, since I needed to know when
-lunwind is needed.  Hope that part looks OK.

To test this for real, you'll need libunwind v0.2, which will be
released shortly (it's already available in the bitkeeper repo at
http://unwind.bkbits.net/, but I'll make available a regular tar ball
soon; hopefully tomorrow).

	--david

f/ChangeLog:

Wed Jul 17 21:10:07 2002  David Mosberger-Tang  <David.Mosberger@acm.org>

	* f/g77spec.c (LIBUNWIND): New macro.
	(lang_specific_driver) [USE_LIBUNWIND_EXCEPTIONS]: Append -lunwind
	if needed.

ChangeLog:

2002-07-17  David Mosberger-Tang  <David.Mosberger@acm.org>

	* config/ia64/unwind-ia64.c [__USING_LIBUNWIND_EXCEPTIONS__]:
	Include "unwind-libunwind.c".

	* gccspec.c (LIBUNWIND): New macro.
	(lang_specific_driver): Remove ATTRIBUTE_UNUSED from
	in_added_libraries.  Keep track of arguments to see whether
	libraries are needed (similar logic as in cp/g++spec.c).
	If libraries are needed and USE_LIBUNWIND_EXCEPTIONS is in
	use, add -lunwind.

	* except.h [USE_LIBUNWIND_EXCEPTIONS]:
	Define USING_LIBUNWIND_EXCEPTIONS as 1, USING_SJLJ_EXCEPTIONS as 0.
	[!USE_LIBUNWIND_EXCEPTIONS]: Define USING_LIBUNWIND_EXCEPTIONS as 0.

	* c-common.c (cb_register_builtins): If USING_LIBUNWIND_EXCEPTIONS,
	define macro __USING_LIBUNWIND_EXCEPTIONS__.

	* unwind-libunwind.c: New file.

Index: c-common.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.348
diff -u -r1.348 c-common.c
--- c-common.c	7 Jul 2002 22:10:16 -0000	1.348
+++ c-common.c	18 Jul 2002 04:02:54 -0000
@@ -4310,6 +4310,8 @@
   /* libgcc needs to know this.  */
   if (USING_SJLJ_EXCEPTIONS)
     cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");
+  if (USING_LIBUNWIND_EXCEPTIONS)
+    cpp_define (pfile, "__USING_LIBUNWIND_EXCEPTIONS__");
 
   /* stddef.h needs to know these.  */
   builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0);
Index: except.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/except.h,v
retrieving revision 1.64
diff -u -r1.64 except.h
--- except.h	10 Apr 2002 00:15:58 -0000	1.64
+++ except.h	18 Jul 2002 04:02:54 -0000
@@ -159,25 +159,31 @@
 #define MUST_USE_SJLJ_EXCEPTIONS	0
 #endif
 
-#ifdef CONFIG_SJLJ_EXCEPTIONS
-# if CONFIG_SJLJ_EXCEPTIONS == 1
-#  define USING_SJLJ_EXCEPTIONS		1
-# endif
-# if CONFIG_SJLJ_EXCEPTIONS == 0
-#  define USING_SJLJ_EXCEPTIONS		0
-#  ifndef EH_RETURN_DATA_REGNO
-    #error "EH_RETURN_DATA_REGNO required"
-#  endif
-#  ifndef EH_RETURN_STACKADJ_RTX
-    #error "EH_RETURN_STACKADJ_RTX required"
-#  endif
-#  if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)
-    #error "EH_RETURN_HANDLER_RTX or eh_return required"
+#ifdef USE_LIBUNWIND_EXCEPTIONS
+# define USING_LIBUNWIND_EXCEPTIONS	1
+# define USING_SJLJ_EXCEPTIONS		0
+#else
+# define USING_LIBUNWIND_EXCEPTIONS	0
+# ifdef CONFIG_SJLJ_EXCEPTIONS
+#  if CONFIG_SJLJ_EXCEPTIONS == 1
+#   define USING_SJLJ_EXCEPTIONS		1
 #  endif
-#  if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO)
-    #error "{DWARF2,IA64}_UNWIND_INFO required"
+#  if CONFIG_SJLJ_EXCEPTIONS == 0
+#   define USING_SJLJ_EXCEPTIONS		0
+#   ifndef EH_RETURN_DATA_REGNO
+     #error "EH_RETURN_DATA_REGNO required"
+#   endif
+#   ifndef EH_RETURN_STACKADJ_RTX
+     #error "EH_RETURN_STACKADJ_RTX required"
+#   endif
+#   if !defined(EH_RETURN_HANDLER_RTX) && !defined(HAVE_eh_return)
+     #error "EH_RETURN_HANDLER_RTX or eh_return required"
+#   endif
+#   if !defined(DWARF2_UNWIND_INFO) && !defined(IA64_UNWIND_INFO)
+     #error "{DWARF2,IA64}_UNWIND_INFO required"
+#   endif
 #  endif
+# else
+#  define USING_SJLJ_EXCEPTIONS		MUST_USE_SJLJ_EXCEPTIONS
 # endif
-#else
-# define USING_SJLJ_EXCEPTIONS		MUST_USE_SJLJ_EXCEPTIONS
 #endif
Index: gccspec.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/gccspec.c,v
retrieving revision 1.8
diff -u -r1.8 gccspec.c
--- gccspec.c	4 Jun 2002 11:30:26 -0000	1.8
+++ gccspec.c	18 Jul 2002 04:02:59 -0000
@@ -22,12 +22,16 @@
 #include "system.h"
 #include "gcc.h"
 
+#ifndef LIBUNWIND
+#define LIBUNWIND "-lunwind"
+#endif
+
 /* Filter argc and argv before processing by the gcc driver proper.  */
 void
 lang_specific_driver (in_argc, in_argv, in_added_libraries)
      int *in_argc ATTRIBUTE_UNUSED;
      const char *const **in_argv ATTRIBUTE_UNUSED;
-     int *in_added_libraries ATTRIBUTE_UNUSED;
+     int *in_added_libraries;
 {
 #ifdef ENABLE_SHARED_LIBGCC
   int i;
@@ -38,9 +42,18 @@
   /* True if we should add -shared-libgcc to the command-line.  */
   int shared_libgcc = 0;
 
+  /* True if we compile with -shared-libgcc.  */
+  int saw_shared_libgcc = 0;
+
+  int added_options = 0;
+
   /* The total number of arguments with the new stuff.  */
   int argc;
 
+  /* This will be 0 if we encounter a situation where we should not
+     link in libraries.  */
+  int library = 1;
+
   /* The argument list.  */
   const char *const *argv;
 
@@ -51,9 +64,31 @@
     {
       if (argv[i][0] == '-')
 	{
-	  if (strcmp (argv[i], "-static-libgcc") == 0
-	      || strcmp (argv[i], "-static") == 0)
-	    return;
+	  if (library != 0)
+	    {
+	      if ((argc == 2 && strcmp (argv[i], "-v") == 0)
+		  || strcmp (argv[i], "-nostdlib") == 0
+		  || strcmp (argv[i], "-nodefaultlibs") == 0
+		  || strcmp (argv[i], "-MM") == 0
+		  || strcmp (argv[i], "-fsyntax-only") == 0
+		  || (argv[i][2] == '\0'
+		      && strchr ("cSEM", argv[i][1]) != NULL))
+		{
+		  library = 0;
+		}
+	    }
+
+	  if (strcmp (argv[i], "-shared-libgcc") == 0)
+	    {
+	      saw_shared_libgcc = 1;
+	      shared_libgcc = 1;
+	    }
+	  else if (strcmp (argv[i], "-static-libgcc") == 0
+		   || strcmp (argv[i], "-static") == 0)
+	    {
+	      saw_shared_libgcc = 0;
+	      shared_libgcc = 0;
+	    }
 	}
       else
 	{
@@ -69,10 +104,17 @@
 	}
     }
 
-  if  (shared_libgcc)
+  added_options = (shared_libgcc - saw_shared_libgcc);
+#ifdef USE_LIBUNWIND_EXCEPTIONS
+  if (library)
+    added_options += shared_libgcc;
+#endif
+
+  if (added_options)
     {
       /* Make sure to have room for the trailing NULL argument.  */
-      arglist = (const char **) xmalloc ((argc+2) * sizeof (char *));
+      arglist = (const char **) xmalloc ((argc + added_options + 1)
+					 * sizeof (char *));
 
       i = 0;
       do
@@ -82,8 +124,15 @@
 	}
       while (i < argc);
 
-      arglist[i++] = "-shared-libgcc";
-
+      if (shared_libgcc == 0)
+	arglist[i++] = "-shared-libgcc";
+#ifdef USE_LIBUNWIND_EXCEPTIONS
+      if (library)
+	{
+	  arglist[i++] = LIBUNWIND;
+	  ++*in_added_libraries;
+	}
+#endif
       arglist[i] = NULL;
 
       *in_argc = i;
Index: config/ia64/unwind-ia64.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/config/ia64/unwind-ia64.c,v
retrieving revision 1.10
diff -u -r1.10 unwind-ia64.c
--- config/ia64/unwind-ia64.c	1 Apr 2002 23:28:46 -0000	1.10
+++ config/ia64/unwind-ia64.c	18 Jul 2002 04:03:03 -0000
@@ -41,6 +41,9 @@
 #undef ENABLE_MALLOC_CHECKING
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
+# ifdef __USING_LIBUNWIND_EXCEPTIONS__
+#  include "unwind-libunwind.c"
+# else /* !__USING_LIBUNWIND_EXCEPTIONS__ */
 #define UNW_VER(x)		((x) >> 48)
 #define UNW_FLAG_MASK		0x0000ffff00000000
 #define UNW_FLAG_OSMASK		0x0000f00000000000
@@ -2238,4 +2241,5 @@
 }
 
 #include "unwind.inc"
+# endif /* !__USING_LIBUNWIND_EXCEPTIONS__ */
 #endif
Index: f/g77spec.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/f/g77spec.c,v
retrieving revision 1.37
diff -u -r1.37 g77spec.c
--- f/g77spec.c	31 Jan 2002 19:36:24 -0000	1.37
+++ f/g77spec.c	18 Jul 2002 04:03:04 -0000
@@ -61,6 +61,10 @@
 #define FORTRAN_LIBRARY "-lg2c"
 #endif
 
+#ifndef LIBUNWIND
+#define LIBUNWIND "-lunwind"
+#endif
+
 /* Options this driver needs to recognize, not just know how to
    skip over.  */
 typedef enum
@@ -537,7 +541,12 @@
 	    break;
     
       if (i == g77_newargc)
-	append_arg ("-shared-libgcc");
+	{
+	  append_arg ("-shared-libgcc");
+#ifdef USE_LIBUNWIND_EXCEPTIONS
+	  append_arg (LIBUNWIND);
+#endif
+	}
     }
   
 #endif

--- /dev/null	Sat Mar 24 01:35:12 2001
+++ unwind-libunwind.c	Wed Jul 17 21:04:07 2002
@@ -0,0 +1,149 @@
+/* Subroutines needed for unwinding stack frames via the libunwind API.
+   Copyright (C) 2002
+   Free Software Foundation, Inc.
+   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define UNW_LOCAL_ONLY
+
+#include <libunwind.h>
+
+typedef struct {
+  _Unwind_Personality_Fn personality;
+} _Unwind_FrameState;
+
+struct _Unwind_Context {
+  unw_cursor_t cursor;
+};
+
+
+/* First come the helper-routines that are needed by unwind.inc.  */
+
+static _Unwind_Reason_Code
+uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  unw_word_t handler;
+
+  if (unw_step (&context->cursor) <= 0)
+    return _URC_END_OF_STACK;
+
+  unw_get_reg (&context->cursor, UNW_REG_HANDLER, &handler);
+  fs->personality = (_Unwind_Personality_Fn) handler;
+
+  return _URC_NO_REASON;
+}
+
+#define uw_update_context(context,fs)	do { ; } while (0)
+
+static inline _Unwind_Ptr
+uw_identify_context (struct _Unwind_Context *context)
+{
+  unw_word_t ip;
+  unw_get_reg (&context->cursor, UNW_REG_IP, &ip);
+  return (_Unwind_Ptr) ip;
+}
+
+#define uw_init_context(context)		\
+do						\
+  {						\
+    unw_context_t uc;				\
+    unw_getcontext (&uc);			\
+    unw_init_local (&(context)->cursor, &uc);	\
+  }						\
+while (0)
+
+static inline void __attribute__ ((noreturn))
+uw_install_context (struct _Unwind_Context *current __attribute__ ((unused)),
+		    struct _Unwind_Context *target)
+{
+  unw_resume (&(target)->cursor);
+  abort ();
+}
+
+
+/* Now come the helper-routines which may be called from an exception
+   handler.  The interface for these routines are defined by the C++
+   ABI.  See: http://www.codesourcery.com/cxx-abi/abi-eh.html */
+
+_Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *context, int index)
+{
+  unw_word_t ret;
+
+  /* Note: here we depend on the fact that general registers are
+     expected to start with register number 0!  */
+  unw_get_reg (&context->cursor, index, &ret);
+  return ret;
+}
+
+/* Overwrite the saved value for register REG in CONTEXT with VAL.  */
+
+void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+  /* Note: here we depend on the fact that general registers are
+     expected to start with register number 0!  */
+  unw_set_reg (&context->cursor, index, val);
+}
+
+/* Retrieve the return address for CONTEXT.  */
+
+inline _Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+  unw_word_t ret;
+
+  unw_get_reg (&context->cursor, UNW_REG_IP, &ret);
+  return ret;
+}
+
+/* Overwrite the return address for CONTEXT with VAL.  */
+
+inline void
+_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
+{
+  unw_set_reg (&context->cursor, UNW_REG_IP, val);
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
+{
+  unw_word_t ret;
+
+  unw_get_reg (&context->cursor, UNW_REG_LSDA, &ret);
+  return (void *) ret;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *context)
+{
+  unw_word_t ret;
+
+  unw_get_reg (&context->cursor, UNW_REG_PROC_START, &ret);
+  return (_Unwind_Ptr) ret;
+}
+
+#include "unwind.inc"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]