c-common.c (handle_cleanup_attribute): New.
* 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
This commit is contained in:
parent
3edc56a9e5
commit
0bfa5f65bf
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* Check for valid arguments being passed to a function. */
|
||||
void
|
||||
|
37
gcc/c-decl.c
37
gcc/c-decl.c
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
36
gcc/testsuite/gcc.dg/cleanup-1.c
Normal file
36
gcc/testsuite/gcc.dg/cleanup-1.c
Normal file
@ -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" } */
|
22
gcc/testsuite/gcc.dg/cleanup-2.c
Normal file
22
gcc/testsuite/gcc.dg/cleanup-2.c
Normal file
@ -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 ();
|
||||
}
|
45
gcc/testsuite/gcc.dg/cleanup-3.c
Normal file
45
gcc/testsuite/gcc.dg/cleanup-3.c
Normal file
@ -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;
|
||||
}
|
39
gcc/testsuite/gcc.dg/cleanup-4.c
Normal file
39
gcc/testsuite/gcc.dg/cleanup-4.c
Normal file
@ -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;
|
||||
}
|
50
gcc/testsuite/gcc.dg/cleanup-5.c
Normal file
50
gcc/testsuite/gcc.dg/cleanup-5.c
Normal file
@ -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 ();
|
||||
}
|
14
gcc/testsuite/gcc.dg/cleanup-6.c
Normal file
14
gcc/testsuite/gcc.dg/cleanup-6.c
Normal file
@ -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" } } */
|
22
gcc/testsuite/gcc.dg/cleanup-7.c
Normal file
22
gcc/testsuite/gcc.dg/cleanup-7.c
Normal file
@ -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 ();
|
||||
}
|
186
gcc/unwind-c.c
Normal file
186
gcc/unwind-c.c
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user