about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-04-12 08:38:14 +0000
committerUlrich Drepper <drepper@redhat.com>2003-04-12 08:38:14 +0000
commit68107ec092e7cc3fcd1f56edf9da8085cffed00d (patch)
tree4297addf21ce4bc6d324a145ecacaf7920b336d4
parent09d65ff393e9183eecba1e5cb877e95dbdd3d4a4 (diff)
downloadglibc-68107ec092e7cc3fcd1f56edf9da8085cffed00d.tar.gz
glibc-68107ec092e7cc3fcd1f56edf9da8085cffed00d.tar.xz
glibc-68107ec092e7cc3fcd1f56edf9da8085cffed00d.zip
Update.
	* sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h: Likewise.
-rw-r--r--nptl/ChangeLog1
-rw-r--r--nptl/descr.h24
-rw-r--r--nptl/sysdeps/pthread/pthread.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h108
-rw-r--r--nptl/unwind.c30
5 files changed, 132 insertions, 33 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index bbda8c591e..d40118b42d 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -30,6 +30,7 @@
 	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/x86_64/sysdep-cancel.h: Likewise.
 	* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Define
 	__cleanup_fct_attribute.
 
diff --git a/nptl/descr.h b/nptl/descr.h
index 28b7afa1a1..efb25c7479 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -63,18 +63,19 @@
    information.  */
 struct pthread_unwind_buf
 {
+  struct
+  {
+    __jmp_buf jmp_buf;
+    int mask_was_saved;
+  } cancel_jmp_buf[1];
+
   union
   {
     /* This is the placeholder of the public version.  */
-    void *pad[16];
+    void *pad[4];
 
     struct
     {
-#ifdef HAVE_FORCED_UNWIND
-      /* First the machine-specific unwind info.  */
-      struct _Unwind_Exception exc;
-#endif
-
       /* Pointer to the previous cleanup buffer.  */
       __pthread_unwind_buf_t *prev;
 
@@ -87,12 +88,6 @@ struct pthread_unwind_buf
       int canceltype;
     } data;
   } priv;
-
-  struct
-  {
-    __jmp_buf jmp_buf;
-    int mask_was_saved;
-  } cancel_jmp_buf[1];
 };
 
 
@@ -226,6 +221,11 @@ struct pthread
   /* Next descriptor with a pending event.  */
   struct pthread *nextevent;
 
+#ifdef HAVE_FORCED_UNWIND
+  /* Machine-specific unwind info.  */
+  struct _Unwind_Exception exc;
+#endif
+
   /* If nonzero pointer to area allocated for the stack and its
      size.  */
   void *stackblock;
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index 5373b80dcf..1c59e1ea2e 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -385,12 +385,12 @@ extern void pthread_testcancel (void) __THROW;
 
 typedef struct
 {
-  void *__pad[16];
   struct
   {
     __jmp_buf __cancel_jmp_buf;
     int __mask_was_saved;
   } __cancel_jmp_buf[1];
+  void *__pad[4];
 } __pthread_unwind_buf_t __attribute__ ((__aligned__));
 
 /* No special attributes by default.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
index fde001d4a6..7e7bc49073 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h
@@ -29,6 +29,7 @@
 # define PSEUDO(name, syscall_name, args)				      \
   .text;								      \
   ENTRY (name)								      \
+  L(name##START):							      \
     SINGLE_THREAD_P;							      \
     jne L(pseudo_cancel);						      \
     DO_CALL (syscall_name, args);					      \
@@ -54,7 +55,100 @@
     RESTSTK_##args							      \
     cmpq $-4095, %rax;							      \
     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 -8;							      \
+    /* Return address register column.  */				      \
+    .byte 16;								      \
+    /* Augmentation value length.  */					      \
+    .uleb128 1;								      \
+    /* Encoding: DW_EH_PE_pcrel + DW_EH_PE_sdata4.  */			      \
+    .byte 0x1b;								      \
+    /* Start of the table initialization.  */				      \
+    .byte 0xc;								      \
+    .uleb128 7;								      \
+    .uleb128 8;								      \
+    .byte 0x90;								      \
+    .uleb128 1;								      \
+    .align 8;								      \
+  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
+
+# define EH_FRAME_0(name) \
+    .byte 4;								      \
+    .long L(SAVESTK)-L(name##START);					      \
+    .byte 14;								      \
+    .uleb128 32;							      \
+    .byte 4;								      \
+    .long L(RESTSTK)-L(SAVESTK);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .align 8
+
+# define EH_FRAME_1(name) EH_FRAME_0 (name)
+# define EH_FRAME_2(name) EH_FRAME_1 (name)
+
+# define EH_FRAME_3(name) \
+    .byte 4;								      \
+    .long L(SAVESTK)-L(name##START);					      \
+    .byte 14;								      \
+    .uleb128 48;							      \
+    .byte 4;								      \
+    .long L(RESTSTK)-L(SAVESTK);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .align 8
+
+# define EH_FRAME_4(name) EH_FRAME_3 (name)
+
+# define EH_FRAME_5(name) \
+    .byte 4;								      \
+    .long L(SAVESTK)-L(name##START);					      \
+    .byte 14;								      \
+    .uleb128 64;							      \
+    .byte 4;								      \
+    .long L(RESTSTK)-L(SAVESTK);					      \
+    .byte 14;								      \
+    .uleb128 8;								      \
+    .align 8
+
+# define EH_FRAME_6(name) EH_FRAME_5 (name)
+
+
+# undef ASM_SIZE_DIRECTIVE
+# define ASM_SIZE_DIRECTIVE(name) L(name##END): .size name,.-name;
 
 # define PUSHARGS_0	/* Nothing.  */
 # define PUSHARGS_1	PUSHARGS_0 movq %rdi, 8(%rsp);
@@ -73,20 +167,20 @@
 # define POPARGS_6	POPARGS_5 movq 48(%rsp), %r9;
 
 /* We always have to align the stack before calling a function.  */
-# define SAVESTK_0	subq $24, %rsp;
+# define SAVESTK_0	subq $24, %rsp; L(SAVESTK):
 # define SAVESTK_1	SAVESTK_0
 # define SAVESTK_2	SAVESTK_1
-# define SAVESTK_3	subq $40, %rsp;
+# define SAVESTK_3	subq $40, %rsp; L(SAVESTK):
 # define SAVESTK_4	SAVESTK_3
-# define SAVESTK_5	subq $56, %rsp;
+# define SAVESTK_5	subq $56, %rsp; L(SAVESTK):
 # define SAVESTK_6	SAVESTK_5
 
-# define RESTSTK_0	addq $24,%rsp;
+# define RESTSTK_0	addq $24,%rsp; L(RESTSTK):
 # define RESTSTK_1	RESTSTK_0
 # define RESTSTK_2	RESTSTK_1
-# define RESTSTK_3	addq $40, %rsp;
+# define RESTSTK_3	addq $40, %rsp; L(RESTSTK):
 # define RESTSTK_4	RESTSTK_3
-# define RESTSTK_5	addq $56, %rsp;
+# define RESTSTK_5	addq $56, %rsp; L(RESTSTK):
 # define RESTSTK_6	RESTSTK_5
 
 # ifdef IS_IN_libpthread
diff --git a/nptl/unwind.c b/nptl/unwind.c
index 46c896d5b3..7529174d5a 100644
--- a/nptl/unwind.c
+++ b/nptl/unwind.c
@@ -69,28 +69,32 @@ __pthread_unwind (__pthread_unwind_buf_t *buf)
   struct _pthread_cleanup_buffer *oldp = ibuf->priv.data.cleanup;
   struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup);
 
-  while (curp != oldp)
+  if (curp != oldp)
     {
-      /* Pointer to the next element.  */
-      struct _pthread_cleanup_buffer *nextp = curp->__prev;
+      do
+	{
+	  /* Pointer to the next element.  */
+	  struct _pthread_cleanup_buffer *nextp = curp->__prev;
 
-      /* Call the handler.  */
-      curp->__routine (curp->__arg);
+	  /* Call the handler.  */
+	  curp->__routine (curp->__arg);
 
-      /* To the next.  */
-      curp = nextp;
-    }
+	  /* To the next.  */
+	  curp = nextp;
+	}
+      while (curp != oldp);
 
-  /* Mark the current element as handled.  */
-  THREAD_SETMEM (self, cleanup, curp);
+      /* 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;
+  THREAD_SETMEM (self, exc.exception_class, 0);
+  THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup);
 
-  _Unwind_ForcedUnwind (&ibuf->priv.data.exc, unwind_stop, ibuf);
+  _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
 #else
   /* We simply jump to the registered setjmp buffer.  */
   __libc_longjmp ((struct __jmp_buf_tag *) ibuf->cancel_jmp_buf, 1);