about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/aarch64/makecontext.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/aarch64/makecontext.c')
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/makecontext.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/aarch64/makecontext.c b/sysdeps/unix/sysv/linux/aarch64/makecontext.c
index 9e66b6761c..779f7e55aa 100644
--- a/sysdeps/unix/sysv/linux/aarch64/makecontext.c
+++ b/sysdeps/unix/sysv/linux/aarch64/makecontext.c
@@ -20,7 +20,9 @@
 #include <sysdep.h>
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <ucontext.h>
+#include <sys/mman.h>
 
 #define GCS_MAGIC 0x47435300
 
@@ -29,6 +31,47 @@ static struct _aarch64_ctx *extension (void *p)
   return p;
 }
 
+struct gcs_list {
+  struct gcs_list *next;
+  void *base;
+  size_t size;
+};
+
+static __thread struct gcs_list *gcs_list_head = NULL;
+
+static void
+record_gcs (void *base, size_t size)
+{
+  struct gcs_list *p = malloc (sizeof *p);
+  if (p == NULL)
+    abort ();
+  p->base = base;
+  p->size = size;
+  p->next = gcs_list_head;
+  gcs_list_head = p;
+}
+
+static void
+free_gcs_list (void)
+{
+  for (;;)
+    {
+      struct gcs_list *p = gcs_list_head;
+      if (p == NULL)
+	break;
+      gcs_list_head = p->next;
+      __munmap (p->base, p->size);
+      free (p);
+    }
+}
+
+/* Called during thread shutdown to free resources.  */
+void
+__libc_aarch64_thread_freeres (void)
+{
+  free_gcs_list ();
+}
+
 #ifndef __NR_map_shadow_stack
 # define __NR_map_shadow_stack 453
 #endif
@@ -58,6 +101,9 @@ alloc_makecontext_gcs (size_t stack_size)
   if (base == (void *) -1)
     /* ENOSYS, bad size or OOM.  */
     abort ();
+
+  record_gcs (base, size);
+
   uint64_t *gcsp = (uint64_t *) ((char *) base + size);
   /* Skip end of GCS token.  */
   gcsp--;
@@ -69,6 +115,25 @@ alloc_makecontext_gcs (size_t stack_size)
   return gcsp + 1;
 }
 
+void
+__free_makecontext_gcs (void *gcs)
+{
+  struct gcs_list *p = gcs_list_head;
+  struct gcs_list **q = &gcs_list_head;
+  for (;;)
+    {
+      if (p == NULL)
+	abort ();
+      if (gcs == p->base + p->size - 8)
+	break;
+      q = &p->next;
+      p = p->next;
+    }
+  *q = p->next;
+  __munmap (p->base, p->size);
+  free (p);
+}
+
 /* makecontext sets up a stack and the registers for the
    user context.  The stack looks like this: