]> gcc.gnu.org Git - gcc.git/commitdiff
c-common.c (handle_cleanup_attribute): New.
authorRichard Henderson <rth@redhat.com>
Wed, 4 Jun 2003 17:06:00 +0000 (10:06 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 4 Jun 2003 17:06:00 +0000 (10:06 -0700)
        * c-common.c (handle_cleanup_attribute): New.
        (c_common_attributes): Add it.
        * c-decl.c (finish_decl): Honor the cleanup attribute.
        * doc/extend.texi (Variable Attributes): Document it.

        * unwind-c.c: New file.
        * Makefile.in (LIB2ADDEH): Add it.
        * config/t-darwin, config/t-linux, config/t-linux-gnulibc1,
        config/ia64/t-ia64: Likewise.

        * gcc.dg/cleanup-1.c: New.
        * gcc.dg/cleanup-2.c: New.
        * gcc.dg/cleanup-3.c: New.
        * gcc.dg/cleanup-4.c: New.
        * gcc.dg/cleanup-5.c: New.
        * gcc.dg/cleanup-6.c: New.
        * gcc.dg/cleanup-7.c: New.

From-SVN: r67449

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/c-decl.c
gcc/config/ia64/t-ia64
gcc/config/t-darwin
gcc/config/t-linux
gcc/config/t-linux-gnulibc1
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cleanup-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cleanup-7.c [new file with mode: 0644]
gcc/unwind-c.c [new file with mode: 0644]

index 6bb5c6af19b9e55db7a6a9eb976fe2cad18aa0f8..548ba28ea86c8d0d3a94a3ea16d1d6656933dc67 100644 (file)
@@ -1,3 +1,15 @@
+2003-06-04  Richard Henderson  <rth@redhat.com>
+
+        * c-common.c (handle_cleanup_attribute): New.
+        (c_common_attributes): Add it.
+        * c-decl.c (finish_decl): Honor the cleanup attribute.
+        * doc/extend.texi (Variable Attributes): Document it.
+
+        * unwind-c.c: New file.
+        * Makefile.in (LIB2ADDEH): Add it.
+        * config/t-darwin, config/t-linux, config/t-linux-gnulibc1,
+        config/ia64/t-ia64: Likewise.
+
 2003-06-04  Jakub Jelinek  <jakub@redhat.com>
 
        * function.c (trampolines_created): New variable.
index f0ca525716ebfe8488ff68d5056059c6a58111f8..6755643d7425c108bffe2f2845a32644b85ec7d4 100644 (file)
@@ -472,7 +472,7 @@ CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
 
 # Additional sources to handle exceptions; overridden by targets as needed.
 LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
-   $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c
+   $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c
 LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
 
 # nm flags to list global symbols in libgcc object files.
@@ -1261,7 +1261,7 @@ c-incpath.o: c-incpath.c c-incpath.h $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) \
 c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     $(RTL_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) flags.h function.h output.h \
     $(EXPR_H) debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) \
-    c-pragma.h gt-c-decl.h cgraph.h $(HASHTAB_H)
+    c-pragma.h gt-c-decl.h cgraph.h $(HASHTAB_H) libfuncs.h except.h
 c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \
     $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H)
 c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \
@@ -1310,7 +1310,8 @@ tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h
 c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
        $(OBSTACK_H) $(C_COMMON_H) flags.h toplev.h output.h c-pragma.h intl.h \
        $(GGC_H) $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def \
-       diagnostic.h gt-c-common.h langhooks.h varray.h $(RTL_H) $(TARGET_H)
+       diagnostic.h gt-c-common.h langhooks.h varray.h $(RTL_H) $(TARGET_H) \
+       c-tree.h
 c-pretty-print.o : c-pretty-print.c c-pretty-print.h pretty-print.h \
        $(C_COMMON_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) real.h
 
index fe196b124bf3331f2dce916e614da56aec691bab..d194012e9560cb5b29b1da9c620860d6831ad98a 100644 (file)
@@ -41,7 +41,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "langhooks.h"
 #include "tree-inline.h"
-
+#include "c-tree.h"
 
 cpp_reader *parse_in;          /* Declared in c-pragma.h.  */
 
@@ -792,6 +792,8 @@ static tree handle_nonnull_attribute        PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_nothrow_attribute   PARAMS ((tree *, tree, tree, int,
                                                 bool *));
+static tree handle_cleanup_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
 static tree vector_size_helper PARAMS ((tree, tree));
 
 static void check_function_nonnull     PARAMS ((tree, tree));
@@ -868,6 +870,8 @@ const struct attribute_spec c_common_attribute_table[] =
   { "nothrow",                0, 0, true,  false, false,
                              handle_nothrow_attribute },
   { "may_alias",             0, 0, false, true, false, NULL },
+  { "cleanup",               1, 1, true, false, false,
+                             handle_cleanup_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -6093,6 +6097,55 @@ handle_nothrow_attribute (node, name, args, flags, no_add_attrs)
 
   return NULL_TREE;
 }
+
+/* Handle a "cleanup" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_cleanup_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+  tree cleanup_id, cleanup_decl;
+
+  /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do
+     for global destructors in C++.  This requires infrastructure that
+     we don't have generically at the moment.  It's also not a feature
+     we'd be missing too much, since we do have attribute constructor.  */
+  if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Verify that the argument is a function in scope.  */
+  /* ??? We could support pointers to functions here as well, if
+     that was considered desirable.  */
+  cleanup_id = TREE_VALUE (args);
+  if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE)
+    {
+      error ("cleanup arg not an identifier");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  cleanup_decl = lookup_name (cleanup_id);
+  if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL)
+    {
+      error ("cleanup arg not a function");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* That the function has proper type is checked with the 
+     eventual call to build_function_call.  */
+
+  return NULL_TREE;
+}
 \f
 /* Check for valid arguments being passed to a function.  */
 void
index 6eb0f55fd25afffb476f6d0ccb1155f5f70f5db0..f9124e4a976222fde308add0fb95babedc6b9492 100644 (file)
@@ -50,6 +50,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "c-pragma.h"
 #include "cgraph.h"
 #include "hashtab.h"
+#include "libfuncs.h"
+#include "except.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -2985,6 +2987,41 @@ finish_decl (decl, init, asmspec_tree)
      computing them in the following function definition.  */
   if (current_binding_level == global_binding_level)
     get_pending_sizes ();
+
+  /* Install a cleanup (aka destructor) if one was given.  */
+  if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
+    {
+      tree attr = lookup_attribute ("cleanup", DECL_ATTRIBUTES (decl));
+      if (attr)
+       {
+         static bool eh_initialized_p;
+
+         tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
+         tree cleanup_decl = lookup_name (cleanup_id);
+         tree cleanup;
+
+         /* Build "cleanup(&decl)" for the destructor.  */
+         cleanup = build_unary_op (ADDR_EXPR, decl, 0);
+         cleanup = build_tree_list (NULL_TREE, cleanup);
+         cleanup = build_function_call (cleanup_decl, cleanup);
+
+         /* Don't warn about decl unused; the cleanup uses it.  */
+         TREE_USED (decl) = 1;
+
+         /* Initialize EH, if we've been told to do so.  */
+         if (flag_exceptions && !eh_initialized_p)
+           {
+             eh_initialized_p = true;
+             eh_personality_libfunc
+               = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+                                   ? "__gcc_personality_sj0"
+                                   : "__gcc_personality_v0");
+             using_eh_for_cleanups ();
+           }
+
+         add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+       }
+    }
 }
 
 /* Given a parsed parameter declaration,
index 4474b0a9294687b557b036049dd344badefdba5b..0b8ab156b60ff26b161b212abd6064b97964ab43 100644 (file)
@@ -40,7 +40,8 @@ crtfastmath.o: $(srcdir)/config/ia64/crtfastmath.c $(GCC_PASSES)
        $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -c -o crtfastmath.o \
                $(srcdir)/config/ia64/crtfastmath.c
 
-LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c
+LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \
+  $(srcdir)/unwind-c.c
 
 ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(CONFIG_H) $(SYSTEM_H) \
     coretypes.h $(TM_H) $(TREE_H) $(CPPLIB_H) $(C_COMMON_H) c-pragma.h toplev.h
index e8682e17db8d5f9b8ac751e42f9366f5b94d7aa2..c5741e432343871e09f0b167aff87b0d0006710b 100644 (file)
@@ -18,5 +18,5 @@ $(T)crt2$(objext): $(srcdir)/config/darwin-crt2.c $(GCC_PASSES) \
 
 # Use unwind-dw2-fde-darwin
 LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-darwin.c \
-  $(srcdir)/unwind-sjlj.c
+  $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
 LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c
index b971c46ea212d02f8e0357d430655c6a603dbcd2..752387c62ad236d88276d9a3aeb18f5a50aaf7b4 100644 (file)
@@ -12,5 +12,5 @@ SHLIB_MAPFILES += $(srcdir)/config/libgcc-glibc.ver
 
 # Use unwind-dw2-fde-glibc
 LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \
-  $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c
+  $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c
 LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c gthr-gnat.c
index 56a471579edfcdad0e1b809a46aa2147a4ca74d1..52effd5ca2f3701328f1135c6115c4de4c996e60 100644 (file)
@@ -3,5 +3,5 @@ T_CFLAGS = -DUSE_GNULIBC_1
 
 # Use unwind-dw2-fde
 LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
-  $(srcdir)/unwind-sjlj.c
+  $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
 LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
index c4152ef009225edb9f3cce7e138e3a7fd5ab278e..0da4407b2dc3d2be1d297d44d03c974a61213a37 100644 (file)
@@ -3034,6 +3034,22 @@ up to a maximum of 8 byte alignment, then specifying @code{aligned(16)}
 in an @code{__attribute__} will still only provide you with 8 byte
 alignment.  See your linker documentation for further information.
 
+@item cleanup (@var{cleanup_function})
+@cindex @code{cleanup} attribute
+The @code{cleanup} attribute runs a function when the variable goes
+out of scope.  This attribute can only be applied to auto function
+scope variables; it may not be applied to parameters or variables
+with static storage duration.  The function must take one parameter,
+a pointer to a type compatible with the variable.  The return value
+of the function (if any) is ignored.
+
+If @option{-fexceptions} is enabled, then @var{cleanup_function}
+will be run during the stack unwinding that happens during the
+processing of the exception.  Note that the @code{cleanup} attribute
+does not allow the exception to be caught, only to perform an action.
+It is undefined what happens if @var{cleanup_function} does not
+return normally.
+
 @item common
 @itemx nocommon
 @cindex @code{common} attribute
index ec5e799b41c357d447d6e54d3f2dfaf9228e6e4f..1acdb65494c0919f2ad4e65b5ece1e687199cf26 100644 (file)
@@ -1,3 +1,13 @@
+2003-06-04  Richard Henderson  <rth@redhat.com>
+
+        * gcc.dg/cleanup-1.c: New.
+        * gcc.dg/cleanup-2.c: New.
+        * gcc.dg/cleanup-3.c: New.
+        * gcc.dg/cleanup-4.c: New.
+        * gcc.dg/cleanup-5.c: New.
+        * gcc.dg/cleanup-6.c: New.
+        * gcc.dg/cleanup-7.c: New.
+
 2003-06-04  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/abi/vague1.C: Use xfail, rather than embedded Tcl code.
diff --git a/gcc/testsuite/gcc.dg/cleanup-1.c b/gcc/testsuite/gcc.dg/cleanup-1.c
new file mode 100644 (file)
index 0000000..e5853c4
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+/* Validate expected warnings and errors.  */
+
+#define U      __attribute__((unused))
+#define C(x)   __attribute__((cleanup(x)))
+
+static int f1(void *x U) { return 0; }
+static void f2() { }
+static void f3(void) { }
+static void f4(void *x U) { }
+static void f5(int *x U) { }
+static void f6(double *x U) { }
+static void f7(const int *x U) { }
+static void f8(const int *x U, int y U) { }
+static void f9(int x U) { }
+
+void test(void)
+{
+  int o1 C(f1);
+  int o2 C(f2);
+  int o3 C(f3);                /* { dg-error "too many arguments" } */
+  int o4 C(f4);
+  int o5 C(f5);
+  int o6 C(f6);                /* { dg-warning "incompatible pointer type" } */
+  int o7 C(f7);
+  int o8 C(f8);                /* { dg-error "too few arguments" } */
+  int o9 C(f9);                /* { dg-warning "from pointer without a cast" } */
+  int o10 U C(undef);  /* { dg-error "not a function" } */
+  int o11 U C(o1);     /* { dg-error "not a function" } */
+  int o12 U C("f1");   /* { dg-error "not an identifier" } */
+  static int o13 U C(f1); /* { dg-warning "attribute ignored" } */
+}
+
+int o14 C(f1);         /* { dg-warning "attribute ignored" } */
+void t15(int o U C(f1)) {} /* { dg-warning "attribute ignored" } */
diff --git a/gcc/testsuite/gcc.dg/cleanup-2.c b/gcc/testsuite/gcc.dg/cleanup-2.c
new file mode 100644 (file)
index 0000000..2c79802
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify that cleanup works in the most basic of ways.  */
+
+extern void exit(int);
+extern void abort(void);
+
+static void handler(void *p __attribute__((unused)))
+{
+  exit (0);
+}
+
+static void doit(void)
+{
+  int x __attribute__((cleanup (handler)));
+}
+
+int main()
+{
+  doit ();
+  abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-3.c b/gcc/testsuite/gcc.dg/cleanup-3.c
new file mode 100644 (file)
index 0000000..b5b01fd
--- /dev/null
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify that the cleanup handler receives the proper contents
+   of the variable.  */
+
+extern void exit(int);
+extern void abort(void);
+
+static int expected;
+
+static void
+handler(int *p)
+{
+  if (*p != expected)
+    abort ();
+}
+
+static void __attribute__((noinline))
+bar(void)
+{
+}
+
+static void doit(int x, int y)
+{
+  int r __attribute__((cleanup (handler)));
+  if (x < y)
+    {
+      r = 0;
+      return;
+    }
+
+  bar();
+  r = x + y;
+}
+
+int main()
+{
+  expected = 0;
+  doit (1, 2);
+
+  expected = 3;
+  doit (2, 1);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-4.c b/gcc/testsuite/gcc.dg/cleanup-4.c
new file mode 100644 (file)
index 0000000..a548755
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify cleanup execution on non-trivial exit from a block.  */
+
+extern void exit(int);
+extern void abort(void);
+
+static int counter;
+
+static void
+handler(int *p)
+{
+  counter += *p;
+}
+
+static void __attribute__((noinline))
+bar(void)
+{
+}
+
+static void doit(int n, int n2)
+{
+  int i;
+  for (i = 0; i < n; ++i)
+    {
+      int dummy __attribute__((cleanup (handler))) = i;
+      if (i == n2)
+       break;
+      bar();
+    }
+}
+
+int main()
+{
+  doit (10, 6);
+  if (counter != 0 + 1 + 2 + 3 + 4 + 5 + 6)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-5.c b/gcc/testsuite/gcc.dg/cleanup-5.c
new file mode 100644 (file)
index 0000000..f5306db
--- /dev/null
@@ -0,0 +1,50 @@
+/* { dg-do run } */
+/* { dg-options "-fexceptions" } */
+/* Verify that cleanups work with exception handling.  */
+
+#include <unwind.h>
+#include <stdlib.h>
+
+static _Unwind_Reason_Code
+force_unwind_stop (int version, _Unwind_Action actions,
+                   _Unwind_Exception_Class exc_class,
+                   struct _Unwind_Exception *exc_obj,
+                   struct _Unwind_Context *context,
+                   void *stop_parameter)
+{
+  if (actions & _UA_END_OF_STACK)
+    abort ();
+  return _URC_NO_REASON;
+}
+
+static void force_unwind ()
+{
+  struct _Unwind_Exception *exc = malloc (sizeof (*exc));
+  exc->exception_class = 0;
+  exc->exception_cleanup = 0;
+                   
+#ifndef __USING_SJLJ_EXCEPTIONS__
+  _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
+#else
+  _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
+#endif
+                   
+  abort ();
+}
+
+static void handler (void *p __attribute__((unused)))
+{
+  exit (0);
+}
+
+static void doit ()
+{
+  char dummy __attribute__((cleanup (handler)));
+  force_unwind ();
+}
+
+int main()
+{ 
+  doit ();
+  abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/cleanup-6.c b/gcc/testsuite/gcc.dg/cleanup-6.c
new file mode 100644 (file)
index 0000000..4e3d538
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* Verify that a cleanup marked "inline" gets inlined.  */
+
+static inline void xyzzy(void *p __attribute__((unused)))
+{
+}
+
+void doit(void)
+{
+  int x __attribute__((cleanup (xyzzy)));
+}
+
+/* { dg-final { scan-assembler-not "xyzzy" } } */
diff --git a/gcc/testsuite/gcc.dg/cleanup-7.c b/gcc/testsuite/gcc.dg/cleanup-7.c
new file mode 100644 (file)
index 0000000..eae3d52
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "" } */
+/* Verify that the search for function happens in the proper scope.  */
+
+extern void exit(int);
+extern void abort(void);
+
+int main()
+{
+  auto void xyzzy(void *p __attribute__((unused)))
+  {
+    exit (0);
+  }
+
+  auto void doit ()
+  {
+    int x __attribute__((cleanup (xyzzy)));
+  }
+
+  doit ();
+  abort ();
+}
diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c
new file mode 100644 (file)
index 0000000..9ce0956
--- /dev/null
@@ -0,0 +1,186 @@
+/* Supporting functions for C exception handling.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Aldy Hernandez <aldy@quesejoda.com>.
+   Shamelessly stolen from the Java front end.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "unwind.h"
+#include "unwind-pe.h"
+
+typedef struct
+{
+  _Unwind_Ptr Start;
+  _Unwind_Ptr LPStart;
+  _Unwind_Ptr ttype_base;
+  const unsigned char *TType;
+  const unsigned char *action_table;
+  unsigned char ttype_encoding;
+  unsigned char call_site_encoding;
+} lsda_header_info;
+
+static const unsigned char *
+parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
+                  lsda_header_info *info)
+{
+  _Unwind_Word tmp;
+  unsigned char lpstart_encoding;
+
+  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
+
+  /* Find @LPStart, the base to which landing pad offsets are relative.  */
+  lpstart_encoding = *p++;
+  if (lpstart_encoding != DW_EH_PE_omit)
+    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
+  else
+    info->LPStart = info->Start;
+
+  /* Find @TType, the base of the handler and exception spec type data.  */
+  info->ttype_encoding = *p++;
+  if (info->ttype_encoding != DW_EH_PE_omit)
+    {
+      p = read_uleb128 (p, &tmp);
+      info->TType = p + tmp;
+    }
+  else
+    info->TType = 0;
+
+  /* The encoding and length of the call-site table; the action table
+     immediately follows.  */
+  info->call_site_encoding = *p++;
+  p = read_uleb128 (p, &tmp);
+  info->action_table = p + tmp;
+
+  return p;
+}
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define PERSONALITY_FUNCTION    __gcc_personality_sj0
+#define __builtin_eh_return_data_regno(x) x
+#else
+#define PERSONALITY_FUNCTION    __gcc_personality_v0
+#endif
+#define PERSONALITY_FUNCTION    __gcc_personality_v0
+
+_Unwind_Reason_Code
+PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
+                     struct _Unwind_Exception *, struct _Unwind_Context *);
+
+_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)
+{
+  lsda_header_info info;
+  const unsigned char *language_specific_data, *p, *action_record;
+  _Unwind_Ptr landing_pad, ip;
+
+  if (version != 1)
+    return _URC_FATAL_PHASE1_ERROR;
+
+  /* Currently we only support cleanups for C.  */
+  if ((actions & _UA_CLEANUP_PHASE) == 0)
+    return _URC_CONTINUE_UNWIND;
+
+  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);
+  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.  */
+  return _URC_CONTINUE_UNWIND;
+
+ found_something:
+  if (landing_pad == 0)
+    {
+      /* IP is present, but has a null landing pad.
+        No handler to be run.  */
+      return _URC_CONTINUE_UNWIND;
+    }
+
+  _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;
+}
This page took 0.095477 seconds and 5 git commands to generate.