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 &parameters)
 				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 &parameters)
 				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 &parameters)
 				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 &parameters)
 				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 &parameters)
 			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 &parameters = Parameters::Instance;
-	parameters.SetDefaultValues();
-	parameters.SetLocalPlayerNameFromEnv();
+		Parameters &parameters = 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);