2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
24 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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "win_local.h"
47 #pragma comment (lib, "wbemuuid.lib")
55 int Sys_Milliseconds( void ) {
57 static int sys_timeBase;
58 static bool initialized = false;
61 sys_timeBase = timeGetTime();
64 sys_curtime = timeGetTime() - sys_timeBase;
73 returns amount of physical memory in MB
76 int Sys_GetSystemRam( void ) {
77 MEMORYSTATUSEX statex;
78 statex.dwLength = sizeof ( statex );
79 GlobalMemoryStatusEx (&statex);
80 int physRam = statex.ullTotalPhys / ( 1024 * 1024 );
81 // HACK: For some reason, ullTotalPhys is sometimes off by a meg or two, so we round up to the nearest 16 megs
82 physRam = ( physRam + 8 ) & ~15;
93 int Sys_GetDriveFreeSpace( const char *path ) {
94 DWORDLONG lpFreeBytesAvailable;
95 DWORDLONG lpTotalNumberOfBytes;
96 DWORDLONG lpTotalNumberOfFreeBytes;
98 //FIXME: see why this is failing on some machines
99 if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
100 ret = ( double )( lpFreeBytesAvailable ) / ( 1024.0 * 1024.0 );
112 int Sys_GetVideoRam( void ) {
116 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 ) {
124 CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
125 CComPtr<IWbemServices> spServices;
128 hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
129 if ( hr != WBEM_S_NO_ERROR ) {
133 // Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.
134 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 );
139 // Get the vid controller
140 CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
141 hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst );
142 if ( hr != WBEM_S_NO_ERROR || spEnumInst == NULL ) {
146 ULONG uNumOfInstances = 0;
147 CComPtr<IWbemClassObject> spInstance = NULL;
148 hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
150 if ( hr == S_OK && spInstance ) {
151 // Get properties from the object
153 hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
155 retSize = varSize.intVal / ( 1024 * 1024 );
156 if ( retSize == 0 ) {
167 Sys_GetCurrentMemoryStatus
170 all values are in kB except the memoryload
173 void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
174 MEMORYSTATUSEX statex;
175 unsigned __int64 work;
177 memset( &statex, sizeof( statex ), 0 );
178 statex.dwLength = sizeof( statex );
179 GlobalMemoryStatusEx( &statex );
181 memset( &stats, 0, sizeof( stats ) );
183 stats.memoryLoad = statex.dwMemoryLoad;
185 work = statex.ullTotalPhys >> 20;
186 stats.totalPhysical = *(int*)&work;
188 work = statex.ullAvailPhys >> 20;
189 stats.availPhysical = *(int*)&work;
191 work = statex.ullAvailPageFile >> 20;
192 stats.availPageFile = *(int*)&work;
194 work = statex.ullTotalPageFile >> 20;
195 stats.totalPageFile = *(int*)&work;
197 work = statex.ullTotalVirtual >> 20;
198 stats.totalVirtual = *(int*)&work;
200 work = statex.ullAvailVirtual >> 20;
201 stats.availVirtual = *(int*)&work;
203 work = statex.ullAvailExtendedVirtual >> 20;
204 stats.availExtendedVirtual = *(int*)&work;
212 bool Sys_LockMemory( void *ptr, int bytes ) {
213 return ( VirtualLock( ptr, (SIZE_T)bytes ) != FALSE );
221 bool Sys_UnlockMemory( void *ptr, int bytes ) {
222 return ( VirtualUnlock( ptr, (SIZE_T)bytes ) != FALSE );
227 Sys_SetPhysicalWorkMemory
230 void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
231 ::SetProcessWorkingSetSize( GetCurrentProcess(), minBytes, maxBytes );
239 char *Sys_GetCurrentUser( void ) {
240 static char s_userName[1024];
241 unsigned long size = sizeof( s_userName );
244 if ( !GetUserName( s_userName, &size ) ) {
245 strcpy( s_userName, "player" );
248 if ( !s_userName[0] ) {
249 strcpy( s_userName, "player" );
257 ===============================================================================
261 ===============================================================================
265 #define PROLOGUE_SIGNATURE 0x00EC8B55
269 const int UNDECORATE_FLAGS = UNDNAME_NO_MS_KEYWORDS |
270 UNDNAME_NO_ACCESS_SPECIFIERS |
271 UNDNAME_NO_FUNCTION_RETURNS |
272 UNDNAME_NO_ALLOCATION_MODEL |
273 UNDNAME_NO_ALLOCATION_LANGUAGE |
274 UNDNAME_NO_MEMBER_TYPE;
276 #if defined(_DEBUG) && 1
278 typedef struct symbol_s {
281 struct symbol_s * next;
284 typedef struct module_s {
288 struct module_s * next;
298 void SkipRestOfLine( const char **ptr ) {
299 while( (**ptr) != '\0' && (**ptr) != '\n' && (**ptr) != '\r' ) {
302 while( (**ptr) == '\n' || (**ptr) == '\r' ) {
312 void SkipWhiteSpace( const char **ptr ) {
313 while( (**ptr) == ' ' ) {
323 int ParseHexNumber( const char **ptr ) {
325 while( (**ptr) >= '0' && (**ptr) <= '9' || (**ptr) >= 'a' && (**ptr) <= 'f' ) {
327 if ( **ptr >= '0' && **ptr <= '9' ) {
328 n |= ( (**ptr) - '0' );
330 n |= 10 + ( (**ptr) - 'a' );
342 void Sym_Init( long addr ) {
343 TCHAR moduleName[MAX_STRING_CHARS];
344 MEMORY_BASIC_INFORMATION mbi;
346 VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
348 GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
350 char *ext = moduleName + strlen( moduleName );
351 while( ext > moduleName && *ext != '.' ) {
354 if ( ext == moduleName ) {
355 strcat( moduleName, ".map" );
357 strcpy( ext, ".map" );
360 module_t *module = (module_t *) malloc( sizeof( module_t ) );
361 module->name = (char *) malloc( strlen( moduleName ) + 1 );
362 strcpy( module->name, moduleName );
363 module->address = (int)mbi.AllocationBase;
364 module->symbols = NULL;
365 module->next = modules;
368 FILE *fp = fopen( moduleName, "rb" );
373 int pos = ftell( fp );
374 fseek( fp, 0, SEEK_END );
375 int length = ftell( fp );
376 fseek( fp, pos, SEEK_SET );
378 char *text = (char *) malloc( length+1 );
379 fread( text, 1, length, fp );
383 const char *ptr = text;
385 // skip up to " Address" on a new line
386 while( *ptr != '\0' ) {
387 SkipWhiteSpace( &ptr );
388 if ( idStr::Cmpn( ptr, "Address", 7 ) == 0 ) {
389 SkipRestOfLine( &ptr );
392 SkipRestOfLine( &ptr );
397 char symbolName[MAX_STRING_CHARS];
401 while( *ptr != '\0' ) {
403 SkipWhiteSpace( &ptr );
405 ParseHexNumber( &ptr );
411 ParseHexNumber( &ptr );
413 SkipWhiteSpace( &ptr );
417 while( *ptr != '\0' && *ptr != ' ' ) {
418 symbolName[symbolLength++] = *ptr++;
419 if ( symbolLength >= sizeof( symbolName ) - 1 ) {
423 symbolName[symbolLength++] = '\0';
425 SkipWhiteSpace( &ptr );
427 // parse symbol address
428 symbolAddress = ParseHexNumber( &ptr );
430 SkipRestOfLine( &ptr );
432 symbol = (symbol_t *) malloc( sizeof( symbol_t ) );
433 symbol->name = (char *) malloc( symbolLength );
434 strcpy( symbol->name, symbolName );
435 symbol->address = symbolAddress;
436 symbol->next = module->symbols;
437 module->symbols = symbol;
448 void Sym_Shutdown( void ) {
452 for ( m = modules; m != NULL; m = modules ) {
454 for ( s = m->symbols; s != NULL; s = m->symbols ) {
455 m->symbols = s->next;
470 void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
471 MEMORY_BASIC_INFORMATION mbi;
475 VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
477 for ( m = modules; m != NULL; m = m->next ) {
478 if ( m->address == (int) mbi.AllocationBase ) {
487 for ( s = m->symbols; s != NULL; s = s->next ) {
488 if ( s->address == addr ) {
490 char undName[MAX_STRING_CHARS];
491 if ( UnDecorateSymbolName( s->name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
496 for ( int i = 0; i < funcName.Length(); i++ ) {
497 if ( funcName[i] == '(' ) {
498 funcName.CapLength( i );
507 sprintf( funcName, "0x%08x", addr );
511 #elif defined(_DEBUG)
513 DWORD lastAllocationBase = -1;
514 HANDLE processHandle;
522 void Sym_Init( long addr ) {
523 TCHAR moduleName[MAX_STRING_CHARS];
524 TCHAR modShortNameBuf[MAX_STRING_CHARS];
525 MEMORY_BASIC_INFORMATION mbi;
527 if ( lastAllocationBase != -1 ) {
531 VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
533 GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
534 _splitpath( moduleName, NULL, NULL, modShortNameBuf, NULL );
535 lastModule = modShortNameBuf;
537 processHandle = GetCurrentProcess();
538 if ( !SymInitialize( processHandle, NULL, FALSE ) ) {
541 if ( !SymLoadModule( processHandle, NULL, moduleName, NULL, (DWORD)mbi.AllocationBase, 0 ) ) {
542 SymCleanup( processHandle );
546 SymSetOptions( SymGetOptions() & ~SYMOPT_UNDNAME );
548 lastAllocationBase = (DWORD) mbi.AllocationBase;
556 void Sym_Shutdown( void ) {
557 SymUnloadModule( GetCurrentProcess(), lastAllocationBase );
558 SymCleanup( GetCurrentProcess() );
559 lastAllocationBase = -1;
567 void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
568 MEMORY_BASIC_INFORMATION mbi;
570 VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
572 if ( (DWORD) mbi.AllocationBase != lastAllocationBase ) {
576 BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + MAX_STRING_CHARS ];
577 PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)&symbolBuffer[0];
578 pSymbol->SizeOfStruct = sizeof(symbolBuffer);
579 pSymbol->MaxNameLength = 1023;
580 pSymbol->Address = 0;
584 DWORD symDisplacement = 0;
585 if ( SymGetSymFromAddr( processHandle, addr, &symDisplacement, pSymbol ) ) {
586 // clean up name, throwing away decorations that don't affect uniqueness
587 char undName[MAX_STRING_CHARS];
588 if ( UnDecorateSymbolName( pSymbol->Name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
591 funcName = pSymbol->Name;
597 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
600 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
605 LocalFree( lpMsgBuf );
607 // Couldn't retrieve symbol (no debug info?, can't load dbghelp.dll?)
608 sprintf( funcName, "0x%08x", addr );
620 void Sym_Init( long addr ) {
628 void Sym_Shutdown( void ) {
636 void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
638 sprintf( funcName, "0x%08x", addr );
648 address_t GetFuncAddr( address_t midPtPtr ) {
651 temp = (long)(*(long*)midPtPtr);
652 if ( (temp&0x00FFFFFF) == PROLOGUE_SIGNATURE ) {
666 address_t GetCallerAddr( long _ebp ) {
672 mov ecx, [eax] // check for end of stack frames list
673 test ecx, ecx // check for zero stack frame
675 mov eax, [eax+4] // get the ret address
676 test eax, eax // check for zero return address
680 res = GetFuncAddr( midPtPtr );
692 void Sys_GetCallStack( address_t *callStack, const int callStackSize ) {
701 // skip last two functions
702 m_ebp = *((long*)m_ebp);
703 m_ebp = *((long*)m_ebp);
705 for ( i = 0; i < callStackSize; i++ ) {
706 callStack[i] = GetCallerAddr( m_ebp );
707 if ( callStack[i] == 0 ) {
710 m_ebp = *((long*)m_ebp);
715 while( i < callStackSize ) {
725 const char *Sys_GetCallStackStr( const address_t *callStack, const int callStackSize ) {
726 static char string[MAX_STRING_CHARS*2];
728 idStr module, funcName;
731 for ( i = callStackSize-1; i >= 0; i-- ) {
732 Sym_GetFuncInfo( callStack[i], module, funcName );
733 index += sprintf( string+index, " -> %s", funcName.c_str() );
740 Sys_GetCallStackCurStr
743 const char *Sys_GetCallStackCurStr( int depth ) {
744 address_t *callStack;
746 callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
747 Sys_GetCallStack( callStack, depth );
748 return Sys_GetCallStackStr( callStack, depth );
753 Sys_GetCallStackCurAddressStr
756 const char *Sys_GetCallStackCurAddressStr( int depth ) {
757 static char string[MAX_STRING_CHARS*2];
758 address_t *callStack;
761 callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
762 Sys_GetCallStack( callStack, depth );
765 for ( i = depth-1; i >= 0; i-- ) {
766 index += sprintf( string+index, " -> 0x%08x", callStack[i] );
776 void Sys_ShutdownSymbols( void ) {