public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 10/11] Implement _Unwind_Resume in libc on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 01/11] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder Florian Weimer
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

Temporarily move the arm _Unwind_Resume implementation to the file
used by libpthread.  It will be ported next.
---
 sysdeps/arm/arch-unwind-link.h     |  4 +++
 sysdeps/arm/arm-unwind-resume.S    | 26 +++++++-------
 sysdeps/arm/pt-arm-unwind-resume.S | 48 ++++++++++++++++++++++++--
 sysdeps/arm/unwind-resume.c        | 25 ++++++++++++++
 sysdeps/generic/unwind-resume.c    | 55 +++++-------------------------
 5 files changed, 97 insertions(+), 61 deletions(-)
 create mode 100644 sysdeps/arm/unwind-resume.c

diff --git a/sysdeps/arm/arch-unwind-link.h b/sysdeps/arm/arch-unwind-link.h
index b16a94e02a..abb3ba28d6 100644
--- a/sysdeps/arm/arch-unwind-link.h
+++ b/sysdeps/arm/arch-unwind-link.h
@@ -31,4 +31,8 @@
   assert (local.ptr__Unwind_VRS_Get != NULL);                 \
   PTR_MANGLE (local.ptr__Unwind_VRS_Get);
 
+/* This is used by the _Unwind_Resume assembler implementation to
+   obtain the address to jump to.  */
+void *__unwind_link_get_resume (void) attribute_hidden;
+
 #endif /* _ARCH_UNWIND_LINK_H */
diff --git a/sysdeps/arm/arm-unwind-resume.S b/sysdeps/arm/arm-unwind-resume.S
index 60df9aac46..48059475e4 100644
--- a/sysdeps/arm/arm-unwind-resume.S
+++ b/sysdeps/arm/arm-unwind-resume.S
@@ -18,29 +18,29 @@
 
 #include <sysdep.h>
 
-/* This is just implementing exactly what the C version does.
+/* This is equivalent to the following C implementation:
+
+   void
+   _Unwind_Resume (struct _Unwind_Exception *exc)
+   {
+     __unwind_link_get_resume () (exc);
+   }
+
    We do it in assembly just to ensure that we get an unmolested tail
    call to the libgcc function, which is necessary for the ARM unwinder.  */
 
 ENTRY (_Unwind_Resume)
-	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
-	cmp	ip, #0
-	beq	1f
-0:	PTR_DEMANGLE (ip, ip, r2, r3)
-	bx	ip
-
 	/* We need to save and restore LR (for our own return address)
 	   and R0 (for the argument to _Unwind_Resume) around the call.  */
-1:	push	{r0, lr}
+	push	{r0, lr}
 	cfi_adjust_cfa_offset (8)
 	cfi_rel_offset (r0, 0)
 	cfi_rel_offset (lr, 4)
-	bl	__libgcc_s_init
+	bl	__unwind_link_get_resume
+	mov	r3, r0
 	pop	{r0, lr}
 	cfi_adjust_cfa_offset (-8)
-	cfi_restore (r0)
+	cfi_restore (r4)
 	cfi_restore (lr)
-
-	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
-	b	0b
+	bx	r3
 END (_Unwind_Resume)
diff --git a/sysdeps/arm/pt-arm-unwind-resume.S b/sysdeps/arm/pt-arm-unwind-resume.S
index 7cb555c02b..86ff5cbeea 100644
--- a/sysdeps/arm/pt-arm-unwind-resume.S
+++ b/sysdeps/arm/pt-arm-unwind-resume.S
@@ -1,2 +1,46 @@
-#define __libgcc_s_init	pthread_cancel_init
-#include <arm-unwind-resume.S>
+/* _Unwind_Resume wrapper for ARM EABI.
+   Copyright (C) 2015-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/>.  */
+
+#include <sysdep.h>
+
+/* This is just implementing exactly what the C version does.
+   We do it in assembly just to ensure that we get an unmolested tail
+   call to the libgcc function, which is necessary for the ARM unwinder.  */
+
+ENTRY (_Unwind_Resume)
+	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
+	cmp	ip, #0
+	beq	1f
+0:	PTR_DEMANGLE (ip, ip, r2, r3)
+	bx	ip
+
+	/* We need to save and restore LR (for our own return address)
+	   and R0 (for the argument to _Unwind_Resume) around the call.  */
+1:	push	{r0, lr}
+	cfi_adjust_cfa_offset (8)
+	cfi_rel_offset (r0, 0)
+	cfi_rel_offset (lr, 4)
+	bl	pthread_cancel_init
+	pop	{r0, lr}
+	cfi_adjust_cfa_offset (-8)
+	cfi_restore (r0)
+	cfi_restore (lr)
+
+	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
+	b	0b
+END (_Unwind_Resume)
diff --git a/sysdeps/arm/unwind-resume.c b/sysdeps/arm/unwind-resume.c
new file mode 100644
index 0000000000..ea0bf8998a
--- /dev/null
+++ b/sysdeps/arm/unwind-resume.c
@@ -0,0 +1,25 @@
+/* Unwinder function forwarders for libc.  Arm 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <sysdeps/generic/unwind-resume.c>
+
+void *
+__unwind_link_get_resume (void)
+{
+  return UNWIND_LINK_PTR (link (), _Unwind_Resume);
+}
diff --git a/sysdeps/generic/unwind-resume.c b/sysdeps/generic/unwind-resume.c
index 42593c3f61..539b2b3574 100644
--- a/sysdeps/generic/unwind-resume.c
+++ b/sysdeps/generic/unwind-resume.c
@@ -16,68 +16,31 @@
    License along with the GNU C Library; see the file COPYING.LIB.  If
    not, see <https://www.gnu.org/licenses/>.  */
 
-#include <dlfcn.h>
 #include <stdio.h>
-#include <unwind.h>
 #include <gnu/lib-names.h>
+#include <unwind-link.h>
 #include <sysdep.h>
 #include <unwind-resume.h>
 
-
-void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
-  attribute_hidden __attribute__ ((noreturn));
-
-static _Unwind_Reason_Code (*libgcc_s_personality) PERSONALITY_PROTO;
-
-void attribute_hidden __attribute__ ((cold))
-__libgcc_s_init (void)
+static struct unwind_link *
+link (void)
 {
-  void *resume, *personality;
-  void *handle;
-
-  /* See include/dlfcn.h. Use of __libc_dlopen requires RTLD_NOW.  */
-  handle = __libc_dlopen (LIBGCC_S_SO);
-
-  if (handle == NULL
-      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
-      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL)
-    __libc_fatal (LIBGCC_S_SO
-                  " must be installed for unwinding to work\n");
-
-#ifdef PTR_MANGLE
-  PTR_MANGLE (resume);
-#endif
-  __libgcc_s_resume = resume;
-#ifdef PTR_MANGLE
-  PTR_MANGLE (personality);
-#endif
-  libgcc_s_personality = personality;
+  struct unwind_link *unwind_link = __libc_unwind_link_get ();
+  if (unwind_link == NULL)
+    __libc_fatal (LIBGCC_S_SO " must be installed for unwinding to work\n");
+  return unwind_link;
 }
 
 #if !HAVE_ARCH_UNWIND_RESUME
 void
 _Unwind_Resume (struct _Unwind_Exception *exc)
 {
-  if (__glibc_unlikely (__libgcc_s_resume == NULL))
-    __libgcc_s_init ();
-
-  __typeof (__libgcc_s_resume) resume = __libgcc_s_resume;
-#ifdef PTR_DEMANGLE
-  PTR_DEMANGLE (resume);
-#endif
-  (*resume) (exc);
+  UNWIND_LINK_PTR (link (), _Unwind_Resume) (exc);
 }
 #endif
 
 _Unwind_Reason_Code
 __gcc_personality_v0 PERSONALITY_PROTO
 {
-  if (__glibc_unlikely (libgcc_s_personality == NULL))
-    __libgcc_s_init ();
-
-  __typeof (libgcc_s_personality) personality = libgcc_s_personality;
-#ifdef PTR_DEMANGLE
-  PTR_DEMANGLE (personality);
-#endif
-  return (*personality) PERSONALITY_ARGS;
+  return UNWIND_LINK_PTR (link (), personality) PERSONALITY_ARGS;
 }
-- 
2.24.1


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

* [PATCH 05/11] m68k: Implement backtrace on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (6 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 03/11] arm: Implement backtrace on top of <unwind-link.h> Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 09/11] Move sysdeps/gnu/unwind-resume.c to sysdeps/generic/unwind-resume.c Florian Weimer
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/m68k/backtrace.c | 82 +++++++++-------------------------------
 1 file changed, 18 insertions(+), 64 deletions(-)

diff --git a/sysdeps/m68k/backtrace.c b/sysdeps/m68k/backtrace.c
index 6020acae2f..c586a14b0b 100644
--- a/sysdeps/m68k/backtrace.c
+++ b/sysdeps/m68k/backtrace.c
@@ -16,52 +16,18 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
 #include <stdlib.h>
-#include <unwind.h>
+#include <unwind-link.h>
 
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   int cnt, size;
   void *lastfp, *lastsp;
 };
 
-#ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-static _Unwind_Ptr (*unwind_getcfa) (struct _Unwind_Context *);
-static _Unwind_Ptr (*unwind_getgr) (struct _Unwind_Context *, int);
-static void *libgcc_handle;
-
-static void
-init (void)
-{
-  libgcc_handle = __libc_dlopen ("libgcc_s.so.2");
-
-  if (libgcc_handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
-  unwind_getcfa = __libc_dlsym (libgcc_handle, "_Unwind_GetCFA");
-  unwind_getgr = __libc_dlsym (libgcc_handle, "_Unwind_GetGR");
-  if (unwind_getip == NULL || unwind_getgr == NULL || unwind_getcfa == NULL)
-    {
-      unwind_backtrace = NULL;
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
-# define unwind_getcfa _Unwind_GetCFA
-# define unwind_getgr _Unwind_GetGR
-#endif
-
 static _Unwind_Reason_Code
 backtrace_helper (struct _Unwind_Context *ctx, void *a)
 {
@@ -70,13 +36,16 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
   /* We are first called with address in the __backtrace function.
      Skip it.  */
   if (arg->cnt != -1)
-    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+    arg->array[arg->cnt]
+      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
   if (++arg->cnt == arg->size)
     return _URC_END_OF_STACK;
 
   /* %fp is DWARF2 register 14 on M68K.  */
-  arg->lastfp = (void *) unwind_getgr (ctx, 14);
-  arg->lastsp = (void *) unwind_getcfa (ctx);
+  arg->lastfp
+    = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetGR) (ctx, 14);
+  arg->lastsp
+    = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
   return _URC_NO_REASON;
 }
 
@@ -110,20 +79,19 @@ struct layout
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
-
-  if (size <= 0)
-    return 0;
-
-#ifdef SHARED
-  __libc_once_define (static, once);
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1,
+    };
 
-  __libc_once (once, init);
-  if (unwind_backtrace == NULL)
+  if (size <= 0 || arg.unwind_link == NULL)
     return 0;
-#endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
     --arg.cnt;
@@ -146,17 +114,3 @@ __backtrace (void **array, int size)
 }
 weak_alias (__backtrace, backtrace)
 libc_hidden_def (__backtrace)
-
-
-#ifdef SHARED
-/* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
-{
-  unwind_backtrace = NULL;
-  if (libgcc_handle != NULL)
-    {
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#endif
-- 
2.24.1


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

* [PATCH 02/11] backtrace: Implement on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (3 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 04/11] i386: Implement backtrace on top of <unwind-link.h> Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 06/11] sparc: Implement backtrace on top <unwind-link.h> Florian Weimer
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

This reimplements the generic version of backtrace.
---
 debug/backtrace.c | 86 ++++++++++-------------------------------------
 1 file changed, 18 insertions(+), 68 deletions(-)

diff --git a/debug/backtrace.c b/debug/backtrace.c
index cc4b9a5c90..921c9053c8 100644
--- a/debug/backtrace.c
+++ b/debug/backtrace.c
@@ -17,57 +17,19 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
-#include <gnu/lib-names.h>
 #include <stdlib.h>
-#include <unwind.h>
+#include <unwind-link.h>
 
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   _Unwind_Word cfa;
   int cnt;
   int size;
 };
 
-#ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
-static void *libgcc_handle;
-
-
-/* Dummy version in case libgcc_s does not contain the real code.  */
-static _Unwind_Word
-dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
-{
-  return 0;
-}
-
-
-static void
-init (void)
-{
-  libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
-
-  if (libgcc_handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
-  if (unwind_getip == NULL)
-    unwind_backtrace = NULL;
-  unwind_getcfa = (__libc_dlsym (libgcc_handle, "_Unwind_GetCFA")
-		  ?: dummy_getcfa);
-}
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
-# define unwind_getcfa _Unwind_GetCFA
-#endif
-
 static _Unwind_Reason_Code
 backtrace_helper (struct _Unwind_Context *ctx, void *a)
 {
@@ -77,10 +39,12 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
      Skip it.  */
   if (arg->cnt != -1)
     {
-      arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+      arg->array[arg->cnt]
+	= (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
 
       /* Check whether we make any progress.  */
-      _Unwind_Word cfa = unwind_getcfa (ctx);
+      _Unwind_Word cfa
+	= UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
 
       if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
 	 && cfa == arg->cfa)
@@ -95,20 +59,20 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
-
-  if (size <= 0)
-    return 0;
-
-#ifdef SHARED
-  __libc_once_define (static, once);
-
-  __libc_once (once, init);
-  if (unwind_backtrace == NULL)
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .cfa = 0,
+     .size = size,
+     .cnt = -1
+    };
+
+  if (size <= 0 || arg.unwind_link == NULL)
     return 0;
-#endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   /* _Unwind_Backtrace seems to put NULL address above
      _start.  Fix it up here.  */
@@ -118,17 +82,3 @@ __backtrace (void **array, int size)
 }
 weak_alias (__backtrace, backtrace)
 libc_hidden_def (__backtrace)
-
-
-#ifdef SHARED
-/* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
-{
-  unwind_backtrace = NULL;
-  if (libgcc_handle != NULL)
-    {
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#endif
-- 
2.24.1


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

* [PATCH 06/11] sparc: Implement backtrace on top <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (4 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 02/11] backtrace: Implement " Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 03/11] arm: Implement backtrace on top of <unwind-link.h> Florian Weimer
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/sparc/backtrace.c | 66 +++++++++------------------------------
 1 file changed, 15 insertions(+), 51 deletions(-)

diff --git a/sysdeps/sparc/backtrace.c b/sysdeps/sparc/backtrace.c
index 297da33904..8cedf7fb3a 100644
--- a/sysdeps/sparc/backtrace.c
+++ b/sysdeps/sparc/backtrace.c
@@ -21,9 +21,8 @@
 #include <stddef.h>
 #include <sysdep.h>
 #include <sys/trap.h>
-#include <dlfcn.h>
-#include <unwind.h>
 #include <backtrace.h>
+#include <unwind-link.h>
 
 struct layout
 {
@@ -36,45 +35,12 @@ struct layout
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   _Unwind_Word cfa;
   int cnt;
   int size;
 };
 
-#ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
-static void *libgcc_handle;
-
-/* Dummy version in case libgcc_s does not contain the real code.  */
-static _Unwind_Word
-dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
-{
-  return 0;
-}
-
-static void
-init (void)
-{
-  libgcc_handle = __libc_dlopen ("libgcc_s.so.1");
-
-  if (libgcc_handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
-  if (unwind_getip == NULL)
-    unwind_backtrace = NULL;
-  unwind_getcfa = (__libc_dlsym (libgcc_handle, "_Unwind_GetCFA")
-		  ?: dummy_getcfa);
-}
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
-# define unwind_getcfa _Unwind_GetCFA
-#endif
-
 static _Unwind_Reason_Code
 backtrace_helper (struct _Unwind_Context *ctx, void *a)
 {
@@ -85,11 +51,12 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
      Skip it.  */
   if (arg->cnt != -1)
     {
-      ip = unwind_getip (ctx);
+      ip = UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
       arg->array[arg->cnt] = (void *) ip;
 
       /* Check whether we make any progress.  */
-      _Unwind_Word cfa = unwind_getcfa (ctx);
+      _Unwind_Word cfa
+	= UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
 
       if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
 	 && cfa == arg->cfa)
@@ -104,23 +71,19 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
-  bool use_unwinder;
   int count;
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1,
+    };
 
   if (size <= 0)
     return 0;
 
-  use_unwinder = true;
-#ifdef SHARED
-  __libc_once_define (static, once);
-
-  __libc_once (once, init);
-  if (unwind_backtrace == NULL)
-    use_unwinder = false;
-#endif
-
-  if (use_unwinder == false)
+  if (arg.unwind_link == NULL)
     {
       struct layout *current;
       unsigned long fp, i7;
@@ -145,7 +108,8 @@ __backtrace (void **array, int size)
     }
   else
     {
-      unwind_backtrace (backtrace_helper, &arg);
+      UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+	(backtrace_helper, &arg);
 
       /* _Unwind_Backtrace seems to put NULL address above
 	 _start.  Fix it up here.  */
-- 
2.24.1


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

* [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder
@ 2020-02-13 17:08 Florian Weimer
  2020-02-13 17:08 ` [PATCH 10/11] Implement _Unwind_Resume in libc on top of <unwind-link.h> Florian Weimer
                   ` (10 more replies)
  0 siblings, 11 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

This series unifies the way glibc loads the libgcc_s unwinder via
internal dlopen.  There are presently four uses:

* The backtrace function.

* Legacy support for unwinder frame registration, which needs
  __frame_state_for.

* GCC unwind personality support (__gcc_personality_v0 _Unwind_Resume)
  for C sources with -fexceptions.  This is needed in libc and
  libpthread.

* The libpthread unwinder, which also needs the canonical frame address
  to properly de-interleave longjump frames.

Only the backtrace function could be ported separately in a
per-architecture fashion.  The last two commits in the series correspond
to the libc part of the personality support, and the libpthread
personality support and the unwinder there.

The S/390 version preserves the backchain fallback for now.

Tested on aarch64-linux-gnu, arm-linux-gnueabi, s390-linux-gnu,
s390x-linux-gnu, i686-linux-gnu, powerpc-linux-gnu, powerpc64-linux-gnu,
powerpc64le-linux-gnu, x86_64-linux-gnu.  Built successfully with
build-many-glibcs.py.

Thanks,
Florian

Florian Weimer (11):
  Implement <unwind-link.h> for dynamically loading the libgcc_s
    unwinder
  backtrace: Implement on top of <unwind-link.h>
  arm: Implement backtrace on top of <unwind-link.h>
  i386: Implement backtrace on top of <unwind-link.h>
  m68k: Implement backtrace on top of <unwind-link.h>
  sparc: Implement backtrace on top <unwind-link.h>
  s390: Implement backtrace on top of <unwind-link.h>
  __frame_state_for: Use <unwind-link.h> for unwinder access
  Move sysdeps/gnu/unwind-resume.c to sysdeps/generic/unwind-resume.c
  Implement _Unwind_Resume in libc on top of <unwind-link.h>
  nptl: Use <unwind-link.h> for accessing the libgcc_s unwinder

 debug/backtrace.c                             |  86 +++-------
 malloc/set-freeres.c                          |   5 +
 misc/Makefile                                 |   2 +-
 misc/Versions                                 |   1 +
 misc/unwind-link.c                            | 149 ++++++++++++++++++
 nptl/nptlfreeres.c                            |   1 -
 nptl/pthreadP.h                               |   6 +-
 nptl/pthread_cancel.c                         |   3 +-
 sysdeps/alpha/arch-unwind-link.h              |  27 ++++
 sysdeps/arm/arch-unwind-link.h                |  38 +++++
 sysdeps/arm/arm-unwind-resume.S               |  26 +--
 sysdeps/arm/backtrace.c                       |  77 +++------
 sysdeps/arm/nptl/unwind-forcedunwind.c        |  25 +++
 sysdeps/arm/pt-arm-unwind-resume.S            |  22 ++-
 sysdeps/arm/unwind-resume.c                   |  25 +++
 sysdeps/generic/arch-unwind-link.h            |  32 ++++
 sysdeps/generic/framestate.c                  |  21 +--
 sysdeps/generic/unwind-link.h                 |  99 ++++++++++++
 sysdeps/generic/unwind-resume.c               |  46 ++++++
 sysdeps/gnu/unwind-resume.c                   |  83 ----------
 sysdeps/i386/arch-unwind-link.h               |  38 +++++
 sysdeps/i386/backtrace.c                      |  82 +++-------
 sysdeps/ia64/arch-unwind-link.h               |  31 ++++
 sysdeps/m68k/arch-unwind-link.h               |  34 ++++
 sysdeps/m68k/backtrace.c                      |  82 +++-------
 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/nptl/unwind-forcedunwind.c            | 115 ++------------
 sysdeps/powerpc/powerpc32/arch-unwind-link.h  |  27 ++++
 sysdeps/s390/arch-unwind-link.h               |  27 ++++
 sysdeps/s390/s390-32/backtrace.c              |  45 ++----
 sysdeps/s390/s390-64/backtrace.c              |  46 ++----
 sysdeps/sh/arch-unwind-link.h                 |  27 ++++
 sysdeps/sparc/arch-unwind-link.h              |  27 ++++
 sysdeps/sparc/backtrace.c                     |  66 ++------
 .../sysv/linux/ia64/unwind-forcedunwind.c     |  16 +-
 38 files changed, 899 insertions(+), 597 deletions(-)
 create mode 100644 misc/unwind-link.c
 create mode 100644 sysdeps/alpha/arch-unwind-link.h
 create mode 100644 sysdeps/arm/arch-unwind-link.h
 create mode 100644 sysdeps/arm/nptl/unwind-forcedunwind.c
 create mode 100644 sysdeps/arm/unwind-resume.c
 create mode 100644 sysdeps/generic/arch-unwind-link.h
 create mode 100644 sysdeps/generic/unwind-link.h
 create mode 100644 sysdeps/generic/unwind-resume.c
 delete mode 100644 sysdeps/gnu/unwind-resume.c
 create mode 100644 sysdeps/i386/arch-unwind-link.h
 create mode 100644 sysdeps/ia64/arch-unwind-link.h
 create mode 100644 sysdeps/m68k/arch-unwind-link.h
 create mode 100644 sysdeps/m68k/m680x0/arch-unwind-link.h
 create mode 100644 sysdeps/mips/arch-unwind-link.h
 create mode 100644 sysdeps/powerpc/powerpc32/arch-unwind-link.h
 create mode 100644 sysdeps/s390/arch-unwind-link.h
 create mode 100644 sysdeps/sh/arch-unwind-link.h
 create mode 100644 sysdeps/sparc/arch-unwind-link.h

-- 
2.24.1

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

* [PATCH 08/11] __frame_state_for: Use <unwind-link.h> for unwinder access
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (9 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h> Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/generic/framestate.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/sysdeps/generic/framestate.c b/sysdeps/generic/framestate.c
index e342ce8e54..83cfcd20fd 100644
--- a/sysdeps/generic/framestate.c
+++ b/sysdeps/generic/framestate.c
@@ -17,7 +17,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <dlfcn.h>
 #include <stdlib.h>
 #define STATIC static
 #define __frame_state_for fallback_frame_state_for
@@ -25,6 +24,8 @@
 #undef __frame_state_for
 #include <gnu/lib-names.h>
 
+#include <unwind-link.h>
+
 typedef struct frame_state * (*framesf)(void *pc, struct frame_state *);
 struct frame_state *__frame_state_for (void *pc,
 				       struct frame_state *frame_state);
@@ -32,21 +33,15 @@ struct frame_state *__frame_state_for (void *pc,
 struct frame_state *
 __frame_state_for (void *pc, struct frame_state *frame_state)
 {
-  static framesf frame_state_for;
-
-  if (frame_state_for == NULL)
+  struct unwind_link *unwind_link = __libc_unwind_link_get ();
+  if (unwind_link != NULL)
+    return UNWIND_LINK_PTR (unwind_link, __frame_state_for) (pc, frame_state);
+  else
     {
-      void *handle = __libc_dlopen (LIBGCC_S_SO);
-
-      if (handle == NULL
-	  || (frame_state_for
-	      = (framesf) __libc_dlsym (handle, "__frame_state_for")) == NULL)
 #ifndef __USING_SJLJ_EXCEPTIONS__
-	frame_state_for = fallback_frame_state_for;
+      return fallback_frame_state_for (pc, frame_state);
 #else
-	frame_state_for = abort;
+      abort ();
 #endif
     }
-
-  return frame_state_for (pc, frame_state);
 }
-- 
2.24.1


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

* [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (8 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 09/11] Move sysdeps/gnu/unwind-resume.c to sysdeps/generic/unwind-resume.c Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-14 11:55   ` Stefan Liebler
  2020-02-13 17:08 ` [PATCH 08/11] __frame_state_for: Use <unwind-link.h> for unwinder access Florian Weimer
  10 siblings, 1 reply; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/s390/s390-32/backtrace.c | 45 ++++++++++---------------------
 sysdeps/s390/s390-64/backtrace.c | 46 ++++++++++----------------------
 2 files changed, 28 insertions(+), 63 deletions(-)

diff --git a/sysdeps/s390/s390-32/backtrace.c b/sysdeps/s390/s390-32/backtrace.c
index 497e4f8875..21da6761f2 100644
--- a/sysdeps/s390/s390-32/backtrace.c
+++ b/sysdeps/s390/s390-32/backtrace.c
@@ -17,12 +17,10 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
 #include <stddef.h>
 #include <stdlib.h>
-#include <unwind.h>
+#include <unwind-link.h>
 
 /* This is a global variable set at program start time.  It marks the
    highest used stack address.  */
@@ -57,27 +55,11 @@ struct layout
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   int cnt, size;
 };
 
 #ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-
-static void
-init (void)
-{
-  void *handle = __libc_dlopen ("libgcc_s.so.1");
-
-  if (handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (handle, "_Unwind_GetIP");
-  if (unwind_getip == NULL)
-    unwind_backtrace = NULL;
-}
-
 static int
 __backchain_backtrace (void **array, int size)
 {
@@ -103,9 +85,6 @@ __backchain_backtrace (void **array, int size)
 
   return cnt;
 }
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
 #endif
 
 static _Unwind_Reason_Code
@@ -116,7 +95,8 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
   /* We are first called with address in the __backtrace function.
      Skip it.  */
   if (arg->cnt != -1)
-    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+    arg->array[arg->cnt]
+      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
   if (++arg->cnt == arg->size)
     return _URC_END_OF_STACK;
   return _URC_NO_REASON;
@@ -125,21 +105,24 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1
+    };
 
   if (size <= 0)
     return 0;
 
 #ifdef SHARED
-  __libc_once_define (static, once);
-
-  __libc_once (once, init);
-
-  if (unwind_backtrace == NULL)
+  if (arg.unwind_link == NULL)
     return __backchain_backtrace (array, size);
 #endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   return arg.cnt != -1 ? arg.cnt : 0;
 }
diff --git a/sysdeps/s390/s390-64/backtrace.c b/sysdeps/s390/s390-64/backtrace.c
index 5d14e01280..1b8818f219 100644
--- a/sysdeps/s390/s390-64/backtrace.c
+++ b/sysdeps/s390/s390-64/backtrace.c
@@ -17,13 +17,10 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
 #include <stddef.h>
 #include <stdlib.h>
-#include <unwind.h>
-
+#include <unwind-link.h>
 
 /* This is a global variable set at program start time.  It marks the
    highest used stack address.  */
@@ -56,27 +53,11 @@ struct layout
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   int cnt, size;
 };
 
 #ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-
-static void
-init (void)
-{
-  void *handle = __libc_dlopen ("libgcc_s.so.1");
-
-  if (handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (handle, "_Unwind_GetIP");
-  if (unwind_getip == NULL)
-    unwind_backtrace = NULL;
-}
-
 static int
 __backchain_backtrace (void **array, int size)
 {
@@ -102,9 +83,6 @@ __backchain_backtrace (void **array, int size)
 
   return cnt;
 }
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
 #endif
 
 static _Unwind_Reason_Code
@@ -115,7 +93,8 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
   /* We are first called with address in the __backtrace function.
      Skip it.  */
   if (arg->cnt != -1)
-    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+    arg->array[arg->cnt]
+      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
   if (++arg->cnt == arg->size)
     return _URC_END_OF_STACK;
   return _URC_NO_REASON;
@@ -124,21 +103,24 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1
+    };
 
   if (size <= 0)
     return 0;
 
 #ifdef SHARED
-  __libc_once_define (static, once);
-
-  __libc_once (once, init);
-
-  if (unwind_backtrace == NULL)
+  if (arg.unwind_link == NULL)
     return __backchain_backtrace (array, size);
 #endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   return arg.cnt != -1 ? arg.cnt : 0;
 }
-- 
2.24.1


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

* [PATCH 09/11] Move sysdeps/gnu/unwind-resume.c to sysdeps/generic/unwind-resume.c
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (7 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 05/11] m68k: " Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h> Florian Weimer
  2020-02-13 17:08 ` [PATCH 08/11] __frame_state_for: Use <unwind-link.h> for unwinder access Florian Weimer
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

This change allows architecture-specific sysdeps directories to override
it.
---
 sysdeps/{gnu => generic}/unwind-resume.c | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename sysdeps/{gnu => generic}/unwind-resume.c (100%)

diff --git a/sysdeps/gnu/unwind-resume.c b/sysdeps/generic/unwind-resume.c
similarity index 100%
rename from sysdeps/gnu/unwind-resume.c
rename to sysdeps/generic/unwind-resume.c
-- 
2.24.1


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

* [PATCH 11/11] nptl: Use <unwind-link.h> for accessing the libgcc_s unwinder
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
  2020-02-13 17:08 ` [PATCH 10/11] Implement _Unwind_Resume in libc on top of <unwind-link.h> Florian Weimer
  2020-02-13 17:08 ` [PATCH 01/11] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 04/11] i386: Implement backtrace on top of <unwind-link.h> Florian Weimer
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 nptl/nptlfreeres.c                            |   1 -
 nptl/pthreadP.h                               |   6 +-
 nptl/pthread_cancel.c                         |   3 +-
 sysdeps/arm/nptl/unwind-forcedunwind.c        |  25 ++++
 sysdeps/arm/pt-arm-unwind-resume.S            |  30 +----
 sysdeps/nptl/unwind-forcedunwind.c            | 115 +++---------------
 .../sysv/linux/ia64/unwind-forcedunwind.c     |  16 +--
 7 files changed, 50 insertions(+), 146 deletions(-)
 create mode 100644 sysdeps/arm/nptl/unwind-forcedunwind.c

diff --git a/nptl/nptlfreeres.c b/nptl/nptlfreeres.c
index dda11e5922..644d196ab4 100644
--- a/nptl/nptlfreeres.c
+++ b/nptl/nptlfreeres.c
@@ -27,5 +27,4 @@ __libpthread_freeres (void)
 {
   call_function_static_weak (__nptl_stacks_freeres);
   call_function_static_weak (__shm_directory_freeres);
-  call_function_static_weak (__nptl_unwind_freeres);
 }
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 7e0ab8ef42..2f370ae0ae 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -290,9 +290,11 @@ hidden_proto (__pthread_unwind_next)
 hidden_proto (__pthread_register_cancel)
 hidden_proto (__pthread_unregister_cancel)
 # ifdef SHARED
-extern void attribute_hidden pthread_cancel_init (void);
+/* The difference from __libc_unwind_link_get is that here, errors
+   terminate the process.  */
+struct unwind_link ;
+struct unwind_link *__pthread_unwind_link_get (void) attribute_hidden;
 # endif
-extern void __nptl_unwind_freeres (void) attribute_hidden;
 #endif
 
 
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
index 8e7be996e9..42b58b7034 100644
--- a/nptl/pthread_cancel.c
+++ b/nptl/pthread_cancel.c
@@ -35,7 +35,8 @@ __pthread_cancel (pthread_t th)
     return ESRCH;
 
 #ifdef SHARED
-  pthread_cancel_init ();
+  /* Trigger an error if libgcc_s cannot be loaded.  */
+  __pthread_unwind_link_get ();
 #endif
   int result = 0;
   int oldval;
diff --git a/sysdeps/arm/nptl/unwind-forcedunwind.c b/sysdeps/arm/nptl/unwind-forcedunwind.c
new file mode 100644
index 0000000000..ae64e61b85
--- /dev/null
+++ b/sysdeps/arm/nptl/unwind-forcedunwind.c
@@ -0,0 +1,25 @@
+/* Unwinder function forwarders for libpthread.  Arm 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <sysdeps/nptl/unwind-forcedunwind.c>
+
+void *
+__unwind_link_get_resume (void)
+{
+  return UNWIND_LINK_PTR (__pthread_unwind_link_get (), _Unwind_Resume);
+}
diff --git a/sysdeps/arm/pt-arm-unwind-resume.S b/sysdeps/arm/pt-arm-unwind-resume.S
index 86ff5cbeea..d01e129cf4 100644
--- a/sysdeps/arm/pt-arm-unwind-resume.S
+++ b/sysdeps/arm/pt-arm-unwind-resume.S
@@ -16,31 +16,5 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
-
-/* This is just implementing exactly what the C version does.
-   We do it in assembly just to ensure that we get an unmolested tail
-   call to the libgcc function, which is necessary for the ARM unwinder.  */
-
-ENTRY (_Unwind_Resume)
-	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
-	cmp	ip, #0
-	beq	1f
-0:	PTR_DEMANGLE (ip, ip, r2, r3)
-	bx	ip
-
-	/* We need to save and restore LR (for our own return address)
-	   and R0 (for the argument to _Unwind_Resume) around the call.  */
-1:	push	{r0, lr}
-	cfi_adjust_cfa_offset (8)
-	cfi_rel_offset (r0, 0)
-	cfi_rel_offset (lr, 4)
-	bl	pthread_cancel_init
-	pop	{r0, lr}
-	cfi_adjust_cfa_offset (-8)
-	cfi_restore (r0)
-	cfi_restore (lr)
-
-	LDR_HIDDEN (ip, ip, __libgcc_s_resume, 0)
-	b	0b
-END (_Unwind_Resume)
+/* The implementation in libpthread is identical to the one in libc.  */
+#include <sysdeps/arm/arm-unwind-resume.S>
diff --git a/sysdeps/nptl/unwind-forcedunwind.c b/sysdeps/nptl/unwind-forcedunwind.c
index 50a089282b..f57a3d0c18 100644
--- a/sysdeps/nptl/unwind-forcedunwind.c
+++ b/sysdeps/nptl/unwind-forcedunwind.c
@@ -16,134 +16,49 @@
    License along with the GNU C Library; see the file COPYING.LIB.  If
    not, see <https://www.gnu.org/licenses/>.  */
 
-#include <dlfcn.h>
 #include <stdio.h>
-#include <unwind.h>
+#include <unwind-link.h>
 #include <pthreadP.h>
 #include <sysdep.h>
 #include <gnu/lib-names.h>
 #include <unwind-resume.h>
 
-static void *libgcc_s_handle;
-void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
-  attribute_hidden __attribute__ ((noreturn));
-static _Unwind_Reason_Code (*libgcc_s_personality) PERSONALITY_PROTO;
-static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
-  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
-static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
-
-void
-__attribute_noinline__
-pthread_cancel_init (void)
+struct unwind_link *
+__pthread_unwind_link_get (void)
 {
-  void *resume;
-  void *personality;
-  void *forcedunwind;
-  void *getcfa;
-  void *handle;
-
-  if (__glibc_likely (libgcc_s_handle != NULL))
-    {
-      /* Force gcc to reload all values.  */
-      asm volatile ("" ::: "memory");
-      return;
-    }
-
-  /* See include/dlfcn.h. Use of __libc_dlopen requires RTLD_NOW.  */
-  handle = __libc_dlopen (LIBGCC_S_SO);
-
-  if (handle == NULL
-      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
-      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
-      || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
-	 == NULL
-      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
-#ifdef ARCH_CANCEL_INIT
-      || ARCH_CANCEL_INIT (handle)
-#endif
-      )
-    __libc_fatal (LIBGCC_S_SO " must be installed for pthread_cancel to work\n");
-
-  PTR_MANGLE (resume);
-  __libgcc_s_resume = resume;
-  PTR_MANGLE (personality);
-  libgcc_s_personality = personality;
-  PTR_MANGLE (forcedunwind);
-  libgcc_s_forcedunwind = forcedunwind;
-  PTR_MANGLE (getcfa);
-  libgcc_s_getcfa = getcfa;
-  /* Make sure libgcc_s_handle is written last.  Otherwise,
-     pthread_cancel_init might return early even when the pointer the
-     caller is interested in is not initialized yet.  */
-  atomic_write_barrier ();
-  libgcc_s_handle = handle;
-}
-
-/* Register for cleanup in libpthread.so.  */
-void
-__nptl_unwind_freeres (void)
-{
-  void *handle = libgcc_s_handle;
-  if (handle != NULL)
-    {
-      libgcc_s_handle = NULL;
-      __libc_dlclose (handle);
-    }
+  struct unwind_link *unwind_link = __libc_unwind_link_get ();
+  if (unwind_link == NULL)
+    __libc_fatal (LIBGCC_S_SO
+		  " must be installed for pthread_cancel to work\n");
+  return unwind_link;
 }
 
 #if !HAVE_ARCH_UNWIND_RESUME
 void
 _Unwind_Resume (struct _Unwind_Exception *exc)
 {
-  if (__glibc_unlikely (libgcc_s_handle == NULL))
-    pthread_cancel_init ();
-  else
-    atomic_read_barrier ();
-
-  void (*resume) (struct _Unwind_Exception *exc) = __libgcc_s_resume;
-  PTR_DEMANGLE (resume);
-  resume (exc);
+  UNWIND_LINK_PTR (__pthread_unwind_link_get (), _Unwind_Resume) (exc);
 }
 #endif
 
 _Unwind_Reason_Code
 __gcc_personality_v0 PERSONALITY_PROTO
 {
-  if (__glibc_unlikely (libgcc_s_handle == NULL))
-    pthread_cancel_init ();
-  else
-    atomic_read_barrier ();
-
-  __typeof (libgcc_s_personality) personality = libgcc_s_personality;
-  PTR_DEMANGLE (personality);
-  return (*personality) PERSONALITY_ARGS;
+  return UNWIND_LINK_PTR (__pthread_unwind_link_get (), personality)
+    PERSONALITY_ARGS;
 }
 
 _Unwind_Reason_Code
 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
 		      void *stop_argument)
 {
-  if (__glibc_unlikely (libgcc_s_handle == NULL))
-    pthread_cancel_init ();
-  else
-    atomic_read_barrier ();
-
-  _Unwind_Reason_Code (*forcedunwind)
-    (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
-    = libgcc_s_forcedunwind;
-  PTR_DEMANGLE (forcedunwind);
-  return forcedunwind (exc, stop, stop_argument);
+  return UNWIND_LINK_PTR (__pthread_unwind_link_get (), _Unwind_ForcedUnwind)
+    (exc, stop, stop_argument);
 }
 
 _Unwind_Word
 _Unwind_GetCFA (struct _Unwind_Context *context)
 {
-  if (__glibc_unlikely (libgcc_s_handle == NULL))
-    pthread_cancel_init ();
-  else
-    atomic_read_barrier ();
-
-  _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
-  PTR_DEMANGLE (getcfa);
-  return getcfa (context);
+  return UNWIND_LINK_PTR (__pthread_unwind_link_get (), _Unwind_GetCFA)
+    (context);
 }
diff --git a/sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c
index 4c953bf63c..17c35aa68a 100644
--- a/sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c
+++ b/sysdeps/unix/sysv/linux/ia64/unwind-forcedunwind.c
@@ -16,23 +16,11 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <dlfcn.h>
-#include <stdio.h>
-#include <unwind.h>
-#include <pthreadP.h>
-
-static _Unwind_Word (*libgcc_s_getbsp) (struct _Unwind_Context *);
-
-#define ARCH_CANCEL_INIT(handle) \
-  ((libgcc_s_getbsp = __libc_dlsym (handle, "_Unwind_GetBSP")) == NULL)
-
 #include <sysdeps/nptl/unwind-forcedunwind.c>
 
 _Unwind_Word
 _Unwind_GetBSP (struct _Unwind_Context *context)
 {
-  if (__builtin_expect (libgcc_s_getbsp == NULL, 0))
-    pthread_cancel_init ();
-
-  return libgcc_s_getbsp (context);
+  return UNWIND_LINK_PTR (__pthread_unwind_link_get (), _Unwind_GetBSP)
+    (context);
 }
-- 
2.24.1

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

* [PATCH 04/11] i386: Implement backtrace on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (2 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 11/11] nptl: Use <unwind-link.h> for accessing " Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 02/11] backtrace: Implement " Florian Weimer
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/i386/backtrace.c | 82 +++++++++-------------------------------
 1 file changed, 18 insertions(+), 64 deletions(-)

diff --git a/sysdeps/i386/backtrace.c b/sysdeps/i386/backtrace.c
index 2491a637d9..29027a478d 100644
--- a/sysdeps/i386/backtrace.c
+++ b/sysdeps/i386/backtrace.c
@@ -17,52 +17,18 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
 #include <stdlib.h>
-#include <unwind.h>
+#include <unwind-link.h>
 
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   int cnt, size;
   void *lastebp, *lastesp;
 };
 
-#ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
-static _Unwind_Ptr (*unwind_getcfa) (struct _Unwind_Context *);
-static _Unwind_Ptr (*unwind_getgr) (struct _Unwind_Context *, int);
-static void *libgcc_handle;
-
-static void
-init (void)
-{
-  libgcc_handle = __libc_dlopen ("libgcc_s.so.1");
-
-  if (libgcc_handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
-  unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP");
-  unwind_getcfa = __libc_dlsym (libgcc_handle, "_Unwind_GetCFA");
-  unwind_getgr = __libc_dlsym (libgcc_handle, "_Unwind_GetGR");
-  if (unwind_getip == NULL || unwind_getgr == NULL || unwind_getcfa == NULL)
-    {
-      unwind_backtrace = NULL;
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#else
-# define unwind_backtrace _Unwind_Backtrace
-# define unwind_getip _Unwind_GetIP
-# define unwind_getcfa _Unwind_GetCFA
-# define unwind_getgr _Unwind_GetGR
-#endif
-
 static _Unwind_Reason_Code
 backtrace_helper (struct _Unwind_Context *ctx, void *a)
 {
@@ -71,13 +37,16 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
   /* We are first called with address in the __backtrace function.
      Skip it.  */
   if (arg->cnt != -1)
-    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+    arg->array[arg->cnt]
+      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
   if (++arg->cnt == arg->size)
     return _URC_END_OF_STACK;
 
   /* %ebp is DWARF2 register 5 on IA-32.  */
-  arg->lastebp = (void *) unwind_getgr (ctx, 5);
-  arg->lastesp = (void *) unwind_getcfa (ctx);
+  arg->lastebp
+    = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetGR) (ctx, 5);
+  arg->lastesp
+    = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetCFA) (ctx);
   return _URC_NO_REASON;
 }
 
@@ -111,20 +80,19 @@ struct layout
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
-
-  if (size <= 0)
-    return 0;
-
-#ifdef SHARED
-  __libc_once_define (static, once);
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1,
+    };
 
-  __libc_once (once, init);
-  if (unwind_backtrace == NULL)
+  if (size <= 0 || arg.unwind_link == NULL)
     return 0;
-#endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
     --arg.cnt;
@@ -147,17 +115,3 @@ __backtrace (void **array, int size)
 }
 weak_alias (__backtrace, backtrace)
 libc_hidden_def (__backtrace)
-
-
-#ifdef SHARED
-/* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
-{
-  unwind_backtrace = NULL;
-  if (libgcc_handle != NULL)
-    {
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#endif
-- 
2.24.1


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

* [PATCH 03/11] arm: Implement backtrace on top of <unwind-link.h>
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
                   ` (5 preceding siblings ...)
  2020-02-13 17:08 ` [PATCH 06/11] sparc: Implement backtrace on top <unwind-link.h> Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 05/11] m68k: " Florian Weimer
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

---
 sysdeps/arm/backtrace.c | 77 +++++++++++------------------------------
 1 file changed, 20 insertions(+), 57 deletions(-)

diff --git a/sysdeps/arm/backtrace.c b/sysdeps/arm/backtrace.c
index ffd3f526b2..893ca39272 100644
--- a/sysdeps/arm/backtrace.c
+++ b/sysdeps/arm/backtrace.c
@@ -17,58 +17,36 @@
    License along with the GNU C Library.  If not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <libc-lock.h>
-#include <dlfcn.h>
 #include <execinfo.h>
 #include <stdlib.h>
-#include <unwind.h>
+#include <unwind-link.h>
 
 struct trace_arg
 {
   void **array;
+  struct unwind_link *unwind_link;
   int cnt, size;
 };
 
 #ifdef SHARED
-static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
-static _Unwind_VRS_Result (*unwind_vrs_get) (_Unwind_Context *,
-					     _Unwind_VRS_RegClass,
-					     _uw,
-					     _Unwind_VRS_DataRepresentation,
-					     void *);
-
-static void *libgcc_handle;
-
-static void
-init (void)
-{
-  libgcc_handle = __libc_dlopen ("libgcc_s.so.1");
-
-  if (libgcc_handle == NULL)
-    return;
-
-  unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace");
-  unwind_vrs_get = __libc_dlsym (libgcc_handle, "_Unwind_VRS_Get");
-  if (unwind_vrs_get == NULL)
-    unwind_backtrace = NULL;
-}
-
 /* This function is identical to "_Unwind_GetGR", except that it uses
    "unwind_vrs_get" instead of "_Unwind_VRS_Get".  */
 static inline _Unwind_Word
-unwind_getgr (_Unwind_Context *context, int regno)
+unwind_getgr (struct unwind_link *unwind_link,
+	      _Unwind_Context *context, int regno)
 {
   _uw val;
-  unwind_vrs_get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
+  UNWIND_LINK_PTR (unwind_link, _Unwind_VRS_Get)
+    (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
   return val;
 }
 
 /* This macro is identical to the _Unwind_GetIP macro, except that it
    uses "unwind_getgr" instead of "_Unwind_GetGR".  */
-# define unwind_getip(context) \
-  (unwind_getgr (context, 15) & ~(_Unwind_Word)1)
-#else
-# define unwind_backtrace _Unwind_Backtrace
+#define unwind_getip(context) \
+  (unwind_getgr (arg->unwind_link, context, 15) & ~(_Unwind_Word)1)
+
+#else /* !SHARED */
 # define unwind_getip _Unwind_GetIP
 #endif
 
@@ -89,20 +67,19 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
 int
 __backtrace (void **array, int size)
 {
-  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
-
-  if (size <= 0)
-    return 0;
-
-#ifdef SHARED
-  __libc_once_define (static, once);
+  struct trace_arg arg =
+    {
+     .array = array,
+     .unwind_link = __libc_unwind_link_get (),
+     .size = size,
+     .cnt = -1
+    };
 
-  __libc_once (once, init);
-  if (unwind_backtrace == NULL)
+  if (size <= 0 || arg.unwind_link == NULL)
     return 0;
-#endif
 
-  unwind_backtrace (backtrace_helper, &arg);
+  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
+    (backtrace_helper, &arg);
 
   if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
     --arg.cnt;
@@ -110,17 +87,3 @@ __backtrace (void **array, int size)
 }
 weak_alias (__backtrace, backtrace)
 libc_hidden_def (__backtrace)
-
-
-#ifdef SHARED
-/* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
-{
-  unwind_backtrace = NULL;
-  if (libgcc_handle != NULL)
-    {
-      __libc_dlclose (libgcc_handle);
-      libgcc_handle = NULL;
-    }
-}
-#endif
-- 
2.24.1


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

* [PATCH 01/11] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder
  2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
  2020-02-13 17:08 ` [PATCH 10/11] Implement _Unwind_Resume in libc on top of <unwind-link.h> Florian Weimer
@ 2020-02-13 17:08 ` Florian Weimer
  2020-02-13 17:08 ` [PATCH 11/11] nptl: Use <unwind-link.h> for accessing " Florian Weimer
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 13+ messages in thread
From: Florian Weimer @ 2020-02-13 17:08 UTC (permalink / raw)
  To: libc-alpha

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.
---
 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(-)
 create mode 100644 misc/unwind-link.c
 create mode 100644 sysdeps/alpha/arch-unwind-link.h
 create mode 100644 sysdeps/arm/arch-unwind-link.h
 create mode 100644 sysdeps/generic/arch-unwind-link.h
 create mode 100644 sysdeps/generic/unwind-link.h
 create mode 100644 sysdeps/i386/arch-unwind-link.h
 create mode 100644 sysdeps/ia64/arch-unwind-link.h
 create mode 100644 sysdeps/m68k/arch-unwind-link.h
 create mode 100644 sysdeps/m68k/m680x0/arch-unwind-link.h
 create mode 100644 sysdeps/mips/arch-unwind-link.h
 create mode 100644 sysdeps/powerpc/powerpc32/arch-unwind-link.h
 create mode 100644 sysdeps/s390/arch-unwind-link.h
 create mode 100644 sysdeps/sh/arch-unwind-link.h
 create mode 100644 sysdeps/sparc/arch-unwind-link.h

diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index aa80eb64b8..a80cd301a1 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 e0465980c7..aae52412ef 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 e749582369..a9cfe3b912 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 0000000000..49076f8a59
--- /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 0000000000..998e47c949
--- /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 0000000000..b16a94e02a
--- /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 0000000000..f63a3f7a7d
--- /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 function is needed and re-exported from glibc.  */
+#define UNWIND_LINK_FRAME_STATE_FOR 0
+
+/* There are no extra fields in struct unwind_link in the generic version.  */
+#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 0000000000..56488e997d
--- /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 *, 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 0000000000..bc9c3a1f97
--- /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 0000000000..570b711dcd
--- /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 0000000000..e0105140ed
--- /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 0000000000..1adbf23c79
--- /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 32783069ec..1d4819ed53 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 0000000000..9835c0f9d6
--- /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 f5cf88d68c..19e8381bb1 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 0000000000..6a87daaa88
--- /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 0000000000..c50b7f2f0d
--- /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 0000000000..519c224093
--- /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 0000000000..4b7e2f160d
--- /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 */
-- 
2.24.1


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

* Re: [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h>
  2020-02-13 17:08 ` [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h> Florian Weimer
@ 2020-02-14 11:55   ` Stefan Liebler
  0 siblings, 0 replies; 13+ messages in thread
From: Stefan Liebler @ 2020-02-14 11:55 UTC (permalink / raw)
  To: libc-alpha

Hi Florian,

I've applied your patch series and also successfully run the testsuite 
on s390x/s390.

For s390, this is okay.



Just as info for future readers regarding
"The S/390 version preserves the backchain fallback for now.":
Here is the previous discussion:
https://www.sourceware.org/ml/libc-alpha/2020-02/msg00453.html
As soon as I have any news, I will reply there.

If we remove the backchain fallback. I assume the s390 specific 
backtrace.c files can be removed. Thus the debug/backtrace.c would be 
used. But I have to double check at this time.

If we still need the backchain fallback, I would either update the 
implementation in order to also get those "features":
/* Check whether we make any progress.  */
/* _Unwind_Backtrace seems to put NULL address above
    _start.  Fix it up here.  */

Or perhaps even better, add an architecture-fallback-hook in the default 
implementation.


Bye,
Stefan

On 2/13/20 6:08 PM, Florian Weimer wrote:
> ---
>   sysdeps/s390/s390-32/backtrace.c | 45 ++++++++++---------------------
>   sysdeps/s390/s390-64/backtrace.c | 46 ++++++++++----------------------
>   2 files changed, 28 insertions(+), 63 deletions(-)
> 
> diff --git a/sysdeps/s390/s390-32/backtrace.c b/sysdeps/s390/s390-32/backtrace.c
> index 497e4f8875..21da6761f2 100644
> --- a/sysdeps/s390/s390-32/backtrace.c
> +++ b/sysdeps/s390/s390-32/backtrace.c
> @@ -17,12 +17,10 @@
>      License along with the GNU C Library; if not, see
>      <https://www.gnu.org/licenses/>.  */
>   
> -#include <libc-lock.h>
> -#include <dlfcn.h>
>   #include <execinfo.h>
>   #include <stddef.h>
>   #include <stdlib.h>
> -#include <unwind.h>
> +#include <unwind-link.h>
>   
>   /* This is a global variable set at program start time.  It marks the
>      highest used stack address.  */
> @@ -57,27 +55,11 @@ struct layout
>   struct trace_arg
>   {
>     void **array;
> +  struct unwind_link *unwind_link;
>     int cnt, size;
>   };
>   
>   #ifdef SHARED
> -static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
> -static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
> -
> -static void
> -init (void)
> -{
> -  void *handle = __libc_dlopen ("libgcc_s.so.1");
> -
> -  if (handle == NULL)
> -    return;
> -
> -  unwind_backtrace = __libc_dlsym (handle, "_Unwind_Backtrace");
> -  unwind_getip = __libc_dlsym (handle, "_Unwind_GetIP");
> -  if (unwind_getip == NULL)
> -    unwind_backtrace = NULL;
> -}
> -
>   static int
>   __backchain_backtrace (void **array, int size)
>   {
> @@ -103,9 +85,6 @@ __backchain_backtrace (void **array, int size)
>   
>     return cnt;
>   }
> -#else
> -# define unwind_backtrace _Unwind_Backtrace
> -# define unwind_getip _Unwind_GetIP
>   #endif
>   
>   static _Unwind_Reason_Code
> @@ -116,7 +95,8 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
>     /* We are first called with address in the __backtrace function.
>        Skip it.  */
>     if (arg->cnt != -1)
> -    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
> +    arg->array[arg->cnt]
> +      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
>     if (++arg->cnt == arg->size)
>       return _URC_END_OF_STACK;
>     return _URC_NO_REASON;
> @@ -125,21 +105,24 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
>   int
>   __backtrace (void **array, int size)
>   {
> -  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
> +  struct trace_arg arg =
> +    {
> +     .array = array,
> +     .unwind_link = __libc_unwind_link_get (),
> +     .size = size,
> +     .cnt = -1
> +    };
>   
>     if (size <= 0)
>       return 0;
>   
>   #ifdef SHARED
> -  __libc_once_define (static, once);
> -
> -  __libc_once (once, init);
> -
> -  if (unwind_backtrace == NULL)
> +  if (arg.unwind_link == NULL)
>       return __backchain_backtrace (array, size);
>   #endif
>   
> -  unwind_backtrace (backtrace_helper, &arg);
> +  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
> +    (backtrace_helper, &arg);
>   
>     return arg.cnt != -1 ? arg.cnt : 0;
>   }
> diff --git a/sysdeps/s390/s390-64/backtrace.c b/sysdeps/s390/s390-64/backtrace.c
> index 5d14e01280..1b8818f219 100644
> --- a/sysdeps/s390/s390-64/backtrace.c
> +++ b/sysdeps/s390/s390-64/backtrace.c
> @@ -17,13 +17,10 @@
>      License along with the GNU C Library; if not, see
>      <https://www.gnu.org/licenses/>.  */
>   
> -#include <libc-lock.h>
> -#include <dlfcn.h>
>   #include <execinfo.h>
>   #include <stddef.h>
>   #include <stdlib.h>
> -#include <unwind.h>
> -
> +#include <unwind-link.h>
>   
>   /* This is a global variable set at program start time.  It marks the
>      highest used stack address.  */
> @@ -56,27 +53,11 @@ struct layout
>   struct trace_arg
>   {
>     void **array;
> +  struct unwind_link *unwind_link;
>     int cnt, size;
>   };
>   
>   #ifdef SHARED
> -static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
> -static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
> -
> -static void
> -init (void)
> -{
> -  void *handle = __libc_dlopen ("libgcc_s.so.1");
> -
> -  if (handle == NULL)
> -    return;
> -
> -  unwind_backtrace = __libc_dlsym (handle, "_Unwind_Backtrace");
> -  unwind_getip = __libc_dlsym (handle, "_Unwind_GetIP");
> -  if (unwind_getip == NULL)
> -    unwind_backtrace = NULL;
> -}
> -
>   static int
>   __backchain_backtrace (void **array, int size)
>   {
> @@ -102,9 +83,6 @@ __backchain_backtrace (void **array, int size)
>   
>     return cnt;
>   }
> -#else
> -# define unwind_backtrace _Unwind_Backtrace
> -# define unwind_getip _Unwind_GetIP
>   #endif
>   
>   static _Unwind_Reason_Code
> @@ -115,7 +93,8 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
>     /* We are first called with address in the __backtrace function.
>        Skip it.  */
>     if (arg->cnt != -1)
> -    arg->array[arg->cnt] = (void *) unwind_getip (ctx);
> +    arg->array[arg->cnt]
> +      = (void *) UNWIND_LINK_PTR (arg->unwind_link, _Unwind_GetIP) (ctx);
>     if (++arg->cnt == arg->size)
>       return _URC_END_OF_STACK;
>     return _URC_NO_REASON;
> @@ -124,21 +103,24 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a)
>   int
>   __backtrace (void **array, int size)
>   {
> -  struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
> +  struct trace_arg arg =
> +    {
> +     .array = array,
> +     .unwind_link = __libc_unwind_link_get (),
> +     .size = size,
> +     .cnt = -1
> +    };
>   
>     if (size <= 0)
>       return 0;
>   
>   #ifdef SHARED
> -  __libc_once_define (static, once);
> -
> -  __libc_once (once, init);
> -
> -  if (unwind_backtrace == NULL)
> +  if (arg.unwind_link == NULL)
>       return __backchain_backtrace (array, size);
>   #endif
>   
> -  unwind_backtrace (backtrace_helper, &arg);
> +  UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
> +    (backtrace_helper, &arg);
>   
>     return arg.cnt != -1 ? arg.cnt : 0;
>   }
> 

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

end of thread, other threads:[~2020-02-14 11:55 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-13 17:08 [PATCH 00/11] Unify dynamic loading of the libgcc_s unwinder Florian Weimer
2020-02-13 17:08 ` [PATCH 10/11] Implement _Unwind_Resume in libc on top of <unwind-link.h> Florian Weimer
2020-02-13 17:08 ` [PATCH 01/11] Implement <unwind-link.h> for dynamically loading the libgcc_s unwinder Florian Weimer
2020-02-13 17:08 ` [PATCH 11/11] nptl: Use <unwind-link.h> for accessing " Florian Weimer
2020-02-13 17:08 ` [PATCH 04/11] i386: Implement backtrace on top of <unwind-link.h> Florian Weimer
2020-02-13 17:08 ` [PATCH 02/11] backtrace: Implement " Florian Weimer
2020-02-13 17:08 ` [PATCH 06/11] sparc: Implement backtrace on top <unwind-link.h> Florian Weimer
2020-02-13 17:08 ` [PATCH 03/11] arm: Implement backtrace on top of <unwind-link.h> Florian Weimer
2020-02-13 17:08 ` [PATCH 05/11] m68k: " Florian Weimer
2020-02-13 17:08 ` [PATCH 09/11] Move sysdeps/gnu/unwind-resume.c to sysdeps/generic/unwind-resume.c Florian Weimer
2020-02-13 17:08 ` [PATCH 07/11] s390: Implement backtrace on top of <unwind-link.h> Florian Weimer
2020-02-14 11:55   ` Stefan Liebler
2020-02-13 17:08 ` [PATCH 08/11] __frame_state_for: Use <unwind-link.h> for unwinder access 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).