about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--nptl/ChangeLog42
-rw-r--r--nptl/Makefile19
-rw-r--r--nptl/Versions5
-rw-r--r--nptl/sysdeps/pthread/bits/libc-lock.h13
-rwxr-xr-xnptl/sysdeps/pthread/configure55
-rw-r--r--nptl/sysdeps/pthread/configure.in13
-rw-r--r--nptl/sysdeps/pthread/pthread-functions.h2
-rw-r--r--nptl/sysdeps/pthread/pthread.h103
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h263
-rw-r--r--nptl/unwind.c112
-rw-r--r--nptl/version.c6
-rw-r--r--sysdeps/alpha/bits/setjmp.h9
-rw-r--r--sysdeps/generic/libc-start.c59
-rw-r--r--sysdeps/generic/unwind.h53
-rw-r--r--sysdeps/i386/bits/setjmp.h8
-rw-r--r--sysdeps/powerpc/bits/setjmp.h10
-rw-r--r--sysdeps/sh/bits/setjmp.h10
-rw-r--r--sysdeps/unix/sysv/linux/i386/sysdep.h14
-rw-r--r--sysdeps/unix/sysv/linux/ia64/bits/setjmp.h9
-rw-r--r--sysdeps/x86_64/bits/setjmp.h8
22 files changed, 729 insertions, 102 deletions
diff --git a/ChangeLog b/ChangeLog
index 9f1eb446f1..57be8c46bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2003-04-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/generic/libc-start.c: Cleanup MAIN_AUXVEC_ARG handling.
+	Remove HAVE_CANCELBUF code.  Replace with code using the new
+	initializers for unwind-based cleanup handling.
+	* sysdeps/generic/unwind.h: Update from latest gcc version.
+	* sysdeps/unix/sysv/linux/i386/sysdep.h: Define labels in a few
+	places to allow unwind data generation.
+	* sysdeps/i386/bits/setjmp.h: Allow file to be included multiple times.
+	* sysdeps/x86_64/bits/setjmp.h: Likewise.
+	* sysdeps/sh/bits/setjmp.h: Likewise.
+	* sysdeps/powerpc/bits/setjmp.h: Likewise.
+	* sysdeps/unix/sysv/linux/ia64/bits/setjmp.h: Likewise.
+	* sysdeps/alpha/bits/setjmp.h: Likewise.
+
 2003-04-11  Roland McGrath  <roland@redhat.com>
 
 	* csu/tst-empty.c: New file.
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 6ffe62314e..bbda8c591e 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,45 @@
+2003-04-11  Ulrich Drepper  <drepper@redhat.com>
+
+	* pthread.h: Define new data structure for cleanup buffer.  Declare
+	new cleanup handler interfaces.
+	* descr.h: Include <unwind.h> if necessary.  Define pthread_unwind_buf.
+	(struct pthread): Add cleanup_jmp_buf pointer.  Define
+	HAVE_CLEANUP_JMP_BUF and not HAVE_CANCELBUF.
+	* pthreadP.h: Declare __pthread_unwind.  Define __do_cancel to use
+	it.  Declare old cleanup handler installation functions.
+	* cleanup.c: Rewrite.  Install handler for unwind-based cleanup
+	handling.
+	* cleanup_defer.c: Likewise.
+	* cleanup_compat.c: New file.  Old cleanup code.
+	* cleanup_def_compat.c: New file.  Old cleanup code.
+	* pthread_create.c (start_thread): Initialize cleanup_jmp_buf element
+	if own thread descriptor.
+	* unwind.c: New file.
+	* forward.c: Add __pthread_unwind.
+	* init.c (pthread_functions): Add __pthread_unwind.
+	* sysdeps/pthread/pthread-functions.s (struct pthread_functions):
+	Add ptr___pthread_unwind.
+	* Versions [GLIBC_2.3.3] (libpthread): Export new cleanup handling
+	and unwind function.
+	* Makefile (libpthread-routines): Add cleanup_compat,
+	cleanup_def_compat, and unwind.  Define CFLAGS to enable unwind
+	table generation if necessary.
+	* version.c: Record whether unwind support is compiled in.
+	* sysdeps/pthread/configure.in: Add checks for unwind unterfaces.
+	* sysdeps/pthread/bits/libc-lock.h: Add prototypes of the old cleanup
+	handler interfaces.
+	* sysdeps/unix/sysv/linux/i386/sysdep-cancel.h: Add quite a bit of
+	complication to generate unwind information for syscall wrappers.
+	* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define
+	__cleanup_fct_attribute.
+
+	* Makefile: Add rules to build and run tst-cleanup0.
+	* tst-cleanup0.c: New file.
+	* tst-cleanup0.expect: New file.
+
+	* pthread_create.c (deallocate_tsd): Don't take parameter.  Adjust
+	caller.  Optimize to avoid often unecessary local variable.
+
 2003-04-11  Roland McGrath  <roland@redhat.com>
 
 	* Makefile ($(objpfx)multidir.mk): New target, generated makefile that
diff --git a/nptl/Makefile b/nptl/Makefile
index cd8ad98c38..79d28c9a30 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -98,7 +98,8 @@ libpthread-routines = init events version \
 		      sem_open sem_close sem_unlink \
 		      sem_getvalue \
 		      sem_wait sem_trywait sem_timedwait sem_post \
-		      cleanup cleanup_defer \
+		      cleanup cleanup_defer cleanup_compat \
+		      cleanup_defer_compat unwind \
 		      pt-longjmp \
 		      cancellation \
 		      lowlevellock lowlevelmutex \
@@ -122,6 +123,10 @@ libpthread-static-only-routines = pthread_atfork
 libpthread-nonshared = pthread_atfork
 
 CFLAGS-pthread_atfork.c = -DNOT_IN_libc
+CFLAGS-init.c = -fexceptions -fasynchronous-unwind-tables
+CFLAGS-unwind.c = -fexceptions
+CFLAGS-cancellation.c = -fasynchronous-unwind-tables
+CFLAGS-libc-cancellation.c = -fasynchronous-unwind-tables
 
 # Don't generate deps for calls with no sources.  See sysdeps/unix/Makefile.
 omit-deps = $(unix-syscalls:%=ptw-%)
@@ -153,7 +158,7 @@ tests = tst-attr1 tst-attr2 \
 	tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
 	tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
 	tst-cancel11 \
-	tst-cleanup1 tst-cleanup2 tst-cleanup3 \
+	tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \
 	tst-flock1 tst-flock2 \
 	tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
 	tst-exec1 tst-exec2 tst-exec3 \
@@ -208,6 +213,9 @@ CFLAGS-flockfile.c = -D_IO_MTSAFE_IO
 CFLAGS-ftrylockfile.c = -D_IO_MTSAFE_IO
 CFLAGS-funlockfile.c = -D_IO_MTSAFE_IO
 
+# Ugly, ugly.  We have to link with libgcc_eh but how?
+link-libc-static := $(common-objpfx)libc.a $(gnulib) -lgcc_eh $(common-objpfx)libc.a
+
 ifeq ($(build-static),yes)
 tests-static += tst-locale1 tst-locale2
 endif
@@ -220,7 +228,6 @@ ifeq (yes,$(build-shared))
 # Make sure these things are built in the `make lib' pass so they can be used
 # to run programs during the `make others' pass.
 lib-noranlib: $(addprefix $(objpfx),$(extra-objs))
-endif
 
 # What we install as libpthread.so for programs to link against is in fact a
 # link script.  It contains references for the various libraries we need.
@@ -229,6 +236,7 @@ endif
 # We need to use absolute paths since otherwise local copies (if they exist)
 # of the files are taken by the linker.
 install: $(inst_libdir)/libpthread.so
+
 $(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \
 			      $(objpfx)libpthread.so$(libpthread.so-version) \
 			      $(inst_libdir)/$(patsubst %,$(libtype.oS),\
@@ -245,6 +253,8 @@ $(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \
 	mv -f $@.new $@
 $(inst_libdir)/libpthread_nonshared.a: $(objpfx)libpthread_nonshared.a
 	$(do-install)
+endif
+
 
 # 'pthread_self' is a simple memory or register load.  Setting up the
 # stack frame is more work than the actual operation.  Disable the
@@ -313,6 +323,9 @@ $(objpfx)pt-initfini.s: pt-initfini.c
 	$(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \
 		$(patsubst -f%,-fno-%,$(exceptions)) -o $@
 
+$(objpfx)tst-cleanup0.out: /dev/null $(objpfx)tst-cleanup0
+	$(make-test-out) 2>&1 | cmp - tst-cleanup0.expect >& $@
+
 # We only have one kind of startup code files.  Static binaries and
 # shared libraries are build using the PIC version.
 $(objpfx)crti.S: $(objpfx)pt-initfini.s
diff --git a/nptl/Versions b/nptl/Versions
index 5824108426..4f52eb66f3 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -211,6 +211,11 @@ libpthread {
 
     # Proposed API extensions.
     pthread_tryjoin_np; pthread_timedjoin_np;
+
+    # New cancellation cleanup handling.
+    __pthread_register_cancel; __pthread_unregister_cancel;
+    __pthread_register_cancel_defer; __pthread_unregister_cancel_restore;
+    __pthread_unwind_next;
   }
 
   GLIBC_PRIVATE {
diff --git a/nptl/sysdeps/pthread/bits/libc-lock.h b/nptl/sysdeps/pthread/bits/libc-lock.h
index 3a3d3cc6d3..945a81cb82 100644
--- a/nptl/sysdeps/pthread/bits/libc-lock.h
+++ b/nptl/sysdeps/pthread/bits/libc-lock.h
@@ -345,6 +345,19 @@ typedef pthread_key_t __libc_key_t;
   } while (0)
 
 
+/* Note that for I/O cleanup handling we are using the old-style
+   cancel handling.  It does not have to be integrated with C++ snce
+   no C++ code is called in the middle.  The old-style handling is
+   faster and the support is not going away.  */
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer,
+                                   void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer,
+                                  int execute);
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer,
+                                         void (*routine) (void *), void *arg);
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer,
+                                          int execute);
+
 /* Start critical region with cleanup.  */
 #define __libc_cleanup_region_start(DOIT, FCT, ARG) \
   { struct _pthread_cleanup_buffer _buffer;				      \
diff --git a/nptl/sysdeps/pthread/configure b/nptl/sysdeps/pthread/configure
index 8999d37e5a..50293a4f1c 100755
--- a/nptl/sysdeps/pthread/configure
+++ b/nptl/sysdeps/pthread/configure
@@ -5,3 +5,58 @@ if test "x$libc_cv_gcc___thread" != xyes; then
 echo "$as_me: error: compiler support for __thread is required" >&2;}
    { (exit 1); exit 1; }; }
 fi
+
+
+echo "$as_me:$LINENO: checking for forced unwind support" >&5
+echo $ECHO_N "checking for forced unwind support... $ECHO_C" >&6
+if test "${libc_cv_forced_unwind+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <unwind.h>
+int
+main ()
+{
+
+struct _Unwind_Exception exc;
+struct _Unwind_Context *context;
+_Unwind_GetCFA (context)
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  libc_cv_forced_unwind=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+libc_cv_forced_unwind=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $libc_cv_forced_unwind" >&5
+echo "${ECHO_T}$libc_cv_forced_unwind" >&6
+if test $libc_cv_forced_unwind = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_FORCED_UNWIND 1
+_ACEOF
+
+fi
diff --git a/nptl/sysdeps/pthread/configure.in b/nptl/sysdeps/pthread/configure.in
index 8350f86dc0..e4ea6830d6 100644
--- a/nptl/sysdeps/pthread/configure.in
+++ b/nptl/sysdeps/pthread/configure.in
@@ -4,3 +4,16 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
 if test "x$libc_cv_gcc___thread" != xyes; then
   AC_MSG_ERROR(compiler support for __thread is required)
 fi
+
+dnl Iff <unwind.h> is available, make sure it is the right one and it
+dnl contains struct _Unwind_Exception.
+AC_CACHE_CHECK(dnl
+for forced unwind support, libc_cv_forced_unwind, [dnl
+AC_TRY_LINK([#include <unwind.h>], [
+struct _Unwind_Exception exc;
+struct _Unwind_Context *context;
+_Unwind_GetCFA (context)],
+libc_cv_forced_unwind=yes, libc_cv_forced_unwind=no)])
+if test $libc_cv_forced_unwind = yes; then
+  AC_DEFINE(HAVE_FORCED_UNWIND)
+fi
diff --git a/nptl/sysdeps/pthread/pthread-functions.h b/nptl/sysdeps/pthread/pthread-functions.h
index 9f38e34053..93ba089982 100644
--- a/nptl/sysdeps/pthread/pthread-functions.h
+++ b/nptl/sysdeps/pthread/pthread-functions.h
@@ -85,6 +85,8 @@ struct pthread_functions
 					    int);
 #define HAVE_PTR_NTHREADS
   int *ptr_nthreads;
+  void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *)
+       __attribute ((noreturn)) __cleanup_fct_attribute;
 };
 
 /* Variable in libc.so.  */
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index 72673d11a6..5373b80dcf 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -26,6 +26,7 @@
 #define __need_sigset_t
 #include <signal.h>
 #include <bits/pthreadtypes.h>
+#include <bits/setjmp.h>
 
 
 /* Detach state.  */
@@ -380,6 +381,24 @@ extern int pthread_cancel (pthread_t __th) __THROW;
 extern void pthread_testcancel (void) __THROW;
 
 
+/* Cancellation handling with integration into exception handling.  */
+
+typedef struct
+{
+  void *__pad[16];
+  struct
+  {
+    __jmp_buf __cancel_jmp_buf;
+    int __mask_was_saved;
+  } __cancel_jmp_buf[1];
+} __pthread_unwind_buf_t __attribute__ ((__aligned__));
+
+/* No special attributes by default.  */
+#ifndef __cleanup_fct_attribute
+# define __cleanup_fct_attribute
+#endif
+
+
 /* Install a cleanup handler: ROUTINE will be called with arguments ARG
    when the thread is cancelled or calls pthread_exit.  ROUTINE will also
    be called with arguments ARG when the matching pthread_cleanup_pop
@@ -387,43 +406,83 @@ extern void pthread_testcancel (void) __THROW;
 
    pthread_cleanup_push and pthread_cleanup_pop are macros and must always
    be used in matching pairs at the same nesting level of braces.  */
-#define pthread_cleanup_push(routine,arg) \
-  { struct _pthread_cleanup_buffer _buffer;				      \
-    _pthread_cleanup_push (&_buffer, (routine), (arg));
-
-extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
-				   void (*__routine) (void *), void *__arg)
-     __THROW;
+#define pthread_cleanup_push(routine, arg) \
+  do {									      \
+    __pthread_unwind_buf_t __cancel_buf;				      \
+    void (*__cancel_routine) (void *) = (routine);			      \
+    void *__cancel_arg = (arg);						      \
+    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)		      \
+				      __cancel_buf.__cancel_jmp_buf, 0);      \
+    if (__builtin_expect (not_first_call, 0))				      \
+      {									      \
+	__cancel_routine (__cancel_arg);				      \
+	__pthread_unwind_next (&__cancel_buf);				      \
+	/* NOTREACHED */						      \
+      }									      \
+									      \
+    __pthread_register_cancel (&__cancel_buf);				      \
+    do {
+extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
 
 /* Remove a cleanup handler installed by the matching pthread_cleanup_push.
    If EXECUTE is non-zero, the handler function is called. */
 #define pthread_cleanup_pop(execute) \
-    _pthread_cleanup_pop (&_buffer, (execute)); }
-
-extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
-				  int __execute) __THROW;
+    } while (0);							      \
+    __pthread_unregister_cancel (&__cancel_buf);			      \
+    if (execute)							      \
+      __cancel_routine (__cancel_arg);					      \
+  } while (0)
+extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
+  __cleanup_fct_attribute;
 
 #ifdef __USE_GNU
 /* Install a cleanup handler as pthread_cleanup_push does, but also
    saves the current cancellation type and sets it to deferred
    cancellation.  */
-# define pthread_cleanup_push_defer_np(routine,arg) \
-  { struct _pthread_cleanup_buffer _buffer;				      \
-    _pthread_cleanup_push_defer (&_buffer, (routine), (arg));
-
-extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
-					 void (*__routine) (void *),
-					 void *__arg) __THROW;
+# define pthread_cleanup_push_defer(routine, arg) \
+  do {									      \
+    __pthread_unwind_buf_t __cancel_buf;				      \
+    void (*__cancel_routine) (void *) = (routine);			      \
+    void *__cancel_arg = (arg);						      \
+    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)		      \
+				      __cancel_buf.__cancel_jmp_buf, 0);      \
+    if (__builtin_expect (not_first_call, 0))				      \
+      {									      \
+	__cancel_routine (__cancel_arg);				      \
+	__pthread_unwind_next (&__cancel_buf);				      \
+	/* NOTREACHED */						      \
+      }									      \
+									      \
+    __pthread_register_cancel_defer (&__cancel_buf);			      \
+    do {
+extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute;
 
 /* Remove a cleanup handler as pthread_cleanup_pop does, but also
    restores the cancellation type that was in effect when the matching
    pthread_cleanup_push_defer was called.  */
-# define pthread_cleanup_pop_restore_np(execute) \
-  _pthread_cleanup_pop_restore (&_buffer, (execute)); }
+# define pthread_cleanup_pop_cleanup(execute) \
+    } while (0);							      \
+    __pthread_unregister_cancel_restore (&__cancel_buf);		      \
+    if (execute)							      \
+      __cancel_routine (__cancel_arg);					      \
+  } while (0)
+extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf)
+  __cleanup_fct_attribute;
+#endif
 
-extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
-					  int __execute) __THROW;
+/* Internal interface to initiate cleanup.  */
+extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
+     __cleanup_fct_attribute __attribute ((__noreturn__))
+#ifndef SHARED
+     __attribute ((__weak__))
 #endif
+     ;
+
+/* Function used in the macros.  */
+struct __jmp_buf_tag;
+extern int __sigsetjmp (struct __jmp_buf_tag __env[1], int __savemask) __THROW;
 
 
 /* Mutex handling.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index c14f1b1ef6..0834894c25 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -149,4 +149,7 @@ typedef union
 #endif
 
 
+/* Extra attributes for the cleanup functions.  */
+#define __cleanup_fct_attribute __attribute ((regparm (1)))
+
 #endif	/* bits/pthreadtypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
index 35f05e1cc2..b7009d753f 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
@@ -29,6 +29,7 @@
 # define PSEUDO(name, syscall_name, args)				      \
   .text;								      \
   ENTRY (name)								      \
+  L(name##START):							      \
     cmpl $0, %gs:MULTIPLE_THREADS_OFFSET;				      \
     jne L(pseudo_cancel);						      \
     DO_CALL (syscall_name, args);					      \
@@ -38,29 +39,262 @@
   L(pseudo_cancel):							      \
     CENABLE								      \
     SAVE_OLDTYPE_##args							      \
-    PUSHARGS_##args							      \
+    PUSHCARGS_##args							      \
     DOCARGS_##args							      \
     movl $SYS_ify (syscall_name), %eax;					      \
-    ENTER_KERNEL							      \
-    POPARGS_##args;							      \
-    POPCARGS_##args							      \
+    /* Until we can handle unwinding from the sysenter page the kernel	      \
+       provides we cannot use ENTER_KERNEL here.  */			      \
+    int $0x80;								      \
+    POPCARGS_##args;							      \
+    POPSTATE_##args							      \
     cmpl $-4095, %eax;							      \
     jae SYSCALL_ERROR_LABEL;						      \
-  L(pseudo_end):
+  L(pseudo_end):							      \
+									      \
+  /* Create unwinding information for the syscall wrapper.  */		      \
+  .section .eh_frame,"a",@progbits;					      \
+  L(STARTFRAME):							      \
+    /* Length of the CIE.  */						      \
+    .long L(ENDCIE)-L(STARTCIE);					      \
+  L(STARTCIE):								      \
+    /* CIE ID.  */							      \
+    .long 0;								      \
+    /* Version number.  */						      \
+    .byte 1;								      \
+    /* NUL-terminated augmentation string.  Note "z" means there is an	      \
+       augmentation value later on.  */					      \
+    .string "zR";							      \
+    /* Code alignment factor.  */					      \
+    .uleb128 1;								      \
+    /* Data alignment factor.  */					      \
+    .sleb128 -4;							      \
+    /* Return address register column.  */				      \
+    .byte 8;								      \
+    /* Augmentation value length.  */					      \
+    .uleb128 1;								      \
+    /* Encoding: DW_EH_PE_pcrel + DW_EH_PE_sdata4.  */			      \
+    .byte 0x1b;								      \
+    /* Start of the table initialization.  */				      \
+    .byte 0xc;								      \
+    .uleb128 4;								      \
+    .uleb128 4;								      \
+    .byte 0x88;								      \
+    .uleb128 1;								      \
+    .align 4;								      \
+  L(ENDCIE):								      \
+    /* Length of the FDE.  */						      \
+    .long L(ENDFDE)-L(STARTFDE);					      \
+  L(STARTFDE):								      \
+    /* CIE pointer.  */							      \
+    .long L(STARTFDE)-L(STARTFRAME);					      \
+    /* PC-relative start address of the code.  */			      \
+    .long L(name##START)-.;						      \
+    /* Length of the code.  */						      \
+    .long L(name##END)-L(name##START);					      \
+    /* No augmentation data.  */					      \
+    .uleb128 0;								      \
+    /* The rest of the code depends on the number of parameters the syscall   \
+       takes.  */							      \
+    EH_FRAME_##args(name);						      \
+    .align 4;								      \
+  L(ENDFDE):								      \
+  .previous
+
+/* Callframe description for syscalls without parameters.  This is very
+   simple.  The only place the stack pointer is changed is when the old
+   cancellation state value is saved.  */
+# define EH_FRAME_0(name) \
+    .byte 4;								      \
+    .long L(PUSHSTATE)-name;						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPSTATE)-L(PUSHSTATE);					      \
+    .byte 14;								      \
+    .uleb128 4
+
+/* For syscalls with one and two parameters the code is the same as for
+   those which take no parameter.  */
+# define EH_FRAME_1(name) EH_FRAME_0 (name)
+# define EH_FRAME_2(name) EH_FRAME_1 (name)
+
+/* For syscalls with three parameters the stack pointer is changed
+   also to save the content of the %ebx register.  */
+# define EH_FRAME_3(name) \
+    .byte 4;								      \
+    .long L(PUSHBX1)-name;						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPBX1)-L(PUSHBX1);						      \
+    .byte 14;								      \
+    .uleb128 4;								      \
+    .byte 4;								      \
+    .long L(PUSHSTATE)-L(POPBX1);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(PUSHBX2)-L(PUSHSTATE);					      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(POPBX2)-L(PUSHBX2);						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPSTATE)-L(POPBX2);					      \
+    .byte 14;								      \
+    .uleb128 4
+
+/* With four parameters the syscall wrappers have to save %ebx and %esi.  */
+# define EH_FRAME_4(name) \
+    .byte 4;								      \
+    .long L(PUSHSI1)-name;						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(PUSHBX1)-L(PUSHSI1);					      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(POPBX1)-L(PUSHBX1);						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPSI1)-L(POPBX1);						      \
+    .byte 14;								      \
+    .uleb128 4;								      \
+    .byte 4;								      \
+    .long L(PUSHSTATE)-L(POPSI1);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(PUSHSI2)-L(PUSHSTATE);					      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(PUSHBX2)-L(PUSHSI2);					      \
+    .byte 14;								      \
+    .uleb128 16;							      \
+    .byte 4;								      \
+    .long L(POPBX2)-L(PUSHBX2);						      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(POPSI2)-L(POPBX2);						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPSTATE)-L(POPSI2);					      \
+    .byte 14;								      \
+    .uleb128 4
+
+/* With five parameters the syscall wrappers have to save %ebx, %esi,
+   and %edi.  */
+# define EH_FRAME_5(name) \
+    .byte 4;								      \
+    .long L(PUSHDI1)-name;						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(PUSHSI1)-L(PUSHDI1);					      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(PUSHBX1)-L(PUSHSI1);					      \
+    .byte 14;								      \
+    .uleb128 16;							      \
+    .byte 4;								      \
+    .long L(POPBX1)-L(PUSHBX1);						      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(POPSI1)-L(POPBX1);						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPDI1)-L(POPSI1);						      \
+    .byte 14;								      \
+    .uleb128 4;								      \
+    .byte 4;								      \
+    .long L(PUSHSTATE)-L(POPDI1);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(PUSHDI2)-L(PUSHSTATE);					      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(PUSHSI2)-L(PUSHDI2);					      \
+    .byte 14;								      \
+    .uleb128 16;							      \
+    .byte 4;								      \
+    .long L(PUSHBX2)-L(PUSHSI2);					      \
+    .byte 14;								      \
+    .uleb128 20;							      \
+    .byte 4;								      \
+    .long L(POPBX2)-L(PUSHBX2);						      \
+    .byte 14;								      \
+    .uleb128 16;							      \
+    .byte 4;								      \
+    .long L(POPSI2)-L(POPBX2);						      \
+    .byte 14;								      \
+    .uleb128 12;							      \
+    .byte 4;								      \
+    .long L(POPDI2)-L(POPSI2);						      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .byte 4;								      \
+    .long L(POPSTATE)-L(POPDI2);					      \
+    .byte 14;								      \
+    .uleb128 4
+
+
+# undef ASM_SIZE_DIRECTIVE
+# define ASM_SIZE_DIRECTIVE(name) L(name##END): .size name,.-name;
 
 # define SAVE_OLDTYPE_0	movl %eax, %edx;
 # define SAVE_OLDTYPE_1	SAVE_OLDTYPE_0
-# define SAVE_OLDTYPE_2	pushl %eax;
+# define SAVE_OLDTYPE_2	pushl %eax; L(PUSHSTATE):
 # define SAVE_OLDTYPE_3	SAVE_OLDTYPE_2
 # define SAVE_OLDTYPE_4	SAVE_OLDTYPE_2
 # define SAVE_OLDTYPE_5	SAVE_OLDTYPE_2
 
-# define DOCARGS_0	DOARGS_0
-# define DOCARGS_1	DOARGS_1
+# define PUSHCARGS_0	/* No arguments to push.  */
+# define DOCARGS_0	/* No arguments to frob.  */
+# define POPCARGS_0	/* No arguments to pop.  */
+# define _PUSHCARGS_0	/* No arguments to push.  */
+# define _POPCARGS_0	/* No arguments to pop.  */
+
+# define PUSHCARGS_1	movl %ebx, %edx; PUSHCARGS_0
+# define DOCARGS_1	_DOARGS_1 (4)
+# define POPCARGS_1	POPCARGS_0; movl %edx, %ebx
+# define _PUSHCARGS_1	pushl %ebx; L(PUSHBX2): _PUSHCARGS_0
+# define _POPCARGS_1	_POPCARGS_0; popl %ebx; L(POPBX2):
+
+# define PUSHCARGS_2	PUSHCARGS_1
 # define DOCARGS_2	_DOARGS_2 (12)
+# define POPCARGS_2	POPCARGS_1
+# define _PUSHCARGS_2	_PUSHCARGS_1
+# define _POPCARGS_2	_POPCARGS_1
+
+# define PUSHCARGS_3	_PUSHCARGS_2
 # define DOCARGS_3	_DOARGS_3 (20)
+# define POPCARGS_3	_POPCARGS_3
+# define _PUSHCARGS_3	_PUSHCARGS_2
+# define _POPCARGS_3	_POPCARGS_2
+
+# define PUSHCARGS_4	_PUSHCARGS_4
 # define DOCARGS_4	_DOARGS_4 (28)
+# define POPCARGS_4	_POPCARGS_4
+# define _PUSHCARGS_4	pushl %esi; L(PUSHSI2): _PUSHCARGS_3
+# define _POPCARGS_4	_POPCARGS_3; popl %esi; L(POPSI2):
+
+# define PUSHCARGS_5	_PUSHCARGS_5
 # define DOCARGS_5	_DOARGS_5 (36)
+# define POPCARGS_5	_POPCARGS_5
+# define _PUSHCARGS_5	pushl %edi; L(PUSHDI2): _PUSHCARGS_4
+# define _POPCARGS_5	_POPCARGS_4; popl %edi; L(POPDI2):
 
 # ifdef IS_IN_libpthread
 #  define CENABLE	call __pthread_enable_asynccancel;
@@ -69,12 +303,13 @@
 #  define CENABLE	call __libc_enable_asynccancel;
 #  define CDISABLE	call __libc_disable_asynccancel
 # endif
-# define POPCARGS_0	pushl %eax; movl %ecx, %eax; CDISABLE; popl %eax;
-# define POPCARGS_1	POPCARGS_0
-# define POPCARGS_2	xchgl (%esp), %eax; CDISABLE; popl %eax;
-# define POPCARGS_3	POPCARGS_2
-# define POPCARGS_4	POPCARGS_2
-# define POPCARGS_5	POPCARGS_2
+# define POPSTATE_0 \
+ pushl %eax; L(PUSHSTATE): movl %ecx, %eax; CDISABLE; popl %eax; L(POPSTATE):
+# define POPSTATE_1	POPSTATE_0
+# define POPSTATE_2	xchgl (%esp), %eax; CDISABLE; popl %eax; L(POPSTATE):
+# define POPSTATE_3	POPSTATE_2
+# define POPSTATE_4	POPSTATE_3
+# define POPSTATE_5	POPSTATE_4
 
 # ifndef __ASSEMBLER__
 #  define SINGLE_THREAD_P \
diff --git a/nptl/unwind.c b/nptl/unwind.c
new file mode 100644
index 0000000000..46c896d5b3
--- /dev/null
+++ b/nptl/unwind.c
@@ -0,0 +1,112 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>
+   and Richard Henderson <rth@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+#ifdef HAVE_FORCED_UNWIND
+
+static _Unwind_Reason_Code
+unwind_stop (int version, _Unwind_Action actions,
+	     _Unwind_Exception_Class exc_class,
+	     struct _Unwind_Exception *exc_obj,
+	     struct _Unwind_Context *context, void *stop_parameter)
+{
+  struct pthread_unwind_buf *buf = stop_parameter;
+
+  /* Do longjmp if we're at "end of stack", aka "end of unwind data".
+     We assume there are only C frame without unwind data in between
+     here and the jmp_buf target.  Otherwise simply note that the CFA
+     of a function is NOT within it's stack frame; it's the SP of the
+     previous frame.  */
+  if ((actions & _UA_END_OF_STACK)
+      || ! _JMPBUF_UNWINDS  (buf->cancel_jmp_buf[0].jmp_buf,
+			     _Unwind_GetCFA (context)))
+    __libc_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1);
+
+  return _URC_NO_REASON;
+}
+
+
+static void
+unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)
+{
+  /* Nothing to do.  */
+}
+
+#endif	/* have forced unwind */
+
+
+void
+__cleanup_fct_attribute __attribute ((noreturn))
+__pthread_unwind (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+  struct pthread *self = THREAD_SELF;
+
+  /* Handle the compatibility stuff first.  Execute all handlers
+     registered with the old method.  We don't execute them in order,
+     instead, they will run first.  */
+  struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup;
+  struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
+
+  while (curp != oldp)
+    {
+      /* Pointer to the next element.  */
+      struct _pthread_cleanup_buffer *nextp = curp->__prev;
+
+      /* Call the handler.  */
+      curp->__routine (curp->__arg);
+
+      /* To the next.  */
+      curp = nextp;
+    }
+
+  /* Mark the current element as handled.  */
+  THREAD_SETMEM (self, cleanup, curp);
+
+#ifdef HAVE_FORCED_UNWIND
+  /* This is not a catchable exception, so don't provide any details about
+     the exception type.  We do need to initialize the field though.  */
+  ibuf->priv.data.exc.exception_class = 0;
+  ibuf->priv.data.exc.exception_cleanup = unwind_cleanup;
+
+  _Unwind_ForcedUnwind (&ibuf->priv.data.exc, unwind_stop, ibuf);
+#else
+  /* We simply jump to the registered setjmp buffer.  */
+  __libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1);
+#endif
+  /* NOTREACHED */
+
+  /* We better do not get here.  */
+  abort ();
+}
+
+
+void
+__cleanup_fct_attribute __attribute ((noreturn))
+__pthread_unwind_next (__pthread_unwind_buf_t *buf)
+{
+  struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+
+  __pthread_unwind (ibuf->priv.data.prev);
+}
diff --git a/nptl/version.c b/nptl/version.c
index d0658bac0c..f2fd25fd6d 100644
--- a/nptl/version.c
+++ b/nptl/version.c
@@ -26,7 +26,11 @@ static const char banner[] =
 "Copyright (C) 2003 Free Software Foundation, Inc.\n\
 This is free software; see the source for copying conditions.\n\
 There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
-PARTICULAR PURPOSE.\n";
+PARTICULAR PURPOSE.\n"
+#ifdef HAVE_FORCED_UNWIND
+"Forced unwind support included.\n"
+#endif
+;
 
 
 extern void __nptl_main (void) __attribute__ ((noreturn));
diff --git a/sysdeps/alpha/bits/setjmp.h b/sysdeps/alpha/bits/setjmp.h
index fcd57d61d1..c603a35554 100644
--- a/sysdeps/alpha/bits/setjmp.h
+++ b/sysdeps/alpha/bits/setjmp.h
@@ -1,5 +1,5 @@
 /* Define the machine-dependent type `jmp_buf'.  Alpha version.
-   Copyright (C) 1992, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1997, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,7 +17,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#ifndef _SETJMP_H
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -80,3 +83,5 @@ typedef long int __jmp_buf[17];
 #define _JMPBUF_UNWINDS(_jmpbuf, _address)				\
      ((void *)(_address) < (void *)((_jmpbuf)[JB_SP]))
 #endif
+
+#endif  /* bits/setjmp.h */
diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c
index 351205d636..b98f0a2aa0 100644
--- a/sysdeps/generic/libc-start.c
+++ b/sysdeps/generic/libc-start.c
@@ -51,12 +51,17 @@ extern void __pthread_initialize_minimal (void)
 # define LIBC_START_MAIN BP_SYM (__libc_start_main)
 #endif
 
-STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
 #ifdef MAIN_AUXVEC_ARG
-					 , void *
+/* main gets passed a pointer to the auxiliary.  */
+# define MAIN_AUXVEC_DECL	, void *
+# define MAIN_AUXVEC_PARAM	, auxvec
+#else
+# define MAIN_AUXVEC_DECL
+# define MAIN_AUXVEC_PARAM
 #endif
 
-					 ),
+STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
+					 MAIN_AUXVEC_DECL),
 			    int argc,
 			    char *__unbounded *__unbounded ubp_av,
 #ifdef LIBC_START_MAIN_AUXVEC_ARG
@@ -73,11 +78,7 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
      __attribute__ ((noreturn));
 
 STATIC int
-LIBC_START_MAIN (int (*main) (int, char **, char **
-#ifdef MAIN_AUXVEC_ARG
-			      , void *
-#endif
-			      ),
+LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
 		 int argc, char *__unbounded *__unbounded ubp_av,
 #ifdef LIBC_START_MAIN_AUXVEC_ARG
 		 ElfW(auxv_t) *__unbounded auxvec,
@@ -172,10 +173,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char **
   if (init)
     (*init) (
 #ifdef INIT_MAIN_ARGS
-	     argc, argv, __environ
-# ifdef MAIN_AUXVEC_ARG
-	     , auxvec
-# endif
+	     argc, argv, __environ MAIN_AUXVEC_PARAM
 #endif
 	     );
 
@@ -184,38 +182,45 @@ LIBC_START_MAIN (int (*main) (int, char **, char **
     _dl_debug_printf ("\ntransferring control: %s\n\n", argv[0]);
 #endif
 
-#ifdef HAVE_CANCELBUF
-  if (setjmp (THREAD_SELF->cancelbuf) == 0)
-#endif
+#ifdef HAVE_CLEANUP_JMP_BUF
+  /* Memory for the cancellation buffer.  */
+  struct pthread_unwind_buf unwind_buf;
+
+  int not_first_call;
+  not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+  if (__builtin_expect (! not_first_call, 1))
     {
-      /* XXX This is where the try/finally handling must be used.  */
+      struct pthread *self = THREAD_SELF;
 
-      result = main (argc, argv, __environ
-#ifdef MAIN_AUXVEC_ARG
-		     , auxvec
-#endif
+      /* Store old info.  */
+      unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+      unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
 
-		     );
+      /* Store the new cleanup handler info.  */
+      THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
+
+      /* Run the program.  */
+      result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
     }
-#ifdef HAVE_CANCELBUF
   else
     {
-# ifdef HAVE_PTR_NTHREADS
       /* One less thread.  Decrement the counter.  If it is zero we
 	 terminate the entire process.  */
       result = 0;
-#  ifdef SHARED
+# ifdef SHARED
       int *const ptr = __libc_pthread_functions.ptr_nthreads;
-#  else
+# else
       extern int __nptl_nthreads __attribute ((weak));
       int *const ptr = &__nptl_nthreads;
-#  endif
+# endif
 
       if (! atomic_decrement_and_test (ptr))
-# endif
 	/* Not much left to do but to exit the thread, not the process.  */
 	__exit_thread (0);
     }
+#else
+  /* Nothing fancy, just call the function.  */
+  result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);
 #endif
 
   exit (result);
diff --git a/sysdeps/generic/unwind.h b/sysdeps/generic/unwind.h
index ce43365a31..08d3381175 100644
--- a/sysdeps/generic/unwind.h
+++ b/sysdeps/generic/unwind.h
@@ -1,26 +1,36 @@
 /* Exception handling and frame unwind runtime interface routines.
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2003 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   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
+   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.
 
-   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.
+   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 GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   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.  */
+
+/* As a special exception, if you include this header file into source
+   files compiled by GCC, this header file 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.  */
 
 /* This is derived from the C++ ABI for IA-64.  Where we diverge
    for cross-architecture compatibility are noted with "@@@".  */
 
+#ifndef _UNWIND_H
+#define _UNWIND_H	1
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -31,7 +41,12 @@ extern "C" {
    inefficient for 32-bit and smaller machines.  */
 typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
 typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+#if defined(__ia64__) && defined(__hpux__)
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__)));
+#else
 typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+#endif
+typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
 
 /* @@@ The IA-64 ABI uses a 64-bit word to identify the producer and
    consumer of an exception.  We'll go along with this for now even on
@@ -87,6 +102,7 @@ typedef int _Unwind_Action;
 #define _UA_CLEANUP_PHASE	2
 #define _UA_HANDLER_FRAME	4
 #define _UA_FORCE_UNWIND	8
+#define _UA_END_OF_STACK	16
 
 /* This is an opaque type used to refer to a system-specific data
    structure used by the system unwinder. This context is created and
@@ -125,6 +141,9 @@ extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
 extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
 extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
 
+/* @@@ Retrieve the CFA of the given context.  */
+extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+
 extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
 
 extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
@@ -135,15 +154,15 @@ extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
    library and language-specific exception handling semantics.  It is
    specific to the code fragment described by an unwind info block, and
    it is always referenced via the pointer in the unwind info block, and
-   hence it has no ABI-specified name. 
+   hence it has no ABI-specified name.
 
    Note that this implies that two different C++ implementations can
    use different names, and have different contents in the language
-   specific data area.  Moreover, that the language specific data 
+   specific data area.  Moreover, that the language specific data
    area contains no version info because name of the function invoked
    provides more effective versioning by detecting at link time the
    lack of code to handle the different data format.  */
-   
+
 typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)
      (int, _Unwind_Action, _Unwind_Exception_Class,
       struct _Unwind_Exception *, struct _Unwind_Context *);
@@ -186,6 +205,12 @@ extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *);
 extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *);
 #endif
 
+/* @@@ Given an address, return the entry point of the function that
+   contains it.  */
+extern void * _Unwind_FindEnclosingFunction (void *pc);
+
 #ifdef __cplusplus
 }
 #endif
+
+#endif	/* unwind.h */
diff --git a/sysdeps/i386/bits/setjmp.h b/sysdeps/i386/bits/setjmp.h
index e5e493bcae..107fe58b35 100644
--- a/sysdeps/i386/bits/setjmp.h
+++ b/sysdeps/i386/bits/setjmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,8 +17,10 @@
    02111-1307 USA.  */
 
 /* Define the machine-dependent type `jmp_buf'.  Intel 386 version.  */
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H	1
 
-#ifndef _SETJMP_H
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -40,3 +42,5 @@ typedef int __jmp_buf[6];
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf)[JB_SP])
+
+#endif	/* bits/setjmp.h */
diff --git a/sysdeps/powerpc/bits/setjmp.h b/sysdeps/powerpc/bits/setjmp.h
index e17bde1351..f849fe23ff 100644
--- a/sysdeps/powerpc/bits/setjmp.h
+++ b/sysdeps/powerpc/bits/setjmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,8 +17,10 @@
    02111-1307 USA.  */
 
 /* Define the machine-dependent type `jmp_buf'.  PowerPC version.  */
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H  1
 
-#ifndef _SETJMP_H
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -43,7 +45,7 @@
 #  define JB_CR     21 /* Condition code registers.  */
 #  define JB_FPRS   22 /* FPRs 14 through 31 are saved, 18*2 words total.  */
 #  define JB_SIZE   (58*4)
-# endif 
+# endif
 #endif
 
 #ifndef	_ASM
@@ -58,3 +60,5 @@ typedef long int __jmp_buf[58];
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf)[JB_GPR1])
+
+#endif  /* bits/setjmp.h */
diff --git a/sysdeps/sh/bits/setjmp.h b/sysdeps/sh/bits/setjmp.h
index 55bc66549b..22497703af 100644
--- a/sysdeps/sh/bits/setjmp.h
+++ b/sysdeps/sh/bits/setjmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,8 +17,10 @@
    02111-1307 USA.  */
 
 /* Define the machine-dependent type `jmp_buf'.  SH version. */
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H  1
 
-#ifndef _SETJMP_H
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -43,10 +45,12 @@ typedef struct
 #endif
 
 #if defined __USE_MISC || defined _ASM
-#define JB_SIZE		(4 * 15)
+# define JB_SIZE		(4 * 15)
 #endif
 
 /* Test if longjmp to JMPBUF would unwind the frame
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < &(jmpbuf)[0].__regs[7])
+
+#endif  /* bits/setjmp.h */
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index 2e660c39fc..14984b64f2 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -164,7 +164,7 @@ __i686.get_pc_thunk.reg:						      \
 # else
 /* Store (- %eax) into errno through the GOT.  */
 #  define SYSCALL_ERROR_HANDLER						      \
-0:SETUP_PIC_REG(cx);						      \
+0:SETUP_PIC_REG(cx);							      \
   addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \
   xorl %edx, %edx;							      \
   subl %eax, %edx;							      \
@@ -250,9 +250,9 @@ __i686.get_pc_thunk.reg:						      \
 #define PUSHARGS_1	movl %ebx, %edx; PUSHARGS_0
 #define	DOARGS_1	_DOARGS_1 (4)
 #define	POPARGS_1	POPARGS_0; movl %edx, %ebx
-#define	_PUSHARGS_1	pushl %ebx; _PUSHARGS_0
+#define	_PUSHARGS_1	pushl %ebx; L(PUSHBX1): _PUSHARGS_0
 #define _DOARGS_1(n)	movl n(%esp), %ebx; _DOARGS_0(n-4)
-#define	_POPARGS_1	_POPARGS_0; popl %ebx
+#define	_POPARGS_1	_POPARGS_0; popl %ebx; L(POPBX1):
 
 #define PUSHARGS_2	PUSHARGS_1
 #define	DOARGS_2	_DOARGS_2 (8)
@@ -271,16 +271,16 @@ __i686.get_pc_thunk.reg:						      \
 #define PUSHARGS_4	_PUSHARGS_4
 #define DOARGS_4	_DOARGS_4 (24)
 #define POPARGS_4	_POPARGS_4
-#define _PUSHARGS_4	pushl %esi; _PUSHARGS_3
+#define _PUSHARGS_4	pushl %esi; L(PUSHSI1): _PUSHARGS_3
 #define _DOARGS_4(n)	movl n(%esp), %esi; _DOARGS_3 (n-4)
-#define _POPARGS_4	_POPARGS_3; popl %esi
+#define _POPARGS_4	_POPARGS_3; popl %esi; L(POPSI1):
 
 #define PUSHARGS_5	_PUSHARGS_5
 #define DOARGS_5	_DOARGS_5 (32)
 #define POPARGS_5	_POPARGS_5
-#define _PUSHARGS_5	pushl %edi; _PUSHARGS_4
+#define _PUSHARGS_5	pushl %edi; L(PUSHDI1): _PUSHARGS_4
 #define _DOARGS_5(n)	movl n(%esp), %edi; _DOARGS_4 (n-4)
-#define _POPARGS_5	_POPARGS_4; popl %edi
+#define _POPARGS_5	_POPARGS_4; popl %edi; L(POPDI1):
 
 #else	/* !__ASSEMBLER__ */
 
diff --git a/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h b/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h
index 3ef2396250..76625753d9 100644
--- a/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h
+++ b/sysdeps/unix/sysv/linux/ia64/bits/setjmp.h
@@ -1,5 +1,5 @@
 /* Define the machine-dependent type `jmp_buf'.  Linux/IA-64 version.
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
 
@@ -18,7 +18,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#ifndef _SETJMP_H
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H  1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -33,3 +36,5 @@ typedef long __jmp_buf[_JBLEN] __attribute__ ((aligned (16))); /* guarantees 128
    variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(_jmpbuf, _address)		\
      ((void *)(_address) < (void *)(((long *)_jmpbuf)[0]))
+
+#endif  /* bits/setjmp.h */
diff --git a/sysdeps/x86_64/bits/setjmp.h b/sysdeps/x86_64/bits/setjmp.h
index ba5dd2c112..96646efdda 100644
--- a/sysdeps/x86_64/bits/setjmp.h
+++ b/sysdeps/x86_64/bits/setjmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -17,8 +17,10 @@
    02111-1307 USA.  */
 
 /* Define the machine-dependent type `jmp_buf'.  x86-64 version.  */
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H  1
 
-#ifndef _SETJMP_H
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -72,3 +74,5 @@ typedef int __jmp_buf[6];
   ((void *) (address) < (void *) (jmpbuf)[JB_SP])
 # endif
 #endif
+
+#endif  /* bits/setjmp.h */