Subversion Repositories Games.Carmageddon

Rev

Rev 14 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // Based on https://gist.github.com/jvranish/4441299
  2.  
  3. #ifdef _WIN32 // Pierre-Marie Baty -- added compile guard
  4.  
  5. // this has to be first
  6. #include <windows.h>
  7.  
  8. #include <imagehlp.h>
  9.  
  10. #include "harness/config.h"
  11. #include "harness/os.h"
  12.  
  13. #include <assert.h>
  14. #include <direct.h>
  15. #include <errno.h>
  16. #include <limits.h>
  17. #include <signal.h>
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #ifdef _WIN64
  25. #define Esp Rsp
  26. #define Eip Rip
  27. #define Ebp Rbp
  28. #endif
  29.  
  30. void dr_dprintf(char* fmt_string, ...);
  31.  
  32. static int stack_nbr = 0;
  33. static char windows_program_name[1024];
  34.  
  35. static char dirname_buf[_MAX_DIR];
  36. static char fname_buf[_MAX_FNAME];
  37.  
  38. static int addr2line(char const* const program_name, void const* const addr) {
  39.     char addr2line_cmd[512] = { 0 };
  40.  
  41.     sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
  42.  
  43.     fprintf(stderr, "%d: ", stack_nbr++);
  44.     return system(addr2line_cmd);
  45. }
  46.  
  47. static void print_stacktrace(CONTEXT* context) {
  48. #if 0 // Pierre-Marie Baty -- looks like this doesn't build right away on Windows
  49.     SymInitialize(GetCurrentProcess(), 0, true);
  50.  
  51.     STACKFRAME frame = { 0 };
  52.  
  53.     /* setup initial stack frame */
  54.     frame.AddrPC.Offset = context->Eip;
  55.     frame.AddrPC.Mode = AddrModeFlat;
  56.     frame.AddrStack.Offset = context->Esp;
  57.     frame.AddrStack.Mode = AddrModeFlat;
  58.     frame.AddrFrame.Offset = context->Ebp;
  59.     frame.AddrFrame.Mode = AddrModeFlat;
  60.  
  61.     while (StackWalk(IMAGE_FILE_MACHINE_I386,
  62.         GetCurrentProcess(),
  63.         GetCurrentThread(),
  64.         &frame,
  65.         context,
  66.         0,
  67.         SymFunctionTableAccess,
  68.         SymGetModuleBase,
  69.         0)) {
  70.         addr2line(windows_program_name, (void*)frame.AddrPC.Offset);
  71.     }
  72.  
  73.     SymCleanup(GetCurrentProcess());
  74. #endif // 0
  75. }
  76.  
  77. static LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS* ExceptionInfo) {
  78.     switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
  79.     case EXCEPTION_ACCESS_VIOLATION:
  80.         fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
  81.         break;
  82.     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  83.         fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
  84.         break;
  85.     case EXCEPTION_BREAKPOINT:
  86.         fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
  87.         break;
  88.     case EXCEPTION_DATATYPE_MISALIGNMENT:
  89.         fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
  90.         break;
  91.     case EXCEPTION_FLT_DENORMAL_OPERAND:
  92.         fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
  93.         break;
  94.     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  95.         fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
  96.         break;
  97.     case EXCEPTION_FLT_INEXACT_RESULT:
  98.         fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
  99.         break;
  100.     case EXCEPTION_FLT_INVALID_OPERATION:
  101.         fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
  102.         break;
  103.     case EXCEPTION_FLT_OVERFLOW:
  104.         fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
  105.         break;
  106.     case EXCEPTION_FLT_STACK_CHECK:
  107.         fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
  108.         break;
  109.     case EXCEPTION_FLT_UNDERFLOW:
  110.         fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
  111.         break;
  112.     case EXCEPTION_ILLEGAL_INSTRUCTION:
  113.         fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
  114.         break;
  115.     case EXCEPTION_IN_PAGE_ERROR:
  116.         fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
  117.         break;
  118.     case EXCEPTION_INT_DIVIDE_BY_ZERO:
  119.         fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
  120.         break;
  121.     case EXCEPTION_INT_OVERFLOW:
  122.         fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
  123.         break;
  124.     case EXCEPTION_INVALID_DISPOSITION:
  125.         fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
  126.         break;
  127.     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
  128.         fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
  129.         break;
  130.     case EXCEPTION_PRIV_INSTRUCTION:
  131.         fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
  132.         break;
  133.     case EXCEPTION_SINGLE_STEP:
  134.         fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
  135.         break;
  136.     case EXCEPTION_STACK_OVERFLOW:
  137.         fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
  138.         break;
  139.     default:
  140.         fputs("Error: Unrecognized Exception\n", stderr);
  141.         break;
  142.     }
  143.     fflush(stderr);
  144.     /* If this is a stack overflow then we can't walk the stack, so just show
  145.       where the error happened */
  146.     if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
  147.         print_stacktrace(ExceptionInfo->ContextRecord);
  148.     } else {
  149.         addr2line(windows_program_name, (void*)ExceptionInfo->ContextRecord->Eip);
  150.     }
  151.  
  152.     return EXCEPTION_EXECUTE_HANDLER;
  153. }
  154.  
  155. void OS_InstallSignalHandler(char* program_name) {
  156.     strcpy(windows_program_name, program_name);
  157.     SetUnhandledExceptionFilter(windows_exception_handler);
  158. }
  159.  
  160. FILE* OS_fopen(const char* pathname, const char* mode) {
  161.     FILE* f;
  162.     errno_t err;
  163.  
  164.     f = NULL;
  165.     err = fopen_s(&f, pathname, mode);
  166.     if (harness_game_config.verbose) {
  167.         if (err != 0) {
  168.             fprintf(stderr, "Failed to open \"%s\" (%s)\n", pathname, strerror(err));
  169.         }
  170.     }
  171.  
  172.     return f;
  173. }
  174.  
  175. size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) {
  176.     // FIXME: unsafe implementation (echos the password)
  177.     pBuffer[0] = '\0';
  178.     fgets(pBuffer, pBufferLen, stdin);
  179.     return strlen(pBuffer);
  180. }
  181.  
  182. char* OS_Dirname(const char* path) {
  183.     _splitpath(path, NULL, dirname_buf, NULL, NULL);
  184.     return dirname_buf;
  185. }
  186.  
  187. char* OS_Basename(const char* path) {
  188.     _splitpath(path, NULL, NULL, fname_buf, NULL);
  189.     return fname_buf;
  190. }
  191.  
  192. #endif // _WIN32
  193.