public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/fw/unwind-link] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
@ 2020-02-10 17:08 Florian Weimer
  0 siblings, 0 replies; 3+ messages in thread
From: Florian Weimer @ 2020-02-10 17:08 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=01b41a99850200248e385e7fd9abee899ed75777

commit 01b41a99850200248e385e7fd9abee899ed75777
Author: Florian Weimer <fweimer@redhat.com>
Date:   Mon Feb 10 14:23:16 2020 +0100

    Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
    
    This will be used to consolidate the libgcc_s access for backtrace
    and pthread_cancel.
    
    Unlike the backtrace implementations, it provides some hardening
    based on pointer mangling.

Diff:
---
 malloc/set-freeres.c                       |   5 ++
 misc/Makefile                              |   2 +-
 misc/Versions                              |   1 +
 misc/unwind-link.c                         | 114 +++++++++++++++++++++++++++++
 sysdeps/arm/unwind-link.h                  |  33 +++++++++
 sysdeps/generic/unwind-link.h              |  85 +++++++++++++++++++++
 sysdeps/i386/unwind-link.h                 |  31 ++++++++
 sysdeps/unix/sysv/linux/ia64/unwind-link.h |  31 ++++++++
 8 files changed, 301 insertions(+), 1 deletion(-)

diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index aa80eb6..a80cd30 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <set-hooks.h>
 #include <libc-internal.h>
+#include <unwind-link.h>
 
 #include "../libio/libioP.h"
 
@@ -56,6 +57,10 @@ __libc_freeres (void)
       if (&__libpthread_freeres != NULL)
 	__libpthread_freeres ();
 
+#ifdef SHARED
+      __libc_unwind_link_freeres ();
+#endif
+
       for (p = symbol_set_first_element (__libc_freeres_ptrs);
            !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
         free (*p);
diff --git a/misc/Makefile b/misc/Makefile
index e046598..aae5241 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -72,7 +72,7 @@ routines := brk sbrk sstk ioctl \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list makedev \
-	    allocate_once
+	    allocate_once unwind-link
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/Versions b/misc/Versions
index e749582..a9cfe3b 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -169,5 +169,6 @@ libc {
     __mmap; __munmap; __mprotect;
     __sched_get_priority_min; __sched_get_priority_max;
     __libc_allocate_once_slow;
+    __libc_unwind_link_get;
   }
 }
diff --git a/misc/unwind-link.c b/misc/unwind-link.c
new file mode 100644
index 0000000..b0d5a70
--- /dev/null
+++ b/misc/unwind-link.c
@@ -0,0 +1,114 @@
+/* Dynamic loading of the libgcc unwinder.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+
+#include <allocate_once.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <unwind-link.h>
+
+/* Used by allocate_one.  */
+static void *place;
+
+/* Open libgcc_s and look up the symbols required by glibc.  */
+static void *
+allocate_link (void *closure)
+{
+  struct unwind_link *result = malloc (sizeof (*result));
+  if (result == NULL)
+    return NULL;
+
+  result->libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
+  if (result->libgcc_handle == NULL)
+    {
+      /* Assume that this is a transient failure.  */
+      free (result);
+      return NULL;
+    }
+
+  result->ptr__Unwind_Backtrace
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_Backtrace");
+  result->ptr__Unwind_ForcedUnwind
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_ForcedUnwind");
+  result->ptr__Unwind_GetCFA
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_GetCFA");
+#ifndef UNWIND_LINK_NO_GETIP
+  result->ptr__Unwind_GetIP
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_GetIP");
+#endif
+  result->ptr__Unwind_Resume
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_Resume");
+  result->ptr_personality
+    = __libc_dlsym (result->libgcc_handle, "__gcc_personality_v0");
+#ifdef UNWIND_LINK_EXTRA_INIT
+  UNWIND_LINK_EXTRA_INIT
+#endif
+
+  /* If a symbol is missing, libgcc_s has somehow been corrupted.  */
+  assert (result->ptr__Unwind_Backtrace != NULL);
+  assert (result->ptr__Unwind_ForcedUnwind != NULL);
+  assert (result->ptr__Unwind_GetCFA != NULL);
+#ifndef UNWIND_LINK_NO_GETIP
+  assert (result->ptr__Unwind_GetIP != NULL);
+#endif
+  assert (result->ptr__Unwind_Resume != NULL);
+  assert (result->ptr_personality != NULL);
+
+#ifdef PTR_MANGLE
+  PTR_MANGLE (result->ptr__Unwind_Backtrace);
+  PTR_MANGLE (result->ptr__Unwind_ForcedUnwind);
+  PTR_MANGLE (result->ptr__Unwind_GetCFA);
+# ifndef UNWIND_LINK_NO_GETIP
+  PTR_MANGLE (result->ptr__Unwind_GetIP);
+# endif
+  PTR_MANGLE (result->ptr__Unwind_Resume);
+  PTR_MANGLE (result->ptr_personality);
+#endif
+
+  return result;
+}
+
+/* Deallocate the object after the race was lost.  */
+static void
+deallocate_link (void *closure, void *result)
+{
+  struct unwind_link *link = result;
+  __libc_dlclose (link->libgcc_handle);
+  free (link);
+}
+
+struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  return allocate_once (&place, allocate_link, deallocate_link, NULL);
+}
+libc_hidden_def (__libc_unwind_link_get)
+
+void __libc_freeres_fn_section
+__libc_unwind_link_freeres (void)
+{
+  if (place != NULL)
+    {
+      deallocate_link (NULL, place);
+      place = NULL;
+    }
+}
+
+#endif /* SHARED */
diff --git a/sysdeps/arm/unwind-link.h b/sysdeps/arm/unwind-link.h
new file mode 100644
index 0000000..2372bd8
--- /dev/null
+++ b/sysdeps/arm/unwind-link.h
@@ -0,0 +1,33 @@
+/* Dynamic loading of the libgcc unwinder.  Arm overrides.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+
+/* On arm, _Unwind_GetIP is a macro.  */
+#define UNWIND_LINK_NO_GETIP
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_VRS_Get) *ptr__Unwind_VRS_Get;
+#define UNWIND_LINK_EXTRA_INIT                                  \
+  result->ptr__Unwind_VRS_Get                                   \
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_VRS_Get");  \
+  assert (result->ptr__Unwind_VRS_Get != NULL);                 \
+  PTR_MANGLE (result->ptr__Unwind_VRS_Get);
+
+#include <sysdeps/generic/unwind-link.h>
+
+#endif /* _UNWIND_LINK_H */
diff --git a/sysdeps/generic/unwind-link.h b/sysdeps/generic/unwind-link.h
new file mode 100644
index 0000000..4fca352
--- /dev/null
+++ b/sysdeps/generic/unwind-link.h
@@ -0,0 +1,85 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+#define _UNWIND_LINK_H
+
+#include <unwind.h>
+
+#ifdef SHARED
+
+#include <sysdep.h>
+#include <unwind-resume.h>
+
+struct unwind_link
+{
+  void *libgcc_handle;
+  __typeof (_Unwind_Backtrace) *ptr__Unwind_Backtrace;
+  __typeof (_Unwind_ForcedUnwind) *ptr__Unwind_ForcedUnwind;
+  __typeof (_Unwind_GetCFA) *ptr__Unwind_GetCFA;
+# ifndef UNWIND_LINK_NO_GETIP
+  __typeof (_Unwind_GetIP) *ptr__Unwind_GetIP;
+# endif
+  __typeof (_Unwind_Resume) *ptr__Unwind_Resume;
+  _Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
+# ifdef UNWIND_LINK_EXTRA_FIELDS
+  UNWIND_LINK_EXTRA_FIELDS
+# endif
+};
+
+/* Return a pointer to the implementation, or NULL on failure.  */
+struct unwind_link *__libc_unwind_link_get (void);
+libc_hidden_proto (__libc_unwind_link_get)
+
+/* UNWIND_LINK_CALL invokes the stored function pointer NAME via the
+   cached unwind link OBJ (which was previously returned by
+   __libc_unwind_link_get).  */
+# ifdef PTR_DEMANGLE
+#  define UNWIND_LINK_CALL(obj, name, ...)                          \
+  ({                                                                \
+    __typeof ((obj)->ptr_##name) __unwind_fptr = (obj)->ptr_##name; \
+    PTR_DEMANGLE (__unwind_fptr);                                   \
+    __unwind_fptr (__VA_ARGS__);                                    \
+  })
+# else /* !PTR_DEMANGLE */
+#  define UNWIND_LINK_CALL(obj, name, ...) ((obj)->ptr_##name (__VA_ARGS__))
+# endif
+
+/* Called from __libc_freeres.  */
+void __libc_unwind_link_freeres (void) attribute_hidden;
+
+#else /* !SHARED */
+
+/* Dummy implementation so that the code can be shared with the SHARED
+   version.  */
+struct unwind_link;
+static inline struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Return something that is not a null pointer, so that error checks
+     succeed.  */
+  return (struct unwind_link *) 1;
+}
+
+/* Directly call the static implementation.  */
+# define UNWIND_LINK_CALL(obj, name, ...) \
+  ((void) (obj), (name (__VA_ARGS__)))
+
+#endif /* !SHARED */
+
+#endif /* _UNWIND_LINK_H */
diff --git a/sysdeps/i386/unwind-link.h b/sysdeps/i386/unwind-link.h
new file mode 100644
index 0000000..ef5999f
--- /dev/null
+++ b/sysdeps/i386/unwind-link.h
@@ -0,0 +1,31 @@
+/* Dynamic loading of the libgcc unwinder.  i386 overrides.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetGR) *ptr__Unwind_GetGR;
+#define UNWIND_LINK_EXTRA_INIT                                \
+  result->ptr__Unwind_GetGR                                   \
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_GetGR");  \
+  assert (result->ptr__Unwind_GetGR != NULL);                 \
+  PTR_MANGLE (result->ptr__Unwind_GetGR);
+
+#include <sysdeps/generic/unwind-link.h>
+
+#endif /* _UNWIND_LINK_H */
diff --git a/sysdeps/unix/sysv/linux/ia64/unwind-link.h b/sysdeps/unix/sysv/linux/ia64/unwind-link.h
new file mode 100644
index 0000000..32dd74b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/ia64/unwind-link.h
@@ -0,0 +1,31 @@
+/* Dynamic loading of the libgcc unwinder.  ia64 overrides.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetBSP) *ptr__Unwind_GetBSP;
+#define UNWIND_LINK_EXTRA_INIT                                 \
+  result->ptr__Unwind_GetBSP                                   \
+    = __libc_dlsym (result->libgcc_handle, "_Unwind_GetBSP");  \
+  assert (result->ptr__Unwind_GetBSP != NULL);                 \
+  PTR_MANGLE (result->ptr__Unwind_GetBSP);
+
+#include <sysdeps/generic/unwind-link.h>
+
+#endif /* _UNWIND_LINK_H */


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [glibc/fw/unwind-link] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
@ 2020-02-13 16:22 Florian Weimer
  0 siblings, 0 replies; 3+ messages in thread
From: Florian Weimer @ 2020-02-13 16:22 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=030c3e22e6b32b890d78c5b3ee7c3023a3013c94

commit 030c3e22e6b32b890d78c5b3ee7c3023a3013c94
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Feb 13 17:05:50 2020 +0100

    Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
    
    This will be used to consolidate the libgcc_s access for backtrace
    and pthread_cancel.
    
    Unlike the backtrace implementations, it provides some hardening
    based on pointer mangling.

Diff:
---
 malloc/set-freeres.c                         |   5 +
 misc/Makefile                                |   2 +-
 misc/Versions                                |   1 +
 misc/unwind-link.c                           | 149 +++++++++++++++++++++++++++
 sysdeps/alpha/arch-unwind-link.h             |  27 +++++
 sysdeps/arm/arch-unwind-link.h               |  34 ++++++
 sysdeps/generic/arch-unwind-link.h           |  32 ++++++
 sysdeps/generic/unwind-link.h                |  99 ++++++++++++++++++
 sysdeps/i386/arch-unwind-link.h              |  38 +++++++
 sysdeps/ia64/arch-unwind-link.h              |  31 ++++++
 sysdeps/m68k/arch-unwind-link.h              |  34 ++++++
 sysdeps/m68k/m680x0/arch-unwind-link.h       |  26 +++++
 sysdeps/mach/hurd/fork.c                     |   3 +
 sysdeps/mips/arch-unwind-link.h              |  27 +++++
 sysdeps/nptl/fork.c                          |   3 +
 sysdeps/powerpc/powerpc32/arch-unwind-link.h |  27 +++++
 sysdeps/s390/arch-unwind-link.h              |  27 +++++
 sysdeps/sh/arch-unwind-link.h                |  27 +++++
 sysdeps/sparc/arch-unwind-link.h             |  27 +++++
 19 files changed, 618 insertions(+), 1 deletion(-)

diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index aa80eb6..a80cd30 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <set-hooks.h>
 #include <libc-internal.h>
+#include <unwind-link.h>
 
 #include "../libio/libioP.h"
 
@@ -56,6 +57,10 @@ __libc_freeres (void)
       if (&__libpthread_freeres != NULL)
 	__libpthread_freeres ();
 
+#ifdef SHARED
+      __libc_unwind_link_freeres ();
+#endif
+
       for (p = symbol_set_first_element (__libc_freeres_ptrs);
            !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
         free (*p);
diff --git a/misc/Makefile b/misc/Makefile
index e046598..aae5241 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -72,7 +72,7 @@ routines := brk sbrk sstk ioctl \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list makedev \
-	    allocate_once
+	    allocate_once unwind-link
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/Versions b/misc/Versions
index e749582..a9cfe3b 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -169,5 +169,6 @@ libc {
     __mmap; __munmap; __mprotect;
     __sched_get_priority_min; __sched_get_priority_max;
     __libc_allocate_once_slow;
+    __libc_unwind_link_get;
   }
 }
diff --git a/misc/unwind-link.c b/misc/unwind-link.c
new file mode 100644
index 0000000..49076f8
--- /dev/null
+++ b/misc/unwind-link.c
@@ -0,0 +1,149 @@
+/* Dynamic loading of the libgcc unwinder.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <unwind-link.h>
+#include <libc-lock.h>
+
+/* Statically allocate the object, so that we do not have to deal with
+   malloc failure.  __libc_unwind_link_get must not fail if libgcc_s
+   has already been loaded by other means.  */
+static struct unwind_link global;
+
+/* dlopen handle.  Also used for the double-checked locking idiom.  */
+static void *global_libgcc_handle;
+
+/* We cannot use __libc_once because the pthread_once implementation
+   may depend on unwinding.  */
+__libc_lock_define (static, lock);
+
+struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Double-checked locking idiom.  Synchronizes with the release MO
+     store at the end of this function.  */
+  if (atomic_load_acquire (&global_libgcc_handle) != NULL)
+   return &global;
+
+  /* Initialize a copy of the data, so that we do not need about
+     unlocking in case the dynamic loader somehow triggers
+     unwinding.  */
+  void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
+  if (local_libgcc_handle == NULL)
+    {
+      __libc_lock_unlock (lock);
+      return NULL;
+    }
+
+  struct unwind_link local;
+  local.ptr__Unwind_Backtrace
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_Backtrace");
+  local.ptr__Unwind_ForcedUnwind
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_ForcedUnwind");
+  local.ptr__Unwind_GetCFA
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetCFA");
+#if UNWIND_LINK_GETIP
+  local.ptr__Unwind_GetIP
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetIP");
+#endif
+  local.ptr__Unwind_Resume
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_Resume");
+#if UNWIND_LINK_FRAME_STATE_FOR
+  local.ptr___frame_state_for
+    = __libc_dlsym (local_libgcc_handle, "__frame_state_for");
+#endif
+  local.ptr_personality
+    = __libc_dlsym (local_libgcc_handle, "__gcc_personality_v0");
+  UNWIND_LINK_EXTRA_INIT
+
+  /* If a symbol is missing, libgcc_s has somehow been corrupted.  */
+  assert (local.ptr__Unwind_Backtrace != NULL);
+  assert (local.ptr__Unwind_ForcedUnwind != NULL);
+  assert (local.ptr__Unwind_GetCFA != NULL);
+#if UNWIND_LINK_GETIP
+  assert (local.ptr__Unwind_GetIP != NULL);
+#endif
+  assert (local.ptr__Unwind_Resume != NULL);
+  assert (local.ptr_personality != NULL);
+
+#ifdef PTR_MANGLE
+  PTR_MANGLE (local.ptr__Unwind_Backtrace);
+  PTR_MANGLE (local.ptr__Unwind_ForcedUnwind);
+  PTR_MANGLE (local.ptr__Unwind_GetCFA);
+# if UNWIND_LINK_GETIP
+  PTR_MANGLE (local.ptr__Unwind_GetIP);
+# endif
+  PTR_MANGLE (local.ptr__Unwind_Resume);
+# if UNWIND_LINK_FRAME_STATE_FOR
+  PTR_MANGLE (local.ptr___frame_state_for);
+# endif
+  PTR_MANGLE (local.ptr_personality);
+#endif
+
+  __libc_lock_lock (lock);
+  if (atomic_load_relaxed (&global_libgcc_handle) != NULL)
+    /* This thread lost the race.  Clean up.  */
+    __libc_dlclose (local_libgcc_handle);
+  else
+    {
+      global = local;
+
+      /* Completes the double-checked locking idiom.  */
+      atomic_store_release (&global_libgcc_handle, local_libgcc_handle);
+    }
+
+  __libc_lock_unlock (lock);
+  return &global;
+}
+libc_hidden_def (__libc_unwind_link_get)
+
+void
+__libc_unwind_link_after_fork (void)
+{
+  if (__libc_lock_trylock (lock) == 0)
+    /* The lock was not acquired during the fork.  This covers both
+       the initialized and uninitialized case.  */
+    __libc_lock_unlock (lock);
+  else
+    {
+      /* Initialization was in progress in another thread.
+         Reinitialize the lock.  */
+      __libc_lock_init (lock);
+      global_libgcc_handle = NULL;
+    }
+}
+
+void __libc_freeres_fn_section
+__libc_unwind_link_freeres (void)
+{
+  if (__libc_lock_trylock (lock) == 0)
+    {
+      if (global_libgcc_handle != NULL)
+        {
+          __libc_dlclose (global_libgcc_handle );
+          global_libgcc_handle = NULL;
+        }
+      __libc_lock_unlock (lock);
+    }
+}
+
+#endif /* SHARED */
diff --git a/sysdeps/alpha/arch-unwind-link.h b/sysdeps/alpha/arch-unwind-link.h
new file mode 100644
index 0000000..998e47c
--- /dev/null
+++ b/sysdeps/alpha/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  alpha customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/arm/arch-unwind-link.h b/sysdeps/arm/arch-unwind-link.h
new file mode 100644
index 0000000..b16a94e
--- /dev/null
+++ b/sysdeps/arm/arch-unwind-link.h
@@ -0,0 +1,34 @@
+/* Dynamic loading of the libgcc unwinder.  Arm customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+/* On arm, _Unwind_GetIP is a macro.  */
+#define UNWIND_LINK_GETIP 0
+
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_VRS_Get) *ptr__Unwind_VRS_Get;
+#define UNWIND_LINK_EXTRA_INIT                                \
+  local.ptr__Unwind_VRS_Get                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_VRS_Get");  \
+  assert (local.ptr__Unwind_VRS_Get != NULL);                 \
+  PTR_MANGLE (local.ptr__Unwind_VRS_Get);
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/generic/arch-unwind-link.h b/sysdeps/generic/arch-unwind-link.h
new file mode 100644
index 0000000..efc2292
--- /dev/null
+++ b/sysdeps/generic/arch-unwind-link.h
@@ -0,0 +1,32 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version of parameters.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+/* The _Unwind_GetIP function is supported.  */
+#define UNWIND_LINK_GETIP 1
+
+/* The __frame_state_for is needed and re-exported from glibc.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+
+/* There are no extra fields in struct unwind_link.  */
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/generic/unwind-link.h b/sysdeps/generic/unwind-link.h
new file mode 100644
index 0000000..9e6e134
--- /dev/null
+++ b/sysdeps/generic/unwind-link.h
@@ -0,0 +1,99 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+#define _UNWIND_LINK_H
+
+#include <unwind.h>
+
+#ifdef SHARED
+
+#include <arch-unwind-link.h>
+#include <sysdep.h>
+#include <unwind-resume.h>
+
+#if UNWIND_LINK_FRAME_STATE_FOR
+struct frame_state;
+#endif
+
+struct unwind_link
+{
+  __typeof (_Unwind_Backtrace) *ptr__Unwind_Backtrace;
+  __typeof (_Unwind_ForcedUnwind) *ptr__Unwind_ForcedUnwind;
+  __typeof (_Unwind_GetCFA) *ptr__Unwind_GetCFA;
+# if UNWIND_LINK_GETIP
+  __typeof (_Unwind_GetIP) *ptr__Unwind_GetIP;
+# endif
+  __typeof (_Unwind_Resume) *ptr__Unwind_Resume;
+#if UNWIND_LINK_FRAME_STATE_FOR
+  struct frame_state *(*ptr___frame_state_for)(void *pc, struct frame_state *);
+#endif
+  _Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
+  UNWIND_LINK_EXTRA_FIELDS
+};
+
+/* Return a pointer to the implementation, or NULL on failure.  */
+struct unwind_link *__libc_unwind_link_get (void);
+libc_hidden_proto (__libc_unwind_link_get)
+
+/* UNWIND_LINK_PTR returns the stored function pointer NAME from the
+   cached unwind link OBJ (which was previously returned by
+   __libc_unwind_link_get).  */
+# ifdef PTR_DEMANGLE
+#  define UNWIND_LINK_PTR(obj, name, ...)                          \
+  ({                                                                \
+    __typeof ((obj)->ptr_##name) __unwind_fptr = (obj)->ptr_##name; \
+    PTR_DEMANGLE (__unwind_fptr);                                   \
+    __unwind_fptr;                                                  \
+  })
+# else /* !PTR_DEMANGLE */
+#  define UNWIND_LINK_PTR(obj, name, ...) ((obj)->ptr_##name)
+# endif
+
+/* Called from fork, in the new subprocess.  */
+void __libc_unwind_link_after_fork (void);
+
+/* Called from __libc_freeres.  */
+void __libc_unwind_link_freeres (void) attribute_hidden;
+
+#else /* !SHARED */
+
+/* Dummy implementation so that the code can be shared with the SHARED
+   version.  */
+struct unwind_link;
+static inline struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Return something that is not a null pointer, so that error checks
+     succeed.  */
+  return (struct unwind_link *) 1;
+}
+
+/* Directly call the static implementation.  */
+# define UNWIND_LINK_PTR(obj, name, ...) \
+  ((void) (obj), &name)
+
+static inline void
+__libc_unwind_link_after_fork (void)
+{
+  /* No need to clean up if the unwinder is statically linked.  */
+}
+
+#endif /* !SHARED */
+
+#endif /* _UNWIND_LINK_H */
diff --git a/sysdeps/i386/arch-unwind-link.h b/sysdeps/i386/arch-unwind-link.h
new file mode 100644
index 0000000..bc9c3a1
--- /dev/null
+++ b/sysdeps/i386/arch-unwind-link.h
@@ -0,0 +1,38 @@
+/* Dynamic loading of the libgcc unwinder.  i386 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetGR) *ptr__Unwind_GetGR;
+#define UNWIND_LINK_EXTRA_INIT_SHARED                       \
+  local.ptr__Unwind_GetGR                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetGR");  \
+  assert (local.ptr__Unwind_GetGR != NULL);
+#ifdef PTR_MANGLE
+# define UNWIND_LINK_EXTRA_INIT                 \
+  UNWIND_LINK_EXTRA_INIT_SHARED                 \
+  PTR_MANGLE (local.ptr__Unwind_GetGR);
+#else
+# define UNWIND_LINK_EXTRA_INIT UNWIND_LINK_EXTRA_INIT_SHARED
+#endif
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/ia64/arch-unwind-link.h b/sysdeps/ia64/arch-unwind-link.h
new file mode 100644
index 0000000..570b711
--- /dev/null
+++ b/sysdeps/ia64/arch-unwind-link.h
@@ -0,0 +1,31 @@
+/* Dynamic loading of the libgcc unwinder.  ia64 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetBSP) *ptr__Unwind_GetBSP;
+#define UNWIND_LINK_EXTRA_INIT                               \
+  local.ptr__Unwind_GetBSP                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetBSP");  \
+  assert (local.ptr__Unwind_GetBSP != NULL);                 \
+  PTR_MANGLE (local.ptr__Unwind_GetBSP);
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/m68k/arch-unwind-link.h b/sysdeps/m68k/arch-unwind-link.h
new file mode 100644
index 0000000..e010514
--- /dev/null
+++ b/sysdeps/m68k/arch-unwind-link.h
@@ -0,0 +1,34 @@
+/* Dynamic loading of the libgcc unwinder.  m68k customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetGR) *ptr__Unwind_GetGR;
+#define UNWIND_LINK_EXTRA_INIT                                \
+  local.ptr__Unwind_GetGR                                     \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetGR");    \
+  assert (local.ptr__Unwind_GetGR != NULL);                   \
+  PTR_MANGLE (local.ptr__Unwind_GetGR);
+
+/* This is overriden by the m680x0 variant.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/m68k/m680x0/arch-unwind-link.h b/sysdeps/m68k/m680x0/arch-unwind-link.h
new file mode 100644
index 0000000..1adbf23
--- /dev/null
+++ b/sysdeps/m68k/m680x0/arch-unwind-link.h
@@ -0,0 +1,26 @@
+/* Dynamic loading of the libgcc unwinder.  Baseline m68k customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+
+#include <sysdeps/m68k/arch-unwind-link.h>
+
+#undef UNWIND_LINK_FRAME_STATE_FOR
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 3278306..1d4819e 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -28,6 +28,7 @@
 #include "hurdmalloc.h"		/* XXX */
 #include <tls.h>
 #include <malloc/malloc-internal.h>
+#include <unwind-link.h>
 
 #undef __fork
 
@@ -662,6 +663,8 @@ __fork (void)
       __sigemptyset (&_hurd_global_sigstate->pending);
       __sigemptyset (&ss->pending);
 
+      __libc_unwind_link_after_fork ();
+
       /* Release malloc locks.  */
       _hurd_malloc_fork_child ();
       call_function_static_weak (__malloc_fork_unlock_child);
diff --git a/sysdeps/mips/arch-unwind-link.h b/sysdeps/mips/arch-unwind-link.h
new file mode 100644
index 0000000..9835c0f
--- /dev/null
+++ b/sysdeps/mips/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  MIPS customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index f5cf88d..19e8381 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -32,6 +32,7 @@
 #include <arch-fork.h>
 #include <futex-internal.h>
 #include <malloc/malloc-internal.h>
+#include <unwind-link.h>
 
 static void
 fresetlockfiles (void)
@@ -112,6 +113,8 @@ __libc_fork (void)
       /* Reset the lock state in the multi-threaded case.  */
       if (multiple_threads)
 	{
+	  __libc_unwind_link_after_fork ();
+
 	  /* Release malloc locks.  */
 	  call_function_static_weak (__malloc_fork_unlock_child);
 
diff --git a/sysdeps/powerpc/powerpc32/arch-unwind-link.h b/sysdeps/powerpc/powerpc32/arch-unwind-link.h
new file mode 100644
index 0000000..6a87daa
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  powerpc customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/s390/arch-unwind-link.h b/sysdeps/s390/arch-unwind-link.h
new file mode 100644
index 0000000..c50b7f2
--- /dev/null
+++ b/sysdeps/s390/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  S/390 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/sh/arch-unwind-link.h b/sysdeps/sh/arch-unwind-link.h
new file mode 100644
index 0000000..519c224
--- /dev/null
+++ b/sysdeps/sh/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  SH customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/sparc/arch-unwind-link.h b/sysdeps/sparc/arch-unwind-link.h
new file mode 100644
index 0000000..4b7e2f1
--- /dev/null
+++ b/sysdeps/sparc/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  SPARC customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [glibc/fw/unwind-link] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
@ 2020-02-13 10:45 Florian Weimer
  0 siblings, 0 replies; 3+ messages in thread
From: Florian Weimer @ 2020-02-13 10:45 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=9105752b516e96a3dbcc7f871f4dc48ac304aa26

commit 9105752b516e96a3dbcc7f871f4dc48ac304aa26
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Feb 11 10:14:58 2020 +0100

    Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
    
    This will be used to consolidate the libgcc_s access for backtrace
    and pthread_cancel.
    
    Unlike the backtrace implementations, it provides some hardening
    based on pointer mangling.

Diff:
---
 malloc/set-freeres.c                         |   5 +
 misc/Makefile                                |   2 +-
 misc/Versions                                |   1 +
 misc/unwind-link.c                           | 149 +++++++++++++++++++++++++++
 sysdeps/alpha/arch-unwind-link.h             |  27 +++++
 sysdeps/arm/arch-unwind-link.h               |  34 ++++++
 sysdeps/generic/arch-unwind-link.h           |  32 ++++++
 sysdeps/generic/unwind-link.h                |  99 ++++++++++++++++++
 sysdeps/i386/arch-unwind-link.h              |  38 +++++++
 sysdeps/ia64/arch-unwind-link.h              |  31 ++++++
 sysdeps/m68k/arch-unwind-link.h              |  34 ++++++
 sysdeps/m68k/m680x0/arch-unwind-link.h       |  26 +++++
 sysdeps/mach/hurd/fork.c                     |   3 +
 sysdeps/mips/arch-unwind-link.h              |  27 +++++
 sysdeps/nptl/fork.c                          |   3 +
 sysdeps/powerpc/powerpc32/arch-unwind-link.h |  27 +++++
 sysdeps/s390/arch-unwind-link.h              |  27 +++++
 sysdeps/sparc/arch-unwind-link.h             |  27 +++++
 18 files changed, 591 insertions(+), 1 deletion(-)

diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index aa80eb6..a80cd30 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <set-hooks.h>
 #include <libc-internal.h>
+#include <unwind-link.h>
 
 #include "../libio/libioP.h"
 
@@ -56,6 +57,10 @@ __libc_freeres (void)
       if (&__libpthread_freeres != NULL)
 	__libpthread_freeres ();
 
+#ifdef SHARED
+      __libc_unwind_link_freeres ();
+#endif
+
       for (p = symbol_set_first_element (__libc_freeres_ptrs);
            !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
         free (*p);
diff --git a/misc/Makefile b/misc/Makefile
index e046598..aae5241 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -72,7 +72,7 @@ routines := brk sbrk sstk ioctl \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list makedev \
-	    allocate_once
+	    allocate_once unwind-link
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/Versions b/misc/Versions
index e749582..a9cfe3b 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -169,5 +169,6 @@ libc {
     __mmap; __munmap; __mprotect;
     __sched_get_priority_min; __sched_get_priority_max;
     __libc_allocate_once_slow;
+    __libc_unwind_link_get;
   }
 }
diff --git a/misc/unwind-link.c b/misc/unwind-link.c
new file mode 100644
index 0000000..49076f8
--- /dev/null
+++ b/misc/unwind-link.c
@@ -0,0 +1,149 @@
+/* Dynamic loading of the libgcc unwinder.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <unwind-link.h>
+#include <libc-lock.h>
+
+/* Statically allocate the object, so that we do not have to deal with
+   malloc failure.  __libc_unwind_link_get must not fail if libgcc_s
+   has already been loaded by other means.  */
+static struct unwind_link global;
+
+/* dlopen handle.  Also used for the double-checked locking idiom.  */
+static void *global_libgcc_handle;
+
+/* We cannot use __libc_once because the pthread_once implementation
+   may depend on unwinding.  */
+__libc_lock_define (static, lock);
+
+struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Double-checked locking idiom.  Synchronizes with the release MO
+     store at the end of this function.  */
+  if (atomic_load_acquire (&global_libgcc_handle) != NULL)
+   return &global;
+
+  /* Initialize a copy of the data, so that we do not need about
+     unlocking in case the dynamic loader somehow triggers
+     unwinding.  */
+  void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
+  if (local_libgcc_handle == NULL)
+    {
+      __libc_lock_unlock (lock);
+      return NULL;
+    }
+
+  struct unwind_link local;
+  local.ptr__Unwind_Backtrace
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_Backtrace");
+  local.ptr__Unwind_ForcedUnwind
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_ForcedUnwind");
+  local.ptr__Unwind_GetCFA
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetCFA");
+#if UNWIND_LINK_GETIP
+  local.ptr__Unwind_GetIP
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetIP");
+#endif
+  local.ptr__Unwind_Resume
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_Resume");
+#if UNWIND_LINK_FRAME_STATE_FOR
+  local.ptr___frame_state_for
+    = __libc_dlsym (local_libgcc_handle, "__frame_state_for");
+#endif
+  local.ptr_personality
+    = __libc_dlsym (local_libgcc_handle, "__gcc_personality_v0");
+  UNWIND_LINK_EXTRA_INIT
+
+  /* If a symbol is missing, libgcc_s has somehow been corrupted.  */
+  assert (local.ptr__Unwind_Backtrace != NULL);
+  assert (local.ptr__Unwind_ForcedUnwind != NULL);
+  assert (local.ptr__Unwind_GetCFA != NULL);
+#if UNWIND_LINK_GETIP
+  assert (local.ptr__Unwind_GetIP != NULL);
+#endif
+  assert (local.ptr__Unwind_Resume != NULL);
+  assert (local.ptr_personality != NULL);
+
+#ifdef PTR_MANGLE
+  PTR_MANGLE (local.ptr__Unwind_Backtrace);
+  PTR_MANGLE (local.ptr__Unwind_ForcedUnwind);
+  PTR_MANGLE (local.ptr__Unwind_GetCFA);
+# if UNWIND_LINK_GETIP
+  PTR_MANGLE (local.ptr__Unwind_GetIP);
+# endif
+  PTR_MANGLE (local.ptr__Unwind_Resume);
+# if UNWIND_LINK_FRAME_STATE_FOR
+  PTR_MANGLE (local.ptr___frame_state_for);
+# endif
+  PTR_MANGLE (local.ptr_personality);
+#endif
+
+  __libc_lock_lock (lock);
+  if (atomic_load_relaxed (&global_libgcc_handle) != NULL)
+    /* This thread lost the race.  Clean up.  */
+    __libc_dlclose (local_libgcc_handle);
+  else
+    {
+      global = local;
+
+      /* Completes the double-checked locking idiom.  */
+      atomic_store_release (&global_libgcc_handle, local_libgcc_handle);
+    }
+
+  __libc_lock_unlock (lock);
+  return &global;
+}
+libc_hidden_def (__libc_unwind_link_get)
+
+void
+__libc_unwind_link_after_fork (void)
+{
+  if (__libc_lock_trylock (lock) == 0)
+    /* The lock was not acquired during the fork.  This covers both
+       the initialized and uninitialized case.  */
+    __libc_lock_unlock (lock);
+  else
+    {
+      /* Initialization was in progress in another thread.
+         Reinitialize the lock.  */
+      __libc_lock_init (lock);
+      global_libgcc_handle = NULL;
+    }
+}
+
+void __libc_freeres_fn_section
+__libc_unwind_link_freeres (void)
+{
+  if (__libc_lock_trylock (lock) == 0)
+    {
+      if (global_libgcc_handle != NULL)
+        {
+          __libc_dlclose (global_libgcc_handle );
+          global_libgcc_handle = NULL;
+        }
+      __libc_lock_unlock (lock);
+    }
+}
+
+#endif /* SHARED */
diff --git a/sysdeps/alpha/arch-unwind-link.h b/sysdeps/alpha/arch-unwind-link.h
new file mode 100644
index 0000000..998e47c
--- /dev/null
+++ b/sysdeps/alpha/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  alpha customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/arm/arch-unwind-link.h b/sysdeps/arm/arch-unwind-link.h
new file mode 100644
index 0000000..b16a94e
--- /dev/null
+++ b/sysdeps/arm/arch-unwind-link.h
@@ -0,0 +1,34 @@
+/* Dynamic loading of the libgcc unwinder.  Arm customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+/* On arm, _Unwind_GetIP is a macro.  */
+#define UNWIND_LINK_GETIP 0
+
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_VRS_Get) *ptr__Unwind_VRS_Get;
+#define UNWIND_LINK_EXTRA_INIT                                \
+  local.ptr__Unwind_VRS_Get                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_VRS_Get");  \
+  assert (local.ptr__Unwind_VRS_Get != NULL);                 \
+  PTR_MANGLE (local.ptr__Unwind_VRS_Get);
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/generic/arch-unwind-link.h b/sysdeps/generic/arch-unwind-link.h
new file mode 100644
index 0000000..efc2292
--- /dev/null
+++ b/sysdeps/generic/arch-unwind-link.h
@@ -0,0 +1,32 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version of parameters.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+/* The _Unwind_GetIP function is supported.  */
+#define UNWIND_LINK_GETIP 1
+
+/* The __frame_state_for is needed and re-exported from glibc.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+
+/* There are no extra fields in struct unwind_link.  */
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/generic/unwind-link.h b/sysdeps/generic/unwind-link.h
new file mode 100644
index 0000000..9e6e134
--- /dev/null
+++ b/sysdeps/generic/unwind-link.h
@@ -0,0 +1,99 @@
+/* Dynamic loading of the libgcc unwinder.  Generic version.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _UNWIND_LINK_H
+#define _UNWIND_LINK_H
+
+#include <unwind.h>
+
+#ifdef SHARED
+
+#include <arch-unwind-link.h>
+#include <sysdep.h>
+#include <unwind-resume.h>
+
+#if UNWIND_LINK_FRAME_STATE_FOR
+struct frame_state;
+#endif
+
+struct unwind_link
+{
+  __typeof (_Unwind_Backtrace) *ptr__Unwind_Backtrace;
+  __typeof (_Unwind_ForcedUnwind) *ptr__Unwind_ForcedUnwind;
+  __typeof (_Unwind_GetCFA) *ptr__Unwind_GetCFA;
+# if UNWIND_LINK_GETIP
+  __typeof (_Unwind_GetIP) *ptr__Unwind_GetIP;
+# endif
+  __typeof (_Unwind_Resume) *ptr__Unwind_Resume;
+#if UNWIND_LINK_FRAME_STATE_FOR
+  struct frame_state *(*ptr___frame_state_for)(void *pc, struct frame_state *);
+#endif
+  _Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
+  UNWIND_LINK_EXTRA_FIELDS
+};
+
+/* Return a pointer to the implementation, or NULL on failure.  */
+struct unwind_link *__libc_unwind_link_get (void);
+libc_hidden_proto (__libc_unwind_link_get)
+
+/* UNWIND_LINK_PTR returns the stored function pointer NAME from the
+   cached unwind link OBJ (which was previously returned by
+   __libc_unwind_link_get).  */
+# ifdef PTR_DEMANGLE
+#  define UNWIND_LINK_PTR(obj, name, ...)                          \
+  ({                                                                \
+    __typeof ((obj)->ptr_##name) __unwind_fptr = (obj)->ptr_##name; \
+    PTR_DEMANGLE (__unwind_fptr);                                   \
+    __unwind_fptr;                                                  \
+  })
+# else /* !PTR_DEMANGLE */
+#  define UNWIND_LINK_PTR(obj, name, ...) ((obj)->ptr_##name)
+# endif
+
+/* Called from fork, in the new subprocess.  */
+void __libc_unwind_link_after_fork (void);
+
+/* Called from __libc_freeres.  */
+void __libc_unwind_link_freeres (void) attribute_hidden;
+
+#else /* !SHARED */
+
+/* Dummy implementation so that the code can be shared with the SHARED
+   version.  */
+struct unwind_link;
+static inline struct unwind_link *
+__libc_unwind_link_get (void)
+{
+  /* Return something that is not a null pointer, so that error checks
+     succeed.  */
+  return (struct unwind_link *) 1;
+}
+
+/* Directly call the static implementation.  */
+# define UNWIND_LINK_PTR(obj, name, ...) \
+  ((void) (obj), &name)
+
+static inline void
+__libc_unwind_link_after_fork (void)
+{
+  /* No need to clean up if the unwinder is statically linked.  */
+}
+
+#endif /* !SHARED */
+
+#endif /* _UNWIND_LINK_H */
diff --git a/sysdeps/i386/arch-unwind-link.h b/sysdeps/i386/arch-unwind-link.h
new file mode 100644
index 0000000..bc9c3a1
--- /dev/null
+++ b/sysdeps/i386/arch-unwind-link.h
@@ -0,0 +1,38 @@
+/* Dynamic loading of the libgcc unwinder.  i386 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetGR) *ptr__Unwind_GetGR;
+#define UNWIND_LINK_EXTRA_INIT_SHARED                       \
+  local.ptr__Unwind_GetGR                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetGR");  \
+  assert (local.ptr__Unwind_GetGR != NULL);
+#ifdef PTR_MANGLE
+# define UNWIND_LINK_EXTRA_INIT                 \
+  UNWIND_LINK_EXTRA_INIT_SHARED                 \
+  PTR_MANGLE (local.ptr__Unwind_GetGR);
+#else
+# define UNWIND_LINK_EXTRA_INIT UNWIND_LINK_EXTRA_INIT_SHARED
+#endif
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/ia64/arch-unwind-link.h b/sysdeps/ia64/arch-unwind-link.h
new file mode 100644
index 0000000..570b711
--- /dev/null
+++ b/sysdeps/ia64/arch-unwind-link.h
@@ -0,0 +1,31 @@
+/* Dynamic loading of the libgcc unwinder.  ia64 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetBSP) *ptr__Unwind_GetBSP;
+#define UNWIND_LINK_EXTRA_INIT                               \
+  local.ptr__Unwind_GetBSP                                   \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetBSP");  \
+  assert (local.ptr__Unwind_GetBSP != NULL);                 \
+  PTR_MANGLE (local.ptr__Unwind_GetBSP);
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/m68k/arch-unwind-link.h b/sysdeps/m68k/arch-unwind-link.h
new file mode 100644
index 0000000..e010514
--- /dev/null
+++ b/sysdeps/m68k/arch-unwind-link.h
@@ -0,0 +1,34 @@
+/* Dynamic loading of the libgcc unwinder.  m68k customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_EXTRA_FIELDS \
+  __typeof (_Unwind_GetGR) *ptr__Unwind_GetGR;
+#define UNWIND_LINK_EXTRA_INIT                                \
+  local.ptr__Unwind_GetGR                                     \
+    = __libc_dlsym (local_libgcc_handle, "_Unwind_GetGR");    \
+  assert (local.ptr__Unwind_GetGR != NULL);                   \
+  PTR_MANGLE (local.ptr__Unwind_GetGR);
+
+/* This is overriden by the m680x0 variant.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/m68k/m680x0/arch-unwind-link.h b/sysdeps/m68k/m680x0/arch-unwind-link.h
new file mode 100644
index 0000000..1adbf23
--- /dev/null
+++ b/sysdeps/m68k/m680x0/arch-unwind-link.h
@@ -0,0 +1,26 @@
+/* Dynamic loading of the libgcc unwinder.  Baseline m68k customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+
+#include <sysdeps/m68k/arch-unwind-link.h>
+
+#undef UNWIND_LINK_FRAME_STATE_FOR
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 3278306..1d4819e 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -28,6 +28,7 @@
 #include "hurdmalloc.h"		/* XXX */
 #include <tls.h>
 #include <malloc/malloc-internal.h>
+#include <unwind-link.h>
 
 #undef __fork
 
@@ -662,6 +663,8 @@ __fork (void)
       __sigemptyset (&_hurd_global_sigstate->pending);
       __sigemptyset (&ss->pending);
 
+      __libc_unwind_link_after_fork ();
+
       /* Release malloc locks.  */
       _hurd_malloc_fork_child ();
       call_function_static_weak (__malloc_fork_unlock_child);
diff --git a/sysdeps/mips/arch-unwind-link.h b/sysdeps/mips/arch-unwind-link.h
new file mode 100644
index 0000000..9835c0f
--- /dev/null
+++ b/sysdeps/mips/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  MIPS customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
index f5cf88d..19e8381 100644
--- a/sysdeps/nptl/fork.c
+++ b/sysdeps/nptl/fork.c
@@ -32,6 +32,7 @@
 #include <arch-fork.h>
 #include <futex-internal.h>
 #include <malloc/malloc-internal.h>
+#include <unwind-link.h>
 
 static void
 fresetlockfiles (void)
@@ -112,6 +113,8 @@ __libc_fork (void)
       /* Reset the lock state in the multi-threaded case.  */
       if (multiple_threads)
 	{
+	  __libc_unwind_link_after_fork ();
+
 	  /* Release malloc locks.  */
 	  call_function_static_weak (__malloc_fork_unlock_child);
 
diff --git a/sysdeps/powerpc/powerpc32/arch-unwind-link.h b/sysdeps/powerpc/powerpc32/arch-unwind-link.h
new file mode 100644
index 0000000..6a87daa
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  powerpc customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/s390/arch-unwind-link.h b/sysdeps/s390/arch-unwind-link.h
new file mode 100644
index 0000000..c50b7f2
--- /dev/null
+++ b/sysdeps/s390/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  S/390 customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/sparc/arch-unwind-link.h b/sysdeps/sparc/arch-unwind-link.h
new file mode 100644
index 0000000..4b7e2f1
--- /dev/null
+++ b/sysdeps/sparc/arch-unwind-link.h
@@ -0,0 +1,27 @@
+/* Dynamic loading of the libgcc unwinder.  SPARC customization.
+   Copyright (C) 2020 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
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _ARCH_UNWIND_LINK_H
+#define _ARCH_UNWIND_LINK_H
+
+#define UNWIND_LINK_GETIP 1
+#define UNWIND_LINK_FRAME_STATE_FOR 1
+#define UNWIND_LINK_EXTRA_FIELDS
+#define UNWIND_LINK_EXTRA_INIT
+
+#endif /* _ARCH_UNWIND_LINK_H */


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-02-13 16:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-10 17:08 [glibc/fw/unwind-link] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder Florian Weimer
2020-02-13 10:45 Florian Weimer
2020-02-13 16:22 Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).