Subversion Repositories Games.Carmageddon

Rev

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