This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
ARM EABI backtrace
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: libc-ports at sourceware dot org
- Date: Wed, 24 Jun 2009 16:01:21 +0000 (UTC)
- Subject: ARM EABI backtrace
ARM EABI has no defined standard frame layout, so backtracing can only
reliably be done using unwind information. I've applied this patch to
make backtrace use the ARM EABI unwind information (similar to other
targets using unwind information, but adjusted for the peculiarities of
unwinding on ARM).
The patch supports building with a compiler defaulting to unwind
information being enabled - that is what the configure changes are for, to
avoid some configure tests with -nostdlib breaking because of functions
from libgcc being needed when unwind information is enabled. It also
supports building with a compiler without such a default - backtrace.c is
built with unwind information, and backtraces can be done if all relevant
functions are built with unwind information. Backtraces with incomplete
unwind information will work most reliably (stopping when unwind
information is unavailable rather than confusing the unwinder) with a
version of binutils including patches that went in last month to make the
linker mark address ranges without unwind information (ARM unwind
information uses half-open address ranges, so without special linker
handling code without unwind information would be associated with whatever
previous function was the last one to have unwind information).
diff --git a/ChangeLog.arm b/ChangeLog.arm
index 6750958..dbc00f6 100644
--- a/ChangeLog.arm
+++ b/ChangeLog.arm
@@ -1,3 +1,19 @@
+2009-06-24 Maxim Kuvyrkov <maxim@codesourcery.com>
+ Mark Mitchell <mark@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Kazu Hirata <kazu@codesourcery.com>
+
+ * sysdeps/arm/eabi/backtrace.c: New.
+ * sysdeps/arm/eabi/Makefile (CFLAGS-backtrace.c): Add
+ -funwind-tables.
+ * sysdeps/arm/preconfigure: Add -fno-unwind-tables to CFLAGS.
+ * sysdeps/unix/sysv/linux/arm/eabi/configure.in: Remove
+ -fno-unwind-tables from CFLAGS.
+ * sysdeps/unix/sysv/linux/arm/eabi/configure: Regenerate.
+ * sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h (_Unwind_Trace_Fn):
+ Define.
+ (_Unwind_Backtrace): Declare.
+
2009-05-18 Joseph Myers <joseph@codesourcery.com>
* sysdeps/arm/____longjmp_chk.S (CHECK_SP): Use unsigned
diff --git a/sysdeps/arm/eabi/Makefile b/sysdeps/arm/eabi/Makefile
index 0f92d7a..890d1d9 100644
--- a/sysdeps/arm/eabi/Makefile
+++ b/sysdeps/arm/eabi/Makefile
@@ -11,6 +11,10 @@ static-only-routines += $(aeabi_constants)
gen-as-const-headers += rtld-global-offsets.sym
endif
+ifeq ($(subdir),debug)
+CFLAGS-backtrace.c += -funwind-tables
+endif
+
ifeq ($(subdir),elf)
sysdep_routines += aeabi_unwind_cpp_pr1 find_exidx
shared-only-routines += aeabi_unwind_cpp_pr1
diff --git a/sysdeps/arm/eabi/backtrace.c b/sysdeps/arm/eabi/backtrace.c
new file mode 100644
index 0000000..752a435
--- /dev/null
+++ b/sysdeps/arm/eabi/backtrace.c
@@ -0,0 +1,126 @@
+/* Return backtrace of current program state.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kazu Hirata <kazu@codesourcery.com>, 2008.
+
+ 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <bits/libc-lock.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <stdlib.h>
+#include <unwind.h>
+
+struct trace_arg
+{
+ void **array;
+ 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)
+{
+ _uw val;
+ 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 _Unwind_GetIP
+#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);
+ if (++arg->cnt == arg->size)
+ return _URC_END_OF_STACK;
+ return _URC_NO_REASON;
+}
+
+int
+__backtrace (array, size)
+ void **array;
+ int size;
+{
+ struct trace_arg arg = { .array = array, .size = size, .cnt = -1 };
+#ifdef SHARED
+ __libc_once_define (static, once);
+
+ __libc_once (once, init);
+ if (unwind_backtrace == NULL)
+ return 0;
+#endif
+
+ if (size >= 1)
+ unwind_backtrace (backtrace_helper, &arg);
+
+ 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/arm/preconfigure b/sysdeps/arm/preconfigure
index 337e84f..313da79 100644
--- a/sysdeps/arm/preconfigure
+++ b/sysdeps/arm/preconfigure
@@ -11,3 +11,7 @@ arm*)
esac
;;
esac
+if [ "${CFLAGS+set}" != "set" ]; then
+ CFLAGS="-g -O2"
+fi
+CFLAGS="$CFLAGS -fno-unwind-tables"
diff --git a/sysdeps/unix/sysv/linux/arm/eabi/configure b/sysdeps/unix/sysv/linux/arm/eabi/configure
index 28fb9ef..c7e20cf 100644
--- a/sysdeps/unix/sysv/linux/arm/eabi/configure
+++ b/sysdeps/unix/sysv/linux/arm/eabi/configure
@@ -3,3 +3,4 @@
arch_minimum_kernel=2.6.16
libc_cv_gcc_unwind_find_fde=no
+CFLAGS=${CFLAGS% -fno-unwind-tables}
diff --git a/sysdeps/unix/sysv/linux/arm/eabi/configure.in b/sysdeps/unix/sysv/linux/arm/eabi/configure.in
index d1fb7f4..cc0e9b5 100644
--- a/sysdeps/unix/sysv/linux/arm/eabi/configure.in
+++ b/sysdeps/unix/sysv/linux/arm/eabi/configure.in
@@ -3,3 +3,4 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
arch_minimum_kernel=2.6.16
libc_cv_gcc_unwind_find_fde=no
+CFLAGS=${CFLAGS% -fno-unwind-tables}
diff --git a/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h b/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h
index d625fb2..eeb9cf8 100644
--- a/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h
+++ b/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h
@@ -1,5 +1,5 @@
/* Header file for the ARM EABI unwinder
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
Contributed by Paul Brook
This file is free software; you can redistribute it and/or modify it
@@ -267,6 +267,11 @@ extern "C" {
#define _Unwind_SetIP(context, val) \
_Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)
+ (struct _Unwind_Context *, void *);
+
+extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
--
Joseph S. Myers
joseph@codesourcery.com