From a0d7a4587584b1c217183d7f17a2d55ab44aaf3a Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Sat, 21 Jan 2012 05:59:49 -0800 Subject: 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 --- libubacktrace/arm/Makefile.arch | 21 ++++++++++ libubacktrace/arm/backtrace.c | 90 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 libubacktrace/arm/Makefile.arch create mode 100644 libubacktrace/arm/backtrace.c (limited to 'libubacktrace/arm') 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 + +# 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 + * - ARM specific implementation of backtrace + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + * + */ + +#include +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.3