From 2d98fbb90c881a8d18cd1d6bb66d9b486387e7db Mon Sep 17 00:00:00 2001 From: Tim Felgentreff <tim.felgentreff@oracle.com> Date: Sat, 6 Apr 2019 11:08:00 +0200 Subject: [PATCH] always print stack information on errors --- src/include/st_backtrace.h | 68 ++++++++++++++++++++++++ src/stratagus/stratagus.cpp | 102 ++++++++++++++++++------------------ src/stratagus/util.cpp | 3 ++ 3 files changed, 122 insertions(+), 51 deletions(-) create mode 100644 src/include/st_backtrace.h diff --git a/src/include/st_backtrace.h b/src/include/st_backtrace.h new file mode 100644 index 000000000..69ed2f30d --- /dev/null +++ b/src/include/st_backtrace.h @@ -0,0 +1,68 @@ +#ifndef ST_BACKTRACE_H +#define ST_BACKTRACE_H 1 + +#include "stdio.h" + +#ifdef __GLIBC__ + +#include "execinfo.h" +inline void print_backtrace(void) { + int j, nptrs; + void *buffer[100]; + nptrs = backtrace(buffer, 100); + fprintf(stderr, "backtrace() returned %d addresses\n", nptrs); + backtrace_symbols_fd(buffer, 100, 2); +} + +#elif defined(USE_WIN32) + +#include "windows.h" +#include "dbghelp.h" +#include "process.h" + +inline void print_backtrace(void) { + unsigned int i; + void *stack[100]; + unsigned short frames; + SYMBOL_INFO *symbol; + HANDLE process; + DWORD displacement; + IMAGEHLP_LINE64 *line; + char* name; + + process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + frames = CaptureStackBackTrace(0, 100, stack, NULL); + fprintf(stderr, "backtrace returned %d addresses\n", frames); + symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); + symbol->MaxNameLen = 1024; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + + line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64)); + line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + for(i = 0; i < frames; i++) { + SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); + if (symbol->Name) { + name = symbol->Name; + } else { + name = "<unknown frame>"; + } + if (SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &displacement, line)) { + fprintf("%d: %s in %s:%d 0x%x\n", frames - i - 1, name, line->FileName, line->LineNumber, symbol->Address); + } else { + fprintf("%d: %s 0x%x\n", frames - i - 1, name, symbol->Address); + } + } + free(symbol); +} + +#else + +inline void print_backtrace(void) { +} + +#endif + + +#endif diff --git a/src/stratagus/stratagus.cpp b/src/stratagus/stratagus.cpp index 750ab9288..bd5857224 100644 --- a/src/stratagus/stratagus.cpp +++ b/src/stratagus/stratagus.cpp @@ -210,6 +210,8 @@ extern void beos_init(int argc, char **argv); #include <stdexcept> #include <stacktrace/call_stack.hpp> #include <stacktrace/stack_exception.hpp> +#else +#include "st_backtrace.h" #endif #include <stdlib.h> @@ -434,6 +436,8 @@ void ExitFatal(int err) { #ifdef USE_STACKTRACE throw stacktrace::stack_runtime_error((const char*)err); +#else + print_backtrace(); #endif exit(err); } @@ -577,7 +581,7 @@ void ParseCommandLine(int argc, char **argv, Parameters ¶meters) if (ZoomNoResize) { fprintf(stderr, "Error: -Z only works with OpenGL enabled\n"); Usage(); - ExitFatal(-1); + exit(-1); } continue; case 'O': @@ -605,7 +609,7 @@ void ParseCommandLine(int argc, char **argv, Parameters ¶meters) if (!sep || !*(sep + 1)) { fprintf(stderr, "%s: incorrect format of video mode resolution -- '%s'\n", argv[0], optarg); Usage(); - ExitFatal(-1); + exit(-1); } Video.ViewportHeight = atoi(sep + 1); *sep = 0; @@ -613,7 +617,7 @@ void ParseCommandLine(int argc, char **argv, Parameters ¶meters) if (!Video.ViewportHeight || !Video.ViewportWidth) { fprintf(stderr, "%s: incorrect format of video mode resolution -- '%sx%s'\n", argv[0], optarg, sep + 1); Usage(); - ExitFatal(-1); + exit(-1); } #if defined(USE_OPENGL) || defined(USE_GLES) if (!ZoomNoResize) { @@ -647,7 +651,7 @@ void ParseCommandLine(int argc, char **argv, Parameters ¶meters) if (!sep || !*(sep + 1)) { fprintf(stderr, "%s: incorrect format of video mode resolution -- '%s'\n", argv[0], optarg); Usage(); - ExitFatal(-1); + exit(-1); } Video.Height = atoi(sep + 1); *sep = 0; @@ -660,7 +664,7 @@ void ParseCommandLine(int argc, char **argv, Parameters ¶meters) case 'h': default: Usage(); - ExitFatal(-1); + exit(-1); } break; } @@ -731,72 +735,69 @@ int stratagusMain(int argc, char **argv) Assert(pathPtr); StratagusLibPath = pathPtr; #endif -#ifdef USE_STACKTRACE try { -#endif - Parameters ¶meters = Parameters::Instance; - parameters.SetDefaultValues(); - parameters.SetLocalPlayerNameFromEnv(); + Parameters ¶meters = Parameters::Instance; + parameters.SetDefaultValues(); + parameters.SetLocalPlayerNameFromEnv(); #ifdef REDIRECT_OUTPUT - RedirectOutput(); + RedirectOutput(); #endif - if (argc > 0) { - parameters.applicationName = argv[0]; - } + if (argc > 0) { + parameters.applicationName = argv[0]; + } - // FIXME: Parse options before or after scripts? - ParseCommandLine(argc, argv, parameters); - // Init the random number generator. - InitSyncRand(); + // FIXME: Parse options before or after scripts? + ParseCommandLine(argc, argv, parameters); + // Init the random number generator. + InitSyncRand(); - makedir(parameters.GetUserDirectory().c_str(), 0777); + makedir(parameters.GetUserDirectory().c_str(), 0777); - // Init Lua and register lua functions! - InitLua(); - LuaRegisterModules(); + // Init Lua and register lua functions! + InitLua(); + LuaRegisterModules(); - // Initialise AI module - InitAiModule(); + // Initialise AI module + InitAiModule(); - LoadCcl(parameters.luaStartFilename, parameters.luaScriptArguments); + LoadCcl(parameters.luaStartFilename, parameters.luaScriptArguments); - PrintHeader(); - PrintLicense(); + PrintHeader(); + PrintLicense(); - // Setup video display - InitVideo(); + // Setup video display + InitVideo(); - // Setup sound card - if (!InitSound()) { - InitMusic(); - } + // Setup sound card + if (!InitSound()) { + InitMusic(); + } #ifndef DEBUG // For debug it's better not to have: - srand(time(NULL)); // Random counter = random each start + srand(time(NULL)); // Random counter = random each start #endif - // Show title screens. - SetDefaultTextColors(FontYellow, FontWhite); - LoadFonts(); - SetClipping(0, 0, Video.Width - 1, Video.Height - 1); - Video.ClearScreen(); - ShowTitleScreens(); + // Show title screens. + SetDefaultTextColors(FontYellow, FontWhite); + LoadFonts(); + SetClipping(0, 0, Video.Width - 1, Video.Height - 1); + Video.ClearScreen(); + ShowTitleScreens(); - // Init player data - ThisPlayer = NULL; - //Don't clear the Players structure as it would erase the allowed units. - // memset(Players, 0, sizeof(Players)); - NumPlayers = 0; + // Init player data + ThisPlayer = NULL; + //Don't clear the Players structure as it would erase the allowed units. + // memset(Players, 0, sizeof(Players)); + NumPlayers = 0; - UnitManager.Init(); // Units memory management - PreMenuSetup(); // Load everything needed for menus + UnitManager.Init(); // Units memory management + PreMenuSetup(); // Load everything needed for menus - MenuLoop(); + MenuLoop(); - Exit(0); -#ifdef USE_STACKTRACE + Exit(0); } catch (const std::exception &e) { fprintf(stderr, "Stratagus crashed!\n"); fprintf(stderr, "Please send this call stack to our bug tracker: https://github.com/Wargus/stratagus/issues\n"); @@ -805,7 +806,6 @@ int stratagusMain(int argc, char **argv) fprintf(stderr, "%s", e.what()); exit(1); } -#endif return 0; } diff --git a/src/stratagus/util.cpp b/src/stratagus/util.cpp index 72da69069..f866edfca 100644 --- a/src/stratagus/util.cpp +++ b/src/stratagus/util.cpp @@ -45,6 +45,8 @@ #include <stdexcept> #include <stacktrace/call_stack.hpp> #include <stacktrace/stack_exception.hpp> +#else +#include "st_backtrace.h" #endif #ifdef USE_X11 @@ -530,6 +532,7 @@ void AbortAt(const char *file, int line, const char *funcName, const char *condi throw stacktrace::stack_runtime_error((const char*)buf); #else fprintf(stderr, "%s\n", buf); + print_backtrace(); #endif fflush(stdout); fflush(stderr);