mirror of
git://git.savannah.nongnu.org/eliot.git
synced 2024-12-25 21:59:30 +01:00
Print to stderr the complete stack trace in case of exception or segmentation fault.
This feature will only be activated in debug mode, and if available on the platform. The symbols will even be demangled if possible (i.e. if compiled with g++).
This commit is contained in:
parent
892d0ae0cb
commit
c3785555b9
13 changed files with 353 additions and 37 deletions
|
@ -22,6 +22,9 @@ AC_PROG_MAKE_SET
|
|||
AC_PROG_RANLIB
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_CHECK_HEADERS_ONCE(execinfo.h)
|
||||
AX_CXX_GCC_ABI_DEMANGLE
|
||||
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Checks for compilation flags
|
||||
dnl --------------------------------------------------------------
|
||||
|
|
|
@ -23,6 +23,7 @@ localedir = $(datadir)/locale
|
|||
AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -I$(top_srcdir) -I../intl -I$(top_srcdir)/intl $(INCICONV)
|
||||
|
||||
libdic_a_SOURCES = \
|
||||
base_exception.cpp base_exception.h \
|
||||
dic_exception.cpp dic_exception.h \
|
||||
header.cpp header.h \
|
||||
dic_internals.h \
|
||||
|
@ -30,6 +31,7 @@ libdic_a_SOURCES = \
|
|||
dic.cpp dic.h \
|
||||
dic_search.cpp \
|
||||
encoding.cpp encoding.h \
|
||||
stacktrace.cpp stacktrace.h \
|
||||
automaton.cpp automaton.h \
|
||||
regexp.cpp regexp.h \
|
||||
grammar.cpp grammar.h \
|
||||
|
|
44
dic/base_exception.cpp
Normal file
44
dic/base_exception.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#include "base_exception.h"
|
||||
#include "stacktrace.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
BaseException::BaseException(const string &iMessage)
|
||||
: m_message(iMessage)
|
||||
{
|
||||
m_stack = StackTrace::GetStack();
|
||||
}
|
||||
|
||||
|
||||
const char *BaseException::what() const throw()
|
||||
{
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
|
||||
string BaseException::getStackTrace() const
|
||||
{
|
||||
return m_stack;
|
||||
}
|
||||
|
46
dic/base_exception.h
Normal file
46
dic/base_exception.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef BASE_EXCEPTION_H_
|
||||
#define BASE_EXCEPTION_H_
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
|
||||
/**
|
||||
* Base exception class for all the exception classes in Eliot.
|
||||
* It provides a stack trace.
|
||||
*/
|
||||
class BaseException: public std::exception
|
||||
{
|
||||
public:
|
||||
BaseException(const std::string &iMessage);
|
||||
~BaseException() throw() {}
|
||||
virtual const char *what() const throw();
|
||||
|
||||
std::string getStackTrace() const;
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
std::string m_stack;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2007 Olivier Teulière
|
||||
* Copyright (C) 2007-2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -24,17 +24,11 @@ using namespace std;
|
|||
|
||||
|
||||
DicException::DicException(const string &iMessage)
|
||||
: m_message(iMessage)
|
||||
: BaseException(iMessage)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const char *DicException::what() const throw()
|
||||
{
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
|
||||
InvalidRegexpException::InvalidRegexpException(const string &iMessage)
|
||||
: DicException(iMessage)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2007 Olivier Teulière
|
||||
* Copyright (C) 2007-2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -21,24 +21,19 @@
|
|||
#ifndef DIC_EXCEPTION_H_
|
||||
#define DIC_EXCEPTION_H_
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include "base_exception.h"
|
||||
|
||||
|
||||
/**
|
||||
* Exception class for the dictionary.
|
||||
* It simply inherits from the standard exception and overrides
|
||||
* It simply inherits from the base exception and overrides
|
||||
* its what() method.
|
||||
*/
|
||||
class DicException: public std::exception
|
||||
class DicException: public BaseException
|
||||
{
|
||||
public:
|
||||
DicException(const std::string &iMessage);
|
||||
~DicException() throw() {}
|
||||
virtual const char *what() const throw();
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
|
||||
|
@ -46,7 +41,6 @@ class InvalidRegexpException : public DicException
|
|||
{
|
||||
public:
|
||||
InvalidRegexpException(const std::string &iMessage);
|
||||
~InvalidRegexpException() throw() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
91
dic/stacktrace.cpp
Normal file
91
dic/stacktrace.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "stacktrace.h"
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
# include <execinfo.h>
|
||||
#endif
|
||||
#ifdef HAVE_GCC_ABI_DEMANGLE
|
||||
# include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
string StackTrace::GetStack()
|
||||
{
|
||||
#if defined HAVE_EXECINFO_H && defined(DEBUG)
|
||||
static const int MAX_FRAMES = 42;
|
||||
void *frames[MAX_FRAMES];
|
||||
// Get the frames
|
||||
int nb = backtrace(frames, MAX_FRAMES);
|
||||
// Get the corresponding symbols (ignoring the first frame)
|
||||
char **symbols = backtrace_symbols(frames + 1, nb - 1);
|
||||
// Demangle the symbols and build a nice stack trace
|
||||
ostringstream oss;
|
||||
for (int i = 0; i < nb - 1; ++i)
|
||||
{
|
||||
oss << " at " << Demangle(symbols[i]) << endl;
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// See http://tombarta.wordpress.com/2008/08/01/c-stack-traces-with-gcc/
|
||||
// and http://mykospark.net/2009/09/runtime-backtrace-in-c-with-name-demangling/
|
||||
// for more details
|
||||
string StackTrace::Demangle(char *symbol)
|
||||
{
|
||||
#if defined HAVE_GCC_ABI_DEMANGLE && defined(DEBUG)
|
||||
char temp1[200];
|
||||
char temp2[200];
|
||||
if (sscanf(symbol, "%199[^(]%*[^_]%199[^)+]", temp1, temp2) == 2)
|
||||
{
|
||||
// Try to demangle a C++ name
|
||||
int status;
|
||||
char *demangled = abi::__cxa_demangle(temp2, NULL, NULL, &status);
|
||||
if (demangled != NULL)
|
||||
{
|
||||
string result = temp1 + string(": ") + demangled;
|
||||
free(demangled);
|
||||
return result;
|
||||
}
|
||||
// Try to demangle a C name
|
||||
else if (sscanf(symbol, "%199s", temp2) == 1)
|
||||
{
|
||||
return temp1 + string(": ") + temp2;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else failed, return the symbol
|
||||
#endif
|
||||
return symbol;
|
||||
}
|
38
dic/stacktrace.h
Normal file
38
dic/stacktrace.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef STACK_TRACE_H_
|
||||
#define STACK_TRACE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
class StackTrace
|
||||
{
|
||||
public:
|
||||
static string GetStack();
|
||||
|
||||
private:
|
||||
static string Demangle(char *symbol);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2007 Olivier Teulière
|
||||
* Copyright (C) 2007-2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -24,17 +24,11 @@ using namespace std;
|
|||
|
||||
|
||||
GameException::GameException(const string &iMessage)
|
||||
: m_message(iMessage)
|
||||
: BaseException(iMessage)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const char *GameException::what() const throw()
|
||||
{
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
|
||||
EndGameException::EndGameException(const string &iMessage)
|
||||
: GameException(iMessage)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
* Eliot
|
||||
* Copyright (C) 2007 Olivier Teulière
|
||||
* Copyright (C) 2007-2010 Olivier Teulière
|
||||
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -21,24 +21,19 @@
|
|||
#ifndef GAME_EXCEPTION_H_
|
||||
#define GAME_EXCEPTION_H_
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include "base_exception.h"
|
||||
|
||||
|
||||
/**
|
||||
* Exception class for the Game library.
|
||||
* It simply inherits from the standard exception and overrides
|
||||
* It simply inherits from the base exception and overrides
|
||||
* its what() method.
|
||||
*/
|
||||
class GameException: public std::exception
|
||||
class GameException: public BaseException
|
||||
{
|
||||
public:
|
||||
GameException(const std::string &iMessage);
|
||||
~GameException() throw() {}
|
||||
virtual const char *what() const throw();
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
|
||||
|
|
58
m4/ax_cxx_gcc_abi_demangle.m4
Normal file
58
m4/ax_cxx_gcc_abi_demangle.m4
Normal file
|
@ -0,0 +1,58 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_gcc_abi_demangle.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_GCC_ABI_DEMANGLE
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# If the compiler supports GCC C++ ABI name demangling (has header
|
||||
# cxxabi.h and abi::__cxa_demangle() function), define
|
||||
# HAVE_GCC_ABI_DEMANGLE
|
||||
#
|
||||
# Adapted from AX_CXX_RTTI by Luc Maisonobe
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Neil Ferguson <nferguso@eso.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 8
|
||||
|
||||
AC_DEFUN([AX_CXX_GCC_ABI_DEMANGLE],
|
||||
[AC_CACHE_CHECK(whether the compiler supports GCC C++ ABI name demangling,
|
||||
ax_cv_cxx_gcc_abi_demangle,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_TRY_COMPILE([#include <typeinfo>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
template<typename TYPE>
|
||||
class A {};
|
||||
],[A<int> instance;
|
||||
int status = 0;
|
||||
char* c_name = 0;
|
||||
|
||||
c_name = abi::__cxa_demangle(typeid(instance).name(), 0, 0, &status);
|
||||
|
||||
std::string name(c_name);
|
||||
free(c_name);
|
||||
|
||||
return name == "A<int>";
|
||||
],
|
||||
ax_cv_cxx_gcc_abi_demangle=yes, ax_cv_cxx_gcc_abi_demangle=no)
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
if test "$ax_cv_cxx_gcc_abi_demangle" = yes; then
|
||||
AC_DEFINE(HAVE_GCC_ABI_DEMANGLE,1,
|
||||
[define if the compiler supports GCC C++ ABI name demangling])
|
||||
fi
|
||||
])
|
|
@ -104,6 +104,8 @@ BUILT_SOURCES = $(nodist_eliot_SOURCES)
|
|||
MOSTLYCLEANFILES = $(nodist_eliot_SOURCES)
|
||||
|
||||
eliot_LDADD = ../game/libgame.a ../dic/libdic.a @QT_LIBS@ @LIBINTL@ @LIBCONFIG_LIBS@ @ARABICA_LIBS@ @EXPAT_LDFLAGS@
|
||||
# Needed for proper stack trace handling
|
||||
eliot_LDFLAGS = -rdynamic
|
||||
|
||||
# Generate a cpp file from the resources
|
||||
resources.cpp: eliot.qrc $(RESOURCES)
|
||||
|
|
59
qt/main.cpp
59
qt/main.cpp
|
@ -21,9 +21,13 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <QApplication>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
#include "base_exception.h"
|
||||
#include "stacktrace.h"
|
||||
#include "main_window.h"
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
|
@ -32,11 +36,48 @@
|
|||
# include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
# include <signal.h>
|
||||
# include <execinfo.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
static void bt_sighandler(int);
|
||||
|
||||
// Custom QApplication to catch and log exceptions properly
|
||||
// See http://forum.qtfr.org/viewtopic.php?id=7615
|
||||
class MyApplication : public QApplication
|
||||
{
|
||||
public:
|
||||
MyApplication(int argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
{}
|
||||
|
||||
virtual bool notify(QObject *receiver, QEvent *event)
|
||||
{
|
||||
try
|
||||
{
|
||||
return QApplication::notify(receiver, event);
|
||||
}
|
||||
catch (const BaseException &e)
|
||||
{
|
||||
cerr << "Exception caught: " << e.what() << endl;
|
||||
cerr << e.getStackTrace() << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
// Install a custom signal handler to print a backtrace when crashing
|
||||
// See http://www.linuxjournal.com/article/6391 for inspiration
|
||||
signal(SIGSEGV, &bt_sighandler);
|
||||
#endif
|
||||
|
||||
// On Mac, running Eliot from the dock does not automatically set the LANG
|
||||
// variable, so we do it ourselves.
|
||||
// Note: The following block of code is copied from VLC, and slightly
|
||||
|
@ -77,7 +118,7 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
MyApplication app(argc, argv);
|
||||
app.setWindowIcon(QIcon(":/images/eliot.xpm"));
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
|
@ -121,3 +162,17 @@ int main(int argc, char **argv)
|
|||
qmain.show();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
static void bt_sighandler(int signum)
|
||||
{
|
||||
cerr << "Segmentation fault!" << endl;
|
||||
cerr << "Backtrace:" << endl;
|
||||
cerr << StackTrace::GetStack() << endl;
|
||||
|
||||
// Restore the default handler to generate a nice core dump
|
||||
signal(signum, SIG_DFL);
|
||||
raise(signum);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue