diff options
author | Khem Raj <raj.khem@gmail.com> | 2012-01-21 05:59:49 -0800 |
---|---|---|
committer | Khem Raj <raj.khem@gmail.com> | 2012-01-23 16:10:39 -0800 |
commit | a0d7a4587584b1c217183d7f17a2d55ab44aaf3a (patch) | |
tree | eb501879d7ba3c8a3c65e2db8604ea587ed811c5 | |
parent | bee3ea0f5a8d2cc2cfaeebdc4ef65f2d6b30b749 (diff) |
libubacktrace: Add arm implementation
Arm has a different mechanism of getting
_Unwind_GetIP. Therefore we provide arch
specific backtrace file.
Signed-off-by: Khem Raj <raj.khem@gmail.com>
-rw-r--r-- | libubacktrace/Makefile.in | 26 | ||||
-rw-r--r-- | libubacktrace/arm/Makefile.arch | 21 | ||||
-rw-r--r-- | libubacktrace/arm/backtrace.c | 90 | ||||
-rw-r--r-- | libubacktrace/backtrace.c | 3 |
4 files changed, 131 insertions, 9 deletions
diff --git a/libubacktrace/Makefile.in b/libubacktrace/Makefile.in index b18e3e675..f675bf579 100644 --- a/libubacktrace/Makefile.in +++ b/libubacktrace/Makefile.in @@ -6,7 +6,7 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -subdirs += libubacktrace +subdirs += libubacktrace libubacktrace/$(TARGET_ARCH) CFLAGS-libubacktrace := -DNOT_IN_libc -DIS_IN_libubacktrace $(SSP_ALL_CFLAGS) @@ -23,22 +23,36 @@ libubacktrace_FULL_NAME := libubacktrace-$(VERSION).so libubacktrace_DIR := $(top_srcdir)libubacktrace libubacktrace_OUT := $(top_builddir)libubacktrace +libubacktrace_ARCH_DIR:=$(libubacktrace_DIR)/$(TARGET_ARCH) +libubacktrace_ARCH_OUT:=$(libubacktrace_OUT)/$(TARGET_ARCH) + +-include $(libubacktrace_ARCH_DIR)/Makefile.arch + libubacktrace_SRC-y := libubacktrace_SRC-$(UCLIBC_HAS_BACKTRACE) := backtrace.c backtracesyms.c backtracesymsfd.c +# remove generic sources, if arch specific version is present +ifneq ($(strip $(libubacktrace_ARCH_SRC-y)),) +libubacktrace_SRC-y := $(filter-out $(notdir $(libubacktrace_ARCH_SRC-y)),$(libubacktrace_SRC-y)) +endif + # -fasynchronous-unwind-tables is required for backtrace to work using dwarf2 CFLAGS-backtrace.c := -fasynchronous-unwind-tables +# pass common flags to arch dirs +ifneq ($(strip $(libubacktrace_ARCH_OBJS)),) +CFLAGS-libubacktrace/$(TARGET_ARCH)/ := $(CFLAGS-libubacktrace) +endif -libubacktrace_SRCS := $(addprefix $(libubacktrace_DIR)/,$(libubacktrace_SRC-y)) +libubacktrace_SRCS := $(patsubst %.c,$(libubacktrace_DIR)/%.c,$(libubacktrace_SRC-y)) libubacktrace_OBJS := $(patsubst $(libubacktrace_DIR)/%.c,$(libubacktrace_OUT)/%.o,$(libubacktrace_SRCS)) ifeq ($(DOPIC),y) -libubacktrace-a-y := $(libubacktrace_OBJS:.o=.os) +libubacktrace-a-y += $(libubacktrace_OBJS:.o=.os) else -libubacktrace-a-y := $(libubacktrace_OBJS) +libubacktrace-a-y += $(libubacktrace_OBJS) endif -libubacktrace-so-y := $(libubacktrace_OBJS:.o=.os) +libubacktrace-so-y += $(libubacktrace_OBJS:.o=.os) lib-a-$(UCLIBC_HAS_BACKTRACE) += $(top_builddir)lib/libubacktrace.a lib-so-$(UCLIBC_HAS_BACKTRACE) += $(top_builddir)lib/libubacktrace.so @@ -61,7 +75,7 @@ $(libubacktrace_OUT)/libubacktrace_so.a: $(libubacktrace-so-y) $(Q)$(RM) $@ $(do_ar) -$(libubacktrace_OUT)/libubacktrace.oS: $(libubacktrace_SRCS) +$(libubacktrace_OUT)/libubacktrace.oS: $(libubacktrace_SRCS) $(libubacktrace_ARCH_SRCS) $(Q)$(RM) $@ $(compile-m) diff --git a/libubacktrace/arm/Makefile.arch b/libubacktrace/arm/Makefile.arch new file mode 100644 index 000000000..dab36378e --- /dev/null +++ b/libubacktrace/arm/Makefile.arch @@ -0,0 +1,21 @@ +# Makefile for uClibc (libubacktrace) +# +# Author: Khem Raj <raj.khem@gmail.com> + +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libubacktrace_ARCH_SRC-$(UCLIBC_HAS_BACKTRACE) := backtrace.c +libubacktrace_ARCH_SRCS := $(addprefix $(libubacktrace_ARCH_DIR)/,$(libubacktrace_ARCH_SRC-y)) +libubacktrace_ARCH_OBJS := $(patsubst $(libubacktrace_ARCH_DIR)/%.c,$(libubacktrace_ARCH_OUT)/%.o,$(libubacktrace_ARCH_SRCS)) + +ifeq ($(DOPIC),y) +libubacktrace-a-y+=$(libubacktrace_ARCH_OBJS:.o=.os) +else +libubacktrace-a-y+=$(libubacktrace_ARCH_OBJS) +endif +libubacktrace-so-y+=$(libubacktrace_ARCH_OBJS:.o=.os) + +ifeq ($(CONFIG_ARM_EABI),y) +LIBGCC += $(shell $(CC) -print-file-name=libgcc_eh.a) +endif diff --git a/libubacktrace/arm/backtrace.c b/libubacktrace/arm/backtrace.c new file mode 100644 index 000000000..d4eca3224 --- /dev/null +++ b/libubacktrace/arm/backtrace.c @@ -0,0 +1,90 @@ +/* + * Perform stack unwinding by using the _Unwind_Backtrace. + * + * User application that wants to use backtrace needs to be + * compiled with -fasynchronous-unwid-tables option and -rdynamic i + * to get full symbols printed. + * + * Author(s): Khem Raj <raj.khem@gmail.com> + * - ARM specific implementation of backtrace + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + */ + +#include <execinfo.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <unwind.h> +#include <assert.h> +#include <stdio.h> + +struct trace_arg +{ + void **array; + int cnt, size; +}; + +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 backtrace_init (void) +{ + void *handle = dlopen ("libgcc_s.so.1", RTLD_LAZY); + if (handle == NULL + || ((unwind_backtrace = dlsym (handle, "_Unwind_Backtrace")) == NULL) + || ((unwind_vrs_get = dlsym (handle, "_Unwind_VRS_Get")) == NULL)) { + printf("libgcc_s.so.1 must be installed for backtrace to work\n"); + abort(); + } +} +/* 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) + +static _Unwind_Reason_Code +backtrace_helper (struct _Unwind_Context *ctx, void *a) +{ + struct trace_arg *arg = a; + + assert (unwind_getip != NULL); + + /* 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; +} + +/* + * Perform stack unwinding by using the _Unwind_Backtrace. + * + */ +int backtrace (void **array, int size) +{ + struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; + + if (unwind_backtrace == NULL) + backtrace_init(); + + if (size >= 1) + unwind_backtrace (backtrace_helper, &arg); + + return arg.cnt != -1 ? arg.cnt : 0; +} diff --git a/libubacktrace/backtrace.c b/libubacktrace/backtrace.c index 205a0a0ce..fdd5981fa 100644 --- a/libubacktrace/backtrace.c +++ b/libubacktrace/backtrace.c @@ -66,9 +66,6 @@ backtrace_helper (struct _Unwind_Context *ctx, void *a) /* * Perform stack unwinding by using the _Unwind_Backtrace. * - * User application that wants to use backtrace needs to be - * compiled with -fexceptions option and -rdynamic to get full - * symbols printed. */ int backtrace (void **array, int size) { |