Patchwork Use x86_64 backtrace as generic version

login
register
mail settings
Submitter Joseph Myers
Date March 21, 2018, 1:21 a.m.
Message ID <alpine.DEB.2.20.1803210120100.11698@digraph.polyomino.org.uk>
Download mbox | patch
Permalink /patch/26395/
State New
Headers show

Comments

Joseph Myers - March 21, 2018, 1:21 a.m.
No glibc configuration uses the present debug/backtrace.c, whereas
several #include the x86_64 version.  The x86_64 version is
effectively a generic one (using _Unwind_Backtrace from libgcc, which
works much more reliably than the built-in functions used by
debug/backtrace.c).  This patch moves it to debug/backtrace.c and
removes all the #includes of the x86_64 version from other
architectures which are no longer required.

I do not know whether all the other architecture-specific backtrace
implementations that are based on _Unwind_Backtrace are required, or
whether, where their differences from the generic version do something
useful, suitable hooks could be added to the generic version to reduce
the duplication involved.

Tested with build-many-glibcs.py that installed stripped shared
libraries are unchanged by this patch.

2018-03-20  Joseph Myers  <joseph@codesourcery.com>

	* sysdeps/x86_64/backtrace.c: Move to ....
	* debug/backtrace.c: ... here.
	* sysdeps/aarch64/backtrace.c: Remove file.
	* sysdeps/alpha/backtrace.c: Likewise.
	* sysdeps/hppa/backtrace.c: Likewise.
	* sysdeps/ia64/backtrace.c: Likewise.
	* sysdeps/mips/backtrace.c: Likewise.
	* sysdeps/nios2/backtrace.c: Likewise.
	* sysdeps/riscv/backtrace.c: Likewise.
	* sysdeps/sh/backtrace.c: Likewise.
	* sysdeps/tile/backtrace.c: Likewise.
Adhemerval Zanella Netto - March 21, 2018, 2:34 a.m.
On 21/03/2018 09:21, Joseph Myers wrote:
> No glibc configuration uses the present debug/backtrace.c, whereas
> several #include the x86_64 version.  The x86_64 version is
> effectively a generic one (using _Unwind_Backtrace from libgcc, which
> works much more reliably than the built-in functions used by
> debug/backtrace.c).  This patch moves it to debug/backtrace.c and
> removes all the #includes of the x86_64 version from other
> architectures which are no longer required.
> 
> I do not know whether all the other architecture-specific backtrace
> implementations that are based on _Unwind_Backtrace are required, or
> whether, where their differences from the generic version do something
> useful, suitable hooks could be added to the generic version to reduce
> the duplication involved.

With this change we still have i386, sparc, m68k, arm, and s390 which
uses libgcc based backtrace implementation. I will check if i386, sparc,
and arm can be simplified.

> 
> Tested with build-many-glibcs.py that installed stripped shared
> libraries are unchanged by this patch.
> 
> 2018-03-20  Joseph Myers  <joseph@codesourcery.com>
> 
> 	* sysdeps/x86_64/backtrace.c: Move to ....
> 	* debug/backtrace.c: ... here.
> 	* sysdeps/aarch64/backtrace.c: Remove file.
> 	* sysdeps/alpha/backtrace.c: Likewise.
> 	* sysdeps/hppa/backtrace.c: Likewise.
> 	* sysdeps/ia64/backtrace.c: Likewise.
> 	* sysdeps/mips/backtrace.c: Likewise.
> 	* sysdeps/nios2/backtrace.c: Likewise.
> 	* sysdeps/riscv/backtrace.c: Likewise.
> 	* sysdeps/sh/backtrace.c: Likewise.
> 	* sysdeps/tile/backtrace.c: Likewise.

LGTM.

Reviewed-by: Adhemerval Zanella.


> 
> diff --git a/debug/backtrace.c b/debug/backtrace.c
> index 60d4a15..d423cc0 100644
> --- a/debug/backtrace.c
> +++ b/debug/backtrace.c
> @@ -1,7 +1,7 @@
> -/* Return backtrace of current program state.  Generic version.
> -   Copyright (C) 1998-2018 Free Software Foundation, Inc.
> +/* Return backtrace of current program state.
> +   Copyright (C) 2003-2018 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
> -   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
> +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
>  
>     The GNU C Library is free software; you can redistribute it and/or
>     modify it under the terms of the GNU Lesser General Public
> @@ -17,74 +17,118 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>  
> +#include <libc-lock.h>
> +#include <dlfcn.h>
>  #include <execinfo.h>
> -#include <signal.h>
> -#include <frame.h>
> -#include <sigcontextinfo.h>
> -#include <ldsodefs.h>
> -
> -/* This implementation assumes a stack layout that matches the defaults
> -   used by gcc's `__builtin_frame_address' and `__builtin_return_address'
> -   (FP is the frame pointer register):
> -
> -	  +-----------------+     +-----------------+
> -    FP -> | previous FP --------> | previous FP ------>...
> -	  |                 |     |                 |
> -	  | return address  |     | return address  |
> -	  +-----------------+     +-----------------+
> -
> -  */
> -
> -/* Get some notion of the current stack.  Need not be exactly the top
> -   of the stack, just something somewhere in the current frame.  */
> -#ifndef CURRENT_STACK_FRAME
> -# define CURRENT_STACK_FRAME  ({ char __csf; &__csf; })
> -#endif
> +#include <gnu/lib-names.h>
> +#include <stdlib.h>
> +#include <unwind.h>
>  
> -/* By default we assume that the stack grows downward.  */
> -#ifndef INNER_THAN
> -# define INNER_THAN <
> -#endif
> +struct trace_arg
> +{
> +  void **array;
> +  _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;
> +}
>  
> -/* By default assume the `next' pointer in struct layout points to the
> -   next struct layout.  */
> -#ifndef ADVANCE_STACK_FRAME
> -# define ADVANCE_STACK_FRAME(next) ((struct layout *) (next))
> -#endif
>  
> -/* By default, the frame pointer is just what we get from gcc.  */
> -#ifndef FIRST_FRAME_POINTER
> -# define FIRST_FRAME_POINTER  __builtin_frame_address (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)
> +{
> +  struct trace_arg *arg = 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);
> +
> +      /* Check whether we make any progress.  */
> +      _Unwind_Word cfa = unwind_getcfa (ctx);
> +
> +      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
> +	 && cfa == arg->cfa)
> +       return _URC_END_OF_STACK;
> +      arg->cfa = cfa;
> +    }
> +  if (++arg->cnt == arg->size)
> +    return _URC_END_OF_STACK;
> +  return _URC_NO_REASON;
> +}
> +
>  int
>  __backtrace (void **array, int size)
>  {
> -  struct layout *current;
> -  void *top_frame;
> -  void *top_stack;
> -  int cnt = 0;
> +  struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
>  
> -  top_frame = FIRST_FRAME_POINTER;
> -  top_stack = CURRENT_STACK_FRAME;
> +  if (size <= 0)
> +    return 0;
>  
> -  /* We skip the call to this function, it makes no sense to record it.  */
> -  current = ((struct layout *) top_frame);
> -  while (cnt < size)
> -    {
> -      if ((void *) current INNER_THAN top_stack
> -	  || !((void *) current INNER_THAN __libc_stack_end))
> -       /* This means the address is out of range.  Note that for the
> -	  toplevel we see a frame pointer with value NULL which clearly is
> -	  out of range.  */
> -	break;
> +#ifdef SHARED
> +  __libc_once_define (static, once);
>  
> -      array[cnt++] = current->return_address;
> +  __libc_once (once, init);
> +  if (unwind_backtrace == NULL)
> +    return 0;
> +#endif
>  
> -      current = ADVANCE_STACK_FRAME (current->next);
> -    }
> +  unwind_backtrace (backtrace_helper, &arg);
>  
> -  return cnt;
> +  /* _Unwind_Backtrace seems to put NULL address above
> +     _start.  Fix it up here.  */
> +  if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
> +    --arg.cnt;
> +  return arg.cnt != -1 ? arg.cnt : 0;
>  }
>  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
> diff --git a/sysdeps/aarch64/backtrace.c b/sysdeps/aarch64/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/aarch64/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/alpha/backtrace.c b/sysdeps/alpha/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/alpha/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/hppa/backtrace.c b/sysdeps/hppa/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/hppa/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/ia64/backtrace.c b/sysdeps/ia64/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/ia64/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/mips/backtrace.c b/sysdeps/mips/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/mips/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/nios2/backtrace.c b/sysdeps/nios2/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/nios2/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/riscv/backtrace.c b/sysdeps/riscv/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/riscv/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/sh/backtrace.c b/sysdeps/sh/backtrace.c
> deleted file mode 100644
> index 4f3eafb..0000000
> --- a/sysdeps/sh/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include "../x86_64/backtrace.c"
> diff --git a/sysdeps/tile/backtrace.c b/sysdeps/tile/backtrace.c
> deleted file mode 100644
> index 27ce597..0000000
> --- a/sysdeps/tile/backtrace.c
> +++ /dev/null
> @@ -1 +0,0 @@
> -#include <sysdeps/x86_64/backtrace.c>
> diff --git a/sysdeps/x86_64/backtrace.c b/sysdeps/x86_64/backtrace.c
> deleted file mode 100644
> index d423cc0..0000000
> --- a/sysdeps/x86_64/backtrace.c
> +++ /dev/null
> @@ -1,134 +0,0 @@
> -/* Return backtrace of current program state.
> -   Copyright (C) 2003-2018 Free Software Foundation, Inc.
> -   This file is part of the GNU C Library.
> -   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
> -
> -   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
> -   <http://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>
> -
> -struct trace_arg
> -{
> -  void **array;
> -  _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)
> -{
> -  struct trace_arg *arg = 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);
> -
> -      /* Check whether we make any progress.  */
> -      _Unwind_Word cfa = unwind_getcfa (ctx);
> -
> -      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
> -	 && cfa == arg->cfa)
> -       return _URC_END_OF_STACK;
> -      arg->cfa = cfa;
> -    }
> -  if (++arg->cnt == arg->size)
> -    return _URC_END_OF_STACK;
> -  return _URC_NO_REASON;
> -}
> -
> -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)
> -    return 0;
> -#endif
> -
> -  unwind_backtrace (backtrace_helper, &arg);
> -
> -  /* _Unwind_Backtrace seems to put NULL address above
> -     _start.  Fix it up here.  */
> -  if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
> -    --arg.cnt;
> -  return arg.cnt != -1 ? arg.cnt : 0;
> -}
> -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
>

Patch

diff --git a/debug/backtrace.c b/debug/backtrace.c
index 60d4a15..d423cc0 100644
--- a/debug/backtrace.c
+++ b/debug/backtrace.c
@@ -1,7 +1,7 @@ 
-/* Return backtrace of current program state.  Generic version.
-   Copyright (C) 1998-2018 Free Software Foundation, Inc.
+/* Return backtrace of current program state.
+   Copyright (C) 2003-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -17,74 +17,118 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <libc-lock.h>
+#include <dlfcn.h>
 #include <execinfo.h>
-#include <signal.h>
-#include <frame.h>
-#include <sigcontextinfo.h>
-#include <ldsodefs.h>
-
-/* This implementation assumes a stack layout that matches the defaults
-   used by gcc's `__builtin_frame_address' and `__builtin_return_address'
-   (FP is the frame pointer register):
-
-	  +-----------------+     +-----------------+
-    FP -> | previous FP --------> | previous FP ------>...
-	  |                 |     |                 |
-	  | return address  |     | return address  |
-	  +-----------------+     +-----------------+
-
-  */
-
-/* Get some notion of the current stack.  Need not be exactly the top
-   of the stack, just something somewhere in the current frame.  */
-#ifndef CURRENT_STACK_FRAME
-# define CURRENT_STACK_FRAME  ({ char __csf; &__csf; })
-#endif
+#include <gnu/lib-names.h>
+#include <stdlib.h>
+#include <unwind.h>
 
-/* By default we assume that the stack grows downward.  */
-#ifndef INNER_THAN
-# define INNER_THAN <
-#endif
+struct trace_arg
+{
+  void **array;
+  _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;
+}
 
-/* By default assume the `next' pointer in struct layout points to the
-   next struct layout.  */
-#ifndef ADVANCE_STACK_FRAME
-# define ADVANCE_STACK_FRAME(next) ((struct layout *) (next))
-#endif
 
-/* By default, the frame pointer is just what we get from gcc.  */
-#ifndef FIRST_FRAME_POINTER
-# define FIRST_FRAME_POINTER  __builtin_frame_address (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)
+{
+  struct trace_arg *arg = 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);
+
+      /* Check whether we make any progress.  */
+      _Unwind_Word cfa = unwind_getcfa (ctx);
+
+      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
+	 && cfa == arg->cfa)
+       return _URC_END_OF_STACK;
+      arg->cfa = cfa;
+    }
+  if (++arg->cnt == arg->size)
+    return _URC_END_OF_STACK;
+  return _URC_NO_REASON;
+}
+
 int
 __backtrace (void **array, int size)
 {
-  struct layout *current;
-  void *top_frame;
-  void *top_stack;
-  int cnt = 0;
+  struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
 
-  top_frame = FIRST_FRAME_POINTER;
-  top_stack = CURRENT_STACK_FRAME;
+  if (size <= 0)
+    return 0;
 
-  /* We skip the call to this function, it makes no sense to record it.  */
-  current = ((struct layout *) top_frame);
-  while (cnt < size)
-    {
-      if ((void *) current INNER_THAN top_stack
-	  || !((void *) current INNER_THAN __libc_stack_end))
-       /* This means the address is out of range.  Note that for the
-	  toplevel we see a frame pointer with value NULL which clearly is
-	  out of range.  */
-	break;
+#ifdef SHARED
+  __libc_once_define (static, once);
 
-      array[cnt++] = current->return_address;
+  __libc_once (once, init);
+  if (unwind_backtrace == NULL)
+    return 0;
+#endif
 
-      current = ADVANCE_STACK_FRAME (current->next);
-    }
+  unwind_backtrace (backtrace_helper, &arg);
 
-  return cnt;
+  /* _Unwind_Backtrace seems to put NULL address above
+     _start.  Fix it up here.  */
+  if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
+    --arg.cnt;
+  return arg.cnt != -1 ? arg.cnt : 0;
 }
 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
diff --git a/sysdeps/aarch64/backtrace.c b/sysdeps/aarch64/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/aarch64/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/alpha/backtrace.c b/sysdeps/alpha/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/alpha/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/hppa/backtrace.c b/sysdeps/hppa/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/hppa/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/ia64/backtrace.c b/sysdeps/ia64/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/ia64/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/mips/backtrace.c b/sysdeps/mips/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/mips/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/nios2/backtrace.c b/sysdeps/nios2/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/nios2/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/riscv/backtrace.c b/sysdeps/riscv/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/riscv/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/sh/backtrace.c b/sysdeps/sh/backtrace.c
deleted file mode 100644
index 4f3eafb..0000000
--- a/sysdeps/sh/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include "../x86_64/backtrace.c"
diff --git a/sysdeps/tile/backtrace.c b/sysdeps/tile/backtrace.c
deleted file mode 100644
index 27ce597..0000000
--- a/sysdeps/tile/backtrace.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/x86_64/backtrace.c>
diff --git a/sysdeps/x86_64/backtrace.c b/sysdeps/x86_64/backtrace.c
deleted file mode 100644
index d423cc0..0000000
--- a/sysdeps/x86_64/backtrace.c
+++ /dev/null
@@ -1,134 +0,0 @@ 
-/* Return backtrace of current program state.
-   Copyright (C) 2003-2018 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
-
-   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
-   <http://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>
-
-struct trace_arg
-{
-  void **array;
-  _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)
-{
-  struct trace_arg *arg = 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);
-
-      /* Check whether we make any progress.  */
-      _Unwind_Word cfa = unwind_getcfa (ctx);
-
-      if (arg->cnt > 0 && arg->array[arg->cnt - 1] == arg->array[arg->cnt]
-	 && cfa == arg->cfa)
-       return _URC_END_OF_STACK;
-      arg->cfa = cfa;
-    }
-  if (++arg->cnt == arg->size)
-    return _URC_END_OF_STACK;
-  return _URC_NO_REASON;
-}
-
-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)
-    return 0;
-#endif
-
-  unwind_backtrace (backtrace_helper, &arg);
-
-  /* _Unwind_Backtrace seems to put NULL address above
-     _start.  Fix it up here.  */
-  if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL)
-    --arg.cnt;
-  return arg.cnt != -1 ? arg.cnt : 0;
-}
-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