From 3ad97c9eaba7aa5dff5a26fd35a9ea8a5ecd07fb Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 22 Mar 2012 09:57:43 -0300 Subject: [PATCH] crash handler, logger and oengles changes * save log messages to otclient.txt * fixes in FrameBuffer and HardwareBuffer to work with OpenGLES * possibility to get compilation information from lua (compiler version, build date, build revision, build type) * make crash handler more informatave * handle assert crash signals (SIGABRT) --- src/framework/CMakeLists.txt | 7 +++ src/framework/application.cpp | 1 - src/framework/application.h | 6 ++- src/framework/const.h | 11 +++++ src/framework/core/logger.cpp | 17 +++++++ src/framework/core/logger.h | 2 + src/framework/graphics/framebuffer.cpp | 33 +++++++++----- src/framework/graphics/hardwarebuffer.h | 8 +--- src/framework/luafunctions.cpp | 3 ++ src/framework/platform/unixcrashhandler.cpp | 31 ++++++++----- src/framework/platform/win32crashhandler.cpp | 48 +++++++++----------- src/framework/util/tools.h | 9 ++++ src/otclient/const.h | 3 +- src/otclient/otclient.cpp | 12 +++-- 14 files changed, 128 insertions(+), 63 deletions(-) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 8bed4704..fbed6553 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -10,6 +10,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake;${CMAKE_MODULE_PATH}") OPTION(WINDOWS_CONSOLE "Enables console window on Windows platform" OFF) OPTION(CRASH_HANDLER "Generate crash reports" OFF) OPTION(USE_OPENGL_ES2 "Use OpenGL ES 2.0 (for mobiles devices)" OFF) +SET(BUILD_REVISION "custom" CACHE "Git revision string (intended for releases)" STRING) # set debug as default build type IF(NOT CMAKE_BUILD_TYPE) @@ -47,12 +48,18 @@ SET(CMAKE_C_FLAGS_RELEASE "-Ofast -fomit-frame-pointer") SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -static-libgcc -static-libstdc++ -Wl,--as-needed") MESSAGE(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) +ADD_DEFINITIONS(-DBUILD_TYPE="${CMAKE_BUILD_TYPE}") + +ADD_DEFINITIONS(-DBUILD_REVISION="${BUILD_REVISION}") +MESSAGE(STATUS "Build revision: ${BUILD_REVISION}") + IF(USE_OPENGL_ES2) MESSAGE(STATUS "Renderer: OpenGL ES 2.0") ELSE() MESSAGE(STATUS "Renderer: OpenGL") ENDIF() + IF(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") ADD_DEFINITIONS(-DDEBUG) MESSAGE(STATUS "Debug information: ON") diff --git a/src/framework/application.cpp b/src/framework/application.cpp index 7295c94d..a3fabe97 100644 --- a/src/framework/application.cpp +++ b/src/framework/application.cpp @@ -67,7 +67,6 @@ Application::~Application() void Application::init(const std::vector& args, int appFlags) { m_appFlags = appFlags; - logInfo("Starting ", m_appName, " ", m_appVersion); // capture exit signals signal(SIGTERM, exitSignalHandler); diff --git a/src/framework/application.h b/src/framework/application.h index 04b7cd77..70f32e8e 100644 --- a/src/framework/application.h +++ b/src/framework/application.h @@ -49,7 +49,11 @@ public: bool isStopping() { return m_stopping; } const std::string& getName() { return m_appName; } const std::string& getVersion() { return m_appVersion; } - const std::string& getBuildDate() { return m_appBuildDate; } + + std::string getBuildCompiler() { return BUILD_COMPILER; } + std::string getBuildDate() { return BUILD_DATE; } + std::string getBuildRevision() { return BUILD_REVISION; } + std::string getBuildType() { return BUILD_TYPE; } protected: virtual void render(); diff --git a/src/framework/const.h b/src/framework/const.h index 2321136b..0d7f0953 100644 --- a/src/framework/const.h +++ b/src/framework/const.h @@ -28,6 +28,17 @@ #define DEG_TO_RAD (acos(-1)/180.0) #define RAD_TO_DEC (180.0/acos(-1)) +#define BUILD_COMPILER "gcc "__VERSION__ +#define BUILD_DATE __DATE__ + +#ifndef BUILD_REVISION +#define BUILD_REVISION "custom" +#endif + +#ifndef BUILD_TYPE +#define BUILD_TYPE "unknown" +#endif + namespace Fw { constexpr float pi = 3.14159265; diff --git a/src/framework/core/logger.cpp b/src/framework/core/logger.cpp index 2513ced3..b1b119ad 100644 --- a/src/framework/core/logger.cpp +++ b/src/framework/core/logger.cpp @@ -37,6 +37,11 @@ void Logger::log(Fw::LogLevel level, const std::string& message) std::string outmsg = logPrefixes[level] + message; std::cout << outmsg << std::endl; + if(m_outFile.good()) { + m_outFile << outmsg << std::endl; + m_outFile.flush(); + } + std::size_t now = std::time(NULL); m_logMessages.push_back(LogMessage(level, outmsg, now)); @@ -72,3 +77,15 @@ void Logger::fireOldMessages() m_onLog(logMessage.level, logMessage.message, logMessage.when); } } + +void Logger::setLogFile(const std::string& file) +{ + m_outFile.open(file.c_str(), std::ios::out | std::ios::app); + if(!m_outFile.is_open() || !m_outFile.good()) { + logError("Unable to save log to '", file, "'"); + return; + } + + m_outFile << "\n== application started at " << Fw::dateTimeString() << std::endl; + m_outFile.flush(); +} diff --git a/src/framework/core/logger.h b/src/framework/core/logger.h index b0160cec..47420f53 100644 --- a/src/framework/core/logger.h +++ b/src/framework/core/logger.h @@ -41,11 +41,13 @@ public: void logFunc(Fw::LogLevel level, const std::string& message, std::string prettyFunction); void fireOldMessages(); + void setLogFile(const std::string& file); void setOnLog(const OnLogCallback& onLog) { m_onLog = onLog; } private: std::list m_logMessages; OnLogCallback m_onLog; + std::ofstream m_outFile; }; extern Logger g_logger; diff --git a/src/framework/graphics/framebuffer.cpp b/src/framework/graphics/framebuffer.cpp index 84ef0e6a..dc11d1c8 100644 --- a/src/framework/graphics/framebuffer.cpp +++ b/src/framework/graphics/framebuffer.cpp @@ -47,7 +47,9 @@ void FrameBuffer::internalCreate() glGenFramebuffers(1, &m_fbo); if(!m_fbo) logFatal("Unable to create framebuffer object"); - } else { // use auxiliar buffers when FBOs are not supported + } +#ifndef OPENGL_ES2 + else { // use auxiliar buffers when FBOs are not supported m_fbo = 0; if(auxBuffers.size() == 0) { int maxAuxs = 0; @@ -64,15 +66,19 @@ void FrameBuffer::internalCreate() if(!m_fbo) logFatal("There is no available auxiliar buffer for a new framebuffer, total AUXs: ", auxBuffers.size()-1); } +#endif } FrameBuffer::~FrameBuffer() { if(g_graphics.canUseFBO()) { glDeleteFramebuffers(1, &m_fbo); - } else { + } +#ifndef OPENGL_ES2 + else { auxBuffers[m_fbo] = false; } +#endif } void FrameBuffer::resize(const Size& size) @@ -130,10 +136,7 @@ void FrameBuffer::draw(const Rect& dest, const Rect& src) void FrameBuffer::draw(const Rect& dest) { - if(g_graphics.canUseFBO()) - g_painter.drawTexturedRect(dest, m_texture); - else - g_painter.drawTexturedRect(dest, m_texture, Rect(0, 0, g_window.getSize())); + g_painter.drawTexturedRect(dest, m_texture, Rect(0,0, getSize())); } void FrameBuffer::internalBind() @@ -144,11 +147,14 @@ void FrameBuffer::internalBind() if(g_graphics.canUseFBO()) { glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - } else { + } +#ifndef OPENGL_ES2 + else { int buffer = GL_AUX0 + m_fbo - 1; glDrawBuffer(buffer); glReadBuffer(buffer); } +#endif m_prevBoundFbo = boundFbo; boundFbo = m_fbo; @@ -159,7 +165,9 @@ void FrameBuffer::internalRelease() assert(boundFbo == m_fbo); if(g_graphics.canUseFBO()) { glBindFramebuffer(GL_FRAMEBUFFER, m_prevBoundFbo); - } else { + } +#ifndef OPENGL_ES2 + else { m_texture->bind(); Size size = getSize(); @@ -172,16 +180,19 @@ void FrameBuffer::internalRelease() glDrawBuffer(buffer); glReadBuffer(buffer); } +#endif + boundFbo = m_prevBoundFbo; } Size FrameBuffer::getSize() { - if(g_graphics.canUseFBO()) { - return m_texture->getSize(); - } else { +#ifndef OPENGL_ES2 + if(!g_graphics.canUseFBO()) { // the buffer size is limited by the window size return Size(std::min(m_texture->getWidth(), g_window.getWidth()), std::min(m_texture->getHeight(), g_window.getHeight())); } +#endif + return m_texture->getSize(); } diff --git a/src/framework/graphics/hardwarebuffer.h b/src/framework/graphics/hardwarebuffer.h index d68f3d7c..24f53f36 100644 --- a/src/framework/graphics/hardwarebuffer.h +++ b/src/framework/graphics/hardwarebuffer.h @@ -36,14 +36,8 @@ public: enum UsagePattern { StreamDraw = GL_STREAM_DRAW, - StreamRead = GL_STREAM_READ, - StreamCopy = GL_STREAM_COPY, StaticDraw = GL_STATIC_DRAW, - StaticRead = GL_STATIC_READ, - StaticCopy = GL_STATIC_COPY, - DynamicDraw = GL_DYNAMIC_DRAW, - DynamicRead = GL_DYNAMIC_READ, - DynamicCopy = GL_DYNAMIC_COPY + DynamicDraw = GL_DYNAMIC_DRAW }; HardwareBuffer(Type type ) { diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 7511e3d8..bee8bcc3 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -422,7 +422,10 @@ void Application::registerLuaFunctions() g_lua.bindClassStaticFunction("g_app", "isStopping", std::bind(&Application::isStopping, g_app)); g_lua.bindClassStaticFunction("g_app", "getName", std::bind(&Application::getName, g_app)); g_lua.bindClassStaticFunction("g_app", "getVersion", std::bind(&Application::getVersion, g_app)); + g_lua.bindClassStaticFunction("g_app", "getBuildCompiler", std::bind(&Application::getBuildCompiler, g_app)); g_lua.bindClassStaticFunction("g_app", "getBuildDate", std::bind(&Application::getBuildDate, g_app)); + g_lua.bindClassStaticFunction("g_app", "getBuildRevision", std::bind(&Application::getBuildRevision, g_app)); + g_lua.bindClassStaticFunction("g_app", "getBuildType", std::bind(&Application::getBuildType, g_app)); // ConfigManager g_lua.registerStaticClass("g_configs"); diff --git a/src/framework/platform/unixcrashhandler.cpp b/src/framework/platform/unixcrashhandler.cpp index 34bf0ebe..5d9975e4 100644 --- a/src/framework/platform/unixcrashhandler.cpp +++ b/src/framework/platform/unixcrashhandler.cpp @@ -36,16 +36,17 @@ void crashHandler(int signum, siginfo_t* info, void* secret) { logError("Application crashed"); - ucontext_t context = *(ucontext_t*)secret; - time_t tnow; - char fileName[128]; - time(&tnow); - tm *ts = localtime(&tnow); - strftime(fileName, 128, (g_app->getName() + "-crash_-%d-%m-%Y_%H:%M:%S.txt").c_str(), ts); - std::stringstream ss; + ss << Fw::formatString("app name: %s\n", g_app->getName().c_str()); + ss << Fw::formatString("app version: %s\n", g_app->getVersion().c_str()); + ss << Fw::formatString("build compiler: %s\n", BUILD_COMPILER); + ss << Fw::formatString("build date: %s\n", BUILD_DATE); + ss << Fw::formatString("build type: %s\n", BUILD_TYPE); + ss << Fw::formatString("build revision: %s\n", BUILD_REVISION); + ss << Fw::formatString("crash date: %s\n", Fw::dateTimeString().c_str()); ss.flags(std::ios::hex | std::ios::showbase); + ucontext_t context = *(ucontext_t*)secret; #if __WORDSIZE == 64 ss << " at rip = " << context.uc_mcontext.gregs[REG_RIP] << std::endl; ss << " rax = " << context.uc_mcontext.gregs[REG_RAX] << std::endl; @@ -99,14 +100,21 @@ void crashHandler(int signum, siginfo_t* info, void* secret) logInfo(ss.str()); - std::ofstream out(fileName); - out << ss.str(); - out.close(); - logInfo("Crash report saved to file ", fileName); + std::string fileName = "crash_report.txt"; + std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::app); + if(fout.is_open() && fout.good()) { + fout << "== application crashed\n"; + fout << ss.str(); + fout << "\n"; + fout.close(); + logInfo("Crash report saved to file ", fileName.c_str()); + } else + logError("Failed to save crash report!"); signal(SIGILL, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); + signal(SIGABRT, SIG_DFL); } void installCrashHandler() @@ -119,4 +127,5 @@ void installCrashHandler() sigaction(SIGILL, &sa, NULL); // illegal instruction sigaction(SIGSEGV, &sa, NULL); // segmentation fault sigaction(SIGFPE, &sa, NULL); // floating-point exception + sigaction(SIGABRT, &sa, NULL); // process aborted (asserts) } diff --git a/src/framework/platform/win32crashhandler.cpp b/src/framework/platform/win32crashhandler.cpp index a1fc0909..db45cccf 100644 --- a/src/framework/platform/win32crashhandler.cpp +++ b/src/framework/platform/win32crashhandler.cpp @@ -86,7 +86,6 @@ void Stacktrace(LPEXCEPTION_POINTERS e, std::stringstream& ss) break; dwModBase = SymGetModuleBase(process, sf.AddrPC.Offset); - if(dwModBase) GetModuleFileName((HINSTANCE)dwModBase, modname, MAX_PATH); else @@ -95,13 +94,10 @@ void Stacktrace(LPEXCEPTION_POINTERS e, std::stringstream& ss) pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); pSym->MaxNameLength = MAX_PATH; - if(SymGetSymFromAddr(process, sf.AddrPC.Offset, &Disp, pSym)) { - // this is the code path taken on VC if debugging syms are found. - ss << Fw::formatString(" (%d) %s(%s+%#0lx) [0x%08lX]\n", count, modname, pSym->Name, Disp, sf.AddrPC.Offset); - } else { - // this is the code path taken on MinGW, and VC if no debugging syms are found. - ss << Fw::formatString(" (%d) %s [0x%08lX]\n", count, modname, sf.AddrPC.Offset); - } + if(SymGetSymFromAddr(process, sf.AddrPC.Offset, &Disp, pSym)) + ss << Fw::formatString(" %d: %s(%s+%#0lx) [0x%08lX]\n", count, modname, pSym->Name, Disp, sf.AddrPC.Offset); + else + ss << Fw::formatString(" %d: %s [0x%08lX]\n", count, modname, sf.AddrPC.Offset); ++count; } GlobalFree(pSym); @@ -109,40 +105,38 @@ void Stacktrace(LPEXCEPTION_POINTERS e, std::stringstream& ss) LONG CALLBACK ExceptionHandler(LPEXCEPTION_POINTERS e) { - char date[32]; - time_t tnow; - time(&tnow); - tm *ts = localtime(&tnow); - strftime(date, 32, "%b %d %Y %H:%M:%S", ts); - // generate crash report SymInitialize(GetCurrentProcess(), 0, TRUE); std::stringstream ss; ss << "== application crashed\n"; ss << Fw::formatString("app name: %s\n", g_app->getName().c_str()); ss << Fw::formatString("app version: %s\n", g_app->getVersion().c_str()); - ss << Fw::formatString("app build date: %s\n", g_app->getBuildDate().c_str()); - ss << Fw::formatString("crash date: %s\n", date); + ss << Fw::formatString("build compiler: %s\n", BUILD_COMPILER); + ss << Fw::formatString("build date: %s\n", BUILD_DATE); + ss << Fw::formatString("build type: %s\n", BUILD_TYPE); + ss << Fw::formatString("build revision: %s\n", BUILD_REVISION); + ss << Fw::formatString("crash date: %s\n", Fw::dateTimeString().c_str()); ss << Fw::formatString("exception: %s (0x%08lx)\n", getExceptionName(e->ExceptionRecord->ExceptionCode), e->ExceptionRecord->ExceptionCode); ss << Fw::formatString("exception address: 0x%08lx\n", (long unsigned int)e->ExceptionRecord->ExceptionAddress); - ss << Fw::formatString("backtrace:\n"); + ss << Fw::formatString(" backtrace:\n"); Stacktrace(e, ss); ss << "\n"; SymCleanup(GetCurrentProcess()); - // write stacktrace to crash.txt + // print in stdout + logInfo(ss.str()); + + // write stacktrace to crash_report.txt char dir[MAX_PATH]; GetCurrentDirectory(sizeof(dir) - 1, dir); std::string fileName = Fw::formatString("%s\\crash_report.txt", dir); - - - std::ofstream fout(fileName.c_str(), std::ios_base::out | std::ios_base::ate); - fout << ss.str(); - fout.close(); - - // print in stdout - logInfo(ss.str()); - logInfo("Crash report saved to file ", fileName); + std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::app); + if(fout.is_open() && fout.good()) { + fout << ss.str(); + fout.close(); + logInfo("Crash report saved to file ", fileName); + } else + logError("Failed to save crash report!"); // inform the user std::string msg = Fw::formatString("The application has crashed.\n\n" diff --git a/src/framework/util/tools.h b/src/framework/util/tools.h index b431d390..6127ca07 100644 --- a/src/framework/util/tools.h +++ b/src/framework/util/tools.h @@ -290,6 +290,15 @@ inline std::string resolvePath(const std::string& file, std::string sourcePath) return sourcePath + file; } +inline std::string dateTimeString() { + char date[32]; + std::time_t tnow; + std::time(&tnow); + std::tm *ts = std::localtime(&tnow); + std::strftime(date, 32, "%b %d %Y %H:%M:%S", ts); + return std::string(date); +} + template T randomRange(T min, T max); diff --git a/src/otclient/const.h b/src/otclient/const.h index 49669461..3f51a765 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -29,8 +29,7 @@ namespace Otc { constexpr const char* AppName = "OTClient"; constexpr const char* AppCompactName = "otclient"; - constexpr const char* AppVersion = "0.4.0"; - constexpr const char* AppBuild = "_dev"; + constexpr const char* AppVersion = "0.4.0_dev"; enum { TILE_PIXELS = 32, diff --git a/src/otclient/otclient.cpp b/src/otclient/otclient.cpp index 1e5b2893..19cfa4d9 100644 --- a/src/otclient/otclient.cpp +++ b/src/otclient/otclient.cpp @@ -22,18 +22,24 @@ #include "otclient.h" #include -#include "core/game.h" #include +#include "core/game.h" #include "core/map.h" OTClient::OTClient() : Application(Otc::AppCompactName) { - m_appVersion = Fw::formatString("%s%s", Otc::AppVersion, Otc::AppBuild); - m_appBuildDate = __DATE__; + m_appVersion = Otc::AppVersion; } void OTClient::init(const std::vector& args) { + logInfo(Fw::formatString("%s %s (rev %s) built on %s", + Otc::AppName, + Otc::AppVersion, + BUILD_REVISION, + BUILD_DATE)); + + g_logger.setLogFile(Fw::formatString("%s.txt", Otc::AppCompactName)); Application::init(args, Fw::AppEnableAll); g_modules.discoverModules();