debug.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/debug.cpp $*
  25. * *
  26. * $Author:: Bhayes $*
  27. * *
  28. * $Modtime:: 2/16/02 8:44p $*
  29. * *
  30. * $Revision:: 90 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "debug.h"
  36. #include "input.h"
  37. #include "ww3dtrig.h"
  38. #include "wwphystrig.h"
  39. #include "timemgr.h"
  40. #include "ww3d.h"
  41. #include "mono.h"
  42. #include "registry.h"
  43. #include <stdio.h>
  44. #include "wwaudio.h"
  45. #include "combat.h"
  46. #include "wwmemlog.h"
  47. #include "fastallocator.h"
  48. #ifndef STEVES_NEW_CATCHER
  49. #define LOG_MEMORY 1 // enable this to turn on memory logging
  50. #endif //STEVES_NEW_CATCHER
  51. /*
  52. **
  53. */
  54. int DebugManager::EnabledDevices;
  55. int DebugManager::EnabledTypes;
  56. int DebugManager::EnabledOptions;
  57. bool DebugManager::EnableFileLogging;
  58. bool DebugManager::EnableDiagLogging;
  59. bool DebugManager::LoadDebugScripts;
  60. int DebugManager::VersionNumber = 0;
  61. bool DebugManager::IsSlave = false;
  62. bool DebugManager::AllowCinematicKeys = false;
  63. CriticalSectionClass DebugManager::CriticalSection;
  64. DebugDisplayHandlerClass * DebugManager::DisplayHandler = NULL;
  65. #define DEFAULT_LOGFILE_NAME "_logfile.txt"
  66. LPSTR DebugManager::LOGFILE = DEFAULT_LOGFILE_NAME;
  67. char DebugManager::LogfileNameBuffer[256];
  68. MonoClass ScrollingScreen;
  69. /*
  70. ** local prototypes
  71. */
  72. void wwdebug_message_handler(DebugType type, const char * message);
  73. void wwdebug_assert_handler(const char * message);
  74. bool wwdebug_trigger_handler(int trigger_num);
  75. void wwdebug_profile_start_handler( const char * title );
  76. void wwdebug_profile_stop_handler( const char * title );
  77. char DefaultRegistryModifier[1024] = {""};
  78. /*
  79. **
  80. */
  81. void DebugManager::Init( void )
  82. {
  83. // Enable Mono Screen
  84. ScrollingScreen.Enable();
  85. // Install message handler functions for the WWDebug messages
  86. // and assertion failures.
  87. WWDebug_Install_Message_Handler(wwdebug_message_handler);
  88. WWDebug_Install_Assert_Handler(wwdebug_assert_handler);
  89. WWDebug_Install_Trigger_Handler(wwdebug_trigger_handler);
  90. WWDebug_Install_Profile_Start_Handler(wwdebug_profile_start_handler);
  91. WWDebug_Install_Profile_Stop_Handler(wwdebug_profile_stop_handler);
  92. // Clear all of the debug devices, types, and options
  93. EnabledDevices = -1;
  94. EnabledTypes = -1;
  95. EnabledOptions = 0;
  96. EnableFileLogging = false;
  97. EnableDiagLogging = false;
  98. LoadDebugScripts = false;
  99. //
  100. // By default let us turn these off
  101. //
  102. Disable_Device(DEBUG_DEVICE_SCREEN);
  103. Disable_Type(DEBUG_TYPE_NETWORK_PROLIFIC);
  104. //
  105. // Clear the logfile
  106. //
  107. Init_Logfile();
  108. Debug_Say(( "\n" ));
  109. }
  110. /*
  111. **
  112. */
  113. void DebugManager::Shutdown( void )
  114. {
  115. // Remove message handler functions for the WWDebug messages
  116. // and assertion failures.
  117. WWDebug_Install_Message_Handler(NULL);
  118. WWDebug_Install_Assert_Handler(NULL);
  119. WWDebug_Install_Trigger_Handler(NULL);
  120. WWDebug_Install_Profile_Start_Handler(NULL);
  121. WWDebug_Install_Profile_Stop_Handler(NULL);
  122. // Disable mono screen
  123. ScrollingScreen.Disable();
  124. }
  125. /*
  126. **
  127. */
  128. void DebugManager::Update( void )
  129. {
  130. // Tell the profiler that a frame has passed
  131. if ( Input::Get_State( INPUT_FUNCTION_MAKE_SCREEN_SHOT) ) {
  132. WW3D::Make_Screen_Shot();
  133. }
  134. if ( Input::Get_State( INPUT_FUNCTION_TOGGLE_MOVIE_CAPTURE ) ) {
  135. #ifdef WWDEBUG
  136. WW3D::Toggle_Movie_Capture();
  137. #endif
  138. }
  139. #if 0
  140. // Single Step code
  141. if (WWDEBUG_TRIGGER(0x53 /*S*/)) {
  142. while (!WWDEBUG_TRIGGER(0x20/*SPACE*/)) Input::Update();
  143. while (WWDEBUG_TRIGGER(0x20/*SPACE*/)) Input::Update();
  144. }
  145. #endif
  146. }
  147. void DebugManager::Load_Registry_Settings( const char * sub_key )
  148. {
  149. RegistryClass registry( sub_key );
  150. if ( registry.Is_Valid() ) {
  151. EnabledDevices = registry.Get_Int( "EnabledDevices", EnabledDevices );
  152. EnabledTypes = registry.Get_Int( "EnabledTypes", EnabledTypes );
  153. EnabledOptions = registry.Get_Int( "EnabledOptions", EnabledOptions );
  154. EnableFileLogging = registry.Get_Bool( "EnableFileLogging", EnableFileLogging );
  155. EnableDiagLogging = registry.Get_Bool( "EnableDiagLogging", EnableDiagLogging );
  156. LoadDebugScripts = registry.Get_Bool( "LoadDebugScripts", LoadDebugScripts );
  157. AllowCinematicKeys = registry.Get_Bool( "AllowCinematicKeys", AllowCinematicKeys );
  158. }
  159. #ifdef LOG_MEMORY
  160. Debug_Say(( "*** Memory Logging Enabled ***\n" ));
  161. #endif
  162. }
  163. void DebugManager::Save_Registry_Settings( const char * sub_key )
  164. {
  165. RegistryClass registry( sub_key );
  166. if ( registry.Is_Valid() ) {
  167. registry.Set_Int( "EnabledDevices", EnabledDevices );
  168. registry.Set_Int( "EnabledTypes", EnabledTypes );
  169. registry.Set_Int( "EnabledOptions", EnabledOptions );
  170. registry.Set_Bool( "EnableFileLogging", EnableFileLogging );
  171. registry.Set_Bool( "EnableDiagLogging", EnableDiagLogging );
  172. registry.Set_Bool( "LoadDebugScripts", LoadDebugScripts );
  173. registry.Set_Bool( "AllowCinematicKeys", AllowCinematicKeys );
  174. }
  175. }
  176. /*
  177. **
  178. */
  179. void DebugManager::Display( char const *buffer )
  180. {
  181. CriticalSectionClass::LockClass lock(CriticalSection);
  182. if ( EnabledDevices & DEBUG_DEVICE_SCREEN ) {
  183. Display_Text( buffer );
  184. }
  185. if ( EnabledDevices & DEBUG_DEVICE_MONO ) {
  186. ScrollingScreen.Printf( buffer );
  187. }
  188. #ifdef WWDEBUG
  189. if ( EnabledDevices & DEBUG_DEVICE_DBWIN32 ) {
  190. WWDebug_DBWin32_Message_Handler( buffer );
  191. }
  192. #endif // WWDEBUG
  193. if ( EnabledDevices & DEBUG_DEVICE_LOG ) {
  194. Write_To_File(buffer);
  195. }
  196. if ( EnabledDevices & DEBUG_DEVICE_WINDOWS ) {
  197. OutputDebugString( buffer ); // puts it in the MSVC debug window
  198. }
  199. }
  200. //
  201. //
  202. //
  203. void DebugManager::Display_Script( char const *text, ... )
  204. {
  205. if ( !(EnabledTypes & DEBUG_TYPE_SCRIPT) ) return;
  206. va_list va;
  207. char buffer[256];
  208. va_start(va, text);
  209. vsprintf(buffer, text, va);
  210. buffer[sizeof(buffer)-1] = '\0';
  211. char buffer2[256];
  212. sprintf( buffer2, "SCRIPT:%s", buffer );
  213. Display( buffer2 );
  214. va_end(va);
  215. }
  216. /*
  217. **
  218. */
  219. void DebugManager::Display_Network_Admin(char const *text, ...)
  220. {
  221. if (!(EnabledTypes & DEBUG_TYPE_NETWORK_ADMIN)) {
  222. return;
  223. }
  224. va_list va;
  225. char buffer[1024];
  226. va_start(va, text);
  227. vsprintf(buffer, text, va);
  228. buffer[sizeof(buffer)-1] = '\0';
  229. char buffer2[1024];
  230. sprintf(buffer2, "NET ADMIN:%s\n", buffer);
  231. Display(buffer2);
  232. va_end(va);
  233. }
  234. /*
  235. **
  236. */
  237. void DebugManager::Display_Network_Basic(char const *text, ...)
  238. {
  239. if (!(EnabledTypes & DEBUG_TYPE_NETWORK_BASIC)) {
  240. return;
  241. }
  242. va_list va;
  243. char buffer[1024];
  244. va_start(va, text);
  245. vsprintf(buffer, text, va);
  246. buffer[sizeof(buffer)-1] = '\0';
  247. char buffer2[1024];
  248. sprintf(buffer2, "NET BASIC:%s\n", buffer);
  249. Display(buffer2);
  250. va_end(va);
  251. }
  252. /*
  253. **
  254. */
  255. void DebugManager::Display_Network_Prolific(char const *text, ...)
  256. {
  257. if (!(EnabledTypes & DEBUG_TYPE_NETWORK_PROLIFIC)) {
  258. return;
  259. }
  260. va_list va;
  261. char buffer[1024];
  262. va_start(va, text);
  263. vsprintf(buffer, text, va);
  264. buffer[sizeof(buffer)-1] = '\0';
  265. char buffer2[1024];
  266. sprintf(buffer2, "NET PROLIFIC:%s\n", buffer);
  267. Display(buffer2);
  268. va_end(va);
  269. }
  270. /*
  271. **
  272. */
  273. void DebugManager::Measure_Frame_Textures( void )
  274. {
  275. // WW3D::Flush_Texture_Cache();
  276. }
  277. /*
  278. **
  279. */
  280. void wwdebug_message_handler(DebugType type, const char * message)
  281. {
  282. /*
  283. ** Hand the message off to the scrolling debug screen
  284. */
  285. if ( !DebugManager::Is_Type_Enabled( (DebugManager::DebugType)(1<<type ) ) ) return;
  286. if ( type == WWDEBUG_TYPE_ERROR ) {
  287. DebugManager::Display( "ERROR:" );
  288. }
  289. if ( type == WWDEBUG_TYPE_WARNING ) {
  290. DebugManager::Display( "WARNING:" );
  291. }
  292. DebugManager::Display( message );
  293. }
  294. void wwdebug_assert_handler(const char * message)
  295. {
  296. /*
  297. ** Hand the message off to the scrolling debug screen
  298. */
  299. DebugManager::Display( message );
  300. }
  301. bool wwdebug_trigger_handler(int trigger_num)
  302. {
  303. #ifdef WWDEBUG
  304. switch( trigger_num ) {
  305. case ' ': return Input::Get_State( INPUT_FUNCTION_DEBUG_SINGLE_STEP_STEP );
  306. case 'S': return Input::Get_State( INPUT_FUNCTION_DEBUG_SINGLE_STEP );
  307. case WWDEBUG_TRIGGER_GENERIC0: return Input::Get_State( INPUT_FUNCTION_DEBUG_GENERIC0 );
  308. case WWDEBUG_TRIGGER_GENERIC1: return Input::Get_State( INPUT_FUNCTION_DEBUG_GENERIC1 );
  309. case WWPHYS_TRIGGER_COLLISION_DEBUGGING: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_COLLISION_MESSAGES); //Input::Get_State( INPUT_FUNCTION_DEBUG_COLLISION_MESSAGES );
  310. case WWPHYS_TRIGGER_COLLISION_DISPLAY: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_COLLISION_DISPLAY); //Input::Get_State( INPUT_FUNCTION_DEBUG_SHOW_COLLISIONS );
  311. case WWPHYS_TRIGGER_INVERT_VIS: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_INVERT_VIS); //Input::Get_State( INPUT_FUNCTION_DEBUG_VIS_INVERT );
  312. case WWPHYS_TRIGGER_DISABLE_VIS: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_DISABLE_VIS); //Input::Get_State( INPUT_FUNCTION_DEBUG_VIS_DISABLE );
  313. case WW3D_TRIGGER_PROCESS_STATS: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_PROCESS_STATS); //Input::Get_State( INPUT_FUNCTION_DEBUG_RENDER_STATS );
  314. case WW3D_TRIGGER_RENDER_STATS: return false; //Input::Get_State( INPUT_FUNCTION_DEBUG_RENDER_STATS );
  315. case WW3D_TRIGGER_SURFACE_CACHE_STATS: return DebugManager::Option_Is_Enabled(DebugManager::DEBUG_SURFACE_CACHE); //Input::Get_State( INPUT_FUNCTION_DEBUG_SURFACE_CACHE );
  316. default: Debug_Say(( "Unhandled Trigger %d %c\n", trigger_num, trigger_num));
  317. }
  318. #endif
  319. return false;
  320. }
  321. void wwdebug_profile_start_handler( const char * title )
  322. {
  323. // Perhaps switch to the ProfileManager calls...
  324. }
  325. void wwdebug_profile_stop_handler( const char * title )
  326. {
  327. }
  328. /*
  329. **
  330. */
  331. void DebugManager::Display_Text( const char * string, const Vector4 & color )
  332. {
  333. if (DisplayHandler != NULL) {
  334. DisplayHandler->Display_Text( string, color );
  335. }
  336. }
  337. void DebugManager::Display_Text( const char * string, const Vector3 & color )
  338. {
  339. if (DisplayHandler != NULL) {
  340. DisplayHandler->Display_Text( string, Vector4(color[0],color[1],color[2],1.0f) );
  341. }
  342. }
  343. void DebugManager::Display_Text( const WideStringClass & string, const Vector4 & color )
  344. {
  345. if (DisplayHandler != NULL) {
  346. DisplayHandler->Display_Text( string, color );
  347. }
  348. }
  349. void DebugManager::Display_Text( const WideStringClass & string, const Vector3 & color )
  350. {
  351. if (DisplayHandler != NULL) {
  352. DisplayHandler->Display_Text( string, Vector4(color[0],color[1],color[2],1.0f) );
  353. }
  354. }
  355. //---------------------------------------------------------------------------
  356. void DebugManager::Init_Logfile(void)
  357. {
  358. if (IsSlave) {
  359. sprintf(LogfileNameBuffer, "%s%s", DefaultRegistryModifier, DEFAULT_LOGFILE_NAME);
  360. LOGFILE = LogfileNameBuffer;
  361. }
  362. //
  363. // Destroy contents
  364. //
  365. FILE * file = fopen(LOGFILE, "wt");
  366. if ( file ) {
  367. fclose(file);
  368. }
  369. }
  370. //---------------------------------------------------------------------------
  371. void DebugManager::Write_To_File(LPCSTR str)
  372. {
  373. //
  374. // I open/close for each write so as to maximize integrity of this file.
  375. //
  376. FILE * file = fopen(LOGFILE, "at");
  377. if (file != NULL) {
  378. fwrite(str, 1, strlen(str), file);
  379. fclose(file);
  380. }
  381. }
  382. /*****************************************************************************************************
  383. **
  384. ** WWMEMLOG support - replacement new and delete operators. See the wwmemlog modules in WWDEBUG.LIB
  385. ** for more info!
  386. **
  387. *****************************************************************************************************/
  388. /*
  389. ** Only install the custom new and delete handlers if WWDEBUG is enabled (debug and profile builds)
  390. ** AND _CRTDBG_MAP_ALLOC is not defined (this causes link errors). If you are using _CRTDBG_MAP_ALLOC,
  391. ** the memory log stuff cannot be used...
  392. */
  393. //#ifdef LOG_MEMORY
  394. //#ifdef WWDEBUG
  395. #ifndef _CRTDBG_MAP_ALLOC
  396. #ifndef PARAM_EDITING_ON
  397. #ifndef STEVES_NEW_CATCHER
  398. extern "C" {
  399. void *gsimalloc(size_t size)
  400. {
  401. WWMEMLOG(MEM_BINK);
  402. return(WWMemoryLogClass::Allocate_Memory(size));
  403. }
  404. void gsifree(void *ptr)
  405. {
  406. WWMEMLOG(MEM_BINK);
  407. WWMemoryLogClass::Release_Memory(ptr);
  408. }
  409. }
  410. void * ::operator new (size_t size)
  411. {
  412. void* memory=NULL;
  413. #ifdef LOG_MEMORY
  414. #ifdef WWDEBUG
  415. memory=WWMemoryLogClass::Allocate_Memory(size);
  416. #else
  417. memory=FastAllocatorGeneral::Get_Allocator()->Alloc(size);
  418. #endif
  419. #else
  420. memory=FastAllocatorGeneral::Get_Allocator()->Alloc(size);
  421. #endif
  422. return memory;
  423. }
  424. void ::operator delete (void *ptr)
  425. {
  426. #ifdef LOG_MEMORY
  427. #ifdef WWDEBUG
  428. WWMemoryLogClass::Release_Memory(ptr);
  429. #else
  430. FastAllocatorGeneral::Get_Allocator()->Free(ptr);
  431. #endif
  432. #else
  433. FastAllocatorGeneral::Get_Allocator()->Free(ptr);
  434. #endif
  435. }
  436. #endif //STEVES_NEW_CATCHER
  437. #endif //PARAM_EDITING_ON
  438. #endif //!_CRTDBG_MAP_ALLOC
  439. //#endif //WWDEBUG
  440. //#endif //LOG_MEMORY
  441. /*
  442. **
  443. **
  444. ** Added 'new' operator. Walks the stack to help track memory leaks.
  445. **
  446. **
  447. **
  448. **
  449. **
  450. **
  451. **
  452. */
  453. #include <imagehlp.h>
  454. #define WALK_FRAMES 8
  455. struct NewCallerStruct {
  456. unsigned long Addresses[WALK_FRAMES];
  457. char AddressName[768];
  458. int AddressLine;
  459. };
  460. unsigned long ReturnAddresses[20];
  461. int Stack_Walk(unsigned long *return_addresses, int num_addresses, CONTEXT *);
  462. bool Lookup_Symbol(void *code_ptr, char *symbol, int &displacement);
  463. void *NewMutex = NULL;
  464. #ifdef _DEBUG
  465. #ifdef STEVES_NEW_CATCHER
  466. extern _CRTIMP void * __cdecl operator new(unsigned int, int, const char *, int);
  467. /*
  468. ** List of addresses to 'watch'. You can stuff them in here and compile or manually poke them in with the debugger at run time.
  469. */
  470. #define NUM_WATCH_ADDRESSES 8
  471. unsigned long WatchAddresses[NUM_WATCH_ADDRESSES] = {
  472. 0x00000000,
  473. 0x00000000,
  474. 0x00000000,
  475. 0x00000000,
  476. 0x00000000,
  477. 0x00000000,
  478. 0x00000000,
  479. 0x00000000
  480. };
  481. /*
  482. ** This assumes no more than 100000 places in the code that call 'new'
  483. */
  484. NewCallerStruct NewAddressList[16384];
  485. /***********************************************************************************************
  486. * operator new -- New operator overload to catch memory leaks. *
  487. * *
  488. * *
  489. * *
  490. * INPUT: size of block to allocate *
  491. * *
  492. * OUTPUT: ptr to allocated memory *
  493. * *
  494. * WARNINGS: None *
  495. * *
  496. * HISTORY: *
  497. * 6/12/2001 4:31PM ST : Created *
  498. *=============================================================================================*/
  499. void* __cdecl operator new(unsigned int s)
  500. {
  501. static char _localstr[32];
  502. static unsigned long _return_addr;
  503. static int _address_strings = 0;
  504. static int _index = -1;
  505. static int _i, _j;
  506. static char _temp_str[512];
  507. static char _compose_str[512];
  508. static int _displacement;
  509. static unsigned long _temp_addr;
  510. static char _spaces[33] = {" "};
  511. static int _wa;
  512. //static CriticalSectionClass *_new_mutex = NULL;
  513. /*
  514. ** Length of all locals.
  515. */
  516. static int _locals_size = 0;
  517. /*
  518. ** Wait for exclusive access.
  519. */
  520. //if (_new_mutex == NULL) {
  521. // void *newmem = ::operator new(s, 1, __FILE__, __LINE__);
  522. // _new_mutex = new(newmem) CriticalSectionClass;
  523. //
  524. //}
  525. //CriticalSectionClass::LockClass mutex(*_new_mutex);
  526. if (NewMutex == NULL) {
  527. NewMutex = CreateMutex(NULL, false, NULL);
  528. assert(NewMutex != NULL);
  529. }
  530. if (NewMutex) {
  531. WaitForSingleObject(NewMutex, INFINITE);
  532. }
  533. /*
  534. ** Extract the return address. This is the default worst case amount of info we can get about the
  535. ** stack.
  536. */
  537. __asm
  538. {
  539. mov eax,_locals_size
  540. mov eax,[ebp+eax+4]
  541. mov [_return_addr],eax
  542. }
  543. /*
  544. ** Try using imagehlp.dll to walk the stack and get real return addresses for multiple calls.
  545. */
  546. memset(ReturnAddresses, 0, WALK_FRAMES * sizeof(ReturnAddresses[0]));
  547. int num_frames = 0;
  548. /*
  549. ** If this is an address we are looking for then do the stack walk.
  550. */
  551. #ifdef ONLY_WATCH_ADDRESSES
  552. for (_wa = 0 ; _wa<NUM_WATCH_ADDRESSES ; _wa++) {
  553. if (_return_addr == WatchAddresses[_wa]) {
  554. num_frames = Stack_Walk(ReturnAddresses, WALK_FRAMES, NULL);
  555. break;
  556. }
  557. }
  558. #else //ONLY_WATCH_ADDRESSES
  559. num_frames = Stack_Walk(ReturnAddresses, WALK_FRAMES, NULL);
  560. #endif //ONLY_WATCH_ADDRESSES
  561. if (num_frames == 0) {
  562. ReturnAddresses[0] = _return_addr;
  563. }
  564. /*
  565. ** Find or create the address string.
  566. */
  567. _index = -1;
  568. for (_i=0 ; _i<min(_address_strings, ARRAY_SIZE(NewAddressList)) ; _i++) {
  569. if (memcmp(NewAddressList[_i].Addresses, ReturnAddresses, WALK_FRAMES * sizeof(ReturnAddresses[0])) == 0) {
  570. //if (NewAddressList[_i].Address == _return_addr) {
  571. _index = _i;
  572. break;
  573. }
  574. }
  575. if (_index == -1) {
  576. _index = _address_strings++;
  577. }
  578. if (_index >= ARRAY_SIZE(NewAddressList)) {
  579. void *newmem = ::operator new(s, 1, __FILE__, _address_strings);
  580. if (NewMutex) {
  581. ReleaseMutex(NewMutex);
  582. }
  583. return (newmem);
  584. }
  585. /*
  586. ** If we got no good stack info and just have the return address then print that into this
  587. ** entry.
  588. */
  589. memcpy(NewAddressList[_index].Addresses, ReturnAddresses, WALK_FRAMES * sizeof(ReturnAddresses[0]));
  590. if (num_frames == 0) {
  591. //NewAddressList[_index].Address = _return_addr;
  592. NewAddressList[_index].AddressLine = ReturnAddresses[0];
  593. sprintf(NewAddressList[_index].AddressName, "Addr: %08X ", ReturnAddresses[0]);
  594. } else {
  595. /*
  596. ** Otherwise try and get symbol info for each return address.
  597. */
  598. char *ptr = NewAddressList[_index].AddressName;
  599. bool ok = true;
  600. for (_i=0 ; _i<WALK_FRAMES ; _i++) {
  601. if (!ok) {
  602. break;
  603. }
  604. _temp_addr = NewAddressList[_index].Addresses[_i];
  605. _displacement = 0;
  606. _temp_str[0] = 0;
  607. ok = Lookup_Symbol((void*)_temp_addr, _temp_str, _displacement);
  608. if (_i == 0) {
  609. sprintf(ptr, "\nAddr: %08X (%s + %d)\n", NewAddressList[_index].Addresses[_i], _temp_str, _displacement);
  610. } else {
  611. strcpy(_compose_str, &_spaces[(sizeof(_spaces) -2) -_i]);
  612. //_compose_str[0] = 0;
  613. //for (_j=0 ; _j<_i ; _j++) {
  614. // strcat(_compose_str, " ");
  615. //}
  616. sprintf(_compose_str + strlen(_compose_str), "Called from: %08X (%s + %d)\n", NewAddressList[_index].Addresses[_i], _temp_str, _displacement);
  617. if (strlen(ptr) + strlen(_compose_str) >= sizeof(NewAddressList[_index].AddressName)) {
  618. break;
  619. }
  620. strcat(ptr, _compose_str);
  621. }
  622. }
  623. }
  624. assert(strlen(NewAddressList[_index].AddressName) < sizeof(NewAddressList[_index].AddressName));
  625. /*
  626. ** Call the CRT new to actually allocate the memory. Pass in the string we composed.
  627. */
  628. void *newmem = ::operator new(s, 1, NewAddressList[_index].AddressName, NewAddressList[_index].AddressLine);
  629. if (NewMutex) {
  630. ReleaseMutex(NewMutex);
  631. }
  632. return(newmem);
  633. //return (::operator new(s, 1, __FILE__, __LINE__));
  634. }
  635. #endif //STEVES_NEW_CATCHER
  636. #endif //_DEBUG
  637. #if (0)
  638. /*
  639. ** Definitions to allow run-time linking to the Imagehlp.dll functions.
  640. **
  641. */
  642. typedef BOOL (WINAPI *SymCleanupType) (HANDLE hProcess);
  643. typedef BOOL (WINAPI *SymGetSymFromAddrType) (HANDLE hProcess, DWORD Address, LPDWORD Displacement, PIMAGEHLP_SYMBOL Symbol);
  644. typedef BOOL (WINAPI *SymInitializeType) (HANDLE hProcess, LPSTR UserSearchPath, BOOL fInvadeProcess);
  645. typedef BOOL (WINAPI *SymLoadModuleType) (HANDLE hProcess, HANDLE hFile, LPSTR ImageName, LPSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll);
  646. typedef DWORD (WINAPI *SymSetOptionsType) (DWORD SymOptions);
  647. typedef BOOL (WINAPI *SymUnloadModuleType) (HANDLE hProcess, DWORD BaseOfDll);
  648. 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);
  649. typedef LPVOID (WINAPI *SymFunctionTableAccessType) (HANDLE hProcess, DWORD AddrBase);
  650. typedef DWORD (WINAPI *SymGetModuleBaseType) (HANDLE hProcess, DWORD dwAddr);
  651. SymCleanupType _SymCleanup = NULL;
  652. SymGetSymFromAddrType _SymGetSymFromAddr = NULL;
  653. SymInitializeType _SymInitialize = NULL;
  654. SymLoadModuleType _SymLoadModule = NULL;
  655. SymSetOptionsType _SymSetOptions = NULL;
  656. SymUnloadModuleType _SymUnloadModule = NULL;
  657. StackWalkType _StackWalk = NULL;
  658. SymFunctionTableAccessType _SymFunctionTableAccess = NULL;
  659. SymGetModuleBaseType _SymGetModuleBase = NULL;
  660. static char const *ImagehelpFunctionNames[] = {
  661. "SymCleanup",
  662. "SymGetSymFromAddr",
  663. "SymInitialize",
  664. "SymLoadModule",
  665. "SymSetOptions",
  666. "SymUnloadModule",
  667. "StackWalk",
  668. "SymFunctionTableAccess",
  669. "SymGetModuleBaseType",
  670. NULL
  671. };
  672. bool SymbolsAvailable = false;
  673. HINSTANCE ImageHelp = (HINSTANCE) -1;
  674. /***********************************************************************************************
  675. * Load_Image_Helper -- Load imagehlp.dll and retrieve the programs symbols *
  676. * *
  677. * *
  678. * *
  679. * INPUT: Nothing *
  680. * *
  681. * OUTPUT: Nothing *
  682. * *
  683. * WARNINGS: None *
  684. * *
  685. * HISTORY: *
  686. * 6/12/2001 4:27PM ST : Created *
  687. *=============================================================================================*/
  688. void Load_Image_Helper(void)
  689. {
  690. /*
  691. ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
  692. ** can't be statically linked.
  693. */
  694. if (ImageHelp == (HINSTANCE)-1) {
  695. ImageHelp = LoadLibrary("IMAGEHLP.DLL");
  696. if (ImageHelp != NULL) {
  697. char const *function_name = NULL;
  698. unsigned long *fptr = (unsigned long *) &_SymCleanup;
  699. int count = 0;
  700. do {
  701. function_name = ImagehelpFunctionNames[count];
  702. if (function_name) {
  703. *fptr = (unsigned long) GetProcAddress(ImageHelp, function_name);
  704. fptr++;
  705. count++;
  706. }
  707. }
  708. while (function_name);
  709. }
  710. /*
  711. ** Retrieve the programs symbols if they are available. This can be a .pdb or a .dbg file.
  712. */
  713. if (_SymSetOptions != NULL) {
  714. _SymSetOptions(SYMOPT_DEFERRED_LOADS);
  715. }
  716. int symload = 0;
  717. if (_SymInitialize != NULL && _SymInitialize(GetCurrentProcess(), NULL, FALSE)) {
  718. if (_SymSetOptions != NULL) {
  719. _SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
  720. }
  721. char exe_name[_MAX_PATH];
  722. GetModuleFileName(NULL, exe_name, sizeof(exe_name));
  723. if (_SymLoadModule != NULL) {
  724. symload = _SymLoadModule(GetCurrentProcess(), NULL, exe_name, NULL, 0, 0);
  725. }
  726. if (symload) {
  727. SymbolsAvailable = true;
  728. } else {
  729. //assert (_SymLoadModule != NULL);
  730. //DebugString ("SymLoad failed for module %s with code %d - %s\n", szModuleName, GetLastError(), Last_Error_Text());
  731. }
  732. }
  733. }
  734. }
  735. /***********************************************************************************************
  736. * Lookup_Symbol -- Get the symbol for a given code address *
  737. * *
  738. * *
  739. * *
  740. * INPUT: Address of code to get symbol for *
  741. * Ptr to buffer to return symbol in *
  742. * Reference to int to return displacement *
  743. * *
  744. * OUTPUT: True if symbol found *
  745. * *
  746. * WARNINGS: None *
  747. * *
  748. * HISTORY: *
  749. * 6/12/2001 4:47PM ST : Created *
  750. *=============================================================================================*/
  751. bool Lookup_Symbol(void *code_ptr, char *symbol, int &displacement)
  752. {
  753. /*
  754. ** Locals.
  755. */
  756. char symbol_struct_buf[1024];
  757. IMAGEHLP_SYMBOL *symbol_struct_ptr = (IMAGEHLP_SYMBOL *)symbol_struct_buf;
  758. /*
  759. ** Set default values in case of early exit.
  760. */
  761. displacement = 0;
  762. *symbol = '\0';
  763. /*
  764. ** Make sure symbols are available.
  765. */
  766. if (!SymbolsAvailable || _SymGetSymFromAddr == NULL) {
  767. return(false);
  768. }
  769. /*
  770. ** If it's a bad code pointer then there is no point in trying to match it with a symbol.
  771. */
  772. if (IsBadCodePtr((FARPROC)code_ptr)) {
  773. strcpy(symbol, "Bad code pointer");
  774. return(false);
  775. }
  776. /*
  777. ** Set up the parameters for the call to SymGetSymFromAddr
  778. */
  779. memset (symbol_struct_ptr, 0, sizeof (symbol_struct_buf));
  780. symbol_struct_ptr->SizeOfStruct = sizeof (symbol_struct_buf);
  781. symbol_struct_ptr->MaxNameLength = sizeof(symbol_struct_buf)-sizeof (IMAGEHLP_SYMBOL);
  782. symbol_struct_ptr->Size = 0;
  783. symbol_struct_ptr->Address = (unsigned long)code_ptr;
  784. /*
  785. ** See if we have the symbol for that address.
  786. */
  787. if (_SymGetSymFromAddr(GetCurrentProcess(), (unsigned long)code_ptr, (unsigned long *)&displacement, symbol_struct_ptr)) {
  788. /*
  789. ** Copy it back into the buffer provided.
  790. */
  791. strcpy(symbol, symbol_struct_ptr->Name);
  792. return(true);
  793. }
  794. return(false);
  795. }
  796. /***********************************************************************************************
  797. * Stack_Walk -- Walk the stack and get the last n return addresses *
  798. * *
  799. * *
  800. * *
  801. * INPUT: Ptr to return address list *
  802. * Number of return addresses to fetch *
  803. * Ptr to optional context. NULL means use current *
  804. * *
  805. * OUTPUT: Number of return addresses found *
  806. * *
  807. * WARNINGS: None *
  808. * *
  809. * HISTORY: *
  810. * 6/12/2001 11:57AM ST : Created *
  811. *=============================================================================================*/
  812. int Stack_Walk(unsigned long *return_addresses, int num_addresses, CONTEXT *context)
  813. {
  814. static HINSTANCE _imagehelp = (HINSTANCE) -1;
  815. /*
  816. ** If this is the first time through then fix up the imagehelp function pointers since imagehlp.dll
  817. ** can't be statically linked.
  818. */
  819. if (ImageHelp == (HINSTANCE)-1) {
  820. Load_Image_Helper();
  821. }
  822. /*
  823. ** If there is no debug support .dll available then we can't walk the stack.
  824. */
  825. if (ImageHelp == NULL) {
  826. return(0);
  827. }
  828. /*
  829. ** Set up the stack frame structure for the start point of the stack walk (i.e. here).
  830. */
  831. STACKFRAME stack_frame;
  832. memset(&stack_frame, 0, sizeof(stack_frame));
  833. unsigned long reg_eip, reg_ebp, reg_esp;
  834. __asm {
  835. here:
  836. lea eax,here
  837. mov reg_eip,eax
  838. mov reg_ebp,ebp
  839. mov reg_esp,esp
  840. }
  841. stack_frame.AddrPC.Mode = AddrModeFlat;
  842. stack_frame.AddrPC.Offset = reg_eip;
  843. stack_frame.AddrStack.Mode = AddrModeFlat;
  844. stack_frame.AddrStack.Offset = reg_esp;
  845. stack_frame.AddrFrame.Mode = AddrModeFlat;
  846. stack_frame.AddrFrame.Offset = reg_ebp;
  847. /*
  848. ** Use the context struct if it was provided.
  849. */
  850. if (context) {
  851. stack_frame.AddrPC.Offset = context->Eip;
  852. stack_frame.AddrStack.Offset = context->Esp;
  853. stack_frame.AddrFrame.Offset = context->Ebp;
  854. }
  855. int pointer_index = 0;
  856. /*
  857. ** Walk the stack by the requested number of return address iterations.
  858. */
  859. for (int i = 0; i < num_addresses + 1; i++) {
  860. if (_StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &stack_frame, NULL, NULL, _SymFunctionTableAccess, _SymGetModuleBase, NULL)) {
  861. /*
  862. ** First result will always be the return address we were called from.
  863. */
  864. if (i==0 && context == NULL) {
  865. continue;
  866. }
  867. unsigned long return_address = stack_frame.AddrReturn.Offset;
  868. return_addresses[pointer_index++] = return_address;
  869. } else {
  870. break;
  871. }
  872. }
  873. return(pointer_index);
  874. }
  875. #endif //(0)