From ff4679178975cede4a4173bcf03447f1c0058d73 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 17 Aug 2010 17:10:46 +0200 Subject: [PATCH] ConnMan backtrace support 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. --- Makefile.am | 2 +- src/log.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ test/backtrace | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 test/backtrace diff --git a/Makefile.am b/Makefile.am index ed4689c9..1bf72074 100644 --- a/Makefile.am +++ b/Makefile.am @@ -179,7 +179,7 @@ test_scripts = test/get-state test/list-profiles test/list-services \ test/monitor-manager test/test-counter test/set-ip-method \ test/set-nameservers test/set-domains test/find-service \ test/get-services test/get-proxy-autoconfig \ - test/enable-tethering test/disable-tethering + test/enable-tethering test/disable-tethering test/backtrace if TEST testdir = $(pkglibdir)/test diff --git a/src/log.c b/src/log.c index 327731f2..4dee0031 100644 --- a/src/log.c +++ b/src/log.c @@ -23,8 +23,12 @@ #include #endif +#define _GNU_SOURCE #include #include +#include +#include +#include #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 100644 index 00000000..d33bcb18 --- /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 "-----------------------------------" -- 2.34.1