diff --git a/Makefile.src.in b/Makefile.src.in index 78444f0a9c..61276197a1 100644 --- a/Makefile.src.in +++ b/Makefile.src.in @@ -38,11 +38,13 @@ MAKEDEPEND = !!MAKEDEPEND!! CFLAGS_MAKEDEP = !!CFLAGS_MAKEDEP!! SORT = !!SORT!! AWK = !!AWK!! +CONFIGURE_INVOCATION = !!CONFIGURE_INVOCATION!! CONFIG_CACHE_COMPILER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_COMPILER!! CONFIG_CACHE_LINKER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_LINKER!! CONFIG_CACHE_ENDIAN = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_ENDIAN!! CONFIG_CACHE_SOURCE = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_SOURCE!! CONFIG_CACHE_VERSION = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_VERSION!! +CONFIG_CACHE_INVOCATION = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_INVOCATION!! OBJS_C := !!OBJS_C!! OBJS_CPP := !!OBJS_CPP!! @@ -114,6 +116,8 @@ RES := $(shell if [ "`cat $(CONFIG_CACHE_ENDIAN) 2>/dev/null`" != "$(ENDIAN_FORC RES := $(shell if [ "`cat $(CONFIG_CACHE_SOURCE) 2>/dev/null`" != "$(SRCS)" ]; then echo "$(SRCS)" > $(CONFIG_CACHE_SOURCE); fi ) # If there is a change in the revision, make sure we recompile rev.cpp RES := $(shell if [ "`cat $(CONFIG_CACHE_VERSION) 2>/dev/null`" != "$(REV) $(REV_NR) $(MODIFIED)" ]; then echo "$(REV) $(REV_NR) $(MODIFIED)" > $(CONFIG_CACHE_VERSION); fi ) +# If there is a change in the configure invocation, make sure we recompile rev.cpp +RES := $(shell if [ "`cat $(CONFIG_CACHE_INVOCATION) 2>/dev/null`" != "$(CONFIGURE_INVOCATION)" ]; then echo "$(CONFIGURE_INVOCATION)" > $(CONFIG_CACHE_INVOCATION); fi ) ifndef MAKEDEPEND # The slow, but always correct, dep-check @@ -292,8 +296,8 @@ $(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp # Revision files -$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in - $(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/rev.cpp +$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(CONFIG_CACHE_INVOCATION) $(SRC_DIR)/rev.cpp.in + $(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g;s@\!\!CONFIGURE_INVOCATION\!\!@$(CONFIGURE_INVOCATION)@g;" > $(SRC_DIR)/rev.cpp $(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in $(Q)cat $(SRC_DIR)/os/windows/ottdres.rc.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/os/windows/ottdres.rc diff --git a/config.lib b/config.lib index 6e8faf67c4..9548a70938 100644 --- a/config.lib +++ b/config.lib @@ -97,7 +97,7 @@ set_default() { with_sse="1" with_libbfd="1" with_bfd_extra_debug="1" - with_dbg_gdb="1" + with_self_gdb_debug="1" save_params_array=" build @@ -177,7 +177,7 @@ set_default() { with_sse with_libbfd with_bfd_extra_debug - with_dbg_gdb + with_self_gdb_debug CC CXX CFLAGS CXXFLAGS LDFLAGS CFLAGS_BUILD CXXFLAGS_BUILD LDFLAGS_BUILD" } @@ -479,9 +479,9 @@ detect_params() { --with-bfd-extra-debug) with_bfd_extra_debug="1";; --with-bfd-extra-debug=*) with_bfd_extra_debug="$optarg";; - --without-self-gdb-debug) with_dbg_gdb="0";; - --with-self-gdb-debug) with_dbg_gdb="1";; - --with-self-gdb-debug=*) with_dbg_gdb="$optarg";; + --without-self-gdb-debug) with_self_gdb_debug="0";; + --with-self-gdb-debug) with_self_gdb_debug="1";; + --with-self-gdb-debug=*) with_self_gdb_debug="$optarg";; CC=* | --CC=*) CC="$optarg";; CXX=* | --CXX=*) CXX="$optarg";; @@ -513,6 +513,12 @@ detect_params() { # Clean the logfile echo "" > $config_log log 2 "Invocation: $0 $*" + if [ "$ignore_extra_parameters" = "0" -o ! -f config.invocation ]; then + echo "$0 $*" > config.invocation + CONFIGURE_INVOCATION="$0 $*" + else + CONFIGURE_INVOCATION="`cat config.invocation`" + fi } save_params() { @@ -1660,7 +1666,7 @@ EOL fi HAVE_GDB_DBG= - if [ "$with_dbg_gdb" = "1" ]; then + if [ "$with_self_gdb_debug" = "1" ]; then log 2 "executing $cc_host $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.dbggdb -x c++ -" "$cc_host" $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.dbggdb -x c++ - 2> /dev/null << EOL #include @@ -1710,6 +1716,59 @@ EOL CFLAGS="$CFLAGS -g1" fi fi + + log 2 "executing $cc_host $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.sigaction -x c++ - -ldl" + "$cc_host" $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.sigaction -x c++ - -ldl 2> /dev/null << EOL + #include + void *addr; + int code; + void handler(int sig, siginfo_t *si, void *context) { + addr = si->si_addr; + code = si->si_code; + } + int main() { + struct sigaction sa; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = handler; + sigaction(SIGSEGV, &sa, 0); + return 0; + } +EOL + ret=$? + rm -f tmp.config.sigaction + log 2 " exit code $ret" + if [ $ret -ne 0 ]; then + log 1 "checking sigaction... no" + else + log 1 "checking sigaction... found" + CFLAGS="$CFLAGS -DWITH_SIGACTION" + fi + + log 2 "executing $cc_host $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.ucontext -x c++ - -ldl" + "$cc_host" $CFLAGS $LDFLAGS $STATIC_FLAGS -o tmp.config.ucontext -x c++ - -ldl 2> /dev/null << EOL + #include + int main() { + ucontext_t context; +#if defined(__x86_64__) + void *ptr = (void *) context.uc_mcontext.gregs[REG_RIP]; +#elif defined(__i386) + void *ptr = (void *) context.uc_mcontext.gregs[REG_EIP]; +#else +#error Unknown arch +#endif + return 0; + } +EOL + ret=$? + rm -f tmp.config.ucontext + log 2 " exit code $ret" + if [ $ret -ne 0 ]; then + log 1 "checking ucontext... no" + else + log 1 "checking ucontext... found" + CFLAGS="$CFLAGS -DWITH_UCONTEXT" + fi fi if [ "$os" = "MINGW" ]; then @@ -3433,6 +3492,7 @@ make_sed() { s@!!CONFIG_CACHE_VERSION!!@config.cache.version@g; s@!!CONFIG_CACHE_SOURCE_LIST!!@config.cache.source.list@g; s@!!CONFIG_CACHE_PWD!!@config.cache.pwd@g; + s@!!CONFIG_CACHE_INVOCATION!!@config.cache.invocation@g; s@!!LANG_SUPPRESS!!@$lang_suppress@g; s@!!OBJS_C!!@$OBJS_C@g; s@!!OBJS_CPP!!@$OBJS_CPP@g; @@ -3446,6 +3506,7 @@ make_sed() { s@!!DISTCC!!@$distcc@g; s@!!NFORENUM!!@$nforenum@g; s@!!GRFCODEC!!@$grfcodec@g; + s@!!CONFIGURE_INVOCATION!!@$CONFIGURE_INVOCATION@g; " if [ "$icon_theme_dir" != "" ]; then diff --git a/projects/determineversion.vbs b/projects/determineversion.vbs index e738569e3a..82ccde5f2d 100755 --- a/projects/determineversion.vbs +++ b/projects/determineversion.vbs @@ -27,6 +27,7 @@ Sub UpdateFile(modified, revision, version, cur_date, filename) FindReplaceInFile filename, "!!REVISION!!", revision FindReplaceInFile filename, "!!VERSION!!", version FindReplaceInFile filename, "!!DATE!!", cur_date + FindReplaceInFile filename, "!!CONFIGURE_INVOCATION!!", "" End Sub Sub UpdateFiles(version) diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 75e0f6cf0d..28a99bc77f 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -101,6 +101,12 @@ char *CrashLog::LogCompiler(char *buffer, const char *last) const #endif } +/* virtual */ char *CrashLog::LogOSVersionDetail(char *buffer, const char *last) const +{ + /* Stub implementation; not all OSes support this. */ + return buffer; +} + /* virtual */ char *CrashLog::LogRegisters(char *buffer, const char *last) const { /* Stub implementation; not all OSes support this. */ @@ -135,7 +141,8 @@ char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const " Bits: %d\n" " Endian: %s\n" " Dedicated: %s\n" - " Build date: %s\n\n", + " Build date: %s\n" + " Configure: %s\n\n", _openttd_revision, _openttd_revision_modified, _openttd_newgrf_version, @@ -154,7 +161,8 @@ char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const #else "no", #endif - _openttd_build_date + _openttd_build_date, + _openttd_build_configure ); } @@ -343,10 +351,11 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const #endif buffer = this->LogOpenTTDVersion(buffer, last); - buffer = this->LogRegisters(buffer, last); buffer = this->LogStacktrace(buffer, last); + buffer = this->LogRegisters(buffer, last); buffer = this->LogOSVersion(buffer, last); buffer = this->LogCompiler(buffer, last); + buffer = this->LogOSVersionDetail(buffer, last); buffer = this->LogConfiguration(buffer, last); buffer = this->LogLibraries(buffer, last); buffer = this->LogModules(buffer, last); diff --git a/src/crashlog.h b/src/crashlog.h index 7894dea0ad..37ac9ae10e 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -44,6 +44,14 @@ protected: */ virtual char *LogCompiler(char *buffer, const char *last) const; + /** + * Writes OS' version detail to the buffer, if available. + * @param buffer The begin where to write at. + * @param last The last position in the buffer to write to. + * @return the position of the \c '\0' character after the buffer. + */ + virtual char *LogOSVersionDetail(char *buffer, const char *last) const; + /** * Writes actually encountered error to the buffer. * @param buffer The begin where to write at. @@ -127,6 +135,8 @@ public: static void SetErrorMessage(const char *message); static void AfterCrashLogCleanup(); + + inline const char *GetMessage() const { return this->message; } }; #endif /* CRASHLOG_H */ diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index d8f95908b4..8816b70dd1 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -20,14 +20,13 @@ #include #include #include - -#if defined(WITH_DBG_GDB) #include -#include #include -#include #include #include + +#if defined(WITH_DBG_GDB) +#include #endif /* WITH_DBG_GDB */ #if defined(WITH_PRCTL_PT) @@ -55,6 +54,8 @@ #include #endif +#include + #include "../../safeguards.h" #if defined(__GLIBC__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) @@ -72,12 +73,72 @@ static void LogStacktraceSigSegvHandler(int sig) } #endif +static bool ExecReadStdout(const char *file, char *const *args, char *&buffer, const char *last) +{ + int pipefd[2]; + if (pipe(pipefd) == -1) return false; + + int pid = fork(); + if (pid < 0) return false; + + if (pid == 0) { + /* child */ + + close(pipefd[0]); /* Close unused read end */ + dup2(pipefd[1], STDOUT_FILENO); + close(pipefd[1]); + int null_fd = open("/dev/null", O_RDWR); + if (null_fd != -1) { + dup2(null_fd, STDERR_FILENO); + dup2(null_fd, STDIN_FILENO); + } + + execvp(file, args); + exit(42); + } + + /* parent */ + + close(pipefd[1]); /* Close unused write end */ + + while (buffer < last) { + ssize_t res = read(pipefd[0], buffer, last - buffer); + if (res < 0) { + if (errno == EINTR) continue; + break; + } else if (res == 0) { + break; + } else { + buffer += res; + } + } + buffer += seprintf(buffer, last, "\n"); + + close(pipefd[0]); /* close read end */ + + int status; + int wait_ret = waitpid(pid, &status, 0); + if (wait_ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { + /* command did not appear to run successfully */ + return false; + } else { + /* command executed successfully */ + return true; + } +} + /** * Unix implementation for the crash logger. */ class CrashLogUnix : public CrashLog { /** Signal that has been thrown. */ int signum; +#ifdef WITH_SIGACTION + siginfo_t *si; + void *context; + bool signal_instruction_ptr_valid; + void *signal_instruction_ptr; +#endif /* virtual */ char *LogOSVersion(char *buffer, const char *last) const { @@ -99,16 +160,53 @@ class CrashLogUnix : public CrashLog { ); } + /* virtual */ char *LogOSVersionDetail(char *buffer, const char *last) const + { + struct utsname name; + if (uname(&name) < 0) return buffer; + + if (strcmp(name.sysname, "Linux") == 0) { + char *buffer_orig = buffer; + buffer += seprintf(buffer, last, "Distro version:\n"); + + const char *args[] = { "/bin/sh", "-c", "lsb_release -a || find /etc -maxdepth 1 -type f -a \\( -name '*release' -o -name '*version' \\) -exec head -v {} \\+", NULL }; + if (!ExecReadStdout("/bin/sh", const_cast(args), buffer, last)) { + buffer = buffer_orig; + } + } + return buffer; + } + /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const { - return buffer + seprintf(buffer, last, + buffer += seprintf(buffer, last, "Crash reason:\n" - " Signal: %s (%d)\n" - " Message: %s\n\n", + " Signal: %s (%d)\n", strsignal(this->signum), - this->signum, + this->signum); +#ifdef WITH_SIGACTION + if (this->si) { + buffer += seprintf(buffer, last, + " si_code: %d\n", + this->si->si_code); + if (this->signum != SIGABRT) { + buffer += seprintf(buffer, last, + " Fault address: %p\n", + this->si->si_addr); + if (this->signal_instruction_ptr_valid) { + buffer += seprintf(buffer, last, + " Instruction address: %p\n", + this->signal_instruction_ptr); + } + } + } +#endif + buffer += seprintf(buffer, last, + " Message: %s\n\n", message == NULL ? "" : message ); + + return buffer; } #if defined(SUNOS) @@ -145,7 +243,69 @@ class CrashLogUnix : public CrashLog { #endif /** - * Get a stack backtrace of the current thread's stack using the gdb debugger, if available. + * Show registers if possible + * + * Also log GDB information if available + */ + /* virtual */ char *LogRegisters(char *buffer, const char *last) const + { + buffer = LogGdbInfo(buffer, last); + +#ifdef WITH_UCONTEXT + ucontext_t *ucontext = static_cast(context); +#if defined(__x86_64__) + const gregset_t &gregs = ucontext->uc_mcontext.gregs; + buffer += seprintf(buffer, last, + "Registers:\n" + " rax: %#16llx rbx: %#16llx rcx: %#16llx rdx: %#16llx\n" + " rsi: %#16llx rdi: %#16llx rbp: %#16llx rsp: %#16llx\n" + " r8: %#16llx r9: %#16llx r10: %#16llx r11: %#16llx\n" + " r12: %#16llx r13: %#16llx r14: %#16llx r15: %#16llx\n" + " rip: %#16llx eflags: %#8llx\n\n", + gregs[REG_RAX], + gregs[REG_RBX], + gregs[REG_RCX], + gregs[REG_RDX], + gregs[REG_RSI], + gregs[REG_RDI], + gregs[REG_RBP], + gregs[REG_RSP], + gregs[REG_R8], + gregs[REG_R9], + gregs[REG_R10], + gregs[REG_R11], + gregs[REG_R12], + gregs[REG_R13], + gregs[REG_R14], + gregs[REG_R15], + gregs[REG_RIP], + gregs[REG_EFL] + ); +#elif defined(__i386) + const gregset_t &gregs = ucontext->uc_mcontext.gregs; + buffer += seprintf(buffer, last, + "Registers:\n" + " eax: %#8x ebx: %#8x ecx: %#8x edx: %#8x\n" + " esi: %#8x edi: %#8x ebp: %#8x esp: %#8x\n" + " eip: %#8x eflags: %#8x\n\n", + gregs[REG_EAX], + gregs[REG_EBX], + gregs[REG_ECX], + gregs[REG_EDX], + gregs[REG_ESI], + gregs[REG_EDI], + gregs[REG_EBP], + gregs[REG_ESP], + gregs[REG_EIP], + gregs[REG_EFL] + ); +#endif +#endif + return buffer; + } + + /** + * Get a stack backtrace of the current thread's stack and other info using the gdb debugger, if available. * * Using GDB is useful as it knows about inlined functions and locals, and generally can * do a more thorough job than in LogStacktrace. @@ -153,7 +313,7 @@ class CrashLogUnix : public CrashLog { * and there is some potentially useful information in the output from LogStacktrace * which is not in gdb's output. */ - char *LogStacktraceGdb(char *buffer, const char *last) const + char *LogGdbInfo(char *buffer, const char *last) const { #if defined(WITH_DBG_GDB) @@ -163,55 +323,40 @@ class CrashLogUnix : public CrashLog { pid_t tid = syscall(SYS_gettid); - int pipefd[2]; - if (pipe(pipefd) == -1) return buffer; - - int pid = fork(); - if (pid < 0) return buffer; - - if (pid == 0) { - /* child */ - - close(pipefd[0]); /* Close unused read end */ - dup2(pipefd[1], STDOUT_FILENO); - close(pipefd[1]); - int null_fd = open("/dev/null", O_RDWR); - if (null_fd != -1) { - dup2(null_fd, STDERR_FILENO); - dup2(null_fd, STDIN_FILENO); - } - char buffer[16]; - seprintf(buffer, lastof(buffer), "%d", tid); - execlp("gdb", "gdb", "-n", "-p", buffer, "-batch", "-ex", "bt full", NULL); - exit(42); - } - - /* parent */ - - close(pipefd[1]); /* Close unused write end */ - char *buffer_orig = buffer; - - buffer += seprintf(buffer, last, "Stacktrace (GDB):\n"); - while (buffer < last) { - ssize_t res = read(pipefd[0], buffer, last - buffer); - if (res < 0) { - if (errno == EINTR) continue; - break; - } else if (res == 0) { - break; - } else { - buffer += res; - } + buffer += seprintf(buffer, last, "GDB info:\n"); + + char tid_buffer[16]; + char disasm_buffer[32]; + + seprintf(tid_buffer, lastof(tid_buffer), "%d", tid); + + std::vector args; + args.push_back("gdb"); + args.push_back("-n"); + args.push_back("-p"); + args.push_back(tid_buffer); + args.push_back("-batch"); + + args.push_back("-ex"); + args.push_back("echo \\nBacktrace:\\n"); + args.push_back("-ex"); + args.push_back("bt full"); + +#ifdef WITH_SIGACTION + if (this->GetMessage() == NULL && this->signal_instruction_ptr_valid) { + seprintf(disasm_buffer, lastof(disasm_buffer), "x/1i %p", this->signal_instruction_ptr); + args.push_back("-ex"); + args.push_back("set disassembly-flavor intel"); + args.push_back("-ex"); + args.push_back("echo \\nFault instruction:\\n"); + args.push_back("-ex"); + args.push_back(disasm_buffer); } - buffer += seprintf(buffer, last, "\n"); - - close(pipefd[0]); /* close read end */ +#endif - int status; - int wait_ret = waitpid(pid, &status, 0); - if (wait_ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { - /* gdb did not appear to run successfully */ + args.push_back(NULL); + if (!ExecReadStdout("gdb", const_cast(&(args[0])), buffer, last)) { buffer = buffer_orig; } #endif /* WITH_DBG_GDB */ @@ -244,8 +389,6 @@ class CrashLogUnix : public CrashLog { */ /* virtual */ char *LogStacktrace(char *buffer, const char *last) const { - buffer = LogStacktraceGdb(buffer, last); - buffer += seprintf(buffer, last, "Stacktrace:\n"); #if defined(__GLIBC__) @@ -378,10 +521,29 @@ public: * A crash log is always generated by signal. * @param signum the signal that was caused by the crash. */ +#ifdef WITH_SIGACTION + CrashLogUnix(int signum, siginfo_t *si, void *context) : + signum(signum), si(si), context(context) + { + this->signal_instruction_ptr_valid = false; + +#ifdef WITH_UCONTEXT + ucontext_t *ucontext = static_cast(context); +#if defined(__x86_64__) + this->signal_instruction_ptr = (void *) ucontext->uc_mcontext.gregs[REG_RIP]; + this->signal_instruction_ptr_valid = true; +#elif defined(__i386) + this->signal_instruction_ptr = (void *) ucontext->uc_mcontext.gregs[REG_EIP]; + this->signal_instruction_ptr_valid = true; +#endif +#endif /* WITH_UCONTEXT */ + } +#else CrashLogUnix(int signum) : signum(signum) { } +#endif /* WITH_SIGACTION */ }; /** The signals we want our crash handler to handle. */ @@ -392,7 +554,11 @@ static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGI * @note Not static so it shows up in the backtrace. * @param signum the signal that caused us to crash. */ +#ifdef WITH_SIGACTION +static void CDECL HandleCrash(int signum, siginfo_t *si, void *context) +#else static void CDECL HandleCrash(int signum) +#endif { /* Disable all handling of signals by us, so we don't go into infinite loops. */ for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { @@ -412,7 +578,11 @@ static void CDECL HandleCrash(int signum) abort(); } +#ifdef WITH_SIGACTION + CrashLogUnix log(signum, si, context); +#else CrashLogUnix log(signum); +#endif log.MakeCrashLog(); CrashLog::AfterCrashLogCleanup(); @@ -422,6 +592,15 @@ static void CDECL HandleCrash(int signum) /* static */ void CrashLog::InitialiseCrashLog() { for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { +#ifdef WITH_SIGACTION + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = HandleCrash; + sigaction(*i, &sa, NULL); +#else signal(*i, HandleCrash); +#endif } } diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 899a565bbe..1811a6392e 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -49,6 +49,12 @@ const char _openttd_revision[] = "!!VERSION!!"; */ const char _openttd_build_date[] = __DATE__ " " __TIME__; + +/** + * The configure invocation used to build OpenTTD + */ +const char _openttd_build_configure[] = "!!CONFIGURE_INVOCATION!!"; + /** * Let us know if current build was modified. This detection * works even in the case when revision string is overridden by diff --git a/src/rev.h b/src/rev.h index d31dbb51cc..68e19a3632 100644 --- a/src/rev.h +++ b/src/rev.h @@ -14,6 +14,7 @@ extern const char _openttd_revision[]; extern const char _openttd_build_date[]; +extern const char _openttd_build_configure[]; extern const byte _openttd_revision_modified; extern const uint32 _openttd_newgrf_version; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 5a6454f099..0183cd493e 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -304,12 +304,20 @@ static void InitializeWindowsAndCaches() BuildOwnerLegend(); } +#ifdef WITH_SIGACTION +static struct sigaction _prev_segfault; +static struct sigaction _prev_abort; +static struct sigaction _prev_fpe; + +static void CDECL HandleSavegameLoadCrash(int signum, siginfo_t *si, void *context); +#else typedef void (CDECL *SignalHandlerPointer)(int); static SignalHandlerPointer _prev_segfault = NULL; static SignalHandlerPointer _prev_abort = NULL; static SignalHandlerPointer _prev_fpe = NULL; static void CDECL HandleSavegameLoadCrash(int signum); +#endif /** * Replaces signal handlers of SIGSEGV and SIGABRT @@ -317,9 +325,20 @@ static void CDECL HandleSavegameLoadCrash(int signum); */ static void SetSignalHandlers() { +#ifdef WITH_SIGACTION + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = HandleSavegameLoadCrash; + sigaction(SIGSEGV, &sa, &_prev_segfault); + sigaction(SIGABRT, &sa, &_prev_abort); + sigaction(SIGFPE, &sa, &_prev_fpe); +#else _prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash); _prev_abort = signal(SIGABRT, HandleSavegameLoadCrash); _prev_fpe = signal(SIGFPE, HandleSavegameLoadCrash); +#endif } /** @@ -327,9 +346,15 @@ static void SetSignalHandlers() */ static void ResetSignalHandlers() { +#ifdef WITH_SIGACTION + sigaction(SIGSEGV, &_prev_segfault, NULL); + sigaction(SIGABRT, &_prev_abort, NULL); + sigaction(SIGFPE, &_prev_fpe, NULL); +#else signal(SIGSEGV, _prev_segfault); signal(SIGABRT, _prev_abort); signal(SIGFPE, _prev_fpe); +#endif } /** @@ -369,7 +394,11 @@ bool SaveloadCrashWithMissingNewGRFs() * NewGRFs that are required by the savegame. * @param signum received signal */ +#ifdef WITH_SIGACTION +static void CDECL HandleSavegameLoadCrash(int signum, siginfo_t *si, void *context) +#else static void CDECL HandleSavegameLoadCrash(int signum) +#endif { ResetSignalHandlers(); @@ -416,14 +445,27 @@ static void CDECL HandleSavegameLoadCrash(int signum) ShowInfo(buffer); +#ifdef WITH_SIGACTION + struct sigaction call; +#else SignalHandlerPointer call = NULL; +#endif switch (signum) { case SIGSEGV: call = _prev_segfault; break; case SIGABRT: call = _prev_abort; break; case SIGFPE: call = _prev_fpe; break; default: NOT_REACHED(); } +#ifdef WITH_SIGACTION + if (call.sa_flags & SA_SIGINFO) { + if (call.sa_sigaction != NULL) call.sa_sigaction(signum, si, context); + } else { + if (call.sa_handler != NULL) call.sa_handler(signum); + } +#else if (call != NULL) call(signum); +#endif + } /**