Ares
Public Types | Static Public Member Functions | Static Public Attributes

Debug Class Reference

#include <src/Misc/Debug.h>

List of all members.

Public Types

enum  Severity { Notice = 0x1, Warning = 0x2, Error = 0x3 }

Static Public Member Functions

static const char * SeverityString (Debug::Severity severity)
static void MakeLogFile ()
static void LogFileOpen ()
static void LogFileClose (int tag)
static void LogFileRemove ()
static void DumpObj (byte *data, size_t len)
static void DumpStack (REGISTERS *R, size_t len, size_t startAt=0)
static void (_cdecl *Log)(const char *pFormat
static static void __cdecl LogUnflushed (const char *Format,...)
static void Flush ()
static LONG WINAPI ExceptionHandler (int code, LPEXCEPTION_POINTERS pExs)
static void FreeMouse ()
static void FatalError (bool Dump=false)
static void FatalError (const char *Message,...)
static void FatalErrorAndExit (const char *Message,...)
static int __stdcall FatalDialog_WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static void FullDump (MINIDUMP_EXCEPTION_INFORMATION *pException, wchar_t *generatedFilename=NULL)
static void DevLog (Debug::Severity severity, const char *Format,...)
static void INIParseFailed (const char *section, const char *flag, const char *value, const char *Message=NULL)

Static Public Attributes

static bool bLog = true
static FILE * pLogFile = NULL
static wchar_t LogFileName [MAX_PATH] = "\0"
static wchar_t LogFileTempName [MAX_PATH] = "\0"
static bool bTrackParserErrors = false
static bool bParserErrorDetected = false

Member Enumeration Documentation

Enumerator:
Notice 
Warning 
Error 
                      {
                Notice = 0x1,
                Warning = 0x2,
                Error = 0x3
        };

Member Function Documentation

void Debug::DevLog ( Debug::Severity  severity,
const char *  Format,
  ... 
) [static]
Initial value:
        (void (__cdecl *)(const char *,...))0x4068E0
                                                                  {
        if(Debug::bTrackParserErrors) {
                Debug::bParserErrorDetected = true;
        }
        if(!pLogFile) {
                return;
        }
        va_list args;
        fprintf(pLogFile, "[Developer %s]", Debug::SeverityString(severity));
        va_start(args, Format);
        vfprintf(pLogFile, Format, args);
        va_end(args);
//      fprintf(pLogFile, "\n");
}
void Debug::DumpObj ( byte *  data,
size_t  len 
) [static]
                                          {
        Debug::Log("Dumping %u bytes of object at %X\n", len, data);

        Debug::Log(" 00000 |");
        for(DWORD rem = 0; rem < 0x10; ++rem) {
                Debug::Log(" %02X |", rem);
        }
        Debug::Log("\n\n");
        for(DWORD dec = 0; dec < len / 0x10; ++dec) {
                Debug::Log(" %04X0 |", dec);
                for(DWORD rem = 0; rem < 0x10; ++rem) {
                        Debug::Log(" %02X |", data[dec * 0x10 + rem]);
                }
                for(DWORD rem = 0; rem < 0x10; ++rem) {
                        byte sym = data[dec * 0x10 + rem];
                        Debug::Log("%c", isprint(sym) ? sym : '?');
                }
                Debug::Log("\n");
        }

        DWORD dec = len / 0x10 * 0x10;
        DWORD remlen = len - dec;
        Debug::Log(" %05X |", dec);
        for(DWORD rem = 0; rem < remlen; ++rem) {
                Debug::Log(" %02X |", data[dec + rem]);
        }
        for(DWORD rem = remlen; rem < 0x10; ++rem) {
                Debug::Log(" -- |");
        }
        for(DWORD rem = 0; rem < remlen; ++rem) {
                byte sym = data[dec + rem];
                Debug::Log("%c", isprint(sym) ? sym : '?');
        }
        Debug::Log("\nEnd of dump.\n");
}
void Debug::DumpStack ( REGISTERS *  R,
size_t  len,
size_t  startAt = 0 
) [static]
                                                              {
        Debug::Log("Dumping %X bytes of stack\n", len);
        for(size_t i = startAt; i < len; i += 4) {
                Debug::Log("esp+%04X = %08X\n", i, R->Stack32(i));
        }
        Debug::Log("Done.\n");
}
LONG WINAPI Debug::ExceptionHandler ( int  code,
LPEXCEPTION_POINTERS  pExs 
) [static]

minidump

{
        Debug::FreeMouse();
        Debug::Log("Exception handler fired!\n");
        SetWindowTextW(Game::hWnd, L"Fatal Error - Yuri's Revenge");
//      if (IsDebuggerAttached()) return EXCEPTION_CONTINUE_SEARCH;
        if (pExs->ExceptionRecord->ExceptionCode == ERROR_MOD_NOT_FOUND ||
                pExs->ExceptionRecord->ExceptionCode == ERROR_PROC_NOT_FOUND)
        {
                Debug::Log("Massive failure: Procedure or module not found!\n");
                //tell user
                ExitProcess(pExs->ExceptionRecord->ExceptionCode);
        }

        switch(pExs->ExceptionRecord->ExceptionCode)
        {
                case EXCEPTION_ACCESS_VIOLATION:
                case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
                case EXCEPTION_BREAKPOINT:
                case EXCEPTION_DATATYPE_MISALIGNMENT:
                case EXCEPTION_FLT_DENORMAL_OPERAND:
                case EXCEPTION_FLT_DIVIDE_BY_ZERO:
                case EXCEPTION_FLT_INEXACT_RESULT:
                case EXCEPTION_FLT_INVALID_OPERATION:
                case EXCEPTION_FLT_OVERFLOW:
                case EXCEPTION_FLT_STACK_CHECK:
                case EXCEPTION_FLT_UNDERFLOW:
                case EXCEPTION_ILLEGAL_INSTRUCTION:
                case EXCEPTION_IN_PAGE_ERROR:
                case EXCEPTION_INT_DIVIDE_BY_ZERO:
                case EXCEPTION_INT_OVERFLOW:
                case EXCEPTION_INVALID_DISPOSITION:
                case EXCEPTION_NONCONTINUABLE_EXCEPTION:
                case EXCEPTION_PRIV_INSTRUCTION:
                case EXCEPTION_SINGLE_STEP:
                case EXCEPTION_STACK_OVERFLOW:
                case 0xE06D7363: // exception thrown and not caught
                {
                        wchar_t filename[MAX_PATH];
                        wchar_t path[MAX_PATH];
                        SYSTEMTIME time;

                        GetLocalTime(&time);
                        GetCurrentDirectoryW(MAX_PATH, path);

                        swprintf(filename, MAX_PATH, L"%s\\debug", path);
                        CreateDirectoryW(filename, NULL);

                        swprintf(filename, MAX_PATH, L"%s\\debug\\except.%04u%02u%02u-%02u%02u%02u.txt",
                                path, time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);

                        if(FILE *except = _wfopen(filename, L"w")) {
#define DELIM "---------------------\n"
                                fprintf(except, "Internal Error encountered!\n");
                                fprintf(except, DELIM);
                                fprintf(except, VERSION_STRVER);
                                fprintf(except, "\n" DELIM);

                                fprintf(except, "Exception code: %08X at %08X\n", pExs->ExceptionRecord->ExceptionCode, pExs->ExceptionRecord->ExceptionAddress);

                                fprintf(except, "Registers:\n");
                                PCONTEXT pCtxt = pExs->ContextRecord;
                                fprintf(except, "EIP: %08X\tESP: %08X\tEBP: %08X\n", pCtxt->Eip, pCtxt->Esp, pCtxt->Ebp);
                                fprintf(except, "EAX: %08X\tEBX: %08X\tECX: %08X\n", pCtxt->Eax, pCtxt->Ebx, pCtxt->Ecx);
                                fprintf(except, "EDX: %08X\tESI: %08X\tEDI: %08X\n", pCtxt->Edx, pCtxt->Esi, pCtxt->Edi);

                                fprintf(except, "\nStack dump:\n");
                                DWORD *ptr = (DWORD *)(pCtxt->Esp);
                                for(int i = 0; i < 0x100; ++i) {
                                        fprintf(except, "%08X: %08X\n", ptr, *ptr);
                                        ++ptr;
                                }

                                fclose(except);
                                Debug::Log("Exception data has been saved to file:\n%ls\n", filename);
                        }

                        if(MessageBoxW(Game::hWnd, L"Yuri's Revenge has encountered a fatal error!\nWould you like to create a full crash report for the developers?", L"Fatal Error!", MB_YESNO | MB_ICONERROR) == IDYES) {
                                HCURSOR loadCursor = LoadCursor(NULL, IDC_WAIT);
                                SetClassLong(Game::hWnd, GCL_HCURSOR, (LONG)loadCursor);
                                SetCursor(loadCursor);
                                Debug::Log("Making a memory dump\n");

                                MINIDUMP_EXCEPTION_INFORMATION expParam;
                                expParam.ThreadId = GetCurrentThreadId();
                                expParam.ExceptionPointers = pExs;
                                expParam.ClientPointers = FALSE;

                                Debug::FullDump(&expParam);

                                loadCursor = LoadCursor(NULL, IDC_ARROW);
                                SetClassLong(Game::hWnd, GCL_HCURSOR, (LONG)loadCursor);
                                SetCursor(loadCursor);
                                Debug::FatalError("The cause of this error could not be determined.\r\n"
                                        "%s"
                                        "A crash dump should have been created in your game's \\debug subfolder.\r\n"
                                        "You can submit that to the developers (along with debug.txt and syringe.log)."
                                                , Debug::bParserErrorDetected ? "(One or more parser errors have been detected that might be responsible. Check the debug logs.)\r\n" : ""
                                );
                        }
                        ExitProcess(pExs->ExceptionRecord->ExceptionCode); // Exit.
                        break;
                }
                default:
                        Debug::Log("Massive failure: reason unknown, have fun figuring it out\n");
                        Debug::DumpObj((byte *)pExs->ExceptionRecord, sizeof(*(pExs->ExceptionRecord)));
                        ExitProcess(pExs->ExceptionRecord->ExceptionCode); // Exit.
//                      return EXCEPTION_CONTINUE_SEARCH;
                        break;
        }
};
static int __stdcall Debug::FatalDialog_WndProc ( HWND  hWnd,
UINT  uMsg,
WPARAM  wParam,
LPARAM  lParam 
) [static]
void Debug::FatalError ( bool  Dump = false) [static]
                                {
        wsprintfW(Dialogs::ExceptDetailedMessage,
                L"Ares has encountered an internal error and is unable to continue normally. "
                L"Please visit our website at http://ares.strategy-x.com for updates and support.\n\n"
                L"%hs",
                Ares::readBuffer, 0x400);

        Debug::Log("\nFatal Error:\n");
        Debug::Log("%s\n", Ares::readBuffer);

        MessageBoxW(Game::hWnd,
                Dialogs::ExceptDetailedMessage,
                L"Fatal Error - Yuri's Revenge", MB_OK | MB_ICONERROR);

        if(Dump) {
                Debug::FullDump(NULL);
        }
}
void Debug::FatalError ( const char *  Message,
  ... 
) [static]
                                               {
        Debug::FreeMouse();

        va_list args;
        va_start(args, Message);
        vsnprintf(Ares::readBuffer, Ares::readLength, Message, args); /* note that the message will be truncated somewhere after 0x300 chars... */
        va_end(args);

        Debug::FatalError(false);
}
void Debug::FatalErrorAndExit ( const char *  Message,
  ... 
) [static]
                                                      {
        Debug::FreeMouse();

        va_list args;
        va_start(args, Message);
        vsnprintf(Ares::readBuffer, Ares::readLength, Message, args); /* note that the message will be truncated somewhere after 0x300 chars... */
        va_end(args);

        Debug::FatalError(false);
        Debug::Log("Exiting...\n");
        ExitProcess(1);
}
void Debug::Flush ( ) [static]
                  {
        if(Debug::bLog && Debug::pLogFile) {
                fflush(Debug::pLogFile);
        }
}
void Debug::FreeMouse ( ) [static]
                      {
//      static bool freed = false;
//      if(!freed) {
                Game::sub_53E6B0();

                MouseClass::Instance->SetPointer(0, 0);
                WWMouseClass::Instance->ReleaseMouse();

                ShowCursor(1);

#define BLACK_SURFACE(s) \
                if(DSurface::s) { \
                        DSurface::s->Fill(0); \
                }

                BLACK_SURFACE(Alternate);
                BLACK_SURFACE(Composite);
                BLACK_SURFACE(Hidden);
                BLACK_SURFACE(Hidden_2);
                BLACK_SURFACE(Primary);
                BLACK_SURFACE(Sidebar);
                BLACK_SURFACE(Tile);

                ShowCursor(1);

//              DirectDrawWrap::DisposeOfStuff();
//              DirectDrawWrap::lpDD->SetCooperativeLevel(Game::hWnd, eDDCoopLevel::DDSCL_NORMAL);
//              DirectDrawWrap::lpDD->SetDisplayMode(800, 600, 16);

//              freed = true;
//      }
}
void Debug::FullDump ( MINIDUMP_EXCEPTION_INFORMATION *  pException,
wchar_t *  generatedFilename = NULL 
) [static]
                                                                                            {
        wchar_t filename[MAX_PATH];
        wchar_t path[MAX_PATH];
        SYSTEMTIME time;

        GetLocalTime(&time);
        GetCurrentDirectoryW(MAX_PATH, path);

        swprintf(filename, MAX_PATH, L"%s\\debug", path);
        CreateDirectoryW(filename, NULL);

        swprintf(filename, MAX_PATH, L"%s\\debug\\extcrashdump.%04u%02u%02u-%02u%02u%02u.dmp",
                path, time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);

        if(generatedFilename) {
                CRT::wcsncpy(generatedFilename, filename, MAX_PATH - 1);
        }

        HANDLE dumpFile = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);

        MINIDUMP_TYPE type = (MINIDUMP_TYPE)MiniDumpWithFullMemory;

        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, type, pException, NULL, NULL);
        CloseHandle(dumpFile);
}
void Debug::INIParseFailed ( const char *  section,
const char *  flag,
const char *  value,
const char *  Message = NULL 
) [static]
                                                                                                        {
        if(Debug::bTrackParserErrors) {
                const char * LogMessage = (Message == NULL)
                        ? "Failed to parse INI file content: [%s]%s=%s\n"
                        : "Failed to parse INI file content: [%s]%s=%s (%s)\n"
                ;

                Debug::DevLog(Debug::Warning, LogMessage, section, flag, value, Message);
        }
}
void Debug::LogFileClose ( int  tag) [static]
{
        if(Debug::pLogFile) {
                fprintf(Debug::pLogFile, "Closing log file on request %d", tag);
                fclose(Debug::pLogFile);
                CopyFileW(LogFileTempName, LogFileName, FALSE);
                Debug::pLogFile = NULL;
        }
}
void Debug::LogFileOpen ( ) [static]
{
        MakeLogFile();
        LogFileClose(999);

        pLogFile = _wfopen(LogFileTempName, L"w");
        if(!pLogFile) {
                wchar_t msg[100] = L"\0";
                wsprintfW(msg, L"Log file failed to open. Error code = %X", errno);
                MessageBoxW(Game::hWnd, LogFileTempName, msg, MB_OK | MB_ICONEXCLAMATION);
                ExitProcess(1);
        }
}
void Debug::LogFileRemove ( ) [static]
{
        LogFileClose(555);
        DeleteFileW(LogFileTempName);
}
void __cdecl Debug::LogUnflushed ( const char *  Format,
  ... 
) [static]
                                                        {
        if(Debug::bLog && Debug::pLogFile) {
                va_list ArgList;
                va_start(ArgList, Format);
                vfprintf(Debug::pLogFile, Format, ArgList);
                va_end(ArgList);
        }
}
void Debug::MakeLogFile ( ) [static]
                        {
        static bool made = 0;
        if(!made) {
                wchar_t path[MAX_PATH];

                SYSTEMTIME time;

                GetLocalTime(&time);
                GetCurrentDirectoryW(MAX_PATH, path);

                swprintf(LogFileName, MAX_PATH, L"%s\\debug", path);
                CreateDirectoryW(LogFileName, NULL);

                swprintf(LogFileTempName, MAX_PATH, L"%s\\debug\\debug.log",
                        path);

                swprintf(LogFileName, MAX_PATH, L"%s\\debug\\debug.%04u%02u%02u-%02u%02u%02u.log",
                        path, time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond);

                made = 1;
        }
}
const char * Debug::SeverityString ( Debug::Severity  severity) [static]
                                                         {
        switch(severity) {
                case Notice:
                        return "notice";
                case Warning:
                        return "warning";
                case Error:
                        return "error";
                default:
                        return "wtf";
        }
}
static Debug::void ( _cdecl *  Log) const [static]

Member Data Documentation

bool Debug::bLog = true [static]
bool Debug::bParserErrorDetected = false [static]
bool Debug::bTrackParserErrors = false [static]
wchar_t Debug::LogFileName = "\0" [static]
wchar_t Debug::LogFileTempName = "\0" [static]
FILE * Debug::pLogFile = NULL [static]

The documentation for this class was generated from the following files:
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines