#include "backtrace-string.h"
#define MAX_STACK_SIZE 30
-#define STACK_SKIP_COUNT 2
+#define BACKTRACE_SKIP_PREFIX "backtrace_"
#if defined(HAVE_LIBUNWIND)
int backtrace_append(string_t *str)
{
+ size_t str_orig_size = str_len(str);
char proc_name[256];
int ret;
unsigned int fp = 0;
}
do {
- if (fp < STACK_SKIP_COUNT) {
- fp++;
- continue;
- }
- str_printfa(str, "#%d ", fp - STACK_SKIP_COUNT);
+ str_printfa(str, "#%d ", fp);
if ((ret = unw_get_proc_info(&c, &pip)) != 0) {
str_printfa(str, "[unw_get_proc_info_failed(): %d]", ret);
} else if (pip.start_ip == 0 || pip.end_ip == 0) {
} else if ((ret = unw_get_proc_name(&c, proc_name, sizeof(proc_name), 0)) != 0 &&
ret != UNW_ENOMEM) {
str_printfa(str, "[unw_get_proc_name() failed: %d]", ret);
+ } else if (!success && str_begins(proc_name, BACKTRACE_SKIP_PREFIX)) {
+ str_truncate(str, str_orig_size);
+ continue;
} else {
str_append_max(str, proc_name, sizeof(proc_name));
str_printfa(str, "[0x%08lx]", pip.start_ip);
int backtrace_append(string_t *str)
{
+ size_t str_orig_size = str_len(str);
void *stack[MAX_STACK_SIZE];
char **strings;
int ret, i;
ret = backtrace(stack, N_ELEMENTS(stack));
- if (ret <= STACK_SKIP_COUNT)
+ if (ret <= 0)
return -1;
strings = backtrace_symbols(stack, ret);
- for (i = STACK_SKIP_COUNT; i < ret; i++) {
- if (i > STACK_SKIP_COUNT)
+ for (i = 0; i < ret; i++) {
+ if (str_len(str) > str_orig_size)
str_append(str, " -> ");
- if (strings != NULL)
- str_append(str, strings[i]);
- else {
+ if (strings == NULL) {
/* out of memory case */
str_printfa(str, "0x%p", stack[i]);
- }
+ } else if (str_len(str) != str_orig_size ||
+ !str_begins(strings[i], BACKTRACE_SKIP_PREFIX))
+ str_append(str, strings[i]);
}
free(strings);
return 0;
{
struct walk_context *ctx = context;
- if (ctx->pos >= STACK_SKIP_COUNT) {
- if (ctx->pos > STACK_SKIP_COUNT)
- str_append(ctx->str, " -> ");
- str_printfa(ctx->str, "0x%p", (void *)ptr);
- }
+ if (ctx->pos > 0)
+ str_append(ctx->str, " -> ");
+ str_printfa(ctx->str, "0x%p", (void *)ptr);
ctx->pos++;
return 0;
}
#include "test-lib.h"
+#include "str.h"
#include "backtrace-string.h"
+static void test_backtrace_append(void)
+{
+ test_begin("backtrace_append");
+ string_t *bt = t_str_new(128);
+#if (defined(HAVE_LIBUNWIND))
+ test_assert(backtrace_append(bt) == 0);
+ /* Check that there's a usable function in the backtrace.
+ Note that this function may be inlined, so don't check for
+ test_backtrace_get() */
+ test_assert(strstr(str_c(bt), "test_backtrace") != NULL);
+ /* make sure the backtrace_append is not */
+ test_assert(strstr(str_c(bt), " backtrace_append") == NULL);
+#elif (defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)) || \
+ (defined(HAVE_WALKCONTEXT) && defined(HAVE_UCONTEXT_H))
+ test_assert(backtrace_append(bt) == 0);
+ /* it should have some kind of main in it */
+ test_assert(strstr(str_c(bt), "main") != NULL);
+#else
+ /* should not work in this context */
+ test_assert(backtrace_append(bt) == -1);
+#endif
+ test_end();
+}
+
static void test_backtrace_get(void)
{
test_begin("backtrace_get");
const char *bt = NULL;
#if (defined(HAVE_LIBUNWIND))
test_assert(backtrace_get(&bt) == 0);
- /* check that this function is there */
+ /* Check that there's a usable function in the backtrace.
+ Note that this function may be inlined, so don't check for
+ test_backtrace_get() */
test_assert(strstr(bt, "test_backtrace") != NULL);
/* make sure the backtrace_get is not */
test_assert(strstr(bt, " backtrace_get") == NULL);
void test_backtrace(void)
{
+ test_backtrace_append();
test_backtrace_get();
}