This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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
> 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]