3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-29 22:19:23 +01:00
iwd/src/backtrace.c
Andreas Henriksson b6910e1210 build: only enable backtrace(3) in maintainer mode
Using backtrace() is of no use when building with PIE (which most
distro compilers do by default) and prevents catching the coredump
for later retracing, which is needed since distros usually don't
install debug symbols by default either.

This patch thus only enables backtrace() when --enable-maintainer-mode
is passed and also tries to explicitly disable PIE.
2018-11-26 14:32:04 -06:00

199 lines
3.8 KiB
C

/*
*
* 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 <config.h>
#endif
#define _GNU_SOURCE
#include <features.h>
#ifdef HAVE_BACKTRACE
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <execinfo.h>
#include <dlfcn.h>
#include <linux/limits.h>
#include <ell/ell.h>
#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()
{
static char path[PATH_MAX];
static char cwd[PATH_MAX];
struct sigaction sa;
sigset_t mask;
ssize_t len;
/* Attempt to get the full path to our executable */
len = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (len > 0) {
int i;
path[len] = '\0';
for (i = len - 1; i >= 0; i--) {
if (path[i] != '/')
continue;
program_exec = path;
break;
}
}
if (program_exec == NULL)
return;
program_path = getcwd(cwd, sizeof(cwd));
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