123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../../idlib/precompiled.h"
- #include "win_local.h"
- #include <lmerr.h>
- #include <lmcons.h>
- #include <lmwksta.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <direct.h>
- #include <io.h>
- #include <conio.h>
- #undef StrCmpN
- #undef StrCmpNI
- #undef StrCmpI
- #include <atlbase.h>
- #include <comdef.h>
- #include <comutil.h>
- #include <Wbemidl.h>
- #pragma comment (lib, "wbemuuid.lib")
- #pragma warning(disable:4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
- /*
- ================
- Sys_Milliseconds
- ================
- */
- int Sys_Milliseconds() {
- static DWORD sys_timeBase = timeGetTime();
- return timeGetTime() - sys_timeBase;
- }
- /*
- ========================
- Sys_Microseconds
- ========================
- */
- uint64 Sys_Microseconds() {
- static uint64 ticksPerMicrosecondTimes1024 = 0;
- if ( ticksPerMicrosecondTimes1024 == 0 ) {
- ticksPerMicrosecondTimes1024 = ( (uint64)Sys_ClockTicksPerSecond() << 10 ) / 1000000;
- assert( ticksPerMicrosecondTimes1024 > 0 );
- }
- return ((uint64)( (int64)Sys_GetClockTicks() << 10 )) / ticksPerMicrosecondTimes1024;
- }
- /*
- ================
- Sys_GetSystemRam
- returns amount of physical memory in MB
- ================
- */
- int Sys_GetSystemRam() {
- MEMORYSTATUSEX statex;
- statex.dwLength = sizeof ( statex );
- GlobalMemoryStatusEx (&statex);
- int physRam = statex.ullTotalPhys / ( 1024 * 1024 );
- // HACK: For some reason, ullTotalPhys is sometimes off by a meg or two, so we round up to the nearest 16 megs
- physRam = ( physRam + 8 ) & ~15;
- return physRam;
- }
- /*
- ================
- Sys_GetDriveFreeSpace
- returns in megabytes
- ================
- */
- int Sys_GetDriveFreeSpace( const char *path ) {
- DWORDLONG lpFreeBytesAvailable;
- DWORDLONG lpTotalNumberOfBytes;
- DWORDLONG lpTotalNumberOfFreeBytes;
- int ret = 26;
- //FIXME: see why this is failing on some machines
- if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
- ret = ( double )( lpFreeBytesAvailable ) / ( 1024.0 * 1024.0 );
- }
- return ret;
- }
- /*
- ========================
- Sys_GetDriveFreeSpaceInBytes
- ========================
- */
- int64 Sys_GetDriveFreeSpaceInBytes( const char * path ) {
- DWORDLONG lpFreeBytesAvailable;
- DWORDLONG lpTotalNumberOfBytes;
- DWORDLONG lpTotalNumberOfFreeBytes;
- int64 ret = 1;
- //FIXME: see why this is failing on some machines
- if ( ::GetDiskFreeSpaceEx( path, (PULARGE_INTEGER)&lpFreeBytesAvailable, (PULARGE_INTEGER)&lpTotalNumberOfBytes, (PULARGE_INTEGER)&lpTotalNumberOfFreeBytes ) ) {
- ret = lpFreeBytesAvailable;
- }
- return ret;
- }
- /*
- ================
- Sys_GetVideoRam
- returns in megabytes
- ================
- */
- int Sys_GetVideoRam() {
- unsigned int retSize = 64;
- CComPtr<IWbemLocator> spLoc = NULL;
- HRESULT hr = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, ( LPVOID * ) &spLoc );
- if ( hr != S_OK || spLoc == NULL ) {
- return retSize;
- }
- CComBSTR bstrNamespace( _T( "\\\\.\\root\\CIMV2" ) );
- CComPtr<IWbemServices> spServices;
- // Connect to CIM
- hr = spLoc->ConnectServer( bstrNamespace, NULL, NULL, 0, NULL, 0, 0, &spServices );
- if ( hr != WBEM_S_NO_ERROR ) {
- return retSize;
- }
- // Switch the security level to IMPERSONATE so that provider will grant access to system-level objects.
- 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 );
- if ( hr != S_OK ) {
- return retSize;
- }
- // Get the vid controller
- CComPtr<IEnumWbemClassObject> spEnumInst = NULL;
- hr = spServices->CreateInstanceEnum( CComBSTR( "Win32_VideoController" ), WBEM_FLAG_SHALLOW, NULL, &spEnumInst );
- if ( hr != WBEM_S_NO_ERROR || spEnumInst == NULL ) {
- return retSize;
- }
- ULONG uNumOfInstances = 0;
- CComPtr<IWbemClassObject> spInstance = NULL;
- hr = spEnumInst->Next( 10000, 1, &spInstance, &uNumOfInstances );
- if ( hr == S_OK && spInstance ) {
- // Get properties from the object
- CComVariant varSize;
- hr = spInstance->Get( CComBSTR( _T( "AdapterRAM" ) ), 0, &varSize, 0, 0 );
- if ( hr == S_OK ) {
- retSize = varSize.intVal / ( 1024 * 1024 );
- if ( retSize == 0 ) {
- retSize = 64;
- }
- }
- }
- return retSize;
- }
- /*
- ================
- Sys_GetCurrentMemoryStatus
- returns OS mem info
- all values are in kB except the memoryload
- ================
- */
- void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
- MEMORYSTATUSEX statex = {};
- unsigned __int64 work;
- statex.dwLength = sizeof( statex );
- GlobalMemoryStatusEx( &statex );
- memset( &stats, 0, sizeof( stats ) );
- stats.memoryLoad = statex.dwMemoryLoad;
- work = statex.ullTotalPhys >> 20;
- stats.totalPhysical = *(int*)&work;
- work = statex.ullAvailPhys >> 20;
- stats.availPhysical = *(int*)&work;
- work = statex.ullAvailPageFile >> 20;
- stats.availPageFile = *(int*)&work;
- work = statex.ullTotalPageFile >> 20;
- stats.totalPageFile = *(int*)&work;
- work = statex.ullTotalVirtual >> 20;
- stats.totalVirtual = *(int*)&work;
- work = statex.ullAvailVirtual >> 20;
- stats.availVirtual = *(int*)&work;
- work = statex.ullAvailExtendedVirtual >> 20;
- stats.availExtendedVirtual = *(int*)&work;
- }
- /*
- ================
- Sys_LockMemory
- ================
- */
- bool Sys_LockMemory( void *ptr, int bytes ) {
- return ( VirtualLock( ptr, (SIZE_T)bytes ) != FALSE );
- }
- /*
- ================
- Sys_UnlockMemory
- ================
- */
- bool Sys_UnlockMemory( void *ptr, int bytes ) {
- return ( VirtualUnlock( ptr, (SIZE_T)bytes ) != FALSE );
- }
- /*
- ================
- Sys_SetPhysicalWorkMemory
- ================
- */
- void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
- ::SetProcessWorkingSetSize( GetCurrentProcess(), minBytes, maxBytes );
- }
- /*
- ================
- Sys_GetCurrentUser
- ================
- */
- char *Sys_GetCurrentUser() {
- static char s_userName[1024];
- unsigned long size = sizeof( s_userName );
- if ( !GetUserName( s_userName, &size ) ) {
- strcpy( s_userName, "player" );
- }
- if ( !s_userName[0] ) {
- strcpy( s_userName, "player" );
- }
- return s_userName;
- }
- /*
- ===============================================================================
- Call stack
- ===============================================================================
- */
- #define PROLOGUE_SIGNATURE 0x00EC8B55
- #include <dbghelp.h>
- const int UNDECORATE_FLAGS = UNDNAME_NO_MS_KEYWORDS |
- UNDNAME_NO_ACCESS_SPECIFIERS |
- UNDNAME_NO_FUNCTION_RETURNS |
- UNDNAME_NO_ALLOCATION_MODEL |
- UNDNAME_NO_ALLOCATION_LANGUAGE |
- UNDNAME_NO_MEMBER_TYPE;
- #if defined(_DEBUG) && 1
- typedef struct symbol_s {
- int address;
- char * name;
- struct symbol_s * next;
- } symbol_t;
- typedef struct module_s {
- int address;
- char * name;
- symbol_t * symbols;
- struct module_s * next;
- } module_t;
- module_t *modules;
- /*
- ==================
- SkipRestOfLine
- ==================
- */
- void SkipRestOfLine( const char **ptr ) {
- while( (**ptr) != '\0' && (**ptr) != '\n' && (**ptr) != '\r' ) {
- (*ptr)++;
- }
- while( (**ptr) == '\n' || (**ptr) == '\r' ) {
- (*ptr)++;
- }
- }
- /*
- ==================
- SkipWhiteSpace
- ==================
- */
- void SkipWhiteSpace( const char **ptr ) {
- while( (**ptr) == ' ' ) {
- (*ptr)++;
- }
- }
- /*
- ==================
- ParseHexNumber
- ==================
- */
- int ParseHexNumber( const char **ptr ) {
- int n = 0;
- while( (**ptr) >= '0' && (**ptr) <= '9' || (**ptr) >= 'a' && (**ptr) <= 'f' ) {
- n <<= 4;
- if ( **ptr >= '0' && **ptr <= '9' ) {
- n |= ( (**ptr) - '0' );
- } else {
- n |= 10 + ( (**ptr) - 'a' );
- }
- (*ptr)++;
- }
- return n;
- }
- /*
- ==================
- Sym_Init
- ==================
- */
- void Sym_Init( long addr ) {
- TCHAR moduleName[MAX_STRING_CHARS];
- MEMORY_BASIC_INFORMATION mbi;
- VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
- GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
- char *ext = moduleName + strlen( moduleName );
- while( ext > moduleName && *ext != '.' ) {
- ext--;
- }
- if ( ext == moduleName ) {
- strcat( moduleName, ".map" );
- } else {
- strcpy( ext, ".map" );
- }
- module_t *module = (module_t *) malloc( sizeof( module_t ) );
- module->name = (char *) malloc( strlen( moduleName ) + 1 );
- strcpy( module->name, moduleName );
- module->address = (int)mbi.AllocationBase;
- module->symbols = NULL;
- module->next = modules;
- modules = module;
- FILE * fp = fopen( moduleName, "rb" );
- if ( fp == NULL ) {
- return;
- }
- int pos = ftell( fp );
- fseek( fp, 0, SEEK_END );
- int length = ftell( fp );
- fseek( fp, pos, SEEK_SET );
- char *text = (char *) malloc( length+1 );
- fread( text, 1, length, fp );
- text[length] = '\0';
- fclose( fp );
- const char *ptr = text;
- // skip up to " Address" on a new line
- while( *ptr != '\0' ) {
- SkipWhiteSpace( &ptr );
- if ( idStr::Cmpn( ptr, "Address", 7 ) == 0 ) {
- SkipRestOfLine( &ptr );
- break;
- }
- SkipRestOfLine( &ptr );
- }
- int symbolAddress;
- int symbolLength;
- char symbolName[MAX_STRING_CHARS];
- symbol_t *symbol;
- // parse symbols
- while( *ptr != '\0' ) {
- SkipWhiteSpace( &ptr );
- ParseHexNumber( &ptr );
- if ( *ptr == ':' ) {
- ptr++;
- } else {
- break;
- }
- ParseHexNumber( &ptr );
- SkipWhiteSpace( &ptr );
- // parse symbol name
- symbolLength = 0;
- while( *ptr != '\0' && *ptr != ' ' ) {
- symbolName[symbolLength++] = *ptr++;
- if ( symbolLength >= sizeof( symbolName ) - 1 ) {
- break;
- }
- }
- symbolName[symbolLength++] = '\0';
- SkipWhiteSpace( &ptr );
- // parse symbol address
- symbolAddress = ParseHexNumber( &ptr );
- SkipRestOfLine( &ptr );
- symbol = (symbol_t *) malloc( sizeof( symbol_t ) );
- symbol->name = (char *) malloc( symbolLength );
- strcpy( symbol->name, symbolName );
- symbol->address = symbolAddress;
- symbol->next = module->symbols;
- module->symbols = symbol;
- }
- free( text );
- }
- /*
- ==================
- Sym_Shutdown
- ==================
- */
- void Sym_Shutdown() {
- module_t *m;
- symbol_t *s;
- for ( m = modules; m != NULL; m = modules ) {
- modules = m->next;
- for ( s = m->symbols; s != NULL; s = m->symbols ) {
- m->symbols = s->next;
- free( s->name );
- free( s );
- }
- free( m->name );
- free( m );
- }
- modules = NULL;
- }
- /*
- ==================
- Sym_GetFuncInfo
- ==================
- */
- void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
- MEMORY_BASIC_INFORMATION mbi;
- module_t *m;
- symbol_t *s;
- VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
- for ( m = modules; m != NULL; m = m->next ) {
- if ( m->address == (int) mbi.AllocationBase ) {
- break;
- }
- }
- if ( !m ) {
- Sym_Init( addr );
- m = modules;
- }
- for ( s = m->symbols; s != NULL; s = s->next ) {
- if ( s->address == addr ) {
- char undName[MAX_STRING_CHARS];
- if ( UnDecorateSymbolName( s->name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
- funcName = undName;
- } else {
- funcName = s->name;
- }
- for ( int i = 0; i < funcName.Length(); i++ ) {
- if ( funcName[i] == '(' ) {
- funcName.CapLength( i );
- break;
- }
- }
- module = m->name;
- return;
- }
- }
- sprintf( funcName, "0x%08x", addr );
- module = "";
- }
- #elif defined(_DEBUG)
- DWORD lastAllocationBase = -1;
- HANDLE processHandle;
- idStr lastModule;
- /*
- ==================
- Sym_Init
- ==================
- */
- void Sym_Init( long addr ) {
- TCHAR moduleName[MAX_STRING_CHARS];
- TCHAR modShortNameBuf[MAX_STRING_CHARS];
- MEMORY_BASIC_INFORMATION mbi;
- if ( lastAllocationBase != -1 ) {
- Sym_Shutdown();
- }
- VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
- GetModuleFileName( (HMODULE)mbi.AllocationBase, moduleName, sizeof( moduleName ) );
- _splitpath( moduleName, NULL, NULL, modShortNameBuf, NULL );
- lastModule = modShortNameBuf;
- processHandle = GetCurrentProcess();
- if ( !SymInitialize( processHandle, NULL, FALSE ) ) {
- return;
- }
- if ( !SymLoadModule( processHandle, NULL, moduleName, NULL, (DWORD)mbi.AllocationBase, 0 ) ) {
- SymCleanup( processHandle );
- return;
- }
- SymSetOptions( SymGetOptions() & ~SYMOPT_UNDNAME );
- lastAllocationBase = (DWORD) mbi.AllocationBase;
- }
- /*
- ==================
- Sym_Shutdown
- ==================
- */
- void Sym_Shutdown() {
- SymUnloadModule( GetCurrentProcess(), lastAllocationBase );
- SymCleanup( GetCurrentProcess() );
- lastAllocationBase = -1;
- }
- /*
- ==================
- Sym_GetFuncInfo
- ==================
- */
- void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
- MEMORY_BASIC_INFORMATION mbi;
- VirtualQuery( (void*)addr, &mbi, sizeof(mbi) );
- if ( (DWORD) mbi.AllocationBase != lastAllocationBase ) {
- Sym_Init( addr );
- }
- BYTE symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + MAX_STRING_CHARS ];
- PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)&symbolBuffer[0];
- pSymbol->SizeOfStruct = sizeof(symbolBuffer);
- pSymbol->MaxNameLength = 1023;
- pSymbol->Address = 0;
- pSymbol->Flags = 0;
- pSymbol->Size =0;
- DWORD symDisplacement = 0;
- if ( SymGetSymFromAddr( processHandle, addr, &symDisplacement, pSymbol ) ) {
- // clean up name, throwing away decorations that don't affect uniqueness
- char undName[MAX_STRING_CHARS];
- if ( UnDecorateSymbolName( pSymbol->Name, undName, sizeof(undName), UNDECORATE_FLAGS ) ) {
- funcName = undName;
- } else {
- funcName = pSymbol->Name;
- }
- module = lastModule;
- }
- else {
- LPVOID lpMsgBuf;
- FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- LocalFree( lpMsgBuf );
- // Couldn't retrieve symbol (no debug info?, can't load dbghelp.dll?)
- sprintf( funcName, "0x%08x", addr );
- module = "";
- }
- }
- #else
- /*
- ==================
- Sym_Init
- ==================
- */
- void Sym_Init( long addr ) {
- }
- /*
- ==================
- Sym_Shutdown
- ==================
- */
- void Sym_Shutdown() {
- }
- /*
- ==================
- Sym_GetFuncInfo
- ==================
- */
- void Sym_GetFuncInfo( long addr, idStr &module, idStr &funcName ) {
- module = "";
- sprintf( funcName, "0x%08x", addr );
- }
- #endif
- /*
- ==================
- GetFuncAddr
- ==================
- */
- address_t GetFuncAddr( address_t midPtPtr ) {
- long temp;
- do {
- temp = (long)(*(long*)midPtPtr);
- if ( (temp&0x00FFFFFF) == PROLOGUE_SIGNATURE ) {
- break;
- }
- midPtPtr--;
- } while(true);
- return midPtPtr;
- }
- /*
- ==================
- GetCallerAddr
- ==================
- */
- address_t GetCallerAddr( long _ebp ) {
- long midPtPtr;
- long res = 0;
- __asm {
- mov eax, _ebp
- mov ecx, [eax] // check for end of stack frames list
- test ecx, ecx // check for zero stack frame
- jz label
- mov eax, [eax+4] // get the ret address
- test eax, eax // check for zero return address
- jz label
- mov midPtPtr, eax
- }
- res = GetFuncAddr( midPtPtr );
- label:
- return res;
- }
- /*
- ==================
- Sys_GetCallStack
- use /Oy option
- ==================
- */
- void Sys_GetCallStack( address_t *callStack, const int callStackSize ) {
- #if 1 //def _DEBUG
- int i;
- long m_ebp;
- __asm {
- mov eax, ebp
- mov m_ebp, eax
- }
- // skip last two functions
- m_ebp = *((long*)m_ebp);
- m_ebp = *((long*)m_ebp);
- // list functions
- for ( i = 0; i < callStackSize; i++ ) {
- callStack[i] = GetCallerAddr( m_ebp );
- if ( callStack[i] == 0 ) {
- break;
- }
- m_ebp = *((long*)m_ebp);
- }
- #else
- int i = 0;
- #endif
- while( i < callStackSize ) {
- callStack[i++] = 0;
- }
- }
- /*
- ==================
- Sys_GetCallStackStr
- ==================
- */
- const char *Sys_GetCallStackStr( const address_t *callStack, const int callStackSize ) {
- static char string[MAX_STRING_CHARS*2];
- int index, i;
- idStr module, funcName;
- index = 0;
- for ( i = callStackSize-1; i >= 0; i-- ) {
- Sym_GetFuncInfo( callStack[i], module, funcName );
- index += sprintf( string+index, " -> %s", funcName.c_str() );
- }
- return string;
- }
- /*
- ==================
- Sys_GetCallStackCurStr
- ==================
- */
- const char *Sys_GetCallStackCurStr( int depth ) {
- address_t *callStack;
- callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
- Sys_GetCallStack( callStack, depth );
- return Sys_GetCallStackStr( callStack, depth );
- }
- /*
- ==================
- Sys_GetCallStackCurAddressStr
- ==================
- */
- const char *Sys_GetCallStackCurAddressStr( int depth ) {
- static char string[MAX_STRING_CHARS*2];
- address_t *callStack;
- int index, i;
- callStack = (address_t *) _alloca( depth * sizeof( address_t ) );
- Sys_GetCallStack( callStack, depth );
- index = 0;
- for ( i = depth-1; i >= 0; i-- ) {
- index += sprintf( string+index, " -> 0x%08x", callStack[i] );
- }
- return string;
- }
- /*
- ==================
- Sys_ShutdownSymbols
- ==================
- */
- void Sys_ShutdownSymbols() {
- Sym_Shutdown();
- }
|