Changeset 6abfd07 in opengl-game


Ignore:
Timestamp:
May 31, 2019, 6:26:19 PM (6 years ago)
Author:
Dmitry Portnoy <dmitry.portnoy@…>
Branches:
feature/imgui-sdl, master, points-test
Children:
b373466
Parents:
a23fc08
Message:

Create a log with a stack-trace when the game crashes

Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • CrashLogger.cpp

    ra23fc08 r6abfd07  
    44#include <cstdio>
    55#include <csignal>
     6#include <cstring>
    67
    78#include <fcntl.h>
    89
    910#include "Compiler.h"
     11#include "Consts.h"
     12
     13// TODO: Double-check which includes are necessary
    1014
    1115#ifdef WINDOWS
    12    // most of this can be removed since Windows uses __try __catch instead of signals
    13 
    1416   #include <windows.h>
    15    #include "StackWalker.h"
    16 
    1717   #include <io.h>
    1818   #include <sys/stat.h>
     19
     20   #include "FileStackWalker.h"
    1921
    2022   // The windows analogues to the unix open, close, and write functions
     
    2527
    2628   #define STDERR_FILENO 2
     29
     30   bool handleException(unsigned int expCode, EXCEPTION_POINTERS* pExp, HANDLE thread);
    2731#else
    2832   #include <unistd.h>
     
    3135   #include <cxxabi.h>
    3236   #include <cstring>
     37
     38   void abortHandler(int signum);
     39   static inline void printStackTrace(int fd_out = STDERR_FILENO);
    3340#endif
    3441
    35 CrashLogger::CrashLogger() {
    36    // Apparently, sigaction should be used instead for Linux
    37    // It gives more info. Check if I should bother switching
    38 
    39    signal(SIGABRT, abortHandler);
    40    signal(SIGSEGV, abortHandler);
    41    signal(SIGILL, abortHandler);
    42    signal(SIGFPE, abortHandler);
    43 
    44    write(STDERR_FILENO, "Handlers attached\n", 18);
     42void printInfo(int fd_out);
     43
     44CrashLogger::CrashLogger(int(*mainFunc)(int, char*[]), int argc, char* argv[]) {
     45   write(STDERR_FILENO, "Calling main\n", 13);
     46
     47   #ifdef WINDOWS
     48      __try {
     49         mainFunc(argc, argv);
     50         // maybe do this and call a function inside CrashLogger
     51         // In that case, also pass GetCurrentThread() as a parameter to then pass to handleException
     52         // I could also move almost all of this into CrashLogger by creating a function in CrashLogger that takes a reference
     53         // to the effective main function and, for Windows, wraps it in all this error-handling stuff
     54      } __except (handleException(
     55            GetExceptionCode(),
     56            GetExceptionInformation(),
     57            GetCurrentThread())
     58            ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER) {
     59      }
     60   #else
     61      // Apparently, sigaction should be used instead for Linux
     62      // It gives more info. Check if I should bother switching
     63
     64      signal(SIGABRT, abortHandler);
     65      signal(SIGSEGV, abortHandler);
     66      signal(SIGILL, abortHandler);
     67      signal(SIGFPE, abortHandler);
     68
     69      write(STDERR_FILENO, "Handlers attached\n", 18);
     70
     71      mainFunc(argc, argv);
     72   #endif
    4573}
    4674
     
    4876}
    4977
    50 static inline void printStackTrace(int fd_out = STDERR_FILENO) {
     78#ifdef WINDOWS
     79
     80bool handleException(unsigned int expCode, EXCEPTION_POINTERS* pExp, HANDLE thread) {
     81   int crash_log = open(CRASH_LOG_FILE, O_RDWR | O_CREAT | O_APPEND, _S_IREAD | _S_IWRITE);
     82
     83   if (crash_log == -1) {
     84      // TODO: Figure out exactly what perror does and if I should use it
     85      perror("opening crash.log");  // TODO: Figure out exactly what perror does and if I should use it
     86   }
     87
     88   printInfo(crash_log);
     89
     90   FileStackWalker sw(crash_log == -1 ? STDERR_FILENO  : crash_log);
     91
     92   if (pExp != NULL) {
     93      sw.ShowCallstack(thread, pExp->ContextRecord);
     94   } else {
     95      write(crash_log, "Could not get the stack trace\n", 30);
     96   }
     97
     98   close(crash_log);
     99
     100   if (expCode == EXCEPTION_ACCESS_VIOLATION) {
     101      write(STDERR_FILENO, "ACCESS VIOLATION\n", 17);
     102   }
     103
     104   return true;
     105}
     106
     107#else
     108
     109void abortHandler(int signum) {
     110   int crash_log = open(CRASH_LOG_FILE, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
     111
     112   if (crash_log == -1) {
     113      // TODO: Figure out exactly what perror does and if I should use it
     114      perror("opening crash.log");
     115   }
     116
     117   printInfo(crash_log);
     118
     119   printStackTrace(crash_log);
     120
     121   close(crash_log);
     122
     123   write(STDERR_FILENO, "The game has crashed. Check crash.log for more info\n", 52);
     124
     125   exit(signum);
     126}
     127
     128static inline void printStackTrace(int fd_out) {
    51129   write(fd_out, "stack trace:\n", 13);
    52130
     
    74152      char* begin_name = NULL;
    75153      char* begin_offset = NULL;
    76       char* end_offset = NULL; // Iirc, this is used in the Linux code
    77 
    78       #ifdef MAC
    79          for (char *p = symbollist[i]; *p; p++) {
    80             if ((*p == '_') && (*(p-1) == ' ')) {
    81                begin_name = p-1;
    82             } else if(*p == '+') {
    83                begin_offset = p-1;
    84             }
     154      char* end_offset = NULL; // Iirc, this is used in the Linux code (Check what it's used for)
     155
     156#ifdef MAC
     157      for (char *p = symbollist[i]; *p; p++) {
     158         if ((*p == '_') && (*(p-1) == ' ')) {
     159            begin_name = p-1;
     160         } else if(*p == '+') {
     161            begin_offset = p-1;
    85162         }
    86 
    87          if (begin_name && begin_offset && (begin_name < begin_offset )) {
    88             *begin_name++ = '\0';
    89             *begin_offset++ = '\0';
    90 
    91             // mangled name is now in [begin_name, begin_offset) and caller
    92             // offset in [begin_offset, end_offset). now apply
    93             // __cxa_demangle():
    94             int status;
    95             char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
    96 
    97             if (status == 0)  {
    98                funcname = ret; // use possibly realloc()-ed string
    99                write(fd_out, symbollist[i], strlen(symbollist[i]));
    100                write(fd_out, " ", 1);
    101                write(fd_out, funcname, strlen(funcname));
    102                write(fd_out, " ", 1);
    103                write(fd_out, begin_offset, strlen(begin_offset));
    104             } else {
    105                // demangling failed. Output function name as a C function with no arguments.
    106                write(fd_out, "Error\n", 6);
    107                write(fd_out, symbollist[i], strlen(symbollist[i]));
    108                write(fd_out, " ", 1);
    109                write(fd_out, begin_name, strlen(begin_name));
    110                write(fd_out, "() ", 3);
    111                write(fd_out, begin_offset, strlen(begin_offset));
    112             }
     163      }
     164
     165      if (begin_name && begin_offset && (begin_name < begin_offset )) {
     166         *begin_name++ = '\0';
     167         *begin_offset++ = '\0';
     168
     169         // mangled name is now in [begin_name, begin_offset) and caller
     170         // offset in [begin_offset, end_offset). now apply
     171         // __cxa_demangle():
     172         int status;
     173         char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status);
     174
     175         if (status == 0)  {
     176            funcname = ret; // use possibly realloc()-ed string
     177            write(fd_out, symbollist[i], strlen(symbollist[i]));
     178            write(fd_out, " ", 1);
     179            write(fd_out, funcname, strlen(funcname));
     180            write(fd_out, " ", 1);
     181            write(fd_out, begin_offset, strlen(begin_offset));
    113182         } else {
    114             // couldn't parse the line? print the whole line.
     183            // demangling failed. Output function name as a C function with no arguments.
     184            write(fd_out, "Error\n", 6);
    115185            write(fd_out, symbollist[i], strlen(symbollist[i]));
     186            write(fd_out, " ", 1);
     187            write(fd_out, begin_name, strlen(begin_name));
     188            write(fd_out, "() ", 3);
     189            write(fd_out, begin_offset, strlen(begin_offset));
    116190         }
    117          write(fd_out, "\n", 1);
    118       #else
    119          // Check that this works on Linux Mint
     191      } else {
     192         // couldn't parse the line? print the whole line.
    120193         write(fd_out, symbollist[i], strlen(symbollist[i]));
    121          write(fd_out, "\n", 1);
    122       #endif
     194      }
     195      write(fd_out, "\n", 1);
     196#else
     197      // Check that this works on Linux Mint
     198      write(fd_out, symbollist[i], strlen(symbollist[i]));
     199      write(fd_out, "\n", 1);
     200#endif
    123201   }
    124202
     
    129207}
    130208
    131 // Most of this function could probably be shared between Windows and Linux/Mac
    132 void abortHandler(int signum) {
    133    #ifdef WINDOWS
    134       int crash_log = open("crash.log", O_RDWR | O_CREAT | O_APPEND, _S_IREAD | _S_IWRITE);
     209#endif
     210
     211void printInfo(int fd_out) {
     212   write(fd_out, "Game Version: ", 14);
     213   write(fd_out, GAME_VERSION, strlen(GAME_VERSION));
     214   write(fd_out, "\n", 1);
     215
     216   write(fd_out, "OS: ", 4);
     217   #if defined WINDOWS
     218      write(fd_out, "Windows", 7);
     219   #elif defined LINUX
     220      write(fd_out, "Linux", 5);
     221   #elif defined MAC
     222      write(fd_out, "Mac", 3);
    135223   #else
    136       int crash_log = open("crash.log", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
     224      write(fd_out, "Unknown", 7);
    137225   #endif
    138 
    139    if (crash_log == -1) {
    140       perror("opening crash.log");  // TODO: Figure out exactly what perror does and if I should use it
    141    }
    142 
    143    printStackTrace(crash_log);
    144 
    145    close(crash_log);
    146 
    147    exit(signum);
    148 }
     226   write(fd_out, "\n", 1);
     227
     228   write(fd_out, "\n", 1);
     229}
  • CrashLogger.h

    ra23fc08 r6abfd07  
    22#define CRASH_LOGGER_H
    33
     4#define CRASH_LOG_FILE "crash.log"
     5
    46class CrashLogger {
    57public:
    6    CrashLogger();
     8   CrashLogger(int(*mainFunc)(int, char*[]), int argc, char* argv[]);
    79   ~CrashLogger();
    810};
    911
    10 void abortHandler(int signum);
    11 
    1212#endif
  • FileStackWalker.cpp

    ra23fc08 r6abfd07  
    11#include "FileStackWalker.h"
     2
     3// Put this stuff in some common header shared by this and CrashLogger
     4// Put this stuff in some common header shared by this and CrashLogger
     5
     6#include <io.h>
     7
     8#define write _write
    29
    310FileStackWalker::FileStackWalker(int fd_out) : StackWalker() {
  • NewOpenGLGame.vcxproj

    ra23fc08 r6abfd07  
    136136  <ItemGroup>
    137137    <ClCompile Include="CrashLogger.cpp" />
     138    <ClCompile Include="FileStackWalker.cpp" />
    138139    <ClCompile Include="IMGUI\imgui.cpp" />
    139140    <ClCompile Include="IMGUI\imgui_demo.cpp" />
     
    145146    <ClCompile Include="stb_image_write.h" />
    146147    <ClCompile Include="stb_image.cpp" />
     148    <ClCompile Include="utils.cpp" />
    147149  </ItemGroup>
    148150  <ItemGroup>
    149151    <ClInclude Include="CrashLogger.h" />
     152    <ClInclude Include="FileStackWalker.h" />
    150153    <ClInclude Include="IMGUI\imgui.h" />
    151154    <ClInclude Include="IMGUI\imgui_internal.h" />
  • new-game.cpp

    ra23fc08 r6abfd07  
    3535#include "Compiler.h"
    3636
    37 #ifdef WINDOWS
    38    #include <windows.h>
    39    #include <excpt.h>
    40    #include <io.h>
    41 
    42    #include "FileStackWalker.h"
    43 #else
    44    // TODO: Move as much Windows crash-logging stuff into CrashLogger as well
    45    #include "CrashLogger.h"
    46 #endif
     37#include "CrashLogger.h"
    4738
    4839using namespace std;
     
    300291*/
    301292
    302 CrashLogger logger;
    303 
    304293// Helps to test logging during crashes
    305 /*
    306 void badFunc() {
     294int badFunc() {
    307295   int* test = NULL;
     296
     297   string test2 = "lol";
     298   cout << test2 << endl;
     299
    308300   *test = 1;
    309 }
    310 */
    311 
    312 #ifdef WINDOWS
    313 
    314 // Give it a file handle to crash.log instead (using the code in CrashLogger.cpp)
    315 FileStackWalker sw(2);
    316 
    317 bool handleException(unsigned int expCode, EXCEPTION_POINTERS* pExp, HANDLE thread);
    318 #endif
     301   return *test;
     302}
     303
     304int __main(int argc, char* argv[]);
    319305
    320306int main(int argc, char* argv[]) {
    321 #ifdef WINDOWS
    322    __try {
    323       __main(argc, argv);
    324       // maybe do this and call a function inside CrashLogger
    325       // In that case, also pass GetCurrentThread() as a parameter to then pass to handleException
    326       // I could also move almost all of this into CrashLogger by creating a function in CrashLogger that takes a reference
    327       // to the effective main function and, for Windows, wraps it in all this error-handling stuff
    328    } __except( handleException(GetExceptionCode(), GetExceptionInformation(), GetCurrentThread()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER) {
    329       _write(2, "CAUGHT\n", 7);
    330    }
     307   CrashLogger logger(__main, argc, argv);
    331308
    332309   exit(0);
     
    334311
    335312int __main(int argc, char* argv[]) {
    336 #endif
    337313   cout << "New OpenGL Game" << endl;
    338314
     
    1023999      delete *it;
    10241000   }
    1025 }
    1026 
    1027 #ifdef WINDOWS
    1028 bool handleException(unsigned int expCode, EXCEPTION_POINTERS* pExp, HANDLE thread) {
    1029    if (pExp != NULL) {
    1030       sw.ShowCallstack(thread, pExp->ContextRecord);
    1031    }
    1032 
    1033    if (expCode == EXCEPTION_ACCESS_VIOLATION) {
    1034       _write(2, "ACCESS VIOLATION\n", 17);
    1035    }
    1036 
    1037    return true;
    1038 }
    1039 #endif
     1001
     1002   return 0;
     1003}
    10401004
    10411005void glfw_error_callback(int error, const char* description) {
Note: See TracChangeset for help on using the changeset viewer.