Use x86_64 backtrace as generic version.

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.

	* 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.
This commit is contained in:
Joseph Myers 2018-03-21 17:25:30 +00:00
parent d0c5d731af
commit ffec7b2740
12 changed files with 111 additions and 196 deletions

View File

@ -1,3 +1,17 @@
2018-03-21 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.
2018-03-20 Joseph Myers <joseph@codesourcery.com> 2018-03-20 Joseph Myers <joseph@codesourcery.com>
[BZ #22987] [BZ #22987]

View File

@ -1,7 +1,7 @@
/* Return backtrace of current program state. Generic version. /* Return backtrace of current program state.
Copyright (C) 1998-2018 Free Software Foundation, Inc. Copyright (C) 2003-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library. 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 The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public 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 License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include <libc-lock.h>
#include <dlfcn.h>
#include <execinfo.h> #include <execinfo.h>
#include <signal.h> #include <gnu/lib-names.h>
#include <frame.h> #include <stdlib.h>
#include <sigcontextinfo.h> #include <unwind.h>
#include <ldsodefs.h>
/* This implementation assumes a stack layout that matches the defaults struct trace_arg
used by gcc's `__builtin_frame_address' and `__builtin_return_address' {
(FP is the frame pointer register): void **array;
_Unwind_Word cfa;
int cnt;
int size;
};
+-----------------+ +-----------------+ #ifdef SHARED
FP -> | previous FP --------> | previous FP ------>... static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
| | | | static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *);
| return address | | return address | static _Unwind_Word (*unwind_getcfa) (struct _Unwind_Context *);
+-----------------+ +-----------------+ static void *libgcc_handle;
*/
/* Get some notion of the current stack. Need not be exactly the top /* Dummy version in case libgcc_s does not contain the real code. */
of the stack, just something somewhere in the current frame. */ static _Unwind_Word
#ifndef CURRENT_STACK_FRAME dummy_getcfa (struct _Unwind_Context *ctx __attribute__ ((unused)))
# define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) {
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 #endif
/* By default we assume that the stack grows downward. */ static _Unwind_Reason_Code
#ifndef INNER_THAN backtrace_helper (struct _Unwind_Context *ctx, void *a)
# define INNER_THAN < {
#endif struct trace_arg *arg = a;
/* By default assume the `next' pointer in struct layout points to the /* We are first called with address in the __backtrace function.
next struct layout. */ Skip it. */
#ifndef ADVANCE_STACK_FRAME if (arg->cnt != -1)
# define ADVANCE_STACK_FRAME(next) ((struct layout *) (next)) {
#endif arg->array[arg->cnt] = (void *) unwind_getip (ctx);
/* By default, the frame pointer is just what we get from gcc. */ /* Check whether we make any progress. */
#ifndef FIRST_FRAME_POINTER _Unwind_Word cfa = unwind_getcfa (ctx);
# define FIRST_FRAME_POINTER __builtin_frame_address (0)
#endif 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 int
__backtrace (void **array, int size) __backtrace (void **array, int size)
{ {
struct layout *current; struct trace_arg arg = { .array = array, .cfa = 0, .size = size, .cnt = -1 };
void *top_frame;
void *top_stack;
int cnt = 0;
top_frame = FIRST_FRAME_POINTER; if (size <= 0)
top_stack = CURRENT_STACK_FRAME; return 0;
/* We skip the call to this function, it makes no sense to record it. */ #ifdef SHARED
current = ((struct layout *) top_frame); __libc_once_define (static, once);
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;
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) weak_alias (__backtrace, backtrace)
libc_hidden_def (__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

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -1 +0,0 @@
#include "../x86_64/backtrace.c"

View File

@ -1 +0,0 @@
#include <sysdeps/x86_64/backtrace.c>

View File

@ -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