summaryrefslogtreecommitdiff
path: root/src/log.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2011-10-06 12:23:16 -0700
committerMarcel Holtmann <marcel@holtmann.org>2011-10-06 12:23:16 -0700
commit38a5212e282826ff57b6992f0c2b77e05aab5705 (patch)
treee922ba23105136c47a08b31f1dc13cda8678edaa /src/log.c
parent6b4834abb11edcf15ef9dd92192dba7453913371 (diff)
downloadconnman-38a5212e282826ff57b6992f0c2b77e05aab5705.tar.gz
connman-38a5212e282826ff57b6992f0c2b77e05aab5705.tar.bz2
connman-38a5212e282826ff57b6992f0c2b77e05aab5705.zip
log: Add support for backtrace symbole resolving
Diffstat (limited to 'src/log.c')
-rw-r--r--src/log.c126
1 files changed, 111 insertions, 15 deletions
diff --git a/src/log.c b/src/log.c
index 2301cdc9..04e61f31 100644
--- a/src/log.c
+++ b/src/log.c
@@ -24,14 +24,20 @@
#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);