Add a generic signal handler in order to dump ConnMan backtrace when
crashing. The implementation is based on glibc backtrace() routines and
thus can not resolve static function names. A little python wrapper over
addr2line fixes that by taking a full backtrace from a complete connman
log file.
---
v3:
        * Remove switch from signal handler.
        * Remove extra whitespaces.
        * Rename signal_setup and signal_handler.
        * Prettier formatting.

v2:
        * Leave SIGINT and SIGTERM handling in main.c.
        * Move crashing signals handling to log.c.
        * Inline backtrace dumping and skip the top level frame.
---
 src/log.c      |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 test/backtrace |   55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+), 0 deletions(-)
 create mode 100755 test/backtrace

diff --git a/src/log.c b/src/log.c
index 327731f..af97ccd 100644
--- a/src/log.c
+++ b/src/log.c
@@ -23,8 +23,12 @@
 #include <config.h>
 #endif
 
+#define _GNU_SOURCE
 #include <stdarg.h>
 #include <syslog.h>
+#include <execinfo.h>
+#include <dlfcn.h>
+#include <stdlib.h>
 
 #include "connman.h"
 
@@ -148,6 +152,49 @@ static connman_bool_t is_enabled(struct connman_debug_desc 
*desc)
        return FALSE;
 }
 
+static void signal_handler(int signo)
+{
+       void *frames[64];
+       char **symbols;
+       size_t n_ptrs;
+       unsigned int i;
+
+       n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
+       symbols = backtrace_symbols(frames, n_ptrs);
+       if (symbols == NULL) {
+               connman_error("No backtrace symbols");
+               exit(1);
+       }
+
+       connman_error("Aborting (signal %d)", signo);
+       connman_error("++++++++ ConnMan backtrace ++++++++");
+
+       for (i = 1; i < n_ptrs; i++)
+               connman_error("[%d]: %s", i - 1, symbols[i]);
+
+       connman_error("++++++++++++++++++++++++++++++++++++");
+
+       g_free(symbols);
+       exit(1);
+}
+
+static void signal_setup(sighandler_t handler)
+{
+       struct sigaction sa;
+       sigset_t mask;
+
+       sigemptyset(&mask);
+       sa.sa_handler = handler;
+       sa.sa_mask = mask;
+       sa.sa_flags = 0;
+       sigaction(SIGBUS,  &sa, NULL);
+       sigaction(SIGILL,  &sa, NULL);
+       sigaction(SIGFPE,  &sa, NULL);
+       sigaction(SIGSEGV,  &sa, NULL);
+       sigaction(SIGABRT,  &sa, NULL);
+       sigaction(SIGPIPE,  &sa, NULL);
+}
+
 int __connman_log_init(const char *debug, connman_bool_t detach)
 {
        int option = LOG_NDELAY | LOG_PID;
@@ -179,6 +226,8 @@ int __connman_log_init(const char *debug, connman_bool_t 
detach)
        if (detach == FALSE)
                option |= LOG_PERROR;
 
+       signal_setup(signal_handler);
+
        openlog("connmand", option, LOG_DAEMON);
 
        syslog(LOG_INFO, "Connection Manager version %s", VERSION);
@@ -193,4 +242,6 @@ void __connman_log_cleanup(void)
        closelog();
 
        g_strfreev(enabled);
+
+       signal_setup(SIG_DFL);
 }
diff --git a/test/backtrace b/test/backtrace
new file mode 100755
index 0000000..d33bcb1
--- /dev/null
+++ b/test/backtrace
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+import os
+import re
+import sys
+import subprocess
+
+if (len(sys.argv) < 3):
+       print "Usage: %s [connman binary] [connman log]" % (sys.argv[0])
+       sys.exit(1)
+
+binary = sys.argv[1]
+count = 0
+frames = []
+addrs = []
+
+log_file = open(sys.argv[2], 'r')
+
+# Extract addresses
+for line in log_file:
+    matchobj = re.compile(r'\[(0x[0-9a-f]+)\]$').search(line)
+    if matchobj:
+        addrs.append(matchobj.group(1))
+
+log_file.close()
+
+# Feed into addr2line
+command = ['addr2line', '--demangle', '--functions', '--basename', '-e', 
binary]
+command.extend(addrs)
+
+p = subprocess.Popen(command, shell=False, bufsize=0,
+          stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)
+(child_stdin, child_stdout) = (p.stdin, p.stdout)
+
+child_stdin.close()
+
+# Backtrace display
+for line in child_stdout:
+
+    if line.startswith("??"): continue
+
+    line = line.strip()
+
+    frames.append(line)
+
+child_stdout.close()
+
+frame_count = len(frames);
+
+count = 0
+print "-------- ConnMan backtrace --------"
+while count < frame_count:
+    print "[%d]: %s() [%s]" % (count/2, frames[count], frames[count + 1])
+    count = count + 2
+print "-----------------------------------"
-- 
1.7.1

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to