diff -r 000000000000 -r f0f2b8682603 memana/analyzetoolclient/dynamicmemoryhook/src/analyzetoolmainallocator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memana/analyzetoolclient/dynamicmemoryhook/src/analyzetoolmainallocator.cpp Thu Feb 11 15:51:35 2010 +0200 @@ -0,0 +1,1461 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Definitions for the class RAnalyzeToolMainAllocator. +* +*/ + + +#include "analyzetoolmainallocator.h" +#include "atlog.h" +#include "analyzetooleventhandler.h" +#include "analyzetoolmemoryallocator.h" +#include "analyzetoolpanics.pan" +#include "analyzetoolfastlog.h" +#ifdef __WINSCW__ +#include +#endif +#include + + +// CONSTANTS + +// The name of the memoryhook dll +_LIT8( KMemoryHook, "AToolMemoryHook.dll" ); + +// The name of the storage server dll +_LIT8( KStorageServer, "AToolStorageServerClnt.dll" ); + +// Length of the callstack address +const TUint32 KAddressLength = 4; + +// Thread count +const TInt KThreadCount = 1; + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::RAnalyzeToolMainAllocator() +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +RAnalyzeToolMainAllocator::RAnalyzeToolMainAllocator( TBool aNotFirst, + const TFileName aFileName, TUint32 aLogOption, TUint32 aIsDebug, + TUint32 aAllocCallStackSize, TUint32 aFreeCallStackSize ) : + RAnalyzeToolMemoryAllocator( aNotFirst ), + iAnalyzeToolOpen( EFalse ), + iDeviceDriverLoaded( EFalse ), + iCodeblocks( KATMaxCallstackLength ), + iThreadArray( KATMaxCallstackLength ), + iLogOption( aLogOption ), + iProcessId( RProcess().Id().operator TUint() ), + iAllocMaxCallStack( aAllocCallStackSize ), + iFreeMaxCallStack( aFreeCallStackSize ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::RAnalyzeToolMainAllocator()" ); + + // Basic error variable used in method. + TInt error( KErrNone ); + + // Connect to the storage server if logging mode not fast xti. + if ( iLogOption != EATLogToXtiFast ) + { + error = iStorageServer.Connect(); + + LOGSTR2( "ATMH Opening RATStorageServer error %i", error ); + + if ( KErrNone == error ) + { + iStorageServerOpen = ETrue; + } + else + { + iStorageServerOpen = EFalse; + } + + if ( KErrNone == error ) + { + // Make the storage server handle shared between threads + error = iStorageServer.ShareAuto(); + } + + LOGSTR2( "ATMH Sharing RATStorageServer error %i", error ); + } + + // Create mutex for schedule access to shared resources + error = iMutex.CreateLocal(); + + __ASSERT_ALWAYS( KErrNone == error, AssertPanic( ECantCreateMutex ) ); + + LOGSTR2( "ATMH Creating mutex error %i", error ); + + // Load the kernel side device driver + error = User::LoadLogicalDevice( KAnalyzeToolLddName ); + + if ( error != KErrNone && error != KErrAlreadyExists ) + { + __ASSERT_ALWAYS( EFalse, AssertPanic( ECantLoadDeviceDriver ) ); + } + else + { + iDeviceDriverLoaded = ETrue; + } + + LOGSTR2( "ATMH Loading device driver error %i", error ); + + // Open handle to the kernel sidedevice driver + error = iAnalyzeTool.Open(); + + __ASSERT_ALWAYS( KErrNone == error, AssertPanic( ECantConnectDeviceDriver ) ); + + if ( KErrNone == error ) + { + iAnalyzeToolOpen = ETrue; + } + + LOGSTR2( "ATMH Opening RAnalyzeTool handle %i error", error ); + + // Set memory model by asking kernel side device driver + if ( iAnalyzeToolOpen ) + { + TATMemoryModelBuf model; + if ( KErrNone == iAnalyzeTool.GetMemoryModel( model ) ) + { + iMemoryModel = model().iMemoryModel; + LOGSTR2( "ATMH AnalyzeTool MemoryModel: %i", iMemoryModel ); + } + else + LOGSTR2( "ATMH AnalyzeTool GetMemoryModel error: %i", error ); + } + + // Retrieve the initial process information + LogProcessInformation( aFileName, aLogOption, aIsDebug ); + + // Create handler for receiving kernel events + iEventHandler = new CLibraryEventHandler( iAnalyzeTool, + iCodeblocks, + iStorageServer, + iProcessId, + iMutex, + *this, + aLogOption); + + __ASSERT_ALWAYS( iEventHandler != NULL, AssertPanic( ENoMemory ) ); + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::~RAnalyzeToolMainAllocator() +// Destructor. +// ----------------------------------------------------------------------------- +// +RAnalyzeToolMainAllocator::~RAnalyzeToolMainAllocator() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::~RAnalyzeToolMainAllocator()" ); + + TUint handleLeakCount( 0 ); + if ( iAnalyzeToolOpen && iThreadArray.Count() > 0 ) + { + TProcessHandleInfoBuf params; + params().iProcessId = iProcessId; + TInt error( iAnalyzeTool.GetProcessHandleInfo( params ) ); + handleLeakCount = params().iThreadHandleCount; + } + + // Close handle for process memory blocks + iCodeblocks.Close(); + + // Delete the eventhandler + delete iEventHandler; + + // The count of device driver users + TClientCountBuf count; + + // Check the flag + if ( iAnalyzeToolOpen ) + { + TInt error = iAnalyzeTool.ClientCount( count ); + LOGSTR2( "ATMH closing analyze tool handle error: %i", error ); + iAnalyzeTool.Close(); + } + + // Check the flag + if ( iDeviceDriverLoaded ) + { + LOGSTR2( "ATMH device driver client count: %i", count().iClientCount ); + + // Check if there is another user for device driver + if ( count().iClientCount <= 1 ) + { + // There was no other users -> unload the device driver + TInt error = User::FreeLogicalDevice( KAnalyzeToolLddName ); + LOGSTR2( "ATMH Unloading ldd error: %i", error ); + } + } + + // Close the thread array + iThreadArray.Close(); + + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + if ( iLogOption == EATLogToXtiFast ) + { + LOGSTR1( "ATMH ATFastLogProcessEnded()" ); + ATFastLogProcessEnded( iProcessId, handleLeakCount ); + } + else + { + iStorageServerOpen = EFalse; + // Inform that process has ended and close the handle + LOGSTR1( "ATMH iStorageServer.LogProcessEnded()" ); + iStorageServer.LogProcessEnded( iProcessId, handleLeakCount ); + // Close the handle + iStorageServer.Close(); + } + } + + // Close handle for process handle leaks + + #ifdef __WINSCW__ + // Restore system's exit check + if ( CCoeEnv::Static() ) + CCoeEnv::Static()->DisableExitChecks( EFalse ); + #endif + + // Close the mutex + iMutex.Close(); + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::ShareHeap() +// Share heap with other thread +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::ShareHeap() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ShareHeap()" ); + + // Call the overwrited Open function + Open(); + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Uninstall() +// Uninstalls the current allocator +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::Uninstall() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Uninstall()" ); + + // Acquire the mutex + iMutex.Wait(); + + TMainThreadParamsBuf params; + params().iProcessId = iProcessId; + iAnalyzeTool.MainThreadAlloctor( params ); + + // Release the mutex + iMutex.Signal(); + + // Check if this is shared allocator between threads + if ( iThreadArray.Count() > KThreadCount && !params().iAlone ) + { + // Close the shared allocator + Close(); + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Uninstall() - Close called" ); + return; + } + +#if ( SYMBIAN_VERSION_SUPPORT >= SYMBIAN_3 ) + #ifndef __WINS__ + // Remove dummy Tls handle + UserSvr::DllFreeTls( KDummyHandle ); + #endif +#endif + + // Since this is the last thread using this allocator it can be deleted + delete this; + } + +#ifdef __WINS__ +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Alloc() WINS version +// Allocates a cell of specified size from the heap. +// ----------------------------------------------------------------------------- +// +UEXPORT_C TAny* RAnalyzeToolMainAllocator::Alloc( TInt aSize ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Alloc memory from the original allocator + TAny* p = iAllocator->Alloc( aSize ); + + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::Alloc() - aSize: %i, address: %x", + aSize, (TUint32) p ); + + // Don't collect or log data if storage server not open or logging mode fast xti. + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + TInt error( KErrNone ); + + // Check if eventhandler is active already + if ( !iEventHandler->IsActive() ) + { + // Install the eventhandler if needed + InstallEventHandler(); + } + + // Reset the callstack + iCallStack.Reset(); + + // If we don't want any call stack to be saved skip the next part + if( iAllocMaxCallStack > 0 ) + { + // Find the current thread callstack start address + TUint32 stackstart( 0 ); + TBool found( FindCurrentThreadStack( stackstart ) ); + LOGSTR3( "ATMH > stackstart: %x , found = %i", stackstart, found ); + + TUint32 _sp; + __asm + { + mov [_sp], esp + } + + // Get codeblocks count + TInt blocksCount( iCodeblocks.Count() ); + TUint arrayCounter = 0; + + for ( TUint32 i = _sp; i < stackstart; i = i + KAddressLength )//lint !e1055 !e526 !e628 !e348 + { + TUint32 addr = (TUint32) *( (TUint32*) i ); + if ( ! IsAddressLoadedCode( addr ) ) + continue; + for ( TInt j = 0; j < blocksCount; j++ ) + { + if ( iCodeblocks[j].CheckAddress( addr ) ) + { + // To avoid recursive call to ReAlloc specifying granularity + // Add address to the callstack + iCallStack[arrayCounter] = ( addr ); + arrayCounter++; + break; + } + } + if ( arrayCounter == KATMaxCallstackLength || + arrayCounter == iAllocMaxCallStack ) + { + LOGSTR2( "ATMH > Wanted CallStack items ready( %i )", arrayCounter ); + break; + } + } + } + + // Log the memory allocation information + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + ATFastLogMemoryAllocated( iProcessId, (TUint32) p , iCallStack, aSize ); + } + else + { + // Using storage server. + error = iStorageServer.LogMemoryAllocated( (TUint32) p, + iCallStack, + aSize ); + if ( KErrNone != error ) + { + switch ( error ) + { + case KErrNoMemory: + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc() - KErrNoMemory case" ); + // Check if eventhandler is active + if ( iEventHandler->IsActive() ) + { + // Cancel iEventHandler because not needed anymore + iEventHandler->Cancel(); + } + if ( iStorageServerOpen ) + { + iStorageServerOpen = EFalse; + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc() - close iStorageServer" ); + iStorageServer.Close(); + } + break; + } + default: + { + LOGSTR2( "ATMH LogMemoryAllocated error %i", error ); + break; + } + } + } + } + } + // Release the mutex + iMutex.Signal(); + + return p; + } +#else + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Alloc() ARMV5 version +// Allocates a cell of specified size from the heap. +// ----------------------------------------------------------------------------- +// +TAny* RAnalyzeToolMainAllocator::Alloc( TInt aSize ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc()" ); + + // acquire the mutex + iMutex.Wait(); + + // Alloc memory from the original allocator + TAny* p = iAllocator->Alloc( aSize ); + + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::Alloc() - aSize: %i, address: %x", + aSize, (TUint32) p ); + + TInt error( KErrNone ); + + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + // Check if eventhandler is active already + // IsActive might return false value if a tested software has created many + // threads which install own CActiveScheduler. + if ( !iEventHandler->IsStarted() ) + { + // Install the eventhandler if needed + InstallEventHandler(); + } + + // Reset the callstack + iCallStack.Reset(); + + // If we don't want any call stack to be saved skip the next part + if( iAllocMaxCallStack > 0 ) + { + // Find the current thread callstack start address + TUint32 stackstart( 0 ); + TBool found( FindCurrentThreadStack( stackstart ) ); + LOGSTR3( "ATMH > stackstart: %x , found = %i", stackstart, found ); + + TInt blocksCount( iCodeblocks.Count() ); + + TUint arrayCounter = 0; + + for ( TUint32 i = __current_sp(); i < stackstart; i = i + KAddressLength )//lint !e1055 !e526 !e628 !e348 + { + for ( TInt j = 0; j < blocksCount; j++ ) + { + if ( iCodeblocks[j].CheckAddress( (TUint32) *( (TUint32*) i ) ) ) + { + // To avoid recursive call to ReAlloc specifying granularity + // Add address to the callstack + iCallStack[arrayCounter] = ( (TUint32) *( (TUint32*) i ) ); + arrayCounter++; + break; + } + } + if ( arrayCounter == KATMaxCallstackLength || + arrayCounter == iAllocMaxCallStack ) + { + LOGSTR2( "ATMH > Wanted CallStack items ready( %i )", arrayCounter ); + break; + } + } + } + // Log the memory allocation information + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + ATFastLogMemoryAllocated( iProcessId, (TUint32) p, iCallStack, aSize ); + } + else + { + // Using storage server. + error = iStorageServer.LogMemoryAllocated( (TUint32) p, + iCallStack, + aSize ); + if ( KErrNone != error ) + { + switch ( error ) + { + case KErrNoMemory: + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc() - KErrNoMemory case" ); + // Check if eventhandler is active + if ( iEventHandler->IsActive() ) + { + // Cancel ieventhandler because not needed anymore + iEventHandler->Cancel(); + } + if ( iStorageServerOpen ) + { + iStorageServerOpen = EFalse; + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Alloc() - close iStorageServer" ); + iStorageServer.Close(); + } + break; + } + default: + { + LOGSTR2( "ATMH LogMemoryAllocated error %i", error ); + break; + } + } + } + } + } + + // Release the mutex + iMutex.Signal(); + + // Return the allocatated memory + return p; + } +#endif // __WINS__ + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Free() +// Frees the allocated memory +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::Free( TAny* aPtr ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Free()" ); + + // Acquire the mutex + iMutex.Wait(); + + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + // Reset the callstack + iFreeCallStack.Reset(); + + // Check if XTI logging mode + // Also if we don't want any call stack to be stored skip the next part + if ( (iLogOption == EATUseDefault || iLogOption == EATLogToXti || iLogOption == EATLogToXtiFast ) + && iFreeMaxCallStack > 0 ) + { + // Find the current thread callstack start address + TUint32 stackstart( 0 ); + TBool found( FindCurrentThreadStack( stackstart ) ); + LOGSTR3( "ATMH > stackstart: %x , found = %i", stackstart, found ); + TUint32 _sp; + + #ifdef __WINS__ + __asm + { + mov [_sp], esp + } + #else + _sp = __current_sp(); + #endif + + // Get codeblocks count + TInt blocksCount( iCodeblocks.Count() ); + TUint arrayCounter = 0; + + for ( TUint32 i = _sp; i < stackstart; i = i + KAddressLength )//lint !e1055 !e526 !e628 !e348 + { + TUint32 addr = (TUint32) *( (TUint32*) i ); + if ( ! IsAddressLoadedCode( addr ) ) + continue; + for ( TInt j = 0; j < blocksCount; j++ ) + { + if ( iCodeblocks[j].CheckAddress( addr ) ) + { + // To avoid recursive call to ReAlloc specifying granularity + // Add address to the callstack + iFreeCallStack[arrayCounter] = addr; + arrayCounter++; + break; + } + } + if ( arrayCounter == KATMaxFreeCallstackLength || + arrayCounter == iFreeMaxCallStack ) + { + break; + } + } + LOGSTR2( "ATMH > iFreeCallStack count ( %i )", arrayCounter ); + } + // Log the memory free information. + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + ATFastLogMemoryFreed( iProcessId, (TUint32) aPtr, iFreeCallStack ); + } + else + { + // Using storage server. + TInt err( iStorageServer.LogMemoryFreed( (TUint32) aPtr, iFreeCallStack ) ); + if ( err != KErrNone ) + { + LOGSTR2( "ATMH > LogMemoryFreed err( %i )", err ); + } + } + } + + // Free the memory using original allocator + iAllocator->Free( aPtr ); + + LOGSTR2( "ATMH RAnalyzeToolMainAllocator::Free() - aPtr: %x", (TUint32)aPtr ); + + // Release the mutex + iMutex.Signal(); + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Open() +// Opens this heap for shared access. Opening the heap increases +// the heap's access count by one. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::Open() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Open() " ); + + // Acquire the mutex + iMutex.Wait(); + + // Share the memory using original allocator + TInt error = iAllocator->Open(); + + // If everything is OK add thread to the array which use this allocator + if ( KErrNone == error ) + { + TThreadParamsBuf params; + params().iThreadId = RThread().Id().operator TUint(); + error = iAnalyzeTool.ThreadStack( params ); + + __ASSERT_ALWAYS( KErrNone == error, AssertPanic( ECantAppendToTheArray ) ); + + if ( KErrNone == error ) + { + LOGSTR2( "ATMH Thread stack address: %x", params().iStackAddress ); + LOGSTR2( "ATMH Thread stack size: %x", params().iStackSize ); + iThreadArray.Append( TThreadStack( RThread().Id(), + params().iStackAddress + params().iStackSize ) ); + } + } + + // Release the mutex + iMutex.Signal(); + + // Return the error code + return error; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Close() +// Closes this shared heap. Closing the heap decreases the heap's +// access count by one. +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::Close() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Close()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Close the memory using original allocator + iAllocator->Close(); + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Close() - allocator closed" ); + TInt count = iThreadArray.Count(); + + // Iterate through array of threads to remove current thread + for ( TInt i = 0; i < count; i++ ) + { + // Check if this is current thread + if ( iThreadArray[ i ].Match() ) + { + // Remove the thread + iThreadArray.Remove( i ); + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Close() - thread removed" ); + break; + } + } + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Close() - about to mutex signal" ); + // Release the mutex + iMutex.Signal(); + } + +#ifdef __WINS__ + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::ReAlloc() +// Increases or decreases the size of an existing cell. +// ----------------------------------------------------------------------------- +// +TAny* RAnalyzeToolMainAllocator::ReAlloc( TAny* aPtr, TInt aSize, TInt aMode ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Realloc the memory using original allocator + TAny* ptr = iAllocator->ReAlloc( aPtr, aSize, aMode ); + + // NULL addresses are not in a process under test + if ( ptr && !( aMode & ENeverMove ) ) + { + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - aPtr: %x, ptr: %x", + (TUint32)aPtr, (TUint32)ptr ); + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - aSize: %i, aMode: %i", + aSize, aMode ); + + // Don't collect or log data if storage server not open or logging mode is not fast xti. + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + TInt error( KErrNone ); + TUint arrayCounter = 0; + + // Reset the callstack + iReCallStack.Reset(); + + // If we don't want any call stack to be saved skip the next part + if( iAllocMaxCallStack > 0 ) + { + // find the current thread callstack start address + TUint32 stackstart( 0 ); + TBool found( FindCurrentThreadStack( stackstart ) ); + LOGSTR3( "ATMH > stackstart: %x , find = %i", stackstart, found ); + + // Get current sp + TUint32 _sp( 0 ); + __asm + { + mov [_sp], esp + } + + // Get codeblocks count + TInt blocksCount( iCodeblocks.Count() ); + + for ( TUint32 i = _sp; i < stackstart; i = i + KAddressLength )//lint !e1055 !e526 !e628 !e348 + { + TUint32 addr = (TUint32) *( (TUint32*) i ); + if ( ! IsAddressLoadedCode( addr ) ) + continue; + for ( TInt j = 0; j < blocksCount; j++ ) + { + if ( iCodeblocks[j].CheckAddress( addr ) ) + { + // To avoid recursive call to ReAlloc specifying granularity + // Add address to the callstack + iReCallStack[arrayCounter] = addr; + arrayCounter++; + break; + } + } + if ( arrayCounter == KATMaxCallstackLength || + arrayCounter == iAllocMaxCallStack ) + { + LOGSTR2( "ATMH > Wanted CallStack items ready( %i )", arrayCounter ); + break; + } + } + } + + // No need to report free if the aPtr was NULL + if ( aPtr != NULL ) + { + // Reset the free callstack + iFreeCallStack.Reset(); + + // Check that logging mode is xti/xti fast so we use free call stack + // and call stack size bigger than zero + if ( ( iLogOption == EATUseDefault || iLogOption == EATLogToXti || iLogOption == EATLogToXtiFast ) && iFreeMaxCallStack > 0 ) + { + for ( TInt i = 0; i < arrayCounter; i++ ) + { + if ( i == KATMaxFreeCallstackLength || i == iFreeMaxCallStack ) + { + break; + } + iFreeCallStack[i] = iReCallStack[i]; + } + } + // Try to remove old address from the storage server's + // leak array. If found. it's removed from the array because system frees + // old address directly in the RHeap in ReAlloc case. + if ( iLogOption == EATLogToXtiFast ) + { + ATFastLogMemoryFreed( iProcessId, (TUint32) aPtr, iFreeCallStack ); + } + else + { + iStorageServer.LogMemoryFreed( (TUint32) aPtr, iFreeCallStack ); + } + } + // Log the memory allocation information + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + ATFastLogMemoryAllocated( iProcessId, (TUint32) ptr, iReCallStack, aSize ); + } + else + { + // Using storage server. + error = iStorageServer.LogMemoryAllocated( (TUint32) ptr, + iReCallStack, + aSize ); + if ( KErrNone != error ) + { + switch ( error ) + { + case KErrNoMemory: + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - KErrNoMemory case" ); + // Check if eventhandler is active + if ( iEventHandler->IsActive() ) + { + // Cancel iEventHandler because not needed anymore + iEventHandler->Cancel(); + } + if ( iStorageServerOpen ) + { + iStorageServerOpen = EFalse; + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - close iStorageServer" ); + iStorageServer.Close(); + } + break; + } + default: + { + LOGSTR2( "ATMH LogMemoryAllocated error %i", error ); + break; + } + } + } + } + } + } + + // Release the mutex + iMutex.Signal(); + + // Return pointer to the reallocated cell + return ptr; + } + +#else + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::ReAlloc() +// Increases or decreases the size of an existing cell. +// ----------------------------------------------------------------------------- +// +TAny* RAnalyzeToolMainAllocator::ReAlloc( TAny* aPtr, TInt aSize, TInt aMode ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Realloc the memory using original allocator + TAny* ptr = iAllocator->ReAlloc( aPtr, aSize, aMode ); + + TInt error( KErrNone ); + TUint arrayCounter = 0; + + // NULL addresses are not in a process under test + if ( ptr && !( aMode & ENeverMove ) ) + { + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - aPtr: %x, ptr: %x", + (TUint32)aPtr, (TUint32)ptr ); + LOGSTR3( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - aSize: %i, aMode: %i", + aSize, aMode ); + + // Don't collect or log data if storage server not open or logging mode is not fast xti. + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + // Reset the callstack + iReCallStack.Reset(); + + // If we don't want any call stack to be saved skip the next part + if( iAllocMaxCallStack > 0 ) + { + // find the current thread callstack start address + TUint32 stackstart( 0 ); + TBool found( FindCurrentThreadStack( stackstart ) ); + LOGSTR3( "ATMH > stackstart: %x , find = %i", stackstart, found ); + + // Get codeblocks count + TInt blocksCount( iCodeblocks.Count() ); + + for ( TUint32 i = __current_sp(); i < stackstart; i = i + KAddressLength )//lint !e1055 !e526 !e628 !e348 + { + for ( TInt j = 0; j < blocksCount; j++ ) + { + if ( iCodeblocks[j].CheckAddress( (TUint32) *( (TUint32*) i ) ) ) + { + // To avoid recursive call to ReAlloc specifying granularity + // Add address to the callstack + iReCallStack[arrayCounter] = ( (TUint32) *( (TUint32*) i ) ); + arrayCounter++; + break; + } + } + if ( arrayCounter == KATMaxCallstackLength || + arrayCounter == iAllocMaxCallStack ) + { + LOGSTR2( "ATMH > Wanted CallStack items ready( %i )", arrayCounter ); + break; + } + } + } + + // No need to report free if the aPtr was NULL + if ( aPtr != NULL ) + { + // Reset the free callstack + iFreeCallStack.Reset(); + + // Check that logging mode is xti/xti fast so we use free call stack + // and call stack size bigger than zero + if ( (iLogOption == EATUseDefault || iLogOption == EATLogToXti || iLogOption == EATLogToXtiFast ) + && iFreeMaxCallStack > 0 ) + { + for ( TInt i = 0; i < arrayCounter; i++ ) + { + if ( i == KATMaxFreeCallstackLength || i == iFreeMaxCallStack ) + { + break; + } + iFreeCallStack[i] = ( iReCallStack[i] ); + } + } + + // Try to remove old address from the storage server's + // leak array. If found. it's removed from the array because system frees + // old address directly in the RHeap in ReAlloc case. + if ( iLogOption == EATLogToXtiFast ) + { + ATFastLogMemoryFreed( iProcessId, (TUint32) aPtr, iFreeCallStack ); + } + else + { + iStorageServer.LogMemoryFreed( (TUint32) aPtr, iFreeCallStack ); + } + } + + // Log the memory allocation information + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + ATFastLogMemoryAllocated( iProcessId, (TUint32) ptr, iReCallStack, aSize ); + } + else + { + // Using storage server. + error = iStorageServer.LogMemoryAllocated( (TUint32) ptr, + iReCallStack, + aSize ); + if ( KErrNone != error ) + { + switch ( error ) + { + case KErrNoMemory: + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - KErrNoMemory case" ); + // Check if eventhandler is active + if ( iEventHandler->IsActive() ) + { + // Cancel iEventHandler because not needed anymore + iEventHandler->Cancel(); + } + if ( iStorageServerOpen ) + { + iStorageServerOpen = EFalse; + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::ReAlloc() - close iStorageServer" ); + iStorageServer.Close(); + } + break; + } + default: + { + LOGSTR2( "ATMH LogMemoryAllocated error %i", error ); + break; + } + } + } + } + } + } + + // Release the mutex + iMutex.Signal(); + + // Return pointer to the reallocated cell + return ptr; + } + +#endif // __WINS__ + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Compress() +// The function frees excess committed space from the top of the heap. +// The size of the heap is never reduced below the minimum size +// specified during creation of the heap. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::Compress() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Compress()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Compress the memory using original allocator + TInt compress = iAllocator->Compress(); + + // Release the mutex + iMutex.Signal(); + + // Return the space reclaimed + return compress; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Reset() +// Frees all allocated cells on this heap. +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::Reset() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Reset()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Reset the memory using original allocator + iAllocator->Reset(); + + // Release the mutex + iMutex.Signal(); + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::AllocSize() +// Gets the number of cells allocated on this heap, and +// the total space allocated to them. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::AllocSize( TInt& aTotalAllocSize ) const + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::AllocSize()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Acquire the memory information using original allocator + TInt size = iAllocator->AllocSize( aTotalAllocSize ); + + // Release the mutex + iMutex.Signal(); + + // Return the number of cells allocated on this heap. + return size; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Available() +// Gets the total free space currently available on the heap and the +// space available in the largest free block. The space available +// represents the total space which can be allocated. Note that +// compressing the heap may reduce the total free space available +// and the space available in the largest free block. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::Available( TInt& aBiggestBlock ) const + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Available()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Acquire the memory information using original allocator + TInt available = iAllocator->Available( aBiggestBlock ); + + // Release the mutex + iMutex.Signal(); + + // Return the total free space currently available on the heap + return available; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::AllocLen() +// Gets the length of the available space in the specified +// allocated cell. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::AllocLen( const TAny* aCell ) const + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::AllocLen()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Acquire the memory information using original allocator + TInt len = iAllocator->AllocLen( aCell ); + + // Release the mutex + iMutex.Signal(); + + // Return the length of the available space in the allocated cell. + return len; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::DebugFunction() +// Invocates specified debug funtionality. +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::DebugFunction( TInt aFunc, TAny* a1, TAny* a2 ) + { + LOGSTR2( "ATMH RAnalyzeToolMainAllocator::DebugFunction() %i", aFunc ); + + // Acquire the mutex + iMutex.Wait(); + + // Invocate debug funtion using original allocator + TInt debug = iAllocator->DebugFunction( aFunc, a1, a2 ); + + switch( aFunc ) + { + case EMarkEnd: + { + // Disables the __UHEAP_MARKEND macro + LOGSTR1( "ATMH __UHEAP_MARKEND macro called" ); + if ( debug > 0 ) + { + LOGSTR2( "ATMH __UHEAP_MARKEND detects leaks: %d", debug ); + // Because there is leaks the alloc panic will occur but + // lets return a zero to pretend that everything is OK + debug = 0; + } + } + break; + + default: + { + } + break; + } + + // Release the mutex + iMutex.Signal(); + + // Return information of the debug function success + return debug; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::RemoveKilledThread() +// Remove killed thread from threads array. +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::RemoveKilledThread( const TUint aThreadId ) + { + LOGSTR2( "ATMH RAnalyzeToolMainAllocator::RemoveKilledThread(%i)", + aThreadId ); + + // Acquire the mutex + iMutex.Wait(); + + // Iterate through array of threads to remove current thread + TInt count( iThreadArray.Count() ); + LOGSTR2( "ATMH > iThreadArray.Count() %i", count ); + + for ( TInt i = 0; i < count; i++ ) + { + // Check if this is current thread + if ( iThreadArray[ i ].Match( aThreadId ) ) + { + // Remove the thread + iThreadArray.Remove( i ); + LOGSTR1( "ATMH > thread removed" ); + break; + } + } + + // Release the mutex + iMutex.Signal(); + } +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::Extension_() +// Extension function +// ----------------------------------------------------------------------------- +// +TInt RAnalyzeToolMainAllocator::Extension_( TUint aExtensionId, TAny*& a0, + TAny* a1) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::Extension_()" ); + + // Acquire the mutex + iMutex.Wait(); + + // Invocate extension funtion using original allocator + TInt ext = RAllocator::Extension_( aExtensionId, a0, a1 ); + + // Release the mutex + iMutex.Signal(); + + // Return information of the extension function success + return ext; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::LogProcessInformation() +// Retrieve and log the process initial information +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::LogProcessInformation( const TFileName aFileName, + TUint32 aLogOption, TUint32 aIsDebug ) + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation()" ); + + // Create local variable and retrieve the process information + TProcessIdentityParamsBuf params; + params().iProcessId = iProcessId; + params().iThreadId = RThread().Id().operator TUint(); + TInt error = iAnalyzeTool.GetProcessInfo( params ); + + LOGSTR2( "ATMH GetProcessInfo %i error", error ); + + if ( KErrNone == error ) + { + LOGSTR2( "ATMH Process %i", iProcessId ); + + // Store stack start address + LOGSTR2( "ATMH Thread stack address: %x", params().iStackAddress ); + LOGSTR2( "ATMH Thread stack size: %x", params().iStackSize ); + + // Append thread to array of the users of this allocator + error = iThreadArray.Append( + TThreadStack( RThread().Id(), params().iStackAddress + params().iStackSize) ); + + __ASSERT_ALWAYS( KErrNone == error, AssertPanic( ECantAppendToTheArray ) ); + + // Log process information + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - ATFastLogProcessStarted() #1" ); + ATFastLogProcessStarted( params().iProcessName, iProcessId, aIsDebug ); + } + else + { + // Using storage server. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - iStorageServerOpen #1" ); + error = iStorageServer.LogProcessStarted( + aFileName, + params().iProcessName, + iProcessId, + aLogOption, + aIsDebug ); + } + } + + LOGSTR2( "ATMH LogProcessStarted error %i", error ); + + // Iterate through process codesegments + for( TInt i = 0; i < params().iCodesegCount; i++ ) + { + // Create local variable and retrieve codesegment info + TCodesegInfoBuf codeinfo; + codeinfo().iProcessId = iProcessId; + codeinfo().iIndex = i; + error = iAnalyzeTool.GetCodesegInfo( codeinfo ); + + LOGSTR2( "ATMH GetCodesegInfo error %i", error ); + if ( KErrNone == error ) + { + // Don't log AnalyzeTool libraries + if ( 0 != codeinfo().iFullName.CompareC( KMemoryHook ) && + 0 != codeinfo().iFullName.CompareC( KStorageServer ) ) + { + // Log the loaded codesegment(s) + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - ATFastLogDllLoaded() #2" ); + ATFastLogDllLoaded( iProcessId, + codeinfo().iFullName, + codeinfo().iRunAddress, + codeinfo().iRunAddress + codeinfo().iSize ); + } + else + { + // Using storage server. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - iStorageServerOpen #2" ); + error = iStorageServer.LogDllLoaded( + codeinfo().iFullName, + codeinfo().iRunAddress, + codeinfo().iRunAddress + codeinfo().iSize ); + } + } + + LOGSTR2( "ATMH LogDllLoaded error %i", error ); + + // Check that everything is OK + if ( KErrNone == error ) + { + // Append the codesegment to the array + error = iCodeblocks.Append( + TCodeblock( codeinfo().iRunAddress, + codeinfo().iSize, + codeinfo().iFullName ) ); + LOGSTR2( "ATMH Append error %i", error ); + } + } + } + } + + // Iterate through process dynamic codesegments + for ( TInt i = 0; i < params().iDynamicCount; i++ ) + { + // Create local variable and retrieve codesegment info + TLibraryInfoBuf info; + info().iProcessId = iProcessId; + info().iIndex = i; + error = iAnalyzeTool.GetLibraryInfo( info ); + LOGSTR2( "ATMH GetLibraryInfo error %i", error ); + if ( KErrNone == error ) + { + // Log the loaded dynamic codesegment(s) + if ( iStorageServerOpen || iLogOption == EATLogToXtiFast ) + { + if ( iLogOption == EATLogToXtiFast ) + { + // Using fast xti. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - - ATFastLogDllLoaded()#3" ); + ATFastLogDllLoaded( iProcessId, + info().iLibraryName, + info().iRunAddress, + info().iRunAddress + info().iSize ); + } + else + { + // Using storage server. + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::LogProcessInformation() - iStorageServerOpen #3" ); + error = iStorageServer.LogDllLoaded( + info().iLibraryName, + info().iRunAddress, + info().iRunAddress + info().iSize ); + } + } + + + LOGSTR2( "ATMH LogDllLoaded error %i", error ); + + if ( KErrNone == error ) + { + // Append the codesegment to the array + error = iCodeblocks.Append( + TCodeblock( info().iRunAddress, + info().iSize, info().iLibraryName ) ); + LOGSTR2( "ATMH Append error %i", error ); + } + } + } + } + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::FindCurrentThreadStack() +// Find the current thread which is using the heap +// ----------------------------------------------------------------------------- +// +TBool RAnalyzeToolMainAllocator::FindCurrentThreadStack( TUint32& aStackStart ) + { + LOGSTR2( "ATMH RAnalyzeToolMainAllocator::FindCurrentThreadStack(), count( %i )", + iThreadArray.Count() ); + + // Flag for indicating that right thread has been found + TBool found( EFalse ); + // If threre is only one thread it must be the right thread + if ( iThreadArray.Count() == KThreadCount ) + { + if ( !iThreadArray[ 0 ].ThreadStackStart( aStackStart ) ) + { + // This MUST BE the right thread + //__ASSERT_ALWAYS( EFalse, AssertPanic( ECantFindRightThread ) ); + } + else if ( iThreadArray[ 0 ].ThreadStackStart( aStackStart ) ) + { + found = ETrue; + } + } + else + { + // Iterate through array to find right thread + TInt count = iThreadArray.Count(); + + for ( TInt i = 0; i < count; i++ ) + { + // Check if this is the right thread + if ( iThreadArray[ i ].ThreadStackStart( aStackStart ) ) + { + // Right thread found. Mark the flag + found = ETrue; + break; + } + } + // If right thread was not found the panic must be raised + if ( !found ) + { + //__ASSERT_ALWAYS( EFalse, AssertPanic( ECantFindRightThread ) ); + } + } + return found; + } + +// ----------------------------------------------------------------------------- +// RAnalyzeToolMainAllocator::InstallEventHandler() +// Installs the eventhandler, if possible +// ----------------------------------------------------------------------------- +// +void RAnalyzeToolMainAllocator::InstallEventHandler() + { + LOGSTR1( "ATMH RAnalyzeToolMainAllocator::InstallEventHandler()" ); + + // Active eventhalder is not active, trying to start it + if ( NULL != CActiveScheduler::Current() ) + { + iEventHandler->Start(); + } + + #ifdef __WINSCW__ + // Disable system's exit checks + if ( CCoeEnv::Static() ) + { + CCoeEnv::Static()->DisableExitChecks( ETrue ); + } + #endif + } + +// End of File