This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Use x86_64 backtrace as generic version
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
>