]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: backtrace_get/append() - skip stack frames only based name
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 30 Sep 2019 20:00:37 +0000 (23:00 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 9 Oct 2019 07:58:25 +0000 (07:58 +0000)
It's not really safe to do anything else because functions may potentially
be inlined.

src/lib/backtrace-string.c
src/lib/test-backtrace.c

index d9845e7a17493a5d043af9e839e74f15332a43c6..eb87fc38167bab2ad0bb45e566f21e5fea86d7c5 100644 (file)
@@ -5,7 +5,7 @@
 #include "backtrace-string.h"
 
 #define MAX_STACK_SIZE 30
-#define STACK_SKIP_COUNT 2
+#define BACKTRACE_SKIP_PREFIX "backtrace_"
 
 #if defined(HAVE_LIBUNWIND)
 
@@ -13,6 +13,7 @@
 
 int backtrace_append(string_t *str)
 {
+       size_t str_orig_size = str_len(str);
        char proc_name[256];
        int ret;
        unsigned int fp = 0;
@@ -31,11 +32,7 @@ int backtrace_append(string_t *str)
        }
 
        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) {
@@ -43,6 +40,9 @@ int backtrace_append(string_t *str)
                } 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);
@@ -64,25 +64,26 @@ int backtrace_append(string_t *str)
 
 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;
@@ -101,11 +102,9 @@ static int walk_callback(uintptr_t ptr, int signo ATTR_UNUSED,
 {
        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;
 }
index c6e35495d179289752aa91453dfbc2cf2287fcc8..fdebe0fd38282d45d7a48ce421ac82211ff5d96b 100644 (file)
@@ -1,13 +1,40 @@
 #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);
@@ -25,5 +52,6 @@ static void test_backtrace_get(void)
 
 void test_backtrace(void)
 {
+       test_backtrace_append();
        test_backtrace_get();
 }