| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * $Archive:: /Commando/Code/wwlib/Except.cpp $*
- * *
- * $Author:: Steve_t $*
- * *
- * $Modtime:: 2/07/02 12:28p $*
- * *
- * $Revision:: 14 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * *
- * *
- * *
- * *
- * *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * *
- * Exception_Proc -- Windows dialog callback for the exception dialog *
- * Exception_Dialog -- Brings up the exception options dialog. *
- * Add_Txt -- Add the given text to the machine state dump buffer. *
- * Dump_Exception_Info -- Dump machine state information into a buffer *
- * Exception_Handler -- Exception handler filter function *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #ifdef _MSC_VER
- #include "always.h"
- #include <windows.h>
- #include "assert.h"
- #include "cpudetect.h"
- #include "except.h"
- //#include "debug.h"
- #include "mpu.h"
- //#include "commando\nat.h"
- #include "thread.h"
- #include "wwdebug.h"
- #include "wwmemlog.h"
- #include <conio.h>
- #include <imagehlp.h>
- #include <crtdbg.h>
- #include <stdio.h>
- #ifdef WWDEBUG
- #define DebugString WWDebug_Printf
- #else
- void DebugString(char const *, ...){};
- #endif //WWDEBUG
- /*
- ** Enable this define to get the 'demo timed out' message on a crash or assert failure.
- */
- //#define DEMO_TIME_OUT
- /*
- ** Buffer to dump machine state information to. We don't want to allocate this at run-time
- ** in case the exception was caused by a malfunction in the memory system.
- */
- static char ExceptionText [65536];
- bool SymbolsAvailable = false;
- HINSTANCE ImageHelp = (HINSTANCE) -1;
- void (*AppCallback)(void) = NULL;
- char *(*AppVersionCallback)(void) = NULL;
- /*
- ** Flag to indicate we should exit when an exception occurs.
- */
- bool ExitOnException = false;
- bool TryingToExit = false;
- /*
- ** Register dump variables. These are used to allow the game to restart from an arbitrary
- ** position after an exception occurs.
- */
- unsigned long ExceptionReturnStack = 0;
- unsigned long ExceptionReturnAddress = 0;
- unsigned long ExceptionReturnFrame = 0;
- /*
- ** Number of times the exception handler has recursed. Recursions are bad.
- */
- int ExceptionRecursions = -1;
- /*
- ** List of threads that the exception handler knows about.
- */
- DynamicVectorClass<ThreadInfoType*> ThreadList;
- /*
- ** Definitions to allow run-time linking to the Imagehlp.dll functions.
- **
- */
- typedef BOOL (WINAPI *SymCleanupType) (HANDLE hProcess);
- typedef BOOL (WINAPI *SymGetSymFromAddrType) (HANDLE hProcess, DWORD Address, LPDWORD Displacement, PIMAGEHLP_SYMBOL Symbol);
- typedef BOOL (WINAPI *SymInitializeType) (HANDLE hProcess, LPSTR UserSearchPath, BOOL fInvadeProcess);
- typedef BOOL (WINAPI *SymLoadModuleType) (HANDLE hProcess, HANDLE hFile, LPSTR ImageName, LPSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll);
- typedef DWORD (WINAPI *SymSetOptionsType) (DWORD SymOptions);
- typedef BOOL (WINAPI *SymUnloadModuleType) (HANDLE hProcess, DWORD BaseOfDll);
- typedef BOOL (WINAPI *StackWalkType) (DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, LPVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
- typedef LPVOID (WINAPI *SymFunctionTableAccessType) (HANDLE hProcess, DWORD AddrBase);
- typedef DWORD (WINAPI *SymGetModuleBaseType) (HANDLE hProcess, DWORD dwAddr);
- static SymCleanupType _SymCleanup = NULL;
- static SymGetSymFromAddrType _SymGetSymFromAddr = NULL;
- static SymInitializeType _SymInitialize = NULL;
- static SymLoadModuleType _SymLoadModule = NULL;
- static SymSetOptionsType _SymSetOptions = NULL;
- static SymUnloadModuleType _SymUnloadModule = NULL;
- static StackWalkType _StackWalk = NULL;
- static SymFunctionTableAccessType _SymFunctionTableAccess = NULL;
- static SymGetModuleBaseType _SymGetModuleBase = NULL;
- static char const *ImagehelpFunctionNames[] =
- {
- "SymCleanup",
- "SymGetSymFromAddr",
- "SymInitialize",
- "SymLoadModule",
- "SymSetOptions",
- "SymUnloadModule",
- "StackWalk",
- "SymFunctionTableAccess",
- "SymGetModuleBaseType",
- NULL
- };
- /***********************************************************************************************
- * _purecall -- This function overrides the C library Pure Virtual Function Call error *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: 0 = no error *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/22/00 11:42AM ST : Created *
- *=============================================================================================*/
- int __cdecl _purecall(void)
- {
- int return_code = 0;
- #ifdef WWDEBUG
- /*
- ** Use int3 to cause an exception.
- */
- WWDEBUG_SAY(("Pure Virtual Function call. Oh No!\n"));
- _asm int 0x03;
- #endif //_DEBUG_ASSERT
- return(return_code);
- }
- /***********************************************************************************************
- * Last_Error_Text -- Get the system error text for GetLastError *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Ptr to error string *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/14/98 11:11AM ST : Created *
- *=============================================================================================*/
- char const * Last_Error_Text(void)
- {
- static char message_buffer[256];
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &message_buffer[0], 256, NULL);
- return (message_buffer);
- }
- /***********************************************************************************************
- * Add_Txt -- Add the given text to the machine state dump buffer. *
- * *
- * *
- * *
- * INPUT: Text *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 7/22/97 12:21PM ST : Created *
- *=============================================================================================*/
- static void Add_Txt (char const *txt)
- {
- if (strlen(ExceptionText) + strlen(txt) < 65535) {
- strcat(ExceptionText, txt);
- }
- #if (0)
- /*
- ** Log to debug output too.
- */
- static char _debug_output_txt[512];
- const char *in = txt;
- char *out = _debug_output_txt;
- bool done = false;
- if (strlen(txt) < sizeof(_debug_output_txt)) {
- for (int i=0 ; i<sizeof(_debug_output_txt) ; i++) {
- switch (*in) {
- case '\r':
- in++;
- continue;
- case 0:
- done = true;
- // fall through
- default:
- *out++ = *in++;
- break;
- }
- if (done) {
- break;
- }
- }
- DebugString(_debug_output_txt);
- }
- #endif //(0)
- }
- /***********************************************************************************************
- * Dump_Exception_Info -- Dump machine state information into a buffer *
- * *
- * *
- * *
- * INPUT: ptr to exception information *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 7/22/97 12:21PM ST : Created *
- *=============================================================================================*/
- void Dump_Exception_Info(EXCEPTION_POINTERS *e_info)
- {
- /*
- ** List of possible exceptions
- */
- static const unsigned int _codes[] = {
- EXCEPTION_ACCESS_VIOLATION,
- EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
- EXCEPTION_BREAKPOINT,
- EXCEPTION_DATATYPE_MISALIGNMENT,
- EXCEPTION_FLT_DENORMAL_OPERAND,
- EXCEPTION_FLT_DIVIDE_BY_ZERO,
- EXCEPTION_FLT_INEXACT_RESULT,
- EXCEPTION_FLT_INVALID_OPERATION,
- EXCEPTION_FLT_OVERFLOW,
- EXCEPTION_FLT_STACK_CHECK,
- EXCEPTION_FLT_UNDERFLOW,
- EXCEPTION_ILLEGAL_INSTRUCTION,
- EXCEPTION_IN_PAGE_ERROR,
- EXCEPTION_INT_DIVIDE_BY_ZERO,
- EXCEPTION_INT_OVERFLOW,
- EXCEPTION_INVALID_DISPOSITION,
- EXCEPTION_NONCONTINUABLE_EXCEPTION,
- EXCEPTION_PRIV_INSTRUCTION,
- EXCEPTION_SINGLE_STEP,
- EXCEPTION_STACK_OVERFLOW,
- 0xffffffff
- };
- /*
- ** Information about each exception type.
- */
- static char const * _code_txt[] = {
- "Error code: EXCEPTION_ACCESS_VIOLATION\r\r\nDescription: The thread tried to read from or write to a virtual address for which it does not have the appropriate access.",
- "Error code: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\r\r\nDescription: The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking.",
- "Error code: EXCEPTION_BREAKPOINT\r\r\nDescription: A breakpoint was encountered.",
- "Error code: EXCEPTION_DATATYPE_MISALIGNMENT\r\r\nDescription: The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on.",
- "Error code: EXCEPTION_FLT_DENORMAL_OPERAND\r\r\nDescription: One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.",
- "Error code: EXCEPTION_FLT_DIVIDE_BY_ZERO\r\r\nDescription: The thread tried to divide a floating-point value by a floating-point divisor of zero.",
- "Error code: EXCEPTION_FLT_INEXACT_RESULT\r\r\nDescription: The result of a floating-point operation cannot be represented exactly as a decimal fraction.",
- "Error code: EXCEPTION_FLT_INVALID_OPERATION\r\r\nDescription: Some strange unknown floating point operation was attempted.",
- "Error code: EXCEPTION_FLT_OVERFLOW\r\r\nDescription: The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.",
- "Error code: EXCEPTION_FLT_STACK_CHECK\r\r\nDescription: The stack overflowed or underflowed as the result of a floating-point operation.",
- "Error code: EXCEPTION_FLT_UNDERFLOW\r\r\nDescription: The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.",
- "Error code: EXCEPTION_ILLEGAL_INSTRUCTION\r\r\nDescription: The thread tried to execute an invalid instruction.",
- "Error code: EXCEPTION_IN_PAGE_ERROR\r\r\nDescription: The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network.",
- "Error code: EXCEPTION_INT_DIVIDE_BY_ZERO\r\r\nDescription: The thread tried to divide an integer value by an integer divisor of zero.",
- "Error code: EXCEPTION_INT_OVERFLOW\r\r\nDescription: The result of an integer operation caused a carry out of the most significant bit of the result.",
- "Error code: EXCEPTION_INVALID_DISPOSITION\r\r\nDescription: An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception.",
- "Error code: EXCEPTION_NONCONTINUABLE_EXCEPTION\r\r\nDescription: The thread tried to continue execution after a noncontinuable exception occurred.",
- "Error code: EXCEPTION_PRIV_INSTRUCTION\r\r\nDescription: The thread tried to execute an instruction whose operation is not allowed in the current machine mode.",
- "Error code: EXCEPTION_SINGLE_STEP\r\r\nDescription: A trace trap or other single-instruction mechanism signaled that one instruction has been executed.",
- "Error code: EXCEPTION_STACK_OVERFLOW\r\r\nDescription: The thread used up its stack.",
- "Error code: ?????\r\r\nDescription: Unknown exception."
- };
- DebugString("Dump exception info\n");
- /*
- ** Scrap buffer for constructing dump strings
- */
- char scrap [256];
- /*
- ** Clear out the dump buffer
- */
- memset(ExceptionText, 0, sizeof (ExceptionText));
- /*
- ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
- ** can't be statically linked.
- */
- HINSTANCE imagehelp = LoadLibrary("IMAGEHLP.DLL");
- if (imagehelp != NULL) {
- DebugString ("Exception Handler: Found IMAGEHLP.DLL - linking to required functions\n");
- char const *function_name = NULL;
- unsigned long *fptr = (unsigned long*) &_SymCleanup;
- int count = 0;
- do {
- function_name = ImagehelpFunctionNames[count];
- if (function_name) {
- *fptr = (unsigned long) GetProcAddress(imagehelp, function_name);
- fptr++;
- count++;
- }
- } while (function_name);
- } else {
- DebugString("Exception Handler: Unable to load IMAGEHLP.DLL\n");
- }
- /*
- ** Retrieve the programs symbols if they are available
- */
- if (_SymSetOptions != NULL) {
- _SymSetOptions(SYMOPT_DEFERRED_LOADS);
- }
- int symload = 0;
- int symbols_available = false;
- if (_SymInitialize != NULL && _SymInitialize (GetCurrentProcess(), NULL, false)) {
- DebugString("Exception Handler: Symbols are available\r\n\n");
- symbols_available = true;
- }
- if (!symbols_available) {
- DebugString ("Exception Handler: SymInitialize failed with code %d - %s\n", GetLastError(), Last_Error_Text());
- } else {
- if (_SymSetOptions != NULL) {
- _SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
- }
- char module_name[_MAX_PATH];
- GetModuleFileName(NULL, module_name, sizeof(module_name));
- if (_SymLoadModule != NULL) {
- symload = _SymLoadModule(GetCurrentProcess(), NULL, module_name, NULL, 0, 0);
- }
- if (!symload) {
- assert(_SymLoadModule != NULL);
- DebugString ("Exception Handler: SymLoad failed for module %s with code %d - %s\n", module_name, GetLastError(), Last_Error_Text());
- }
- }
- unsigned char symbol [256];
- unsigned long displacement;
- IMAGEHLP_SYMBOL *symptr = (IMAGEHLP_SYMBOL*)&symbol;
- /*
- ** Get the exception address and the machine context at the time of the exception
- */
- CONTEXT *context = e_info->ContextRecord;
- /*
- ** The following are set for access violation only
- */
- int access_read_write=-1;
- unsigned long access_address = 0;
- if (e_info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
- DebugString("Exception Handler: Exception is access violation\n");
- access_read_write = e_info->ExceptionRecord->ExceptionInformation[0]; // 0=read, 1=write
- access_address = e_info->ExceptionRecord->ExceptionInformation[1];
- } else {
- DebugString ("Exception Handler: Exception code is %d\n", e_info->ExceptionRecord->ExceptionCode);
- }
- /*
- ** Match the exception type with the error string and print it out
- */
- for (int i=0 ; _codes[i] != 0xffffffff ; i++) {
- if (_codes[i] == e_info->ExceptionRecord->ExceptionCode) {
- DebugString("Exception Handler: Found exception description\n");
- break;
- }
- }
- Add_Txt(_code_txt[i]);
- Add_Txt("\r\n");
- /*
- ** For access violations, print out the violation address and if it was read or write.
- */
- if (e_info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
- sprintf(scrap, "Access address:%08X ", access_address);
- Add_Txt(scrap);
- if (access_read_write) {
- Add_Txt("was written to.\r\n");
- } else {
- Add_Txt("was read from.\r\n");
- }
- }
- /*
- ** If symbols are available, print out the exception eip address and the name of the
- ** function it represents.
- */
- memset(symptr, 0, sizeof (IMAGEHLP_SYMBOL));
- symptr->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
- symptr->MaxNameLength = 256-sizeof (IMAGEHLP_SYMBOL);
- symptr->Size = 0;
- symptr->Address = context->Eip;
- if (!IsBadCodePtr((FARPROC)context->Eip)) {
- if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), context->Eip, &displacement, symptr)) {
- sprintf (scrap, "Exception occurred at %08X - %s + %08X\r\n", context->Eip, symptr->Name, displacement);
- } else {
- DebugString ("Exception Handler: Failed to get symbol for EIP\r\n");
- if (_SymGetSymFromAddr != NULL) {
- DebugString ("Exception Handler: SymGetSymFromAddr failed with code %d - %s\n", GetLastError(), Last_Error_Text());
- }
- sprintf (scrap, "Exception occurred at %08X\r\n", context->Eip);
- }
- } else {
- DebugString ("Exception Handler: context->Eip is bad code pointer\n");
- }
- Add_Txt (scrap);
- /*
- ** Try to walk the stack. It might work....
- */
- DebugString("Stack walk...\n");
- Add_Txt("\r\n Stack walk...\r\n");
- unsigned long return_addresses[256];
- int num_addresses = Stack_Walk(return_addresses, 256, context);
- if (num_addresses) {
- for (int s=0 ; s<num_addresses ; s++) {
- unsigned long temp_addr = return_addresses[s];
- displacement = 0;
- for (int space = 0 ; space <= s ; space++) {
- Add_Txt(" ");
- }
- if (symbols_available) {
- symptr->SizeOfStruct = sizeof(symbol);
- symptr->MaxNameLength = 128;
- symptr->Size = 0;
- symptr->Address = temp_addr;
- if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), temp_addr, &displacement, symptr)) {
- char symbuf[256];
- sprintf(symbuf, "%s + %08X\r\n", symptr->Name, displacement);
- Add_Txt(symbuf);
- }
- } else {
- char symbuf[256];
- sprintf(symbuf, "%08x\r\n", temp_addr);
- Add_Txt(symbuf);
- }
- }
- Add_Txt("\r\n\r\n");
- } else {
- DebugString("Stack walk failed!\n");
- Add_Txt("Stack walk failed!\r\n");
- }
- #if (0) //Don't have this info yet for Renegade.
- /*
- ** Add in the version info.
- */
- sprintf(scrap, "\r\nVersion %s\r\n", Version_Name());
- Add_Txt(scrap);
- sprintf(scrap, "Internal Version %s\r\n", VerNum.Version_Name());
- Add_Txt(scrap);
- char buildinfo[128];
- buildinfo[0] = 0;
- Build_Date_String(buildinfo, 128);
- char build_number[128];
- char build_name[128];
- #endif //(0)
- if (AppVersionCallback) {
- sprintf(scrap, "%s\r\n\r\n", AppVersionCallback());
- Add_Txt(scrap);
- }
- /*
- ** Thread list.
- */
- Add_Txt("Thread list\r\n");
- /*
- ** Get the thread info from ThreadClass.
- */
- for (int thread = 0 ; thread < ThreadList.Count() ; thread++) {
- sprintf(scrap, " ID: %08X - %s", ThreadList[thread]->ThreadID, ThreadList[thread]->ThreadName);
- Add_Txt(scrap);
- if (GetCurrentThreadId() == ThreadList[thread]->ThreadID) {
- Add_Txt(" ***CURRENT THREAD***");
- }
- Add_Txt("\r\n");
- }
- /*
- ** CPU type
- */
- sprintf(scrap, "\r\nCPU %s, %d Mhz, Vendor: %s\r\n", (char*)CPUDetectClass::Get_Processor_String(), Get_RDTSC_CPU_Speed(), (char*)CPUDetectClass::Get_Processor_Manufacturer_Name());
- Add_Txt(scrap);
- Add_Txt("\r\nDetails:\r\n");
- DebugString("Register dump...\n");
- /*
- ** Dump the registers.
- */
- sprintf(scrap, "Eip:%08X\tEsp:%08X\tEbp:%08X\r\n", context->Eip, context->Esp, context->Ebp);
- Add_Txt(scrap);
- sprintf(scrap, "Eax:%08X\tEbx:%08X\tEcx:%08X\r\n", context->Eax, context->Ebx, context->Ecx);
- Add_Txt(scrap);
- sprintf(scrap, "Edx:%08X\tEsi:%08X\tEdi:%08X\r\n", context->Edx, context->Esi, context->Edi);
- Add_Txt(scrap);
- sprintf(scrap, "EFlags:%08X \r\n", context->EFlags);
- Add_Txt(scrap);
- sprintf(scrap, "CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x\r\n", context->SegCs, context->SegSs, context->SegDs, context->SegEs, context->SegFs, context->SegGs);
- Add_Txt(scrap);
- /*
- ** Now the FP registers.
- */
- Add_Txt("\r\nFloating point status\r\n");
- sprintf(scrap, " Control word: %08x\r\n", context->FloatSave.ControlWord);
- Add_Txt(scrap);
- sprintf(scrap, " Status word: %08x\r\n", context->FloatSave.StatusWord);
- Add_Txt(scrap);
- sprintf(scrap, " Tag word: %08x\r\n", context->FloatSave.TagWord);
- Add_Txt(scrap);
- sprintf(scrap, " Error Offset: %08x\r\n", context->FloatSave.ErrorOffset);
- Add_Txt(scrap);
- sprintf(scrap, " Error Selector: %08x\r\n", context->FloatSave.ErrorSelector);
- Add_Txt(scrap);
- sprintf(scrap, " Data Offset: %08x\r\n", context->FloatSave.DataOffset);
- Add_Txt(scrap);
- sprintf(scrap, " Data Selector: %08x\r\n", context->FloatSave.DataSelector);
- Add_Txt(scrap);
- sprintf(scrap, " Cr0NpxState: %08x\r\n", context->FloatSave.Cr0NpxState);
- Add_Txt(scrap);
- for (int fp=0 ; fp<SIZE_OF_80387_REGISTERS / 10 ; fp++) {
- sprintf(scrap, "ST%d : ", fp);
- Add_Txt(scrap);
- for (int b=0 ; b<10 ; b++) {
- sprintf(scrap, "%02X", context->FloatSave.RegisterArea[(fp*10) + b]);
- Add_Txt(scrap);
- }
- void *fp_data_ptr = (void*)(&context->FloatSave.RegisterArea[fp*10]);
- double fp_value;
- /*
- ** Convert FP dump from temporary real value (10 bytes) to double (8 bytes).
- */
- _asm {
- push eax
- mov eax,fp_data_ptr
- fld tbyte ptr [eax]
- fstp qword ptr [fp_value]
- pop eax
- }
- sprintf(scrap, " %+#.17e\r\n", fp_value);
- Add_Txt(scrap);
- }
- /*
- ** Dump the bytes at EIP. This will make it easier to match the crash address with later versions of the game.
- */
- DebugString("EIP bytes dump...\n");
- sprintf(scrap, "\r\nBytes at CS:EIP (%08X) : ", context->Eip);
- unsigned char *eip_ptr = (unsigned char *) (context->Eip);
- char bytestr[32];
- for (int c = 0 ; c < 32 ; c++) {
- if (IsBadReadPtr(eip_ptr, 1)) {
- strcat(scrap, "?? ");
- } else {
- sprintf(bytestr, "%02X ", *eip_ptr);
- strcat(scrap, bytestr);
- }
- eip_ptr++;
- }
- strcat(scrap, "\r\n\r\n");
- Add_Txt(scrap);
- /*
- ** Dump out the values on the stack.
- */
- DebugString("Stack dump...\n");
- Add_Txt("Stack dump (* indicates possible code address) :\r\n");
- unsigned long *stackptr = (unsigned long*) context->Esp;
- for (int j=0 ; j<2048 ; j++) {
- if (IsBadReadPtr(stackptr, 4)) {
- /*
- ** The stack contents cannot be read so just print up question marks.
- */
- sprintf(scrap, "%08X: ", stackptr);
- strcat(scrap, "????????\r\n");
- } else {
- /*
- ** If this stack address is in our memory space then try to match it with a code symbol.
- */
- if (IsBadCodePtr((FARPROC)*stackptr)) {
- sprintf(scrap, "%08X: %08X ", stackptr, *stackptr);
- strcat(scrap, "DATA_PTR\r\n");
- } else {
- sprintf(scrap, "%08X: %08X", stackptr, *stackptr);
- if (symbols_available) {
- symptr->SizeOfStruct = sizeof(symbol);
- symptr->MaxNameLength = 128;
- symptr->Size = 0;
- symptr->Address = *stackptr;
- if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), *stackptr, &displacement, symptr)) {
- char symbuf[256];
- sprintf(symbuf, " - %s + %08X", symptr->Name, displacement);
- strcat(scrap, symbuf);
- }
- } else {
- strcat (scrap, " *");
- }
- strcat (scrap, "\r\n");
- }
- }
- Add_Txt(scrap);
- stackptr++;
- }
- /*
- ** Unload the symbols.
- */
- if (symbols_available) {
- if (_SymCleanup != NULL) {
- _SymCleanup (GetCurrentProcess());
- }
- if (symload) {
- if (_SymUnloadModule != NULL) {
- _SymUnloadModule(GetCurrentProcess(), NULL);
- }
- }
- }
- if (imagehelp) {
- FreeLibrary(imagehelp);
- }
- Add_Txt ("\r\n\r\n");
- }
- /***********************************************************************************************
- * Exception_Handler -- Exception handler filter function *
- * *
- * *
- * *
- * INPUT: exception code *
- * pointer to exception information pointers *
- * *
- * OUTPUT: EXCEPTION_EXECUTE_HANDLER -- Excecute the body of the __except construct *
- * or EXCEPTION_CONTINUE_SEARCH -- Pass this exception down to the debugger *
- * or EXCEPTION_CONTINUE_EXECUTION -- Continue to execute at the fault address *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 7/22/97 12:29PM ST : Created *
- *=============================================================================================*/
- int Exception_Handler(int exception_code, EXCEPTION_POINTERS *e_info)
- {
- DebugString("Exception!\n");
- #ifdef DEMO_TIME_OUT
- if ( !WindowedMode ) {
- Load_Title_Page("TITLE.PCX", true);
- MouseCursor->Release_Mouse();
- MessageBox(MainWindow, "This demo has timed out. Thank you for playing Red Alert 2.","Byeee!", MB_ICONEXCLAMATION|MB_OK);
- return (EXCEPTION_EXECUTE_HANDLER);
- }
- #endif //DEMO_TIME_OUT
- /*
- ** If we were trying to quit and we got another exception then just shut down the whole shooting match right here.
- */
- if (TryingToExit) {
- ExitProcess(0);
- }
- /*
- ** Track recursions because we need to know if something here is failing.
- */
- ExceptionRecursions++;
- if (ExceptionRecursions > 1) {
- return (EXCEPTION_CONTINUE_SEARCH);
- }
- /*
- ** If there was a breakpoint then chances are it was set by a debugger. In _DEBUG mode
- ** we probably should ignore breakpoints. Breakpoints become more significant in release
- ** mode since there probably isn't a debugger present.
- */
- #ifdef _DEBUG
- if (exception_code == EXCEPTION_BREAKPOINT) {
- return (EXCEPTION_CONTINUE_SEARCH);
- }
- #else
- exception_code = exception_code;
- #endif //_DEBUG
- #ifdef WWDEBUG
- //CONTEXT *context;
- #endif WWDEBUG
- if (ExceptionRecursions == 0) {
- /*
- ** Create a dump of the exception info.
- */
- Dump_Exception_Info(e_info);
- /*
- ** Log the machine state to disk
- */
- HANDLE debug_file;
- DWORD actual;
- debug_file = CreateFile("_except.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (debug_file != INVALID_HANDLE_VALUE){
- WriteFile(debug_file, ExceptionText, strlen(ExceptionText), &actual, NULL);
- CloseHandle (debug_file);
- #if (0)
- #ifdef _DEBUG_PRINT
- #ifndef _DEBUG
- /*
- ** Copy the exception debug file to the network. No point in doing this for the debug version
- ** since symbols are not normally available.
- */
- DebugString ("About to copy debug file\n");
- char filename[512];
- if (Get_Global_Output_File_Name ("EXCEPT", filename, 512)) {
- DebugString ("Copying DEBUG.TXT to %s\n", filename);
- int result = CopyFile("debug.txt", filename, false);
- if (result == 0) {
- DebugString ("CopyFile failed with error code %d - %s\n", GetLastError(), Last_Error_Text());
- }
- }
- DebugString ("Debug file copied\n");
- #endif //_DEBUG
- #endif //_DEBUG_PRINT
- #endif //(0)
- }
- }
- /*
- ** Call the apps callback function.
- */
- if (AppCallback) {
- AppCallback();
- }
- /*
- ** If an exit is required then turn of memory leak reporting (there will be lots of them) and use
- ** EXCEPTION_EXECUTE_HANDLER to let us fall out of winmain.
- */
- if (ExitOnException) {
- #ifdef _DEBUG
- _CrtSetDbgFlag(0);
- #endif //_DEBUG
- TryingToExit = true;
- unsigned long id = Get_Main_Thread_ID();
- if (id != GetCurrentThreadId()) {
- DebugString("Exiting due to exception in sub thread\n");
- ExitProcess(EXIT_SUCCESS);
- }
- return(EXCEPTION_EXECUTE_HANDLER);
- }
- return (EXCEPTION_CONTINUE_SEARCH);
- }
- /***********************************************************************************************
- * Register_Thread_ID -- Let the exception handler know about a thread *
- * *
- * *
- * *
- * INPUT: Thread ID *
- * Thread name *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/30/2001 3:04PM ST : Created *
- *=============================================================================================*/
- void Register_Thread_ID(unsigned long thread_id, char *thread_name, bool main_thread)
- {
- WWMEMLOG(MEM_GAMEDATA);
- if (thread_name) {
- /*
- ** See if we already know about this thread. Maybe just the thread_id changed.
- */
- for (int i=0 ; i<ThreadList.Count() ; i++) {
- if (strcmp(thread_name, ThreadList[i]->ThreadName) == 0) {
- ThreadList[i]->ThreadID = thread_id;
- return;
- }
- }
- ThreadInfoType *thread = new ThreadInfoType;
- thread->ThreadID = thread_id;
- strcpy(thread->ThreadName, thread_name);
- thread->Main = main_thread;
- thread->ThreadHandle = INVALID_HANDLE_VALUE;
- ThreadList.Add(thread);
- }
- }
- #if (0)
- /***********************************************************************************************
- * Register_Thread_Handle -- Keep a copy of the thread handle that matches this thread ID *
- * *
- * *
- * *
- * INPUT: Thread ID *
- * Thread handle *
- * *
- * OUTPUT: True if thread ID was matched *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 2/6/2002 9:40PM ST : Created *
- *=============================================================================================*/
- bool Register_Thread_Handle(unsigned long thread_id, HANDLE thread_handle)
- {
- for (int i=0 ; i<ThreadList.Count() ; i++) {
- if (ThreadList[i]->ThreadID == thread_id) {
- ThreadList[i]->ThreadHandle = thread_handle;
- return(true);
- break;
- }
- }
- return(false);
- }
- /***********************************************************************************************
- * Get_Num_Threads -- Get the number of threads being tracked. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Number of threads we know about *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 2/6/2002 9:43PM ST : Created *
- *=============================================================================================*/
- int Get_Num_Threads(void)
- {
- return(ThreadList.Count());
- }
- /***********************************************************************************************
- * Get_Thread_Handle -- Get the handle for the given thread index *
- * *
- * *
- * *
- * INPUT: Thread index *
- * *
- * OUTPUT: Thread handle *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 2/6/2002 9:46PM ST : Created *
- *=============================================================================================*/
- HANDLE Get_Thread_Handle(int thread_index)
- {
- if (thread_index < ThreadList.Count()) {
- return(ThreadList[thread_index]->ThreadHandle);
- }
- }
- #endif //(0)
- /***********************************************************************************************
- * Unregister_Thread_ID -- Remove a thread entry from the thread list *
- * *
- * *
- * *
- * INPUT: Thread ID *
- * Thread name *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/30/2001 3:10PM ST : Created *
- *=============================================================================================*/
- void Unregister_Thread_ID(unsigned long thread_id, char *thread_name)
- {
- for (int i=0 ; i<ThreadList.Count() ; i++) {
- if (strcmp(thread_name, ThreadList[i]->ThreadName) == 0) {
- assert(ThreadList[i]->ThreadID == thread_id);
- delete ThreadList[i];
- ThreadList.Delete(i);
- return;
- }
- }
- }
- /***********************************************************************************************
- * Get_Main_Thread_ID -- Get the ID of the processes main thread *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Thread ID *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 12/6/2001 12:20PM ST : Created *
- *=============================================================================================*/
- unsigned long Get_Main_Thread_ID(void)
- {
- for (int i=0 ; i<ThreadList.Count() ; i++) {
- if (ThreadList[i]->Main) {
- return(ThreadList[i]->ThreadID);
- }
- }
- return(0);
- }
- /***********************************************************************************************
- * Load_Image_Helper -- Load imagehlp.dll and retrieve the programs symbols *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 6/12/2001 4:27PM ST : Created *
- *=============================================================================================*/
- void Load_Image_Helper(void)
- {
- /*
- ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
- ** can't be statically linked.
- */
- if (ImageHelp == (HINSTANCE)-1) {
- ImageHelp = LoadLibrary("IMAGEHLP.DLL");
- if (ImageHelp != NULL) {
- char const *function_name = NULL;
- unsigned long *fptr = (unsigned long *) &_SymCleanup;
- int count = 0;
- do {
- function_name = ImagehelpFunctionNames[count];
- if (function_name) {
- *fptr = (unsigned long) GetProcAddress(ImageHelp, function_name);
- fptr++;
- count++;
- }
- }
- while (function_name);
- }
- /*
- ** Retrieve the programs symbols if they are available. This can be a .pdb or a .dbg file.
- */
- if (_SymSetOptions != NULL) {
- _SymSetOptions(SYMOPT_DEFERRED_LOADS);
- }
- int symload = 0;
- if (_SymInitialize != NULL && _SymInitialize(GetCurrentProcess(), NULL, FALSE)) {
- if (_SymSetOptions != NULL) {
- _SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
- }
- char exe_name[_MAX_PATH];
- GetModuleFileName(NULL, exe_name, sizeof(exe_name));
- if (_SymLoadModule != NULL) {
- symload = _SymLoadModule(GetCurrentProcess(), NULL, exe_name, NULL, 0, 0);
- }
- if (symload) {
- SymbolsAvailable = true;
- } else {
- //assert (_SymLoadModule != NULL);
- //DebugString ("SymLoad failed for module %s with code %d - %s\n", szModuleName, GetLastError(), Last_Error_Text());
- }
- }
- }
- }
- /***********************************************************************************************
- * Lookup_Symbol -- Get the symbol for a given code address *
- * *
- * *
- * *
- * INPUT: Address of code to get symbol for *
- * Ptr to buffer to return symbol in *
- * Reference to int to return displacement *
- * *
- * OUTPUT: True if symbol found *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 6/12/2001 4:47PM ST : Created *
- *=============================================================================================*/
- bool Lookup_Symbol(void *code_ptr, char *symbol, int &displacement)
- {
- /*
- ** Locals.
- */
- char symbol_struct_buf[1024];
- IMAGEHLP_SYMBOL *symbol_struct_ptr = (IMAGEHLP_SYMBOL *)symbol_struct_buf;
- /*
- ** Set default values in case of early exit.
- */
- displacement = 0;
- *symbol = '\0';
- /*
- ** Make sure symbols are available.
- */
- if (!SymbolsAvailable || _SymGetSymFromAddr == NULL) {
- return(false);
- }
- /*
- ** If it's a bad code pointer then there is no point in trying to match it with a symbol.
- */
- if (IsBadCodePtr((FARPROC)code_ptr)) {
- strcpy(symbol, "Bad code pointer");
- return(false);
- }
- /*
- ** Set up the parameters for the call to SymGetSymFromAddr
- */
- memset (symbol_struct_ptr, 0, sizeof (symbol_struct_buf));
- symbol_struct_ptr->SizeOfStruct = sizeof (symbol_struct_buf);
- symbol_struct_ptr->MaxNameLength = sizeof(symbol_struct_buf)-sizeof (IMAGEHLP_SYMBOL);
- symbol_struct_ptr->Size = 0;
- symbol_struct_ptr->Address = (unsigned long)code_ptr;
- /*
- ** See if we have the symbol for that address.
- */
- if (_SymGetSymFromAddr(GetCurrentProcess(), (unsigned long)code_ptr, (unsigned long *)&displacement, symbol_struct_ptr)) {
- /*
- ** Copy it back into the buffer provided.
- */
- strcpy(symbol, symbol_struct_ptr->Name);
- return(true);
- }
- return(false);
- }
- /***********************************************************************************************
- * Stack_Walk -- Walk the stack and get the last n return addresses *
- * *
- * *
- * *
- * INPUT: Ptr to return address list *
- * Number of return addresses to fetch *
- * Ptr to optional context. NULL means use current *
- * *
- * OUTPUT: Number of return addresses found *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 6/12/2001 11:57AM ST : Created *
- *=============================================================================================*/
- int Stack_Walk(unsigned long *return_addresses, int num_addresses, CONTEXT *context)
- {
- static HINSTANCE _imagehelp = (HINSTANCE) -1;
- /*
- ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
- ** can't be statically linked.
- */
- if (ImageHelp == (HINSTANCE)-1) {
- Load_Image_Helper();
- }
- /*
- ** If there is no debug support .dll available then we can't walk the stack.
- */
- if (ImageHelp == NULL) {
- return(0);
- }
- /*
- ** Set up the stack frame structure for the start point of the stack walk (i.e. here).
- */
- STACKFRAME stack_frame;
- memset(&stack_frame, 0, sizeof(stack_frame));
- unsigned long reg_eip, reg_ebp, reg_esp;
- __asm {
- here:
- lea eax,here
- mov reg_eip,eax
- mov reg_ebp,ebp
- mov reg_esp,esp
- }
- stack_frame.AddrPC.Mode = AddrModeFlat;
- stack_frame.AddrPC.Offset = reg_eip;
- stack_frame.AddrStack.Mode = AddrModeFlat;
- stack_frame.AddrStack.Offset = reg_esp;
- stack_frame.AddrFrame.Mode = AddrModeFlat;
- stack_frame.AddrFrame.Offset = reg_ebp;
- /*
- ** Use the context struct if it was provided.
- */
- if (context) {
- stack_frame.AddrPC.Offset = context->Eip;
- stack_frame.AddrStack.Offset = context->Esp;
- stack_frame.AddrFrame.Offset = context->Ebp;
- }
- int pointer_index = 0;
- /*
- ** Walk the stack by the requested number of return address iterations.
- */
- for (int i = 0; i < num_addresses + 1; i++) {
- if (_StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &stack_frame, NULL, NULL, _SymFunctionTableAccess, _SymGetModuleBase, NULL)) {
- /*
- ** First result will always be the return address we were called from.
- */
- if (i==0 && context == NULL) {
- continue;
- }
- unsigned long return_address = stack_frame.AddrReturn.Offset;
- return_addresses[pointer_index++] = return_address;
- } else {
- break;
- }
- }
- return(pointer_index);
- }
- void Register_Application_Exception_Callback(void (*app_callback)(void))
- {
- AppCallback = app_callback;
- }
- void Register_Application_Version_Callback(char *(*app_ver_callback)(void))
- {
- AppVersionCallback = app_ver_callback;
- }
- void Set_Exit_On_Exception(bool set)
- {
- ExitOnException = true;
- }
- bool Is_Trying_To_Exit(void)
- {
- return(TryingToExit);
- }
- #endif //_MSC_VER
|