Except.cpp 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Commando/Code/wwlib/Except.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 2/07/02 12:28p $*
  29. * *
  30. * $Revision:: 14 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * *
  34. * *
  35. * *
  36. * *
  37. * *
  38. * *
  39. *---------------------------------------------------------------------------------------------*
  40. * Functions: *
  41. * *
  42. * Exception_Proc -- Windows dialog callback for the exception dialog *
  43. * Exception_Dialog -- Brings up the exception options dialog. *
  44. * Add_Txt -- Add the given text to the machine state dump buffer. *
  45. * Dump_Exception_Info -- Dump machine state information into a buffer *
  46. * Exception_Handler -- Exception handler filter function *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #ifdef _MSC_VER
  49. #include "always.h"
  50. #include <windows.h>
  51. #include "assert.h"
  52. #include "cpudetect.h"
  53. #include "except.h"
  54. //#include "debug.h"
  55. #include "mpu.h"
  56. //#include "commando\nat.h"
  57. #include "thread.h"
  58. #include "wwdebug.h"
  59. #include "wwmemlog.h"
  60. #include <conio.h>
  61. #include <imagehlp.h>
  62. #include <crtdbg.h>
  63. #include <stdio.h>
  64. #ifdef WWDEBUG
  65. #define DebugString WWDebug_Printf
  66. #else
  67. void DebugString(char const *, ...){};
  68. #endif //WWDEBUG
  69. /*
  70. ** Enable this define to get the 'demo timed out' message on a crash or assert failure.
  71. */
  72. //#define DEMO_TIME_OUT
  73. /*
  74. ** Buffer to dump machine state information to. We don't want to allocate this at run-time
  75. ** in case the exception was caused by a malfunction in the memory system.
  76. */
  77. static char ExceptionText [65536];
  78. bool SymbolsAvailable = false;
  79. HINSTANCE ImageHelp = (HINSTANCE) -1;
  80. void (*AppCallback)(void) = NULL;
  81. char *(*AppVersionCallback)(void) = NULL;
  82. /*
  83. ** Flag to indicate we should exit when an exception occurs.
  84. */
  85. bool ExitOnException = false;
  86. bool TryingToExit = false;
  87. /*
  88. ** Register dump variables. These are used to allow the game to restart from an arbitrary
  89. ** position after an exception occurs.
  90. */
  91. unsigned long ExceptionReturnStack = 0;
  92. unsigned long ExceptionReturnAddress = 0;
  93. unsigned long ExceptionReturnFrame = 0;
  94. /*
  95. ** Number of times the exception handler has recursed. Recursions are bad.
  96. */
  97. int ExceptionRecursions = -1;
  98. /*
  99. ** List of threads that the exception handler knows about.
  100. */
  101. DynamicVectorClass<ThreadInfoType*> ThreadList;
  102. /*
  103. ** Definitions to allow run-time linking to the Imagehlp.dll functions.
  104. **
  105. */
  106. typedef BOOL (WINAPI *SymCleanupType) (HANDLE hProcess);
  107. typedef BOOL (WINAPI *SymGetSymFromAddrType) (HANDLE hProcess, DWORD Address, LPDWORD Displacement, PIMAGEHLP_SYMBOL Symbol);
  108. typedef BOOL (WINAPI *SymInitializeType) (HANDLE hProcess, LPSTR UserSearchPath, BOOL fInvadeProcess);
  109. typedef BOOL (WINAPI *SymLoadModuleType) (HANDLE hProcess, HANDLE hFile, LPSTR ImageName, LPSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll);
  110. typedef DWORD (WINAPI *SymSetOptionsType) (DWORD SymOptions);
  111. typedef BOOL (WINAPI *SymUnloadModuleType) (HANDLE hProcess, DWORD BaseOfDll);
  112. 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);
  113. typedef LPVOID (WINAPI *SymFunctionTableAccessType) (HANDLE hProcess, DWORD AddrBase);
  114. typedef DWORD (WINAPI *SymGetModuleBaseType) (HANDLE hProcess, DWORD dwAddr);
  115. static SymCleanupType _SymCleanup = NULL;
  116. static SymGetSymFromAddrType _SymGetSymFromAddr = NULL;
  117. static SymInitializeType _SymInitialize = NULL;
  118. static SymLoadModuleType _SymLoadModule = NULL;
  119. static SymSetOptionsType _SymSetOptions = NULL;
  120. static SymUnloadModuleType _SymUnloadModule = NULL;
  121. static StackWalkType _StackWalk = NULL;
  122. static SymFunctionTableAccessType _SymFunctionTableAccess = NULL;
  123. static SymGetModuleBaseType _SymGetModuleBase = NULL;
  124. static char const *ImagehelpFunctionNames[] =
  125. {
  126. "SymCleanup",
  127. "SymGetSymFromAddr",
  128. "SymInitialize",
  129. "SymLoadModule",
  130. "SymSetOptions",
  131. "SymUnloadModule",
  132. "StackWalk",
  133. "SymFunctionTableAccess",
  134. "SymGetModuleBaseType",
  135. NULL
  136. };
  137. /***********************************************************************************************
  138. * _purecall -- This function overrides the C library Pure Virtual Function Call error *
  139. * *
  140. * *
  141. * *
  142. * INPUT: Nothing *
  143. * *
  144. * OUTPUT: 0 = no error *
  145. * *
  146. * WARNINGS: None *
  147. * *
  148. * HISTORY: *
  149. * 8/22/00 11:42AM ST : Created *
  150. *=============================================================================================*/
  151. int __cdecl _purecall(void)
  152. {
  153. int return_code = 0;
  154. #ifdef WWDEBUG
  155. /*
  156. ** Use int3 to cause an exception.
  157. */
  158. WWDEBUG_SAY(("Pure Virtual Function call. Oh No!\n"));
  159. _asm int 0x03;
  160. #endif //_DEBUG_ASSERT
  161. return(return_code);
  162. }
  163. /***********************************************************************************************
  164. * Last_Error_Text -- Get the system error text for GetLastError *
  165. * *
  166. * *
  167. * *
  168. * INPUT: Nothing *
  169. * *
  170. * OUTPUT: Ptr to error string *
  171. * *
  172. * WARNINGS: None *
  173. * *
  174. * HISTORY: *
  175. * 8/14/98 11:11AM ST : Created *
  176. *=============================================================================================*/
  177. char const * Last_Error_Text(void)
  178. {
  179. static char message_buffer[256];
  180. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &message_buffer[0], 256, NULL);
  181. return (message_buffer);
  182. }
  183. /***********************************************************************************************
  184. * Add_Txt -- Add the given text to the machine state dump buffer. *
  185. * *
  186. * *
  187. * *
  188. * INPUT: Text *
  189. * *
  190. * OUTPUT: Nothing *
  191. * *
  192. * WARNINGS: None *
  193. * *
  194. * HISTORY: *
  195. * 7/22/97 12:21PM ST : Created *
  196. *=============================================================================================*/
  197. static void Add_Txt (char const *txt)
  198. {
  199. if (strlen(ExceptionText) + strlen(txt) < 65535) {
  200. strcat(ExceptionText, txt);
  201. }
  202. #if (0)
  203. /*
  204. ** Log to debug output too.
  205. */
  206. static char _debug_output_txt[512];
  207. const char *in = txt;
  208. char *out = _debug_output_txt;
  209. bool done = false;
  210. if (strlen(txt) < sizeof(_debug_output_txt)) {
  211. for (int i=0 ; i<sizeof(_debug_output_txt) ; i++) {
  212. switch (*in) {
  213. case '\r':
  214. in++;
  215. continue;
  216. case 0:
  217. done = true;
  218. // fall through
  219. default:
  220. *out++ = *in++;
  221. break;
  222. }
  223. if (done) {
  224. break;
  225. }
  226. }
  227. DebugString(_debug_output_txt);
  228. }
  229. #endif //(0)
  230. }
  231. /***********************************************************************************************
  232. * Dump_Exception_Info -- Dump machine state information into a buffer *
  233. * *
  234. * *
  235. * *
  236. * INPUT: ptr to exception information *
  237. * *
  238. * OUTPUT: Nothing *
  239. * *
  240. * WARNINGS: None *
  241. * *
  242. * HISTORY: *
  243. * 7/22/97 12:21PM ST : Created *
  244. *=============================================================================================*/
  245. void Dump_Exception_Info(EXCEPTION_POINTERS *e_info)
  246. {
  247. /*
  248. ** List of possible exceptions
  249. */
  250. static const unsigned int _codes[] = {
  251. EXCEPTION_ACCESS_VIOLATION,
  252. EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
  253. EXCEPTION_BREAKPOINT,
  254. EXCEPTION_DATATYPE_MISALIGNMENT,
  255. EXCEPTION_FLT_DENORMAL_OPERAND,
  256. EXCEPTION_FLT_DIVIDE_BY_ZERO,
  257. EXCEPTION_FLT_INEXACT_RESULT,
  258. EXCEPTION_FLT_INVALID_OPERATION,
  259. EXCEPTION_FLT_OVERFLOW,
  260. EXCEPTION_FLT_STACK_CHECK,
  261. EXCEPTION_FLT_UNDERFLOW,
  262. EXCEPTION_ILLEGAL_INSTRUCTION,
  263. EXCEPTION_IN_PAGE_ERROR,
  264. EXCEPTION_INT_DIVIDE_BY_ZERO,
  265. EXCEPTION_INT_OVERFLOW,
  266. EXCEPTION_INVALID_DISPOSITION,
  267. EXCEPTION_NONCONTINUABLE_EXCEPTION,
  268. EXCEPTION_PRIV_INSTRUCTION,
  269. EXCEPTION_SINGLE_STEP,
  270. EXCEPTION_STACK_OVERFLOW,
  271. 0xffffffff
  272. };
  273. /*
  274. ** Information about each exception type.
  275. */
  276. static char const * _code_txt[] = {
  277. "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.",
  278. "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.",
  279. "Error code: EXCEPTION_BREAKPOINT\r\r\nDescription: A breakpoint was encountered.",
  280. "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.",
  281. "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.",
  282. "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.",
  283. "Error code: EXCEPTION_FLT_INEXACT_RESULT\r\r\nDescription: The result of a floating-point operation cannot be represented exactly as a decimal fraction.",
  284. "Error code: EXCEPTION_FLT_INVALID_OPERATION\r\r\nDescription: Some strange unknown floating point operation was attempted.",
  285. "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.",
  286. "Error code: EXCEPTION_FLT_STACK_CHECK\r\r\nDescription: The stack overflowed or underflowed as the result of a floating-point operation.",
  287. "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.",
  288. "Error code: EXCEPTION_ILLEGAL_INSTRUCTION\r\r\nDescription: The thread tried to execute an invalid instruction.",
  289. "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.",
  290. "Error code: EXCEPTION_INT_DIVIDE_BY_ZERO\r\r\nDescription: The thread tried to divide an integer value by an integer divisor of zero.",
  291. "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.",
  292. "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.",
  293. "Error code: EXCEPTION_NONCONTINUABLE_EXCEPTION\r\r\nDescription: The thread tried to continue execution after a noncontinuable exception occurred.",
  294. "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.",
  295. "Error code: EXCEPTION_SINGLE_STEP\r\r\nDescription: A trace trap or other single-instruction mechanism signaled that one instruction has been executed.",
  296. "Error code: EXCEPTION_STACK_OVERFLOW\r\r\nDescription: The thread used up its stack.",
  297. "Error code: ?????\r\r\nDescription: Unknown exception."
  298. };
  299. DebugString("Dump exception info\n");
  300. /*
  301. ** Scrap buffer for constructing dump strings
  302. */
  303. char scrap [256];
  304. /*
  305. ** Clear out the dump buffer
  306. */
  307. memset(ExceptionText, 0, sizeof (ExceptionText));
  308. /*
  309. ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
  310. ** can't be statically linked.
  311. */
  312. HINSTANCE imagehelp = LoadLibrary("IMAGEHLP.DLL");
  313. if (imagehelp != NULL) {
  314. DebugString ("Exception Handler: Found IMAGEHLP.DLL - linking to required functions\n");
  315. char const *function_name = NULL;
  316. unsigned long *fptr = (unsigned long*) &_SymCleanup;
  317. int count = 0;
  318. do {
  319. function_name = ImagehelpFunctionNames[count];
  320. if (function_name) {
  321. *fptr = (unsigned long) GetProcAddress(imagehelp, function_name);
  322. fptr++;
  323. count++;
  324. }
  325. } while (function_name);
  326. } else {
  327. DebugString("Exception Handler: Unable to load IMAGEHLP.DLL\n");
  328. }
  329. /*
  330. ** Retrieve the programs symbols if they are available
  331. */
  332. if (_SymSetOptions != NULL) {
  333. _SymSetOptions(SYMOPT_DEFERRED_LOADS);
  334. }
  335. int symload = 0;
  336. int symbols_available = false;
  337. if (_SymInitialize != NULL && _SymInitialize (GetCurrentProcess(), NULL, false)) {
  338. DebugString("Exception Handler: Symbols are available\r\n\n");
  339. symbols_available = true;
  340. }
  341. if (!symbols_available) {
  342. DebugString ("Exception Handler: SymInitialize failed with code %d - %s\n", GetLastError(), Last_Error_Text());
  343. } else {
  344. if (_SymSetOptions != NULL) {
  345. _SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
  346. }
  347. char module_name[_MAX_PATH];
  348. GetModuleFileName(NULL, module_name, sizeof(module_name));
  349. if (_SymLoadModule != NULL) {
  350. symload = _SymLoadModule(GetCurrentProcess(), NULL, module_name, NULL, 0, 0);
  351. }
  352. if (!symload) {
  353. assert(_SymLoadModule != NULL);
  354. DebugString ("Exception Handler: SymLoad failed for module %s with code %d - %s\n", module_name, GetLastError(), Last_Error_Text());
  355. }
  356. }
  357. unsigned char symbol [256];
  358. unsigned long displacement;
  359. IMAGEHLP_SYMBOL *symptr = (IMAGEHLP_SYMBOL*)&symbol;
  360. /*
  361. ** Get the exception address and the machine context at the time of the exception
  362. */
  363. CONTEXT *context = e_info->ContextRecord;
  364. /*
  365. ** The following are set for access violation only
  366. */
  367. int access_read_write=-1;
  368. unsigned long access_address = 0;
  369. if (e_info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
  370. DebugString("Exception Handler: Exception is access violation\n");
  371. access_read_write = e_info->ExceptionRecord->ExceptionInformation[0]; // 0=read, 1=write
  372. access_address = e_info->ExceptionRecord->ExceptionInformation[1];
  373. } else {
  374. DebugString ("Exception Handler: Exception code is %d\n", e_info->ExceptionRecord->ExceptionCode);
  375. }
  376. /*
  377. ** Match the exception type with the error string and print it out
  378. */
  379. for (int i=0 ; _codes[i] != 0xffffffff ; i++) {
  380. if (_codes[i] == e_info->ExceptionRecord->ExceptionCode) {
  381. DebugString("Exception Handler: Found exception description\n");
  382. break;
  383. }
  384. }
  385. Add_Txt(_code_txt[i]);
  386. Add_Txt("\r\n");
  387. /*
  388. ** For access violations, print out the violation address and if it was read or write.
  389. */
  390. if (e_info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
  391. sprintf(scrap, "Access address:%08X ", access_address);
  392. Add_Txt(scrap);
  393. if (access_read_write) {
  394. Add_Txt("was written to.\r\n");
  395. } else {
  396. Add_Txt("was read from.\r\n");
  397. }
  398. }
  399. /*
  400. ** If symbols are available, print out the exception eip address and the name of the
  401. ** function it represents.
  402. */
  403. memset(symptr, 0, sizeof (IMAGEHLP_SYMBOL));
  404. symptr->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
  405. symptr->MaxNameLength = 256-sizeof (IMAGEHLP_SYMBOL);
  406. symptr->Size = 0;
  407. symptr->Address = context->Eip;
  408. if (!IsBadCodePtr((FARPROC)context->Eip)) {
  409. if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), context->Eip, &displacement, symptr)) {
  410. sprintf (scrap, "Exception occurred at %08X - %s + %08X\r\n", context->Eip, symptr->Name, displacement);
  411. } else {
  412. DebugString ("Exception Handler: Failed to get symbol for EIP\r\n");
  413. if (_SymGetSymFromAddr != NULL) {
  414. DebugString ("Exception Handler: SymGetSymFromAddr failed with code %d - %s\n", GetLastError(), Last_Error_Text());
  415. }
  416. sprintf (scrap, "Exception occurred at %08X\r\n", context->Eip);
  417. }
  418. } else {
  419. DebugString ("Exception Handler: context->Eip is bad code pointer\n");
  420. }
  421. Add_Txt (scrap);
  422. /*
  423. ** Try to walk the stack. It might work....
  424. */
  425. DebugString("Stack walk...\n");
  426. Add_Txt("\r\n Stack walk...\r\n");
  427. unsigned long return_addresses[256];
  428. int num_addresses = Stack_Walk(return_addresses, 256, context);
  429. if (num_addresses) {
  430. for (int s=0 ; s<num_addresses ; s++) {
  431. unsigned long temp_addr = return_addresses[s];
  432. displacement = 0;
  433. for (int space = 0 ; space <= s ; space++) {
  434. Add_Txt(" ");
  435. }
  436. if (symbols_available) {
  437. symptr->SizeOfStruct = sizeof(symbol);
  438. symptr->MaxNameLength = 128;
  439. symptr->Size = 0;
  440. symptr->Address = temp_addr;
  441. if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), temp_addr, &displacement, symptr)) {
  442. char symbuf[256];
  443. sprintf(symbuf, "%s + %08X\r\n", symptr->Name, displacement);
  444. Add_Txt(symbuf);
  445. }
  446. } else {
  447. char symbuf[256];
  448. sprintf(symbuf, "%08x\r\n", temp_addr);
  449. Add_Txt(symbuf);
  450. }
  451. }
  452. Add_Txt("\r\n\r\n");
  453. } else {
  454. DebugString("Stack walk failed!\n");
  455. Add_Txt("Stack walk failed!\r\n");
  456. }
  457. #if (0) //Don't have this info yet for Renegade.
  458. /*
  459. ** Add in the version info.
  460. */
  461. sprintf(scrap, "\r\nVersion %s\r\n", Version_Name());
  462. Add_Txt(scrap);
  463. sprintf(scrap, "Internal Version %s\r\n", VerNum.Version_Name());
  464. Add_Txt(scrap);
  465. char buildinfo[128];
  466. buildinfo[0] = 0;
  467. Build_Date_String(buildinfo, 128);
  468. char build_number[128];
  469. char build_name[128];
  470. #endif //(0)
  471. if (AppVersionCallback) {
  472. sprintf(scrap, "%s\r\n\r\n", AppVersionCallback());
  473. Add_Txt(scrap);
  474. }
  475. /*
  476. ** Thread list.
  477. */
  478. Add_Txt("Thread list\r\n");
  479. /*
  480. ** Get the thread info from ThreadClass.
  481. */
  482. for (int thread = 0 ; thread < ThreadList.Count() ; thread++) {
  483. sprintf(scrap, " ID: %08X - %s", ThreadList[thread]->ThreadID, ThreadList[thread]->ThreadName);
  484. Add_Txt(scrap);
  485. if (GetCurrentThreadId() == ThreadList[thread]->ThreadID) {
  486. Add_Txt(" ***CURRENT THREAD***");
  487. }
  488. Add_Txt("\r\n");
  489. }
  490. /*
  491. ** CPU type
  492. */
  493. 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());
  494. Add_Txt(scrap);
  495. Add_Txt("\r\nDetails:\r\n");
  496. DebugString("Register dump...\n");
  497. /*
  498. ** Dump the registers.
  499. */
  500. sprintf(scrap, "Eip:%08X\tEsp:%08X\tEbp:%08X\r\n", context->Eip, context->Esp, context->Ebp);
  501. Add_Txt(scrap);
  502. sprintf(scrap, "Eax:%08X\tEbx:%08X\tEcx:%08X\r\n", context->Eax, context->Ebx, context->Ecx);
  503. Add_Txt(scrap);
  504. sprintf(scrap, "Edx:%08X\tEsi:%08X\tEdi:%08X\r\n", context->Edx, context->Esi, context->Edi);
  505. Add_Txt(scrap);
  506. sprintf(scrap, "EFlags:%08X \r\n", context->EFlags);
  507. Add_Txt(scrap);
  508. 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);
  509. Add_Txt(scrap);
  510. /*
  511. ** Now the FP registers.
  512. */
  513. Add_Txt("\r\nFloating point status\r\n");
  514. sprintf(scrap, " Control word: %08x\r\n", context->FloatSave.ControlWord);
  515. Add_Txt(scrap);
  516. sprintf(scrap, " Status word: %08x\r\n", context->FloatSave.StatusWord);
  517. Add_Txt(scrap);
  518. sprintf(scrap, " Tag word: %08x\r\n", context->FloatSave.TagWord);
  519. Add_Txt(scrap);
  520. sprintf(scrap, " Error Offset: %08x\r\n", context->FloatSave.ErrorOffset);
  521. Add_Txt(scrap);
  522. sprintf(scrap, " Error Selector: %08x\r\n", context->FloatSave.ErrorSelector);
  523. Add_Txt(scrap);
  524. sprintf(scrap, " Data Offset: %08x\r\n", context->FloatSave.DataOffset);
  525. Add_Txt(scrap);
  526. sprintf(scrap, " Data Selector: %08x\r\n", context->FloatSave.DataSelector);
  527. Add_Txt(scrap);
  528. sprintf(scrap, " Cr0NpxState: %08x\r\n", context->FloatSave.Cr0NpxState);
  529. Add_Txt(scrap);
  530. for (int fp=0 ; fp<SIZE_OF_80387_REGISTERS / 10 ; fp++) {
  531. sprintf(scrap, "ST%d : ", fp);
  532. Add_Txt(scrap);
  533. for (int b=0 ; b<10 ; b++) {
  534. sprintf(scrap, "%02X", context->FloatSave.RegisterArea[(fp*10) + b]);
  535. Add_Txt(scrap);
  536. }
  537. void *fp_data_ptr = (void*)(&context->FloatSave.RegisterArea[fp*10]);
  538. double fp_value;
  539. /*
  540. ** Convert FP dump from temporary real value (10 bytes) to double (8 bytes).
  541. */
  542. _asm {
  543. push eax
  544. mov eax,fp_data_ptr
  545. fld tbyte ptr [eax]
  546. fstp qword ptr [fp_value]
  547. pop eax
  548. }
  549. sprintf(scrap, " %+#.17e\r\n", fp_value);
  550. Add_Txt(scrap);
  551. }
  552. /*
  553. ** Dump the bytes at EIP. This will make it easier to match the crash address with later versions of the game.
  554. */
  555. DebugString("EIP bytes dump...\n");
  556. sprintf(scrap, "\r\nBytes at CS:EIP (%08X) : ", context->Eip);
  557. unsigned char *eip_ptr = (unsigned char *) (context->Eip);
  558. char bytestr[32];
  559. for (int c = 0 ; c < 32 ; c++) {
  560. if (IsBadReadPtr(eip_ptr, 1)) {
  561. strcat(scrap, "?? ");
  562. } else {
  563. sprintf(bytestr, "%02X ", *eip_ptr);
  564. strcat(scrap, bytestr);
  565. }
  566. eip_ptr++;
  567. }
  568. strcat(scrap, "\r\n\r\n");
  569. Add_Txt(scrap);
  570. /*
  571. ** Dump out the values on the stack.
  572. */
  573. DebugString("Stack dump...\n");
  574. Add_Txt("Stack dump (* indicates possible code address) :\r\n");
  575. unsigned long *stackptr = (unsigned long*) context->Esp;
  576. for (int j=0 ; j<2048 ; j++) {
  577. if (IsBadReadPtr(stackptr, 4)) {
  578. /*
  579. ** The stack contents cannot be read so just print up question marks.
  580. */
  581. sprintf(scrap, "%08X: ", stackptr);
  582. strcat(scrap, "????????\r\n");
  583. } else {
  584. /*
  585. ** If this stack address is in our memory space then try to match it with a code symbol.
  586. */
  587. if (IsBadCodePtr((FARPROC)*stackptr)) {
  588. sprintf(scrap, "%08X: %08X ", stackptr, *stackptr);
  589. strcat(scrap, "DATA_PTR\r\n");
  590. } else {
  591. sprintf(scrap, "%08X: %08X", stackptr, *stackptr);
  592. if (symbols_available) {
  593. symptr->SizeOfStruct = sizeof(symbol);
  594. symptr->MaxNameLength = 128;
  595. symptr->Size = 0;
  596. symptr->Address = *stackptr;
  597. if (_SymGetSymFromAddr != NULL && _SymGetSymFromAddr (GetCurrentProcess(), *stackptr, &displacement, symptr)) {
  598. char symbuf[256];
  599. sprintf(symbuf, " - %s + %08X", symptr->Name, displacement);
  600. strcat(scrap, symbuf);
  601. }
  602. } else {
  603. strcat (scrap, " *");
  604. }
  605. strcat (scrap, "\r\n");
  606. }
  607. }
  608. Add_Txt(scrap);
  609. stackptr++;
  610. }
  611. /*
  612. ** Unload the symbols.
  613. */
  614. if (symbols_available) {
  615. if (_SymCleanup != NULL) {
  616. _SymCleanup (GetCurrentProcess());
  617. }
  618. if (symload) {
  619. if (_SymUnloadModule != NULL) {
  620. _SymUnloadModule(GetCurrentProcess(), NULL);
  621. }
  622. }
  623. }
  624. if (imagehelp) {
  625. FreeLibrary(imagehelp);
  626. }
  627. Add_Txt ("\r\n\r\n");
  628. }
  629. /***********************************************************************************************
  630. * Exception_Handler -- Exception handler filter function *
  631. * *
  632. * *
  633. * *
  634. * INPUT: exception code *
  635. * pointer to exception information pointers *
  636. * *
  637. * OUTPUT: EXCEPTION_EXECUTE_HANDLER -- Excecute the body of the __except construct *
  638. * or EXCEPTION_CONTINUE_SEARCH -- Pass this exception down to the debugger *
  639. * or EXCEPTION_CONTINUE_EXECUTION -- Continue to execute at the fault address *
  640. * *
  641. * WARNINGS: None *
  642. * *
  643. * HISTORY: *
  644. * 7/22/97 12:29PM ST : Created *
  645. *=============================================================================================*/
  646. int Exception_Handler(int exception_code, EXCEPTION_POINTERS *e_info)
  647. {
  648. DebugString("Exception!\n");
  649. #ifdef DEMO_TIME_OUT
  650. if ( !WindowedMode ) {
  651. Load_Title_Page("TITLE.PCX", true);
  652. MouseCursor->Release_Mouse();
  653. MessageBox(MainWindow, "This demo has timed out. Thank you for playing Red Alert 2.","Byeee!", MB_ICONEXCLAMATION|MB_OK);
  654. return (EXCEPTION_EXECUTE_HANDLER);
  655. }
  656. #endif //DEMO_TIME_OUT
  657. /*
  658. ** If we were trying to quit and we got another exception then just shut down the whole shooting match right here.
  659. */
  660. if (TryingToExit) {
  661. ExitProcess(0);
  662. }
  663. /*
  664. ** Track recursions because we need to know if something here is failing.
  665. */
  666. ExceptionRecursions++;
  667. if (ExceptionRecursions > 1) {
  668. return (EXCEPTION_CONTINUE_SEARCH);
  669. }
  670. /*
  671. ** If there was a breakpoint then chances are it was set by a debugger. In _DEBUG mode
  672. ** we probably should ignore breakpoints. Breakpoints become more significant in release
  673. ** mode since there probably isn't a debugger present.
  674. */
  675. #ifdef _DEBUG
  676. if (exception_code == EXCEPTION_BREAKPOINT) {
  677. return (EXCEPTION_CONTINUE_SEARCH);
  678. }
  679. #else
  680. exception_code = exception_code;
  681. #endif //_DEBUG
  682. #ifdef WWDEBUG
  683. //CONTEXT *context;
  684. #endif WWDEBUG
  685. if (ExceptionRecursions == 0) {
  686. /*
  687. ** Create a dump of the exception info.
  688. */
  689. Dump_Exception_Info(e_info);
  690. /*
  691. ** Log the machine state to disk
  692. */
  693. HANDLE debug_file;
  694. DWORD actual;
  695. debug_file = CreateFile("_except.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  696. if (debug_file != INVALID_HANDLE_VALUE){
  697. WriteFile(debug_file, ExceptionText, strlen(ExceptionText), &actual, NULL);
  698. CloseHandle (debug_file);
  699. #if (0)
  700. #ifdef _DEBUG_PRINT
  701. #ifndef _DEBUG
  702. /*
  703. ** Copy the exception debug file to the network. No point in doing this for the debug version
  704. ** since symbols are not normally available.
  705. */
  706. DebugString ("About to copy debug file\n");
  707. char filename[512];
  708. if (Get_Global_Output_File_Name ("EXCEPT", filename, 512)) {
  709. DebugString ("Copying DEBUG.TXT to %s\n", filename);
  710. int result = CopyFile("debug.txt", filename, false);
  711. if (result == 0) {
  712. DebugString ("CopyFile failed with error code %d - %s\n", GetLastError(), Last_Error_Text());
  713. }
  714. }
  715. DebugString ("Debug file copied\n");
  716. #endif //_DEBUG
  717. #endif //_DEBUG_PRINT
  718. #endif //(0)
  719. }
  720. }
  721. /*
  722. ** Call the apps callback function.
  723. */
  724. if (AppCallback) {
  725. AppCallback();
  726. }
  727. /*
  728. ** If an exit is required then turn of memory leak reporting (there will be lots of them) and use
  729. ** EXCEPTION_EXECUTE_HANDLER to let us fall out of winmain.
  730. */
  731. if (ExitOnException) {
  732. #ifdef _DEBUG
  733. _CrtSetDbgFlag(0);
  734. #endif //_DEBUG
  735. TryingToExit = true;
  736. unsigned long id = Get_Main_Thread_ID();
  737. if (id != GetCurrentThreadId()) {
  738. DebugString("Exiting due to exception in sub thread\n");
  739. ExitProcess(EXIT_SUCCESS);
  740. }
  741. return(EXCEPTION_EXECUTE_HANDLER);
  742. }
  743. return (EXCEPTION_CONTINUE_SEARCH);
  744. }
  745. /***********************************************************************************************
  746. * Register_Thread_ID -- Let the exception handler know about a thread *
  747. * *
  748. * *
  749. * *
  750. * INPUT: Thread ID *
  751. * Thread name *
  752. * *
  753. * OUTPUT: Nothing *
  754. * *
  755. * WARNINGS: None *
  756. * *
  757. * HISTORY: *
  758. * 8/30/2001 3:04PM ST : Created *
  759. *=============================================================================================*/
  760. void Register_Thread_ID(unsigned long thread_id, char *thread_name, bool main_thread)
  761. {
  762. WWMEMLOG(MEM_GAMEDATA);
  763. if (thread_name) {
  764. /*
  765. ** See if we already know about this thread. Maybe just the thread_id changed.
  766. */
  767. for (int i=0 ; i<ThreadList.Count() ; i++) {
  768. if (strcmp(thread_name, ThreadList[i]->ThreadName) == 0) {
  769. ThreadList[i]->ThreadID = thread_id;
  770. return;
  771. }
  772. }
  773. ThreadInfoType *thread = new ThreadInfoType;
  774. thread->ThreadID = thread_id;
  775. strcpy(thread->ThreadName, thread_name);
  776. thread->Main = main_thread;
  777. thread->ThreadHandle = INVALID_HANDLE_VALUE;
  778. ThreadList.Add(thread);
  779. }
  780. }
  781. #if (0)
  782. /***********************************************************************************************
  783. * Register_Thread_Handle -- Keep a copy of the thread handle that matches this thread ID *
  784. * *
  785. * *
  786. * *
  787. * INPUT: Thread ID *
  788. * Thread handle *
  789. * *
  790. * OUTPUT: True if thread ID was matched *
  791. * *
  792. * WARNINGS: *
  793. * *
  794. * HISTORY: *
  795. * 2/6/2002 9:40PM ST : Created *
  796. *=============================================================================================*/
  797. bool Register_Thread_Handle(unsigned long thread_id, HANDLE thread_handle)
  798. {
  799. for (int i=0 ; i<ThreadList.Count() ; i++) {
  800. if (ThreadList[i]->ThreadID == thread_id) {
  801. ThreadList[i]->ThreadHandle = thread_handle;
  802. return(true);
  803. break;
  804. }
  805. }
  806. return(false);
  807. }
  808. /***********************************************************************************************
  809. * Get_Num_Threads -- Get the number of threads being tracked. *
  810. * *
  811. * *
  812. * *
  813. * INPUT: Nothing *
  814. * *
  815. * OUTPUT: Number of threads we know about *
  816. * *
  817. * WARNINGS: None *
  818. * *
  819. * HISTORY: *
  820. * 2/6/2002 9:43PM ST : Created *
  821. *=============================================================================================*/
  822. int Get_Num_Threads(void)
  823. {
  824. return(ThreadList.Count());
  825. }
  826. /***********************************************************************************************
  827. * Get_Thread_Handle -- Get the handle for the given thread index *
  828. * *
  829. * *
  830. * *
  831. * INPUT: Thread index *
  832. * *
  833. * OUTPUT: Thread handle *
  834. * *
  835. * WARNINGS: None *
  836. * *
  837. * HISTORY: *
  838. * 2/6/2002 9:46PM ST : Created *
  839. *=============================================================================================*/
  840. HANDLE Get_Thread_Handle(int thread_index)
  841. {
  842. if (thread_index < ThreadList.Count()) {
  843. return(ThreadList[thread_index]->ThreadHandle);
  844. }
  845. }
  846. #endif //(0)
  847. /***********************************************************************************************
  848. * Unregister_Thread_ID -- Remove a thread entry from the thread list *
  849. * *
  850. * *
  851. * *
  852. * INPUT: Thread ID *
  853. * Thread name *
  854. * *
  855. * OUTPUT: Nothing *
  856. * *
  857. * WARNINGS: None *
  858. * *
  859. * HISTORY: *
  860. * 8/30/2001 3:10PM ST : Created *
  861. *=============================================================================================*/
  862. void Unregister_Thread_ID(unsigned long thread_id, char *thread_name)
  863. {
  864. for (int i=0 ; i<ThreadList.Count() ; i++) {
  865. if (strcmp(thread_name, ThreadList[i]->ThreadName) == 0) {
  866. assert(ThreadList[i]->ThreadID == thread_id);
  867. delete ThreadList[i];
  868. ThreadList.Delete(i);
  869. return;
  870. }
  871. }
  872. }
  873. /***********************************************************************************************
  874. * Get_Main_Thread_ID -- Get the ID of the processes main thread *
  875. * *
  876. * *
  877. * *
  878. * INPUT: Nothing *
  879. * *
  880. * OUTPUT: Thread ID *
  881. * *
  882. * WARNINGS: None *
  883. * *
  884. * HISTORY: *
  885. * 12/6/2001 12:20PM ST : Created *
  886. *=============================================================================================*/
  887. unsigned long Get_Main_Thread_ID(void)
  888. {
  889. for (int i=0 ; i<ThreadList.Count() ; i++) {
  890. if (ThreadList[i]->Main) {
  891. return(ThreadList[i]->ThreadID);
  892. }
  893. }
  894. return(0);
  895. }
  896. /***********************************************************************************************
  897. * Load_Image_Helper -- Load imagehlp.dll and retrieve the programs symbols *
  898. * *
  899. * *
  900. * *
  901. * INPUT: Nothing *
  902. * *
  903. * OUTPUT: Nothing *
  904. * *
  905. * WARNINGS: None *
  906. * *
  907. * HISTORY: *
  908. * 6/12/2001 4:27PM ST : Created *
  909. *=============================================================================================*/
  910. void Load_Image_Helper(void)
  911. {
  912. /*
  913. ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
  914. ** can't be statically linked.
  915. */
  916. if (ImageHelp == (HINSTANCE)-1) {
  917. ImageHelp = LoadLibrary("IMAGEHLP.DLL");
  918. if (ImageHelp != NULL) {
  919. char const *function_name = NULL;
  920. unsigned long *fptr = (unsigned long *) &_SymCleanup;
  921. int count = 0;
  922. do {
  923. function_name = ImagehelpFunctionNames[count];
  924. if (function_name) {
  925. *fptr = (unsigned long) GetProcAddress(ImageHelp, function_name);
  926. fptr++;
  927. count++;
  928. }
  929. }
  930. while (function_name);
  931. }
  932. /*
  933. ** Retrieve the programs symbols if they are available. This can be a .pdb or a .dbg file.
  934. */
  935. if (_SymSetOptions != NULL) {
  936. _SymSetOptions(SYMOPT_DEFERRED_LOADS);
  937. }
  938. int symload = 0;
  939. if (_SymInitialize != NULL && _SymInitialize(GetCurrentProcess(), NULL, FALSE)) {
  940. if (_SymSetOptions != NULL) {
  941. _SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
  942. }
  943. char exe_name[_MAX_PATH];
  944. GetModuleFileName(NULL, exe_name, sizeof(exe_name));
  945. if (_SymLoadModule != NULL) {
  946. symload = _SymLoadModule(GetCurrentProcess(), NULL, exe_name, NULL, 0, 0);
  947. }
  948. if (symload) {
  949. SymbolsAvailable = true;
  950. } else {
  951. //assert (_SymLoadModule != NULL);
  952. //DebugString ("SymLoad failed for module %s with code %d - %s\n", szModuleName, GetLastError(), Last_Error_Text());
  953. }
  954. }
  955. }
  956. }
  957. /***********************************************************************************************
  958. * Lookup_Symbol -- Get the symbol for a given code address *
  959. * *
  960. * *
  961. * *
  962. * INPUT: Address of code to get symbol for *
  963. * Ptr to buffer to return symbol in *
  964. * Reference to int to return displacement *
  965. * *
  966. * OUTPUT: True if symbol found *
  967. * *
  968. * WARNINGS: None *
  969. * *
  970. * HISTORY: *
  971. * 6/12/2001 4:47PM ST : Created *
  972. *=============================================================================================*/
  973. bool Lookup_Symbol(void *code_ptr, char *symbol, int &displacement)
  974. {
  975. /*
  976. ** Locals.
  977. */
  978. char symbol_struct_buf[1024];
  979. IMAGEHLP_SYMBOL *symbol_struct_ptr = (IMAGEHLP_SYMBOL *)symbol_struct_buf;
  980. /*
  981. ** Set default values in case of early exit.
  982. */
  983. displacement = 0;
  984. *symbol = '\0';
  985. /*
  986. ** Make sure symbols are available.
  987. */
  988. if (!SymbolsAvailable || _SymGetSymFromAddr == NULL) {
  989. return(false);
  990. }
  991. /*
  992. ** If it's a bad code pointer then there is no point in trying to match it with a symbol.
  993. */
  994. if (IsBadCodePtr((FARPROC)code_ptr)) {
  995. strcpy(symbol, "Bad code pointer");
  996. return(false);
  997. }
  998. /*
  999. ** Set up the parameters for the call to SymGetSymFromAddr
  1000. */
  1001. memset (symbol_struct_ptr, 0, sizeof (symbol_struct_buf));
  1002. symbol_struct_ptr->SizeOfStruct = sizeof (symbol_struct_buf);
  1003. symbol_struct_ptr->MaxNameLength = sizeof(symbol_struct_buf)-sizeof (IMAGEHLP_SYMBOL);
  1004. symbol_struct_ptr->Size = 0;
  1005. symbol_struct_ptr->Address = (unsigned long)code_ptr;
  1006. /*
  1007. ** See if we have the symbol for that address.
  1008. */
  1009. if (_SymGetSymFromAddr(GetCurrentProcess(), (unsigned long)code_ptr, (unsigned long *)&displacement, symbol_struct_ptr)) {
  1010. /*
  1011. ** Copy it back into the buffer provided.
  1012. */
  1013. strcpy(symbol, symbol_struct_ptr->Name);
  1014. return(true);
  1015. }
  1016. return(false);
  1017. }
  1018. /***********************************************************************************************
  1019. * Stack_Walk -- Walk the stack and get the last n return addresses *
  1020. * *
  1021. * *
  1022. * *
  1023. * INPUT: Ptr to return address list *
  1024. * Number of return addresses to fetch *
  1025. * Ptr to optional context. NULL means use current *
  1026. * *
  1027. * OUTPUT: Number of return addresses found *
  1028. * *
  1029. * WARNINGS: None *
  1030. * *
  1031. * HISTORY: *
  1032. * 6/12/2001 11:57AM ST : Created *
  1033. *=============================================================================================*/
  1034. int Stack_Walk(unsigned long *return_addresses, int num_addresses, CONTEXT *context)
  1035. {
  1036. static HINSTANCE _imagehelp = (HINSTANCE) -1;
  1037. /*
  1038. ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
  1039. ** can't be statically linked.
  1040. */
  1041. if (ImageHelp == (HINSTANCE)-1) {
  1042. Load_Image_Helper();
  1043. }
  1044. /*
  1045. ** If there is no debug support .dll available then we can't walk the stack.
  1046. */
  1047. if (ImageHelp == NULL) {
  1048. return(0);
  1049. }
  1050. /*
  1051. ** Set up the stack frame structure for the start point of the stack walk (i.e. here).
  1052. */
  1053. STACKFRAME stack_frame;
  1054. memset(&stack_frame, 0, sizeof(stack_frame));
  1055. unsigned long reg_eip, reg_ebp, reg_esp;
  1056. __asm {
  1057. here:
  1058. lea eax,here
  1059. mov reg_eip,eax
  1060. mov reg_ebp,ebp
  1061. mov reg_esp,esp
  1062. }
  1063. stack_frame.AddrPC.Mode = AddrModeFlat;
  1064. stack_frame.AddrPC.Offset = reg_eip;
  1065. stack_frame.AddrStack.Mode = AddrModeFlat;
  1066. stack_frame.AddrStack.Offset = reg_esp;
  1067. stack_frame.AddrFrame.Mode = AddrModeFlat;
  1068. stack_frame.AddrFrame.Offset = reg_ebp;
  1069. /*
  1070. ** Use the context struct if it was provided.
  1071. */
  1072. if (context) {
  1073. stack_frame.AddrPC.Offset = context->Eip;
  1074. stack_frame.AddrStack.Offset = context->Esp;
  1075. stack_frame.AddrFrame.Offset = context->Ebp;
  1076. }
  1077. int pointer_index = 0;
  1078. /*
  1079. ** Walk the stack by the requested number of return address iterations.
  1080. */
  1081. for (int i = 0; i < num_addresses + 1; i++) {
  1082. if (_StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &stack_frame, NULL, NULL, _SymFunctionTableAccess, _SymGetModuleBase, NULL)) {
  1083. /*
  1084. ** First result will always be the return address we were called from.
  1085. */
  1086. if (i==0 && context == NULL) {
  1087. continue;
  1088. }
  1089. unsigned long return_address = stack_frame.AddrReturn.Offset;
  1090. return_addresses[pointer_index++] = return_address;
  1091. } else {
  1092. break;
  1093. }
  1094. }
  1095. return(pointer_index);
  1096. }
  1097. void Register_Application_Exception_Callback(void (*app_callback)(void))
  1098. {
  1099. AppCallback = app_callback;
  1100. }
  1101. void Register_Application_Version_Callback(char *(*app_ver_callback)(void))
  1102. {
  1103. AppVersionCallback = app_ver_callback;
  1104. }
  1105. void Set_Exit_On_Exception(bool set)
  1106. {
  1107. ExitOnException = true;
  1108. }
  1109. bool Is_Trying_To_Exit(void)
  1110. {
  1111. return(TryingToExit);
  1112. }
  1113. #endif //_MSC_VER