@@ -298,8 +298,10 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
struct pthread *self = THREAD_SELF;
/* Store old info. */
- unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
- unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+ unwind_buf.full.priv.data.prev
+ = THREAD_GETMEM (self, cleanup_jmp_buf);
+ unwind_buf.full.priv.data.cleanup
+ = THREAD_GETMEM (self, cleanup);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
@@ -28,8 +28,9 @@ __pthread_register_cancel (__pthread_unwind_buf_t *buf)
struct pthread *self = THREAD_SELF;
/* Store old info. */
- ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
- ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+ union pthread_unwind_buf_data *priv = UNWIND_BUF_PRIV (self, ibuf);
+ priv->data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+ priv->data.cleanup = THREAD_GETMEM (self, cleanup);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf);
@@ -42,7 +43,9 @@ __cleanup_fct_attribute
__pthread_unregister_cancel (__pthread_unwind_buf_t *buf)
{
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+ struct pthread *self = THREAD_SELF;
- THREAD_SETMEM (THREAD_SELF, cleanup_jmp_buf, ibuf->priv.data.prev);
+ THREAD_SETMEM (self, cleanup_jmp_buf,
+ UNWIND_BUF_PRIV (self, ibuf)->data.prev);
}
hidden_def (__pthread_unregister_cancel)
@@ -28,8 +28,9 @@ __pthread_register_cancel_defer (__pthread_unwind_buf_t *buf)
struct pthread *self = THREAD_SELF;
/* Store old info. */
- ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
- ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+ union pthread_unwind_buf_data *priv = UNWIND_BUF_PRIV (self, ibuf);
+ priv->data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+ priv->data.cleanup = THREAD_GETMEM (self, cleanup);
int cancelhandling = THREAD_GETMEM (self, cancelhandling);
@@ -49,9 +50,9 @@ __pthread_register_cancel_defer (__pthread_unwind_buf_t *buf)
cancelhandling = curval;
}
- ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK
- ? PTHREAD_CANCEL_ASYNCHRONOUS
- : PTHREAD_CANCEL_DEFERRED);
+ priv->data.canceltype = (cancelhandling & CANCELTYPE_BITMASK
+ ? PTHREAD_CANCEL_ASYNCHRONOUS
+ : PTHREAD_CANCEL_DEFERRED);
/* Store the new cleanup handler info. */
THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf);
@@ -64,11 +65,12 @@ __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf)
{
struct pthread *self = THREAD_SELF;
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
+ union pthread_unwind_buf_data *priv = UNWIND_BUF_PRIV (self, ibuf);
- THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev);
+ THREAD_SETMEM (self, cleanup_jmp_buf, priv->data.prev);
int cancelhandling;
- if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED
+ if (priv->data.canceltype != PTHREAD_CANCEL_DEFERRED
&& ((cancelhandling = THREAD_GETMEM (self, cancelhandling))
& CANCELTYPE_BITMASK) == 0)
{
@@ -55,11 +55,30 @@
/ PTHREAD_KEY_2NDLEVEL_SIZE)
+/* Private data in the cleanup buffer. */
+union pthread_unwind_buf_data
+{
+ /* This is the placeholder of the public version. */
+ void *pad[4];
+ struct
+ {
+ /* Pointer to the previous cleanup buffer. */
+ struct pthread_unwind_buf *prev;
-/* Internal version of the buffer to store cancellation handler
+ /* Backward compatibility: state of the old-style cleanup
+ handler at the time of the previous new-style cleanup handler
+ installment. */
+ struct _pthread_cleanup_buffer *cleanup;
+
+ /* Cancellation type before the push call. */
+ int canceltype;
+ } data;
+};
+
+/* Internal full version of the buffer to store cancellation handler
information. */
-struct pthread_unwind_buf
+struct full_pthread_unwind_buf
{
struct
{
@@ -70,27 +89,49 @@ struct pthread_unwind_buf
#endif
} cancel_jmp_buf[1];
- union
+ union pthread_unwind_buf_data priv;
+};
+
+/* Internal compatible version of the buffer to store cancellation
+ handler information. */
+struct compat_pthread_unwind_buf
+{
+ struct
{
- /* This is the placeholder of the public version. */
- void *pad[4];
+ __jmp_buf jmp_buf;
+ int mask_was_saved;
+ } cancel_jmp_buf[1];
+
+ union pthread_unwind_buf_data priv;
+};
+/* Internal version of the buffer to store cancellation handler
+ information. */
+struct pthread_unwind_buf
+{
+ union
+ {
+ /* The common fields of full and compatible versions. */
struct
{
- /* Pointer to the previous cleanup buffer. */
- struct pthread_unwind_buf *prev;
-
- /* Backward compatibility: state of the old-style cleanup
- handler at the time of the previous new-style cleanup handler
- installment. */
- struct _pthread_cleanup_buffer *cleanup;
-
- /* Cancellation type before the push call. */
- int canceltype;
- } data;
- } priv;
+ __jmp_buf jmp_buf;
+ int mask_was_saved;
+ } cancel_jmp_buf[1];
+ struct full_pthread_unwind_buf full;
+ struct compat_pthread_unwind_buf compat;
+ };
};
+/* Get pointer to the priv field from THREAD_SELF, "self", and pointer
+ to the cleanup buffer, "p". By default, the compatible version is
+ used. If a target defines NEED_SAVED_MASK_IN_CANCEL_JMP_BUF, it
+ must provide its own version of UNEIND_BUF_PRIV. */
+#ifndef UNWIND_BUF_PRIV
+# ifdef NEED_SAVED_MASK_IN_CANCEL_JMP_BUF
+# error "UNWIND_BUF_PRIV is undefined!"
+# endif
+# define UNWIND_BUF_PRIV(self,p) (&((p)->compat.priv))
+#endif
/* Opcodes and data types for communication with the signal handler to
change user/group IDs. */
@@ -428,8 +428,8 @@ START_THREAD_DEFN
struct pthread_unwind_buf unwind_buf;
/* No previous handlers. */
- unwind_buf.priv.data.prev = NULL;
- unwind_buf.priv.data.cleanup = NULL;
+ unwind_buf.full.priv.data.prev = NULL;
+ unwind_buf.full.priv.data.cleanup = NULL;
int not_first_call;
not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
@@ -701,6 +701,11 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr,
THREAD_COPY_POINTER_GUARD (pd);
#endif
+ /* Copy additonal info. */
+#ifdef THREAD_COPY_ADDITONAL_INFO
+ THREAD_COPY_ADDITONAL_INFO (pd);
+#endif
+
/* Verify the sysinfo bits were copied in allocate_stack if needed. */
#ifdef NEED_DL_SYSINFO
CHECK_THREAD_SYSINFO (pd);
@@ -66,7 +66,8 @@ unwind_stop (int version, _Unwind_Action actions,
/* Handle the compatibility stuff. Execute all handlers
registered with the old method which would be unwound by this
step. */
- struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup;
+ struct _pthread_cleanup_buffer *oldp
+ = UNWIND_BUF_PRIV (self, buf)->data.cleanup;
void *cfa = (void *) (_Unwind_Ptr) _Unwind_GetCFA (context);
if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj)))
@@ -133,6 +134,7 @@ __pthread_unwind_next (__pthread_unwind_buf_t *buf)
{
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
- __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev);
+ __pthread_unwind ((__pthread_unwind_buf_t *)
+ UNWIND_BUF_PRIV (THREAD_SELF, ibuf)->data.prev);
}
hidden_def (__pthread_unwind_next)
@@ -23,7 +23,7 @@
extern struct pthread_unwind_buf ____pthread_unwind_buf_private;
-_Static_assert (sizeof (____pthread_unwind_buf_private.cancel_jmp_buf)
+_Static_assert (sizeof (____pthread_unwind_buf_private.full.cancel_jmp_buf)
>= sizeof (struct __jmp_buf_tag),
"size of cancel_jmp_buf < sizeof __jmp_buf_tag");
@@ -20,3 +20,17 @@
/* Need saved_mask in cancel_jmp_buf. */
#define NEED_SAVED_MASK_IN_CANCEL_JMP_BUF 1
+
+/* Wee need to copy feature_1 in pthread_create. */
+#define THREAD_COPY_ADDITONAL_INFO(descr) \
+ ((descr)->header.feature_1 \
+ = THREAD_GETMEM (THREAD_SELF, header.feature_1))
+
+/* Use the compatible struct __cancel_jmp_buf_tag if shadow stack is
+ disabled. */
+#undef UNWIND_BUF_PRIV
+#define UNWIND_BUF_PRIV(self,p) \
+ (__extension__ ({ \
+ unsigned int feature_1 = THREAD_GETMEM (self, header.feature_1); \
+ (((feature_1 & (1 << 1)) == 0) \
+ ? &((p)->compat.priv) : &((p)->full.priv));}))