From 3cbbe2cc42170b899bd61301b7dd43fd31a2fedb Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 13 Apr 2016 14:07:36 -0500 Subject: [PATCH] main: Add backtracing support Ported from oFono @ commit df5d691c39b0ff41d3d98a01db078f7157eb0250. --- Makefile.am | 3 +- src/backtrace.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ src/backtrace.h | 25 +++++++ src/main.c | 6 ++ 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/backtrace.c create mode 100644 src/backtrace.h diff --git a/Makefile.am b/Makefile.am index 7a8e665c..70de7f7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -71,8 +71,9 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h \ src/wsc.h src/wsc.c \ src/eap.h src/eap.c \ src/eap-tls.c src/eap-ttls.c \ + src/backtrace.h src/backtrace.c \ src/iwd.h -src_iwd_LDADD = ell/libell-internal.la +src_iwd_LDADD = ell/libell-internal.la -ldl client_iwctl_SOURCES = client/main.c src/kdbus.h src/kdbus.c client_iwctl_LDADD = ell/libell-internal.la diff --git a/src/backtrace.c b/src/backtrace.c new file mode 100644 index 00000000..ec4c4701 --- /dev/null +++ b/src/backtrace.c @@ -0,0 +1,179 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _GNU_SOURCE +#include + +#ifdef __GLIBC__ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "src/backtrace.h" + +static const char *program_exec; +static const char *program_path; + +void __iwd_backtrace_print(unsigned int offset) +{ + 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, L_ARRAY_SIZE(frames)); + 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); + } + + close(outfd[0]); + close(infd[1]); + + l_error("++++++++ backtrace ++++++++"); + + 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) { + l_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; + + l_error("#%-2u %p in %s() at %s", i - offset, + frames[i], buf, pos); + } + + l_error("+++++++++++++++++++++++++++"); + + kill(pid, SIGTERM); + + close(outfd[1]); + close(infd[0]); +} + +static void signal_handler(int signo) +{ + l_error("Aborting (signal %d) [%s]", signo, program_exec); + + __iwd_backtrace_print(2); + + exit(EXIT_FAILURE); +} + +void __iwd_backtrace_init(const char *program) +{ + static char path[PATH_MAX]; + struct sigaction sa; + sigset_t mask; + + program_exec = program; + program_path = getcwd(path, sizeof(path)); + + sigemptyset(&mask); + sa.sa_handler = signal_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); +} +#endif diff --git a/src/backtrace.h b/src/backtrace.h new file mode 100644 index 00000000..973466a0 --- /dev/null +++ b/src/backtrace.h @@ -0,0 +1,25 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2013-2016 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifdef __GLIBC__ +void __iwd_backtrace_init(const char *program); +void __iwd_backtrace_print(unsigned int offset); +#endif diff --git a/src/main.c b/src/main.c index e5f253de..84c7bce2 100644 --- a/src/main.c +++ b/src/main.c @@ -40,6 +40,8 @@ #include "src/scan.h" #include "src/wsc.h" +#include "src/backtrace.h" + static struct l_timeout *timeout = NULL; static void main_loop_quit(struct l_timeout *timeout, void *user_data) @@ -162,6 +164,10 @@ int main(int argc, char *argv[]) l_log_set_stderr(); l_debug_enable("*"); +#ifdef __GLIBC__ + __iwd_backtrace_init(argv[0]); +#endif + l_info("Wireless daemon version %s", VERSION); if (!dbus_init(enable_dbus_debug, enable_kdbus)) {