- added stack trace for windows users when exceptions occur (snagged the idea from sauerbraten)
This commit is contained in:
parent
7c47a51718
commit
8ab95a5305
|
@ -107,6 +107,8 @@ public:
|
||||||
static const char *RANDOMFACTION_SLOTNAME;
|
static const char *RANDOMFACTION_SLOTNAME;
|
||||||
|
|
||||||
static const char *playerTextureCacheLookupKey;
|
static const char *playerTextureCacheLookupKey;
|
||||||
|
|
||||||
|
static const char *application_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PathType {
|
enum PathType {
|
||||||
|
|
|
@ -46,6 +46,7 @@ const char *GameConstants::OBSERVER_SLOTNAME = "*Observer*";
|
||||||
const char *GameConstants::RANDOMFACTION_SLOTNAME = "*Random*";
|
const char *GameConstants::RANDOMFACTION_SLOTNAME = "*Random*";
|
||||||
|
|
||||||
const char *GameConstants::playerTextureCacheLookupKey = "playerTextureCache";
|
const char *GameConstants::playerTextureCacheLookupKey = "playerTextureCache";
|
||||||
|
const char *GameConstants::application_name = "MegaGlest";
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// class Config
|
// class Config
|
||||||
|
|
|
@ -35,6 +35,12 @@
|
||||||
#include "sound_renderer.h"
|
#include "sound_renderer.h"
|
||||||
#include "font_gl.h"
|
#include "font_gl.h"
|
||||||
#include "cache_manager.h"
|
#include "cache_manager.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <eh.h>
|
||||||
|
#include <DbgHelp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "leak_dumper.h"
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
@ -43,6 +49,16 @@
|
||||||
#define _strnicmp strncasecmp
|
#define _strnicmp strncasecmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#ifndef _DEBUG
|
||||||
|
#ifndef __GNUC__
|
||||||
|
|
||||||
|
#define WIN32_STACK_TRACE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Shared::Platform;
|
using namespace Shared::Platform;
|
||||||
using namespace Shared::Util;
|
using namespace Shared::Util;
|
||||||
|
@ -82,6 +98,60 @@ enum GAME_ARG_TYPE {
|
||||||
GAME_ARG_VALIDATE_FACTIONS
|
GAME_ARG_VALIDATE_FACTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
|
||||||
|
void fatal(const char *s, ...) // failure exit
|
||||||
|
{
|
||||||
|
static int errors = 0;
|
||||||
|
errors++;
|
||||||
|
|
||||||
|
if(errors <= 3) { // print up to two extra recursive errors
|
||||||
|
defvformatstring(msg,s,s);
|
||||||
|
//puts(msg);
|
||||||
|
string sErr = string(GameConstants::application_name) + " fatal error";
|
||||||
|
SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",msg);
|
||||||
|
|
||||||
|
if(errors <= 1) { // avoid recursion
|
||||||
|
if(SDL_WasInit(SDL_INIT_VIDEO)) {
|
||||||
|
SDL_ShowCursor(1);
|
||||||
|
SDL_WM_GrabInput(SDL_GRAB_OFF);
|
||||||
|
SDL_SetGamma(1, 1, 1);
|
||||||
|
}
|
||||||
|
#ifdef WIN32
|
||||||
|
MessageBox(NULL, msg, sErr.c_str(), MB_OK|MB_SYSTEMMODAL);
|
||||||
|
#endif
|
||||||
|
//SDL_Quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep) {
|
||||||
|
if(!ep) fatal("unknown type");
|
||||||
|
EXCEPTION_RECORD *er = ep->ExceptionRecord;
|
||||||
|
CONTEXT *context = ep->ContextRecord;
|
||||||
|
stringType out, t;
|
||||||
|
formatstring(out)("%s Exception: 0x%x [0x%x]\n\n", GameConstants::application_name, er->ExceptionCode, er->ExceptionCode==EXCEPTION_ACCESS_VIOLATION ? er->ExceptionInformation[1] : -1);
|
||||||
|
STACKFRAME sf = {{context->Eip, 0, AddrModeFlat}, {}, {context->Ebp, 0, AddrModeFlat}, {context->Esp, 0, AddrModeFlat}, 0};
|
||||||
|
SymInitialize(GetCurrentProcess(), NULL, TRUE);
|
||||||
|
|
||||||
|
while(::StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &sf, context, NULL, ::SymFunctionTableAccess, ::SymGetModuleBase, NULL)) {
|
||||||
|
struct { IMAGEHLP_SYMBOL sym; stringType n; }
|
||||||
|
si = { { sizeof( IMAGEHLP_SYMBOL ), 0, 0, 0, sizeof(stringType) } };
|
||||||
|
IMAGEHLP_LINE li = { sizeof( IMAGEHLP_LINE ) };
|
||||||
|
DWORD off=0;
|
||||||
|
DWORD dwDisp=0;
|
||||||
|
if( SymGetSymFromAddr(GetCurrentProcess(), (DWORD)sf.AddrPC.Offset, &off, &si.sym) &&
|
||||||
|
SymGetLineFromAddr(GetCurrentProcess(), (DWORD)sf.AddrPC.Offset, &dwDisp, &li)) {
|
||||||
|
char *del = strrchr(li.FileName, '\\');
|
||||||
|
formatstring(t)("%s - %s [%d]\n", si.sym.Name, del ? del + 1 : li.FileName, li.LineNumber+dwDisp);
|
||||||
|
concatstring(out, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fatal(out);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// class ExceptionHandler
|
// class ExceptionHandler
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
@ -89,10 +159,10 @@ enum GAME_ARG_TYPE {
|
||||||
class ExceptionHandler: public PlatformExceptionHandler{
|
class ExceptionHandler: public PlatformExceptionHandler{
|
||||||
public:
|
public:
|
||||||
virtual void handle() {
|
virtual void handle() {
|
||||||
string msg = "#1 An error ocurred and Glest will close.\nPlease report this bug to "+mailString;
|
string msg = "#1 An error ocurred and " + string(GameConstants::application_name) + " will close.\nPlease report this bug to "+mailString;
|
||||||
#ifdef WIN32
|
//#ifdef WIN32
|
||||||
msg += ", attaching the generated "+getCrashDumpFileName()+" file.";
|
// msg += ", attaching the generated " + getCrashDumpFileName()+ " file.";
|
||||||
#endif
|
//#endif
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",msg.c_str());
|
SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",msg.c_str());
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",msg.c_str());
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",msg.c_str());
|
||||||
|
|
||||||
|
@ -116,7 +186,7 @@ public:
|
||||||
program->showMessage(msg);
|
program->showMessage(msg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string err = "#2 An error ocurred and Glest will close.\nError msg = [" + (msg != NULL ? string(msg) : string("?")) + "]\n\nPlease report this bug to "+mailString;
|
string err = "#2 An error ocurred and " + string(GameConstants::application_name) + " will close.\nError msg = [" + (msg != NULL ? string(msg) : string("?")) + "]\n\nPlease report this bug to "+mailString;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
err += string(", attaching the generated ") + getCrashDumpFileName() + string(" file.");
|
err += string(", attaching the generated ") + getCrashDumpFileName() + string(" file.");
|
||||||
#endif
|
#endif
|
||||||
|
@ -382,7 +452,7 @@ void MainWindow::eventKeyDown(char key){
|
||||||
|
|
||||||
for(int i=0; i < 250; ++i) {
|
for(int i=0; i < 250; ++i) {
|
||||||
path = GameConstants::folder_path_screenshots;
|
path = GameConstants::folder_path_screenshots;
|
||||||
path += "screen" + intToStr(i + queueSize) + "." + fileFormat;
|
path += string("screen") + intToStr(i + queueSize) + string(".") + fileFormat;
|
||||||
FILE *f= fopen(path.c_str(), "rb");
|
FILE *f= fopen(path.c_str(), "rb");
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
Renderer::getInstance().saveScreen(path);
|
Renderer::getInstance().saveScreen(path);
|
||||||
|
@ -520,8 +590,8 @@ void printParameterHelp(const char *argv0, bool foundInvalidArgs) {
|
||||||
printf("\n \t\texample: %s %s=tech,egypt",argv0,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]);
|
printf("\n \t\texample: %s %s=tech,egypt",argv0,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]);
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
}
|
}
|
||||||
int glestMain(int argc, char** argv){
|
|
||||||
|
|
||||||
|
int glestMain(int argc, char** argv) {
|
||||||
#ifdef SL_LEAK_DUMP
|
#ifdef SL_LEAK_DUMP
|
||||||
AllocRegistry memoryLeaks = AllocRegistry::getInstance();
|
AllocRegistry memoryLeaks = AllocRegistry::getInstance();
|
||||||
#endif
|
#endif
|
||||||
|
@ -597,7 +667,9 @@ int glestMain(int argc, char** argv){
|
||||||
ExceptionHandler exceptionHandler;
|
ExceptionHandler exceptionHandler;
|
||||||
exceptionHandler.install( getCrashDumpFileName() );
|
exceptionHandler.install( getCrashDumpFileName() );
|
||||||
|
|
||||||
|
#ifndef WIN32_STACK_TRACE
|
||||||
try {
|
try {
|
||||||
|
#endif
|
||||||
std::auto_ptr<FileCRCPreCacheThread> preCacheThread;
|
std::auto_ptr<FileCRCPreCacheThread> preCacheThread;
|
||||||
Config &config = Config::getInstance();
|
Config &config = Config::getInstance();
|
||||||
FontGl::setDefault_fontType(config.getString("DefaultFont",FontGl::getDefault_fontType().c_str()));
|
FontGl::setDefault_fontType(config.getString("DefaultFont",FontGl::getDefault_fontType().c_str()));
|
||||||
|
@ -901,7 +973,7 @@ int glestMain(int argc, char** argv){
|
||||||
if(i > 0) {
|
if(i > 0) {
|
||||||
errorText += "\n";
|
errorText += "\n";
|
||||||
}
|
}
|
||||||
errorText += resultErrors[i];
|
errorText = errorText + resultErrors[i];
|
||||||
}
|
}
|
||||||
errorText += "\n=====================\n";
|
errorText += "\n=====================\n";
|
||||||
//throw runtime_error(errorText);
|
//throw runtime_error(errorText);
|
||||||
|
@ -924,7 +996,7 @@ int glestMain(int argc, char** argv){
|
||||||
if(i > 0) {
|
if(i > 0) {
|
||||||
errorText += "\n";
|
errorText += "\n";
|
||||||
}
|
}
|
||||||
errorText += resultErrors[i];
|
errorText = errorText + resultErrors[i];
|
||||||
}
|
}
|
||||||
errorText += "\n=====================\n";
|
errorText += "\n=====================\n";
|
||||||
//throw runtime_error(errorText);
|
//throw runtime_error(errorText);
|
||||||
|
@ -975,6 +1047,8 @@ int glestMain(int argc, char** argv){
|
||||||
}
|
}
|
||||||
// Cache Player textures - END
|
// Cache Player textures - END
|
||||||
|
|
||||||
|
//throw "BLAH!";
|
||||||
|
|
||||||
if(config.getBool("AllowGameDataSynchCheck","false") == true) {
|
if(config.getBool("AllowGameDataSynchCheck","false") == true) {
|
||||||
vector<string> techDataPaths = config.getPathListForType(ptTechs);
|
vector<string> techDataPaths = config.getPathListForType(ptTechs);
|
||||||
preCacheThread.reset(new FileCRCPreCacheThread());
|
preCacheThread.reset(new FileCRCPreCacheThread());
|
||||||
|
@ -998,6 +1072,7 @@ int glestMain(int argc, char** argv){
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
|
#ifndef WIN32_STACK_TRACE
|
||||||
}
|
}
|
||||||
catch(const exception &e){
|
catch(const exception &e){
|
||||||
ExceptionHandler::handleRuntimeError(e.what());
|
ExceptionHandler::handleRuntimeError(e.what());
|
||||||
|
@ -1011,6 +1086,7 @@ int glestMain(int argc, char** argv){
|
||||||
catch(...){
|
catch(...){
|
||||||
ExceptionHandler::handleRuntimeError("Unknown error!");
|
ExceptionHandler::handleRuntimeError("Unknown error!");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
|
|
||||||
|
@ -1027,6 +1103,18 @@ int glestMain(int argc, char** argv){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int glestMainWrapper(int argc, char** argv) {
|
||||||
|
#ifdef WIN32_STACK_TRACE
|
||||||
|
__try {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return glestMain(argc, argv);
|
||||||
|
|
||||||
|
#ifdef WIN32_STACK_TRACE
|
||||||
|
} __except(stackdumper(0, GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) { return 0; }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}}//end namespace
|
}}//end namespace
|
||||||
|
|
||||||
MAIN_FUNCTION(Glest::Game::glestMain)
|
MAIN_FUNCTION(Glest::Game::glestMainWrapper)
|
||||||
|
|
|
@ -54,6 +54,37 @@ string getCommandLine();
|
||||||
void init_win32();
|
void init_win32();
|
||||||
void done_win32();
|
void done_win32();
|
||||||
|
|
||||||
|
|
||||||
|
// The following is used for stacking tracing for windows based exceptions
|
||||||
|
#if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
|
||||||
|
|
||||||
|
// easy safe strings
|
||||||
|
#define MAXSTRLEN 260
|
||||||
|
typedef char stringType[MAXSTRLEN];
|
||||||
|
|
||||||
|
inline void vformatstring(char *d, const char *fmt, va_list v, int len = MAXSTRLEN) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
|
||||||
|
inline char *copystring(char *d, const char *s, size_t len = MAXSTRLEN) { strncpy(d, s, len); d[len-1] = 0; return d; }
|
||||||
|
inline char *concatstring(char *d, const char *s, size_t len = MAXSTRLEN) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; }
|
||||||
|
|
||||||
|
struct stringformatter
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
stringformatter(char *buf): buf((char *)buf) {}
|
||||||
|
void operator()(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list v;
|
||||||
|
va_start(v, fmt);
|
||||||
|
vformatstring(buf, fmt, v);
|
||||||
|
va_end(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define formatstring(d) stringformatter((char *)d)
|
||||||
|
#define defformatstring(d) stringType d; formatstring(d)
|
||||||
|
#define defvformatstring(d,last,fmt) stringType d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
}}//end namespace
|
}}//end namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user