win_shared.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code 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. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../../idlib/precompiled.h"
  22. #include "win_local.h"
  23. #include <lmerr.h>
  24. #include <lmcons.h>
  25. #include <lmwksta.h>
  26. #include <errno.h>
  27. #include <fcntl.h>
  28. #include <direct.h>
  29. #include <io.h>
  30. #include <conio.h>
  31. #undef StrCmpN
  32. #undef StrCmpNI
  33. #undef StrCmpI
  34. #include <atlbase.h>
  35. #include <comdef.h>
  36. #include <comutil.h>
  37. #include <Wbemidl.h>
  38. #pragma comment (lib, "wbemuuid.lib")
  39. #pragma warning(disable:4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
  40. /*
  41. ================
  42. Sys_Milliseconds
  43. ================
  44. */
  45. int Sys_Milliseconds() {
  46. static DWORD sys_timeBase = timeGetTime();
  47. return timeGetTime() - sys_timeBase;
  48. }
  49. /*
  50. ========================
  51. Sys_Microseconds
  52. ========================
  53. */
  54. uint64 Sys_Microseconds() {
  55. static uint64 ticksPerMicrosecondTimes1024 = 0;
  56. if ( ticksPerMicrosecondTimes1024 == 0 ) {
  57. ticksPerMicrosecondTimes1024 = ( (uint64)Sys_ClockTicksPerSecond() << 10 ) / 1000000;
  58. assert( ticksPerMicrosecondTimes1024 > 0 );
  59. }
  60. return ((uint64)( (int64)Sys_GetClockTicks() << 10 )) / ticksPerMicrosecondTimes1024;
  61. }
  62. /*
  63. ================
  64. Sys_GetSystemRam
  65. returns amount of physical memory in MB
  66. ================
  67. */
  68. int Sys_GetSystemRam() {
  69. MEMORYSTATUSEX statex;
  70. statex.dwLength = sizeof ( statex );
  71. GlobalMemoryStatusEx (&statex);
  72. int physRam = statex.ullTotalPhys / ( 1024 * 1024 );
  73. // HACK: For some reason, ullTotalPhys is sometimes off by a meg or two, so we round up to the nearest 16 megs
  74. physRam = ( physRam + 8 ) & ~15;
  75. return physRam;
  76. }
  77. /*
  78. ================
  79. Sys_GetDriveFreeSpace
  80. returns in megabytes
  81. ================
  82. */
  83. int Sys_GetDriveFreeSpace( const char *path ) {
  84. DWORDLONG lpFreeBytesAvailable;
  85. DWORDLONG lpTotalNumberOfBytes;
  86. DWORDLONG lpTotalNumberOfFreeBytes;
  87. int ret = 26;
  88. //FIXME: see why this is failing on some machines
  89. if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
  90. ret = ( double )( lpFreeBytesAvailable ) / ( 1024.0 * 1024.0 );
  91. }
  92. return ret;
  93. }
  94. /*
  95. ========================
  96. Sys_GetDriveFreeSpaceInBytes
  97. ========================
  98. */
  99. int64 Sys_GetDriveFreeSpaceInBytes( const char * path ) {
  100. DWORDLONG lpFreeBytesAvailable;
  101. DWORDLONG lpTotalNumberOfBytes;
  102. DWORDLONG lpTotalNumberOfFreeBytes;
  103. int64 ret = 1;
  104. //FIXME: see why this is failing on some machines
  105. if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
  106. ret = lpFreeBytesAvailable;
  107. }
  108. return ret;
  109. }
  110. /*
  111. ================
  112. Sys_GetVideoRam
  113. returns in megabytes
  114. ================
  115. */
  116. int Sys_GetVideoRam() {
  117. unsigned int retSize = 64;
  118. CComPtr<IWbemLocator> spLoc = NULL;
  119. HRESULT hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, ( LPVOID * ) &spLoc );
  120. if ( hr != S_OK || spLoc == NULL ) {
  121. return retSize;
  122. }
  123. CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
  124. CComPtr<IWbemServices> spServices;
  125. // Connect to CIM
  126. hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
  127. if ( hr != WBEM_S_NO_ERROR ) {
  128. return retSize;
  129. }
  130. // Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.
  131. hr = CoSetProxyBlanket( spServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
  132. if ( hr != S_OK ) {
  133. return retSize;
  134. }
  135. // Get the vid controller
  136. CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
  137. hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst );
  138. if ( hr != WBEM_S_NO_ERROR || spEnumInst == NULL ) {
  139. return retSize;
  140. }
  141. ULONG uNumOfInstances = 0;
  142. CComPtr<IWbemClassObject> spInstance = NULL;
  143. hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
  144. if ( hr == S_OK && spInstance ) {
  145. // Get properties from the object
  146. CComVariant varSize;
  147. hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
  148. if ( hr == S_OK ) {
  149. retSize = varSize.intVal / ( 1024 * 1024 );
  150. if ( retSize == 0 ) {
  151. retSize = 64;
  152. }
  153. }
  154. }
  155. return retSize;
  156. }
  157. /*
  158. ================
  159. Sys_GetCurrentMemoryStatus
  160. returns OS mem info
  161. all values are in kB except the memoryload
  162. ================
  163. */
  164. void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
  165. MEMORYSTATUSEX statex = {};
  166. unsigned __int64 work;
  167. statex.dwLength = sizeof( statex );
  168. GlobalMemoryStatusEx( &statex );
  169. memset( &stats, 0, sizeof( stats ) );
  170. stats.memoryLoad = statex.dwMemoryLoad;
  171. work = statex.ullTotalPhys >> 20;
  172. stats.totalPhysical = *(int*)&work;
  173. work = statex.ullAvailPhys >> 20;
  174. stats.availPhysical = *(int*)&work;
  175. work = statex.ullAvailPageFile >> 20;
  176. stats.availPageFile = *(int*)&work;
  177. work = statex.ullTotalPageFile >> 20;
  178. stats.totalPageFile = *(int*)&work;
  179. work = statex.ullTotalVirtual >> 20;
  180. stats.totalVirtual = *(int*)&work;
  181. work = statex.ullAvailVirtual >> 20;
  182. stats.availVirtual = *(int*)&work;
  183. work = statex.ullAvailExtendedVirtual >> 20;
  184. stats.availExtendedVirtual = *(int*)&work;
  185. }
  186. /*
  187. ================
  188. Sys_LockMemory
  189. ================
  190. */
  191. bool Sys_LockMemory( void *ptr, int bytes ) {
  192. return ( VirtualLock( ptr, (SIZE_T)bytes ) != FALSE );
  193. }
  194. /*
  195. ================
  196. Sys_UnlockMemory
  197. ================
  198. */
  199. bool Sys_UnlockMemory( void *ptr, int bytes ) {
  200. return ( VirtualUnlock( ptr, (SIZE_T)bytes ) != FALSE );
  201. }
  202. /*
  203. ================
  204. Sys_SetPhysicalWorkMemory
  205. ================
  206. */
  207. void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
  208. ::SetProcessWorkingSetSize( GetCurrentProcess(), minBytes, maxBytes );
  209. }
  210. /*
  211. ================
  212. Sys_GetCurrentUser
  213. ================
  214. */
  215. char *Sys_GetCurrentUser() {
  216. static char s_userName[1024];
  217. unsigned long size = sizeof( s_userName );
  218. if ( !GetUserName( s_userName, &size ) ) {
  219. strcpy( s_userName, "player" );
  220. }
  221. if ( !s_userName[0] ) {
  222. strcpy( s_userName, "player" );
  223. }
  224. return s_userName;
  225. }
  226. /*
  227. ===============================================================================
  228. Call stack
  229. ===============================================================================
  230. */
  231. #define PROLOGUE_SIGNATURE 0x00EC8B55
  232. #include <dbghelp.h>
  233. const int UNDECORATE_FLAGS = UNDNAME_NO_MS_KEYWORDS |
  234. UNDNAME_NO_ACCESS_SPECIFIERS |
  235. UNDNAME_NO_FUNCTION_RETURNS |
  236. UNDNAME_NO_ALLOCATION_MODEL |
  237. UNDNAME_NO_ALLOCATION_LANGUAGE |
  238. UNDNAME_NO_MEMBER_TYPE;
  239. #if defined(_DEBUG) && 1
  240. typedef struct symbol_s {
  241. int address;
  242. char * name;
  243. struct symbol_s * next;
  244. } symbol_t;
  245. typedef struct module_s {
  246. int address;
  247. char * name;
  248. symbol_t * symbols;
  249. struct module_s * next;
  250. } module_t;
  251. module_t *modules;
  252. /*
  253. ==================
  254. SkipRestOfLine
  255. ==================
  256. */
  257. void SkipRestOfLine( const char **ptr ) {
  258. while( (**ptr) != '\0' && (**ptr) != '\n' && (**ptr) != '\r' ) {
  259. (*ptr)++;
  260. }
  261. while( (**ptr) == '\n' || (**ptr) == '\r' ) {
  262. (*ptr)++;
  263. }
  264. }
  265. /*
  266. ==================
  267. SkipWhiteSpace
  268. ==================
  269. */
  270. void SkipWhiteSpace( const char **ptr ) {
  271. while( (**ptr) == ' ' ) {
  272. (*ptr)++;
  273. }
  274. }
  275. /*
  276. ==================
  277. ParseHexNumber
  278. ==================
  279. */
  280. int ParseHexNumber( const char **ptr ) {
  281. int n = 0;
  282. while( (**ptr) >= '0' && (**ptr) <= '9' || (**ptr) >= 'a' && (**ptr) <= 'f' ) {
  283. n <<= 4;
  284. if ( **ptr >= '0' && **ptr <= '9' ) {
  285. n |= ( (**ptr) - '0' );
  286. } else {
  287. n |= 10 + ( (**ptr) - 'a' );
  288. }
  289. (*ptr)++;
  290. }
  291. return n;
  292. }
  293. /*
  294. ==================
  295. Sym_Init
  296. ==================
  297. */
  298. void Sym_Init( long addr ) {
  299. TCHAR moduleName[MAX_STRING_CHARS];
  300. MEMORY_BASIC_INFORMATION mbi;
  301. VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
  302. GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
  303. char *ext = moduleName + strlen( moduleName );
  304. while( ext > moduleName && *ext != '.' ) {
  305. ext--;
  306. }
  307. if ( ext == moduleName ) {
  308. strcat( moduleName, ".map" );
  309. } else {
  310. strcpy( ext, ".map" );
  311. }
  312. module_t *module = (module_t *) malloc( sizeof( module_t ) );
  313. module->name = (char *) malloc( strlen( moduleName ) + 1 );
  314. strcpy( module->name, moduleName );
  315. module->address = (int)mbi.AllocationBase;
  316. module->symbols = NULL;
  317. module->next = modules;
  318. modules = module;
  319. FILE * fp = fopen( moduleName, "rb" );
  320. if ( fp == NULL ) {
  321. return;
  322. }
  323. int pos = ftell( fp );
  324. fseek( fp, 0, SEEK_END );
  325. int length = ftell( fp );
  326. fseek( fp, pos, SEEK_SET );
  327. char *text = (char *) malloc( length+1 );
  328. fread( text, 1, length, fp );
  329. text[length] = '\0';
  330. fclose( fp );
  331. const char *ptr = text;
  332. // skip up to " Address" on a new line
  333. while( *ptr != '\0' ) {
  334. SkipWhiteSpace( &ptr );
  335. if ( idStr::Cmpn( ptr, "Address", 7 ) == 0 ) {
  336. SkipRestOfLine( &ptr );
  337. break;
  338. }
  339. SkipRestOfLine( &ptr );
  340. }
  341. int symbolAddress;
  342. int symbolLength;
  343. char symbolName[MAX_STRING_CHARS];
  344. symbol_t *symbol;
  345. // parse symbols
  346. while( *ptr != '\0' ) {
  347. SkipWhiteSpace( &ptr );
  348. ParseHexNumber( &ptr );
  349. if ( *ptr == ':' ) {
  350. ptr++;
  351. } else {
  352. break;
  353. }
  354. ParseHexNumber( &ptr );
  355. SkipWhiteSpace( &ptr );
  356. // parse symbol name
  357. symbolLength = 0;
  358. while( *ptr != '\0' && *ptr != ' ' ) {
  359. symbolName[symbolLength++] = *ptr++;
  360. if ( symbolLength >= sizeof( symbolName ) - 1 ) {
  361. break;
  362. }
  363. }
  364. symbolName[symbolLength++] = '\0';
  365. SkipWhiteSpace( &ptr );
  366. // parse symbol address
  367. symbolAddress = ParseHexNumber( &ptr );
  368. SkipRestOfLine( &ptr );
  369. symbol = (symbol_t *) malloc( sizeof( symbol_t ) );
  370. symbol->name = (char *) malloc( symbolLength );
  371. strcpy( symbol->name, symbolName );
  372. symbol->address = symbolAddress;
  373. symbol->next = module->symbols;
  374. module->symbols = symbol;
  375. }
  376. free( text );
  377. }
  378. /*
  379. ==================
  380. Sym_Shutdown
  381. ==================
  382. */
  383. void Sym_Shutdown() {
  384. module_t *m;
  385. symbol_t *s;
  386. for ( m = modules; m != NULL; m = modules ) {
  387. modules = m->next;
  388. for ( s = m->symbols; s != NULL; s = m->symbols ) {
  389. m->symbols = s->next;
  390. free( s->name );
  391. free( s );
  392. }
  393. free( m->name );
  394. free( m );
  395. }
  396. modules = NULL;
  397. }
  398. /*
  399. ==================
  400. Sym_GetFuncInfo
  401. ==================
  402. */
  403. void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
  404. MEMORY_BASIC_INFORMATION mbi;
  405. module_t *m;
  406. symbol_t *s;
  407. VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
  408. for ( m = modules; m != NULL; m = m->next ) {
  409. if ( m->address == (int) mbi.AllocationBase ) {
  410. break;
  411. }
  412. }
  413. if ( !m ) {
  414. Sym_Init( addr );
  415. m = modules;
  416. }
  417. for ( s = m->symbols; s != NULL; s = s->next ) {
  418. if ( s->address == addr ) {
  419. char undName[MAX_STRING_CHARS];
  420. if ( UnDecorateSymbolName( s->name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
  421. funcName = undName;
  422. } else {
  423. funcName = s->name;
  424. }
  425. for ( int i = 0; i < funcName.Length(); i++ ) {
  426. if ( funcName[i] == '(' ) {
  427. funcName.CapLength( i );
  428. break;
  429. }
  430. }
  431. module = m->name;
  432. return;
  433. }
  434. }
  435. sprintf( funcName, "0x%08x", addr );
  436. module = "";
  437. }
  438. #elif defined(_DEBUG)
  439. DWORD lastAllocationBase = -1;
  440. HANDLE processHandle;
  441. idStr lastModule;
  442. /*
  443. ==================
  444. Sym_Init
  445. ==================
  446. */
  447. void Sym_Init( long addr ) {
  448. TCHAR moduleName[MAX_STRING_CHARS];
  449. TCHAR modShortNameBuf[MAX_STRING_CHARS];
  450. MEMORY_BASIC_INFORMATION mbi;
  451. if ( lastAllocationBase != -1 ) {
  452. Sym_Shutdown();
  453. }
  454. VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
  455. GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
  456. _splitpath( moduleName, NULL, NULL, modShortNameBuf, NULL );
  457. lastModule = modShortNameBuf;
  458. processHandle = GetCurrentProcess();
  459. if ( !SymInitialize( processHandle, NULL, FALSE ) ) {
  460. return;
  461. }
  462. if ( !SymLoadModule( processHandle, NULL, moduleName, NULL, (DWORD)mbi.AllocationBase, 0 ) ) {
  463. SymCleanup( processHandle );
  464. return;
  465. }
  466. SymSetOptions( SymGetOptions() & ~SYMOPT_UNDNAME );
  467. lastAllocationBase = (DWORD) mbi.AllocationBase;
  468. }
  469. /*
  470. ==================
  471. Sym_Shutdown
  472. ==================
  473. */
  474. void Sym_Shutdown() {
  475. SymUnloadModule( GetCurrentProcess(), lastAllocationBase );
  476. SymCleanup( GetCurrentProcess() );
  477. lastAllocationBase = -1;
  478. }
  479. /*
  480. ==================
  481. Sym_GetFuncInfo
  482. ==================
  483. */
  484. void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
  485. MEMORY_BASIC_INFORMATION mbi;
  486. VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
  487. if ( (DWORD) mbi.AllocationBase != lastAllocationBase ) {
  488. Sym_Init( addr );
  489. }
  490. BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + MAX_STRING_CHARS ];
  491. PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)&symbolBuffer[0];
  492. pSymbol->SizeOfStruct = sizeof(symbolBuffer);
  493. pSymbol->MaxNameLength = 1023;
  494. pSymbol->Address = 0;
  495. pSymbol->Flags = 0;
  496. pSymbol->Size =0;
  497. DWORD symDisplacement = 0;
  498. if ( SymGetSymFromAddr( processHandle, addr, &symDisplacement, pSymbol ) ) {
  499. // clean up name, throwing away decorations that don't affect uniqueness
  500. char undName[MAX_STRING_CHARS];
  501. if ( UnDecorateSymbolName( pSymbol->Name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
  502. funcName = undName;
  503. } else {
  504. funcName = pSymbol->Name;
  505. }
  506. module = lastModule;
  507. }
  508. else {
  509. LPVOID lpMsgBuf;
  510. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  511. NULL,
  512. GetLastError(),
  513. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  514. (LPTSTR) &lpMsgBuf,
  515. 0,
  516. NULL
  517. );
  518. LocalFree( lpMsgBuf );
  519. // Couldn't retrieve symbol (no debug info?, can't load dbghelp.dll?)
  520. sprintf( funcName, "0x%08x", addr );
  521. module = "";
  522. }
  523. }
  524. #else
  525. /*
  526. ==================
  527. Sym_Init
  528. ==================
  529. */
  530. void Sym_Init( long addr ) {
  531. }
  532. /*
  533. ==================
  534. Sym_Shutdown
  535. ==================
  536. */
  537. void Sym_Shutdown() {
  538. }
  539. /*
  540. ==================
  541. Sym_GetFuncInfo
  542. ==================
  543. */
  544. void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
  545. module = "";
  546. sprintf( funcName, "0x%08x", addr );
  547. }
  548. #endif
  549. /*
  550. ==================
  551. GetFuncAddr
  552. ==================
  553. */
  554. address_t GetFuncAddr( address_t midPtPtr ) {
  555. long temp;
  556. do {
  557. temp = (long)(*(long*)midPtPtr);
  558. if ( (temp&0x00FFFFFF) == PROLOGUE_SIGNATURE ) {
  559. break;
  560. }
  561. midPtPtr--;
  562. } while(true);
  563. return midPtPtr;
  564. }
  565. /*
  566. ==================
  567. GetCallerAddr
  568. ==================
  569. */
  570. address_t GetCallerAddr( long _ebp ) {
  571. long midPtPtr;
  572. long res = 0;
  573. __asm {
  574. mov eax, _ebp
  575. mov ecx, [eax] // check for end of stack frames list
  576. test ecx, ecx // check for zero stack frame
  577. jz label
  578. mov eax, [eax+4] // get the ret address
  579. test eax, eax // check for zero return address
  580. jz label
  581. mov midPtPtr, eax
  582. }
  583. res = GetFuncAddr( midPtPtr );
  584. label:
  585. return res;
  586. }
  587. /*
  588. ==================
  589. Sys_GetCallStack
  590. use /Oy option
  591. ==================
  592. */
  593. void Sys_GetCallStack( address_t *callStack, const int callStackSize ) {
  594. #if 1 //def _DEBUG
  595. int i;
  596. long m_ebp;
  597. __asm {
  598. mov eax, ebp
  599. mov m_ebp, eax
  600. }
  601. // skip last two functions
  602. m_ebp = *((long*)m_ebp);
  603. m_ebp = *((long*)m_ebp);
  604. // list functions
  605. for ( i = 0; i < callStackSize; i++ ) {
  606. callStack[i] = GetCallerAddr( m_ebp );
  607. if ( callStack[i] == 0 ) {
  608. break;
  609. }
  610. m_ebp = *((long*)m_ebp);
  611. }
  612. #else
  613. int i = 0;
  614. #endif
  615. while( i < callStackSize ) {
  616. callStack[i++] = 0;
  617. }
  618. }
  619. /*
  620. ==================
  621. Sys_GetCallStackStr
  622. ==================
  623. */
  624. const char *Sys_GetCallStackStr( const address_t *callStack, const int callStackSize ) {
  625. static char string[MAX_STRING_CHARS*2];
  626. int index, i;
  627. idStr module, funcName;
  628. index = 0;
  629. for ( i = callStackSize-1; i >= 0; i-- ) {
  630. Sym_GetFuncInfo( callStack[i], module, funcName );
  631. index += sprintf( string+index, " -> %s", funcName.c_str() );
  632. }
  633. return string;
  634. }
  635. /*
  636. ==================
  637. Sys_GetCallStackCurStr
  638. ==================
  639. */
  640. const char *Sys_GetCallStackCurStr( int depth ) {
  641. address_t *callStack;
  642. callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
  643. Sys_GetCallStack( callStack, depth );
  644. return Sys_GetCallStackStr( callStack, depth );
  645. }
  646. /*
  647. ==================
  648. Sys_GetCallStackCurAddressStr
  649. ==================
  650. */
  651. const char *Sys_GetCallStackCurAddressStr( int depth ) {
  652. static char string[MAX_STRING_CHARS*2];
  653. address_t *callStack;
  654. int index, i;
  655. callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
  656. Sys_GetCallStack( callStack, depth );
  657. index = 0;
  658. for ( i = depth-1; i >= 0; i-- ) {
  659. index += sprintf( string+index, " -> 0x%08x", callStack[i] );
  660. }
  661. return string;
  662. }
  663. /*
  664. ==================
  665. Sys_ShutdownSymbols
  666. ==================
  667. */
  668. void Sys_ShutdownSymbols() {
  669. Sym_Shutdown();
  670. }