log: Add support for backtrace symbole resolving
authorMarcel Holtmann <marcel@holtmann.org>
Thu, 6 Oct 2011 19:23:16 +0000 (12:23 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 6 Oct 2011 19:23:16 +0000 (12:23 -0700)
src/connman.h
src/log.c
src/main.c

index ba161d3..e2b0f1c 100644 (file)
@@ -98,7 +98,8 @@ int __connman_agent_report_error(struct connman_service *service,
 
 #include <connman/log.h>
 
-int __connman_log_init(const char *debug, connman_bool_t detach);
+int __connman_log_init(const char *program, const char *debug,
+                                               connman_bool_t detach);
 void __connman_log_cleanup(void);
 void __connman_log_enable(struct connman_debug_desc *start,
                                        struct connman_debug_desc *stop);
index 2301cdc..04e61f3 100644 (file)
--- a/src/log.c
+++ b/src/log.c
 #endif
 
 #define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
 #include <stdarg.h>
-#include <syslog.h>
 #include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
 #include <execinfo.h>
 #include <dlfcn.h>
 
 #include "connman.h"
 
+static const char *program_exec;
+static const char *program_path;
+
 /**
  * connman_info:
  * @format: format string
@@ -104,30 +110,115 @@ void connman_debug(const char *format, ...)
        va_end(ap);
 }
 
-static void signal_handler(int signo)
+static void print_backtrace(unsigned int offset)
 {
-       void *frames[64];
-       char **symbols;
+       void *frames[99];
        size_t n_ptrs;
        unsigned int i;
+       int outfd[2], infd[2];
+       int pathlen;
+       pid_t pid;
+
+       if (program_exec == NULL)
+               return;
+
+       pathlen = strlen(program_path);
 
        n_ptrs = backtrace(frames, G_N_ELEMENTS(frames));
-       symbols = backtrace_symbols(frames, n_ptrs);
-       if (symbols == NULL) {
-               connman_error("No backtrace symbols");
-               exit(1);
+       if (n_ptrs < offset)
+               return;
+
+       if (pipe(outfd) < 0)
+               return;
+
+       if (pipe(infd) < 0) {
+               close(outfd[0]);
+               close(outfd[1]);
+               return;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               close(outfd[0]);
+               close(outfd[1]);
+               close(infd[0]);
+               close(infd[1]);
+               return;
+       }
+
+       if (pid == 0) {
+               close(outfd[1]);
+               close(infd[0]);
+
+               dup2(outfd[0], STDIN_FILENO);
+               dup2(infd[1], STDOUT_FILENO);
+
+               execlp("addr2line", "-C", "-f", "-e", program_exec, NULL);
+
+               exit(EXIT_FAILURE);
        }
 
-       connman_error("Aborting (signal %d)", signo);
+       close(outfd[0]);
+       close(infd[1]);
+
        connman_error("++++++++ backtrace ++++++++");
 
-       for (i = 1; i < n_ptrs; i++)
-               connman_error("[%d]: %s", i - 1, symbols[i]);
+       for (i = offset; i < n_ptrs - 1; i++) {
+               Dl_info info;
+               char addr[20], buf[PATH_MAX * 2];
+               int len, written;
+               char *ptr, *pos;
+
+               dladdr(frames[i], &info);
+
+               len = snprintf(addr, sizeof(addr), "%p\n", frames[i]);
+               if (len < 0)
+                       break;
+
+               written = write(outfd[1], addr, len);
+               if (written < 0)
+                       break;
+
+               len = read(infd[0], buf, sizeof(buf));
+               if (len < 0)
+                       break;
+
+               buf[len] = '\0';
+
+               pos = strchr(buf, '\n');
+               *pos++ = '\0';
+
+               if (strcmp(buf, "??") == 0) {
+                       connman_error("#%-2u %p in %s", i - offset,
+                                               frames[i], info.dli_fname);
+                       continue;
+               }
+
+               ptr = strchr(pos, '\n');
+               *ptr++ = '\0';
+
+               if (strncmp(pos, program_path, pathlen) == 0)
+                       pos += pathlen + 1;
+
+               connman_error("#%-2u %p in %s() at %s", i - offset,
+                                               frames[i], buf, pos);
+       }
 
        connman_error("+++++++++++++++++++++++++++");
 
-       g_free(symbols);
-       exit(1);
+       kill(pid, SIGTERM);
+
+       close(outfd[1]);
+       close(infd[0]);
+}
+
+static void signal_handler(int signo)
+{
+       connman_error("Aborting (signal %d) [%s]", signo, program_exec);
+
+       print_backtrace(2);
+
+       exit(EXIT_FAILURE);
 }
 
 static void signal_setup(sighandler_t handler)
@@ -224,10 +315,15 @@ void __connman_log_enable(struct connman_debug_desc *start,
        }
 }
 
-int __connman_log_init(const char *debug, connman_bool_t detach)
+int __connman_log_init(const char *program, const char *debug,
+                                               connman_bool_t detach)
 {
+       static char path[PATH_MAX];
        int option = LOG_NDELAY | LOG_PID;
 
+       program_exec = program;
+       program_path = getcwd(path, sizeof(path));
+
        if (debug != NULL)
                enabled = g_strsplit_set(debug, ":, ", 0);
 
@@ -238,7 +334,7 @@ int __connman_log_init(const char *debug, connman_bool_t detach)
 
        signal_setup(signal_handler);
 
-       openlog("connmand", option, LOG_DAEMON);
+       openlog(basename(program), option, LOG_DAEMON);
 
        syslog(LOG_INFO, "Connection Manager version %s", VERSION);
 
index f36c4f5..d3b213c 100644 (file)
@@ -320,7 +320,7 @@ int main(int argc, char *argv[])
 
        g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL);
 
-       __connman_log_init(option_debug, option_detach);
+       __connman_log_init(argv[0], option_debug, option_detach);
 
        __connman_dbus_init(conn);