Incorporate siginfo-1
This commit is contained in:
parent
01298d0915
commit
41c7c2d825
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* LADI Session Handler (ladish)
|
||||
*
|
||||
* Copyright (C) 2008,2009,2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
|
||||
* Copyright (C) 2008,2009,2010,2011,2012,2013 Nedko Arnaudov <nedko@arnaudov.name>
|
||||
* Copyright (C) 2008 Juuso Alasuutari <juuso.alasuutari@gmail.com>
|
||||
* Copyright (C) 2002 Robert Ham <rah@bash.sh>
|
||||
*
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include "version.h" /* git version define */
|
||||
#include "proctitle.h"
|
||||
#include "loader.h"
|
||||
#include "sigsegv.h"
|
||||
#include "siginfo.h"
|
||||
#include "control.h"
|
||||
#include "studio.h"
|
||||
#include "../dbus_constants.h"
|
||||
|
@ -329,7 +329,7 @@ int main(int argc, char ** argv, char ** envp)
|
|||
}
|
||||
|
||||
/* setup our SIGSEGV magic that prints nice stack in our logfile */
|
||||
setup_sigsegv();
|
||||
setup_siginfo();
|
||||
|
||||
if (!conf_proxy_init())
|
||||
{
|
||||
|
|
|
@ -0,0 +1,495 @@
|
|||
/* -*- Mode: C ; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2012 Nedko Arnaudov
|
||||
*
|
||||
* print out a stack-trace when program segfaults
|
||||
*
|
||||
* Inspiration: sigsegv.c by Jaco Kroon
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* or write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#define siginfo_log log_error
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
/* These are "defined" for documentation purposes. They should come from the build system with or without config.h */
|
||||
#if 0
|
||||
# define SIGINFO_CPP_DEMANGLE /* whether to attempt c++ demangle. if used, you must link with libstdc++ */
|
||||
# define SIGINFO_AUTO_INIT /* whether to use gcc constructor function for automatic initialization */
|
||||
#endif
|
||||
|
||||
#if !defined(SIGINFO_TEST)
|
||||
# if !defined siginfo_log
|
||||
# error "siginfo_log not defined"
|
||||
# endif
|
||||
#else
|
||||
# define siginfo_log(fmt, args...) fprintf(stderr, fmt "\n", ##args);
|
||||
#endif
|
||||
|
||||
/* dladdr() is a glibc extension */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define SIGINFO_MAX_BT_FRAMES 20
|
||||
|
||||
#if defined(SA_SIGINFO) && !defined(__arm__) && !defined(__ia64__) && !defined(__alpha__) && !defined (__FreeBSD_kernel__) && !defined (__sh__) && !defined(__APPLE__)
|
||||
# define USE_UCONTEXT
|
||||
# include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc64__)
|
||||
# define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.gp_regs[index])
|
||||
#elif defined(__powerpc__)
|
||||
# define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.uc_regs->gregs[index])
|
||||
#elif defined(__sparc__) && defined(__arch64__)
|
||||
# define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.mc_gregs[index])
|
||||
#else
|
||||
# define SIGINFO_REGISTER(ucontext, index) ((ucontext)->uc_mcontext.gregs[index])
|
||||
#endif
|
||||
|
||||
#if defined(REG_RIP)
|
||||
# define SIGINFO_IP_REG REG_RIP
|
||||
# define SIGINFO_BP_REG REG_RBP
|
||||
# define SIGINFO_REGFORMAT "%016llx"
|
||||
# define UINT_PTR_TYPE unsigned long long
|
||||
#elif defined(REG_EIP)
|
||||
# define SIGINFO_IP_REG REG_EIP
|
||||
# define SIGINFO_BP_REG REG_EBP
|
||||
# define SIGINFO_REGFORMAT "%08lx"
|
||||
# define UINT_PTR_TYPE unsigned long
|
||||
#else
|
||||
# define SIGINFO_REGFORMAT "%x"
|
||||
# define SIGINFO_STACK_GENERIC
|
||||
# define UINT_PTR_TYPE unsigned int
|
||||
#endif
|
||||
|
||||
struct si_code_descriptor
|
||||
{
|
||||
int code;
|
||||
const char * description;
|
||||
};
|
||||
|
||||
#ifdef USE_UCONTEXT
|
||||
static struct si_code_descriptor sig_ill_codes[] =
|
||||
{
|
||||
{ ILL_ILLOPC, "ILL_ILLOPC; Illegal opcode" },
|
||||
{ ILL_ILLOPN, "ILL_ILLOPN; Illegal operand" },
|
||||
{ ILL_ILLADR, "ILL_ILLADR; Illegal addressing mode" },
|
||||
{ ILL_ILLTRP, "ILL_ILLTRP; Illegal trap" },
|
||||
{ ILL_PRVOPC, "ILL_PRVOPC; Privileged opcode" },
|
||||
{ ILL_PRVREG, "ILL_PRVREG; Privileged register" },
|
||||
{ ILL_COPROC, "ILL_COPROC; Coprocessor error" },
|
||||
{ ILL_BADSTK, "ILL_BADSTK; Internal stack error" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct si_code_descriptor sig_fpe_codes[] =
|
||||
{
|
||||
{ FPE_INTDIV, "FPE_INTDIV; Integer divide by zero" },
|
||||
{ FPE_INTOVF, "FPE_INTOVF; Integer overflow" },
|
||||
{ FPE_FLTDIV, "FPE_FLTDIV; Floating-point divide by zero" },
|
||||
{ FPE_FLTOVF, "FPE_FLTOVF; Floating-point overflow" },
|
||||
{ FPE_FLTUND, "FPE_FLTUND; Floating-point underflow" },
|
||||
{ FPE_FLTRES, "FPE_FLTRES; Floating-point inexact result" },
|
||||
{ FPE_FLTINV, "FPE_FLTINV; Invalid floating-point operation" },
|
||||
{ FPE_FLTSUB, "FPE_FLTSUB; Subscript out of range" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct si_code_descriptor sig_segv_codes[] = {
|
||||
{ SEGV_MAPERR, "SEGV_MAPERR; Address not mapped to object" },
|
||||
{ SEGV_ACCERR, "SEGV_ACCERR; Invalid permissions for mapped object" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct si_code_descriptor sig_bus_codes[] =
|
||||
{
|
||||
{ BUS_ADRALN, "BUS_ADRALN; Invalid address alignment" },
|
||||
{ BUS_ADRERR, "BUS_ADRERR; Nonexistent physical address" },
|
||||
{ BUS_OBJERR, "BUS_OBJERR; Object-specific hardware error" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct si_code_descriptor sig_any_codes[] =
|
||||
{
|
||||
{ SI_USER, "SI_USER; sent by kill, sigsend, raise" },
|
||||
#if defined(SI_KERNEL)
|
||||
{ SI_KERNEL, "SI_KERNEL; sent by the kernel from somewhere" },
|
||||
#endif
|
||||
{ SI_QUEUE, "SI_QUEUE; Signal sent by the sigqueue()" },
|
||||
{ SI_TIMER, "SI_TIMER; Signal generated by expiration of a timer set by timer_settime()" },
|
||||
{ SI_ASYNCIO, "SI_ASYNCIO; Signal generated by completion of an asynchronous I/O request" },
|
||||
{ SI_MESGQ, "SI_MESGQ; Signal generated by arrival of a message on an empty message queue" },
|
||||
#if defined(SI_ASYNCIO)
|
||||
{ SI_ASYNCIO, "SI_ASYNCIO; sent by AIO completion" },
|
||||
#endif
|
||||
#if defined(SI_SIGIO)
|
||||
{ SI_SIGIO, "SI_SIGIO; sent by queued SIGIO" },
|
||||
#endif
|
||||
#if defined(SI_TKILL)
|
||||
{ SI_TKILL, "SI_TKILL; sent by tkill system call" },
|
||||
#endif
|
||||
#if defined(SI_DETHREAD)
|
||||
{ SI_DETHREAD, "SI_DETHREAD; sent by execve() killing subsidiary threads" },
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
#else /* #ifdef USE_UCONTEXT */
|
||||
# define sig_ill_codes NULL
|
||||
# define sig_fpe_codes NULL
|
||||
# define sig_segv_codes NULL
|
||||
# define sig_bus_codes NULL
|
||||
#endif /* #ifdef USE_UCONTEXT */
|
||||
|
||||
struct signal_descriptor
|
||||
{
|
||||
int signo;
|
||||
const char * descr;
|
||||
struct si_code_descriptor * codes;
|
||||
const char * msg;
|
||||
};
|
||||
|
||||
static struct signal_descriptor signal_descriptors[] =
|
||||
{
|
||||
{ SIGILL, "SIGILL", sig_ill_codes, "Illegal instruction" },
|
||||
{ SIGFPE, "SIGFPE", sig_fpe_codes, "Floating point exception" },
|
||||
{ SIGSEGV, "SIGSEGV", sig_segv_codes, "Segmentation Fault" },
|
||||
{ SIGBUS, "SIGBUS", sig_bus_codes, "Bus error (bad memory access)" },
|
||||
{ SIGABRT, "SIGABRT", NULL, "Abort" },
|
||||
};
|
||||
|
||||
/* ucontext is required for non-generic stack backtrace */
|
||||
#if !defined(USE_UCONTEXT) && !defined(SIGINFO_STACK_GENERIC)
|
||||
# define SIGINFO_STACK_GENERIC
|
||||
#endif
|
||||
|
||||
#if defined(SIGINFO_STACK_GENERIC)
|
||||
|
||||
static void dump_stack(ucontext_t * ucontext)
|
||||
{
|
||||
size_t i;
|
||||
void * bt[SIGINFO_MAX_BT_FRAMES];
|
||||
char ** strings;
|
||||
size_t sz;
|
||||
|
||||
((void)(ucontext)); /* unreferenced parameter */
|
||||
|
||||
siginfo_log("Stack trace (generic):");
|
||||
|
||||
sz = backtrace(bt, SIGINFO_MAX_BT_FRAMES);
|
||||
strings = backtrace_symbols(bt, sz);
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
{
|
||||
siginfo_log("%2zu: %s", i, strings[i]);
|
||||
}
|
||||
|
||||
siginfo_log("End of stack trace");
|
||||
}
|
||||
|
||||
#else /* #if defined(SIGINFO_STACK_GENERIC) */
|
||||
|
||||
#if defined(SIGINFO_CPP_DEMANGLE)
|
||||
char * __cxa_demangle(const char * __mangled_name, char * __output_buffer, size_t * __length, int * __status);
|
||||
#endif
|
||||
|
||||
static void dump_stack(ucontext_t * ucontext)
|
||||
{
|
||||
int frame;
|
||||
Dl_info dlinfo;
|
||||
void ** bp;
|
||||
void * ip;
|
||||
const char * symname;
|
||||
#if defined(SIGINFO_CPP_DEMANGLE)
|
||||
int demangle_status;
|
||||
char * demangled_name;
|
||||
#endif
|
||||
|
||||
ip = (void *) SIGINFO_REGISTER(ucontext, SIGINFO_IP_REG);
|
||||
bp = (void **)SIGINFO_REGISTER(ucontext, SIGINFO_BP_REG);
|
||||
|
||||
siginfo_log("Stack trace:");
|
||||
|
||||
for (frame = 0; bp != NULL && ip != NULL; frame++, ip = bp[1], bp = (void **)bp[0])
|
||||
{
|
||||
//siginfo_log("IP=%p BP=%p", ip, bp);
|
||||
if (dladdr(ip, &dlinfo) == 0)
|
||||
{
|
||||
siginfo_log("%2d: [dladdr failed for %p]", frame, ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
symname = dlinfo.dli_sname;
|
||||
#if defined(SIGINFO_CPP_DEMANGLE)
|
||||
demangled_name = __cxa_demangle(symname, NULL, 0, &demangle_status);
|
||||
if (demangle_status == 0 && demangled_name != NULL)
|
||||
{
|
||||
symname = demangled_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
siginfo_log(
|
||||
"%2d: 0x" SIGINFO_REGFORMAT " <%s+%d> (%s)",
|
||||
frame,
|
||||
(UINT_PTR_TYPE)ip,
|
||||
symname,
|
||||
(int)(ip - dlinfo.dli_saddr),
|
||||
dlinfo.dli_fname);
|
||||
|
||||
#if defined(SIGINFO_NO_CPP_DEMANGLE)
|
||||
free(demangled_name);
|
||||
#endif
|
||||
|
||||
if (dlinfo.dli_sname && strcmp(dlinfo.dli_sname, "main") == 0) break;
|
||||
}
|
||||
|
||||
siginfo_log("End of stack trace");
|
||||
}
|
||||
|
||||
#endif /* #if defined(SIGINFO_STACK_GENERIC) */
|
||||
|
||||
static struct signal_descriptor * lookup_signal_descriptor(int signo)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(signal_descriptors) / sizeof(signal_descriptors[0]); i++)
|
||||
{
|
||||
if (signal_descriptors[i].signo == signo)
|
||||
{
|
||||
return signal_descriptors + i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(USE_UCONTEXT)
|
||||
static const char * si_code_description_lookup(struct si_code_descriptor * descr_ptr, int si_code)
|
||||
{
|
||||
while (descr_ptr->description != NULL)
|
||||
{
|
||||
if (descr_ptr->code == si_code)
|
||||
{
|
||||
return descr_ptr->description;
|
||||
}
|
||||
|
||||
descr_ptr++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char * si_code_description(struct signal_descriptor * descr_ptr, int si_code)
|
||||
{
|
||||
const char * si_code_str = NULL;
|
||||
|
||||
si_code_str = si_code_description_lookup(sig_any_codes, si_code);
|
||||
if (si_code_str != NULL)
|
||||
{
|
||||
return si_code_str;
|
||||
}
|
||||
|
||||
if (descr_ptr != NULL && descr_ptr->codes != NULL)
|
||||
{
|
||||
return si_code_description_lookup(descr_ptr->codes, si_code);
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
#endif /* #if defined(USE_UCONTEXT) */
|
||||
|
||||
static void dump_siginfo(int signo, siginfo_t * info)
|
||||
{
|
||||
struct signal_descriptor * descr_ptr;
|
||||
|
||||
descr_ptr = lookup_signal_descriptor(signo);
|
||||
if (descr_ptr != NULL)
|
||||
{
|
||||
siginfo_log("%s! (%s)", descr_ptr->msg, descr_ptr->descr);
|
||||
}
|
||||
else
|
||||
{
|
||||
siginfo_log("Unknown bad signal %d catched!", signo);
|
||||
}
|
||||
|
||||
#if defined(USE_UCONTEXT)
|
||||
siginfo_log("info.si_signo = %d", info->si_signo);
|
||||
siginfo_log("info.si_errno = %d", info->si_errno);
|
||||
siginfo_log("info.si_code = %d (%s)", info->si_code, si_code_description(descr_ptr, info->si_code));
|
||||
siginfo_log("info.si_addr = %p", info->si_addr);
|
||||
#else
|
||||
(void)info; /* unused parameter */
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_UCONTEXT)
|
||||
#define REGISTER_NAME_CASE(x) case REG_ ## x: return #x
|
||||
static const char * register_name(size_t i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
#if defined(REG_EIP)
|
||||
REGISTER_NAME_CASE(GS);
|
||||
REGISTER_NAME_CASE(FS);
|
||||
REGISTER_NAME_CASE(ES);
|
||||
REGISTER_NAME_CASE(DS);
|
||||
REGISTER_NAME_CASE(EDI);
|
||||
REGISTER_NAME_CASE(ESI);
|
||||
REGISTER_NAME_CASE(EBP);
|
||||
REGISTER_NAME_CASE(ESP);
|
||||
REGISTER_NAME_CASE(EBX);
|
||||
REGISTER_NAME_CASE(EDX);
|
||||
REGISTER_NAME_CASE(ECX);
|
||||
REGISTER_NAME_CASE(EAX);
|
||||
REGISTER_NAME_CASE(TRAPNO);
|
||||
REGISTER_NAME_CASE(ERR);
|
||||
REGISTER_NAME_CASE(EIP);
|
||||
REGISTER_NAME_CASE(CS);
|
||||
REGISTER_NAME_CASE(EFL);
|
||||
REGISTER_NAME_CASE(UESP);
|
||||
REGISTER_NAME_CASE(SS);
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dump_registers(ucontext_t * ucontext)
|
||||
{
|
||||
size_t index;
|
||||
const char * name;
|
||||
char buffer[64];
|
||||
|
||||
for (index = 0; index < NGREG; index++)
|
||||
{
|
||||
name = register_name(index);
|
||||
if (name == NULL)
|
||||
{
|
||||
snprintf(buffer, sizeof(buffer), "reg[%02d]", (int)index);
|
||||
name = buffer;
|
||||
}
|
||||
|
||||
siginfo_log("%6s = 0x" SIGINFO_REGFORMAT, name, (UINT_PTR_TYPE)SIGINFO_REGISTER(ucontext, index));
|
||||
}
|
||||
}
|
||||
#endif /* #if defined(USE_UCONTEXT) */
|
||||
|
||||
static void signal_handler(int signum, siginfo_t * info, void * ptr)
|
||||
{
|
||||
dump_siginfo(signum, info);
|
||||
#if defined(USE_UCONTEXT)
|
||||
dump_registers(ptr);
|
||||
#endif
|
||||
dump_stack(ptr);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#if defined(SIGINFO_AUTO_INIT)
|
||||
static
|
||||
#endif
|
||||
int setup_siginfo(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
size_t i;
|
||||
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_sigaction = signal_handler;
|
||||
#ifdef SA_SIGINFO
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < sizeof(signal_descriptors) / sizeof(signal_descriptors[0]); i++)
|
||||
{
|
||||
if (sigaction(signal_descriptors[i].signo, &action, NULL) < 0)
|
||||
{
|
||||
siginfo_log("sigaction failed for signal %d. errno is %d (%s)", signal_descriptors[i].signo, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(SIGINFO_AUTO_INIT)
|
||||
static void __attribute((constructor)) init(void)
|
||||
{
|
||||
setup_siginfo();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SIGINFO_TEST)
|
||||
|
||||
void crash_abort(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void crash_access(void)
|
||||
{
|
||||
/* why this doesnt cause FPE? */
|
||||
*((float *)123) = 1000.0 / 0.0;
|
||||
}
|
||||
|
||||
void crash_call(void)
|
||||
{
|
||||
((void (*)(void))(0xDEADBEEF))();
|
||||
}
|
||||
|
||||
static void (* tests [])(void) =
|
||||
{
|
||||
crash_abort,
|
||||
crash_access,
|
||||
crash_call,
|
||||
};
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
setup_siginfo();
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
index = atoi(argv[1]);
|
||||
if (index >= sizeof(tests) / sizeof(tests[0]))
|
||||
{
|
||||
siginfo_log("invalid index %d, using 0 instead", index);
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
tests[index]();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: C ; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Copyright (C) 2012 Nedko Arnaudov
|
||||
*
|
||||
* print out a stack-trace when program segfaults
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* or write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef SIGINFO_H__6CFF6012_DED0_4089_8634_F4515370BD10__INCLUDED
|
||||
#define SIGINFO_H__6CFF6012_DED0_4089_8634_F4515370BD10__INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
int setup_siginfo(void);
|
||||
|
||||
#endif /* #ifndef SIGINFO_H__6CFF6012_DED0_4089_8634_F4515370BD10__INCLUDED */
|
205
daemon/sigsegv.c
205
daemon/sigsegv.c
|
@ -1,205 +0,0 @@
|
|||
/* -*- Mode: C ; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* LADI Session Handler (ladish)
|
||||
*
|
||||
* Copyright (C) 2005 - 2008 Jaco Kroon <jaco@kroon.co.za>
|
||||
*
|
||||
**************************************************************************
|
||||
* This file contains code to print out a stack-trace when program segfaults.
|
||||
**************************************************************************
|
||||
*
|
||||
* LADI Session Handler is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LADI Session Handler 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
|
||||
* or write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define NO_CPP_DEMANGLE
|
||||
#define SIGSEGV_NO_AUTO_INIT
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include <errno.h>
|
||||
#ifndef NO_CPP_DEMANGLE
|
||||
//#include <cxxabi.h>
|
||||
char * __cxa_demangle(const char * __mangled_name, char * __output_buffer, size_t * __length, int * __status);
|
||||
#endif
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#if defined(REG_RIP)
|
||||
# define SIGSEGV_STACK_IA64
|
||||
# define REGFORMAT "%016lx"
|
||||
#elif defined(REG_EIP)
|
||||
# define SIGSEGV_STACK_X86
|
||||
# define REGFORMAT "%08x"
|
||||
#else
|
||||
# define SIGSEGV_STACK_GENERIC
|
||||
# define REGFORMAT "%x"
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) || defined(__powerpc__) || defined (__ia64__) || defined (__alpha__) || defined (__FreeBSD_kernel__) || defined (__sh__)
|
||||
# define DISABLE_STACKTRACE
|
||||
#endif
|
||||
|
||||
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
|
||||
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
|
||||
|
||||
#if !defined(DISABLE_STACKTRACE)
|
||||
size_t i;
|
||||
ucontext_t *ucontext = (ucontext_t*)ptr;
|
||||
|
||||
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
|
||||
int f = 0;
|
||||
Dl_info dlinfo;
|
||||
void **bp = 0;
|
||||
void *ip = 0;
|
||||
#else
|
||||
void *bt[20];
|
||||
char **strings;
|
||||
size_t sz;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (signum == SIGSEGV)
|
||||
{
|
||||
log_error("Segmentation Fault!");
|
||||
}
|
||||
else if (signum == SIGABRT)
|
||||
{
|
||||
log_error("Abort!");
|
||||
}
|
||||
else if (signum == SIGILL)
|
||||
{
|
||||
log_error("Illegal instruction!");
|
||||
}
|
||||
else if (signum == SIGFPE)
|
||||
{
|
||||
log_error("Floating point exception!");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("Unknown bad signal catched!");
|
||||
}
|
||||
|
||||
log_error("info.si_signo = %d", signum);
|
||||
log_error("info.si_errno = %d", info->si_errno);
|
||||
log_error("info.si_code = %d (%s)", info->si_code, si_codes[info->si_code]);
|
||||
log_error("info.si_addr = %p", info->si_addr);
|
||||
#if defined(DISABLE_STACKTRACE)
|
||||
log_error("No stack trace");
|
||||
#else
|
||||
for(i = 0; i < NGREG; i++)
|
||||
{
|
||||
log_error("reg[%02d] = 0x" REGFORMAT, (int)i, ucontext->uc_mcontext.gregs[i]);
|
||||
}
|
||||
|
||||
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
|
||||
# if defined(SIGSEGV_STACK_IA64)
|
||||
ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
|
||||
# elif defined(SIGSEGV_STACK_X86)
|
||||
ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
# endif
|
||||
|
||||
log_error("Stack trace:");
|
||||
while(bp && ip) {
|
||||
if(!dladdr(ip, &dlinfo))
|
||||
break;
|
||||
|
||||
const char *symname = dlinfo.dli_sname;
|
||||
#ifndef NO_CPP_DEMANGLE
|
||||
int status;
|
||||
char *tmp = __cxa_demangle(symname, NULL, 0, &status);
|
||||
|
||||
if(status == 0 && tmp)
|
||||
symname = tmp;
|
||||
#endif
|
||||
|
||||
log_error("% 2d: %p <%s+%u> (%s)",
|
||||
++f,
|
||||
ip,
|
||||
symname,
|
||||
(unsigned)(ip - dlinfo.dli_saddr),
|
||||
dlinfo.dli_fname);
|
||||
|
||||
#ifndef NO_CPP_DEMANGLE
|
||||
if(tmp)
|
||||
free(tmp);
|
||||
#endif
|
||||
|
||||
if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
|
||||
break;
|
||||
|
||||
ip = bp[1];
|
||||
bp = (void**)bp[0];
|
||||
}
|
||||
#else
|
||||
log_error("Stack trace (non-dedicated):");
|
||||
sz = backtrace(bt, 20);
|
||||
strings = backtrace_symbols(bt, sz);
|
||||
|
||||
for(i = 0; i < sz; ++i)
|
||||
log_error("%s", strings[i]);
|
||||
#endif
|
||||
log_error("End of stack trace");
|
||||
#endif
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
int setup_sigsegv() {
|
||||
struct sigaction action;
|
||||
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_sigaction = signal_segv;
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
if(sigaction(SIGSEGV, &action, NULL) < 0) {
|
||||
log_error("sigaction failed. errno is %d (%s)", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sigaction(SIGILL, &action, NULL) < 0) {
|
||||
log_error("sigaction failed. errno is %d (%s)", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sigaction(SIGABRT, &action, NULL) < 0) {
|
||||
log_error("sigaction failed. errno is %d (%s)", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(sigaction(SIGFPE, &action, NULL) < 0) {
|
||||
log_error("sigaction failed. errno is %d (%s)", errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef SIGSEGV_NO_AUTO_INIT
|
||||
static void __attribute((constructor)) init(void) {
|
||||
setup_sigsegv();
|
||||
}
|
||||
#endif
|
|
@ -1,34 +0,0 @@
|
|||
/* -*- Mode: C ; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* LADI Session Handler (ladish)
|
||||
*
|
||||
**************************************************************************
|
||||
* This file contains interface to code that print out a stack-trace when
|
||||
* program segfaults.
|
||||
**************************************************************************
|
||||
*
|
||||
* LADI Session Handler is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LADI Session Handler 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
|
||||
* or write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __SIGSEGV_H__
|
||||
#define __SIGSEGV_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
int setup_sigsegv();
|
||||
|
||||
#endif
|
5
wscript
5
wscript
|
@ -94,7 +94,7 @@ def configure(conf):
|
|||
if parallel_debug:
|
||||
conf.load('parallel_debug')
|
||||
|
||||
# dladdr() is used by daemon/sigsegv.c
|
||||
# dladdr() is used by daemon/siginfo.c
|
||||
# dlvsym() is used by the alsapid library
|
||||
conf.check_cc(msg="Checking for libdl", lib=['dl'], uselib_store='DL')
|
||||
|
||||
|
@ -346,13 +346,14 @@ def build(bld):
|
|||
daemon.ver_header = 'version.h'
|
||||
# Make backtrace function lookup to work for functions in the executable itself
|
||||
daemon.env.append_value("LINKFLAGS", ["-Wl,-E"])
|
||||
daemon.defines = ["HAVE_CONFIG_H"]
|
||||
|
||||
daemon.source = ["string_constants.c"]
|
||||
|
||||
for source in [
|
||||
'main.c',
|
||||
'loader.c',
|
||||
'sigsegv.c',
|
||||
'siginfo.c',
|
||||
'proctitle.c',
|
||||
'appdb.c',
|
||||
'procfs.c',
|
||||
|
|
Loading…
Reference in New Issue