libraries/qr3/src/heap.cpp
changeset 0 7f656887cf89
child 69 849a0b46c767
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // heap.cpp
       
     2 // 
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 #include <fshell/qr3dll.h>
       
    13 #include <fshell/memoryaccess.h>
       
    14 #include <f32file.h>
       
    15 
       
    16 EXPORT_C RProxyHeap::RProxyHeap(RMemoryAccess& aMem, TUint aThreadId)
       
    17 	: RHeap(), iMem(aMem), iThreadId(aThreadId)
       
    18 	{
       
    19 	}
       
    20 
       
    21 EXPORT_C void /*CHeapAnalyser::*/ GetHeapDetailsL(THeapDetails& aDetails, RProxyHeap& heap)
       
    22 	{
       
    23 	// This function retained for BC reasons
       
    24 	heap.GetHeapDetailsL(aDetails);
       
    25 	}
       
    26 
       
    27 EXPORT_C void RProxyHeap::GetHeapDetailsL(THeapDetails& aDetails)
       
    28 	{
       
    29 #ifdef FSHELL_ANALYSEHEAP_SUPPORT
       
    30 	RProxyHeap& heap = *this;
       
    31 	RMemoryAccess& iMemoryAccess = heap.iMem;
       
    32 	TUint aThreadId = heap.iThreadId;
       
    33 
       
    34 	TUint8* allocatorAddress;
       
    35 	User::LeaveIfError(iMemoryAccess.GetAllocatorAddress(aThreadId, allocatorAddress));
       
    36 	
       
    37 	TThreadMemoryAccessParams params;
       
    38 	params.iId = aThreadId;
       
    39 	params.iAddr = allocatorAddress;
       
    40 	params.iSize = sizeof(RHeap);
       
    41 	TPckg<RHeap> heapPckg(heap);
       
    42 	User::LeaveIfError(iMemoryAccess.GetThreadMem(params, heapPckg));
       
    43 	
       
    44 	// Base address of the heap
       
    45 	aDetails.iBase = heap.Base(); // inline, returns member variable
       
    46 	// First free cell address in the heap
       
    47 	aDetails.iFirstFree = (TUint8*)heap.iFree.next; // direct read from member variable
       
    48 	// Top address of the heap
       
    49 	aDetails.iTop = heap.iTop;
       
    50 	// Size of heap
       
    51 	aDetails.iSize = heap.Size(); // inline, returns member variables (after simple maths)
       
    52 	
       
    53 	// Heap cell header size
       
    54 	#ifdef UREL_E32
       
    55 	aDetails.iCellHeaderSize = sizeof(RHeap::SCell*);
       
    56 	#elif UDEB_E32
       
    57 	aDetails.iCellHeaderSize = sizeof(RHeap::SDebugCell); // If allocator's UDEB-ness matches ours
       
    58 	#else // match E32 and our own UDEB/URELness
       
    59 	aDetails.iCellHeaderSize = RHeap::EAllocCellSize; // If allocator is urel and we're not
       
    60 	#endif
       
    61 	
       
    62 	aDetails.iTotalAllocSize = heap.iTotalAllocSize;
       
    63 
       
    64 	aDetails.iCellCount = heap.iCellCount;
       
    65 #else
       
    66 	User::Leave(KErrNotSupported);
       
    67 #endif
       
    68 	}
       
    69 
       
    70 //BEGIN pinched directly from anaylseheapremote
       
    71 
       
    72 _LIT(KLitUnderscore, "_");
       
    73 _LIT(KLitHeap, ".heap");
       
    74 _LIT(KLitDash, "-");
       
    75 _LIT(KLitIllegals, ":@[]{}%");
       
    76 	
       
    77 #define AH_DEBUG(x)
       
    78 #define AH_DEBUGINT(x,y)
       
    79 
       
    80 EXPORT_C void RProxyHeap::DumpHeapToSuitableFileInDirectoryL(TFileName& aName)
       
    81 	{
       
    82 	TUint aThreadId = iThreadId;
       
    83 
       
    84 	AH_DEBUG("Dumping to file");
       
    85 	RThread theThread;
       
    86 	User::LeaveIfError(theThread.Open(aThreadId));
       
    87 	CleanupClosePushL(theThread);
       
    88 	AH_DEBUG("Opened thread");
       
    89 
       
    90 	//BaflUtils::
       
    91 	// create a filename <location>\threadName_threadId.heap
       
    92 	TFileName& theFileName(aName);
       
    93 	const TInt fullNameLengthToTake = theFileName.MaxLength() - theFileName.Length() - KLitHeap().Length() - KLitUnderscore().Length() - 4; // 4 for thread ID number
       
    94 	TFullName cleanedName = theThread.FullName().Left(fullNameLengthToTake);
       
    95 	for (TInt whichIllegal = 0;whichIllegal < KLitIllegals().Length(); whichIllegal++)
       
    96 		{
       
    97 		TChar thisIllegal = KLitIllegals()[whichIllegal];
       
    98 		TInt where;
       
    99 		while ((where = cleanedName.Locate(thisIllegal)) != KErrNotFound)
       
   100 			cleanedName.Replace(where,1,KLitDash());
       
   101 		}
       
   102 	theFileName.Append(cleanedName);
       
   103 	theFileName.Append(KLitUnderscore);
       
   104 	theFileName.AppendNum(theThread.Id());
       
   105 	theFileName.Append(KLitHeap);
       
   106 	//RDebug::Print(_L("The filename is %S"), &theFileName);
       
   107 	CleanupStack::PopAndDestroy(); // theThread
       
   108 	AH_DEBUG("Constructed filename");
       
   109 	DumpHeapToFileL(theFileName);
       
   110 	}
       
   111 
       
   112 EXPORT_C void RProxyHeap::DumpHeapToFileL(const TDesC& aFileName)
       
   113 	{
       
   114 	AH_DEBUG("Dumping to arbitrary file");
       
   115 	// Open the file
       
   116 	RFs fs;
       
   117 	User::LeaveIfError(fs.Connect());
       
   118 	CleanupClosePushL(fs);
       
   119 	AH_DEBUG("Connected to F32");
       
   120 	TInt err = fs.Delete(aFileName);
       
   121 	if (err != KErrNotFound && err != KErrNone)
       
   122 		User::Leave(err);
       
   123 	AH_DEBUG("File deleted");
       
   124 	RFile f;
       
   125 	User::LeaveIfError(f.Create(fs,aFileName,EFileWrite));
       
   126 	CleanupClosePushL(f);
       
   127 	AH_DEBUG("File created");
       
   128 	DumpHeapL(f);
       
   129 	AH_DEBUG("Heap dump appeared to succeed");
       
   130 	User::LeaveIfError(f.Flush());
       
   131 	AH_DEBUG("File flushed");
       
   132 	CleanupStack::PopAndDestroy(2); // f, fs
       
   133 	}
       
   134 
       
   135 static void DumpCodeSegsL(RMemoryAccess& aMem, RFile& aDumpFile);
       
   136 
       
   137 EXPORT_C void RProxyHeap::DumpHeapL(RFile& aDumpFile)
       
   138 	{
       
   139 	TUint aThreadId = iThreadId;
       
   140 	// get the thread
       
   141 	RThread thread;
       
   142 	AH_DEBUG("Opening thread");
       
   143 	User::LeaveIfError(thread.Open(aThreadId));
       
   144 	AH_DEBUG("Opened thread");
       
   145 	
       
   146 	THeapDetails heapDetails;
       
   147 	GetHeapDetailsL(heapDetails);
       
   148 	
       
   149 	// write out the heap file in the version 3 format documented in the 'docs' folder.
       
   150 	
       
   151 	// 4 bytes: file format version number (Not present for version 1, number found would be heap base & therefore v.big, >1000)	
       
   152 	TInt version = 3;
       
   153 	AH_DEBUG("Dumping version");
       
   154 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&version, 4)));
       
   155 	
       
   156 	// 4 bytes: thread ID
       
   157 	AH_DEBUG("Dumping thread ID");
       
   158 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&aThreadId, 4)));
       
   159 	
       
   160 	// 4 bytes: owning process - appears unused
       
   161 	AH_DEBUG("Dumping owning process");
       
   162 	TInt nothing = 0;
       
   163 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&nothing, 4)));
       
   164 	
       
   165 	// 4 bytes: length of thread name
       
   166 	AH_DEBUG("Dumping thread name length");
       
   167 	TName threadName = thread.FullName();
       
   168 	TInt threadNameLength = threadName.Length();
       
   169 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&threadNameLength, 4)));
       
   170 	
       
   171 	// a bytes: thread name
       
   172 	AH_DEBUG("Dumping thread name");
       
   173 	HBufC8* asciiName = HBufC8::NewLC(threadNameLength);
       
   174 	asciiName->Des().Copy(threadName);
       
   175 	User::LeaveIfError(aDumpFile.Write(*asciiName));
       
   176 	CleanupStack::PopAndDestroy(asciiName);
       
   177 	
       
   178 
       
   179 	// 4 bytes: base address of the heap
       
   180 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&heapDetails.iBase, 4)));
       
   181 	// 4 bytes: first free cell address in the heap
       
   182 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&heapDetails.iFirstFree, 4)));
       
   183 	// 4 bytes: top address of the heap
       
   184 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&heapDetails.iTop, 4)));
       
   185 	// 4 bytes: cell header size
       
   186 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&heapDetails.iCellHeaderSize, 4)));
       
   187 	// 4 bytes: heap size (n)
       
   188 	User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&heapDetails.iSize, 4)));
       
   189 	
       
   190 	// n bytes: heap contents
       
   191 	// Need to read this across the process boundary
       
   192 	// We need to copy in several chunks as memoryaccess_eka2 cannot currently
       
   193 	// copy > 4096 bytes in one go.
       
   194 	// But this number is not advertised by the memoryaccess_eka2 interface,
       
   195 	// so we will have to be a bit careful in case it changes in future versions.
       
   196 	const TInt KChunkSize = 4096;
       
   197 	AH_DEBUG("Allocating heap storage buffer");
       
   198 	HBufC8* heapBig = HBufC8::NewLC(KChunkSize);
       
   199 	TPtr8 myPtr = heapBig->Des();
       
   200 	TUint8* currentPointer = heapDetails.iBase;
       
   201 	TUint8* endPointer = currentPointer + heapDetails.iSize;
       
   202 	TThreadMemoryAccessParams paramsForHeap;
       
   203 	paramsForHeap.iId = aThreadId;
       
   204 	while (currentPointer < endPointer)
       
   205 		{
       
   206 		AH_DEBUGINT("Copying heap from %d", currentPointer);
       
   207 		paramsForHeap.iAddr = currentPointer;
       
   208 		paramsForHeap.iSize = Min(KChunkSize, (endPointer - currentPointer));
       
   209 		AH_DEBUGINT("Length to copy %d", paramsForHeap.iSize);
       
   210 		User::LeaveIfError(iMem.GetThreadMem(paramsForHeap, myPtr));
       
   211 		AH_DEBUG("Writing some heap");	
       
   212 		User::LeaveIfError(aDumpFile.Write(*heapBig));
       
   213 		currentPointer += heapBig->Length();
       
   214 		}
       
   215 	CleanupStack::PopAndDestroy(heapBig);
       
   216 	
       
   217 	// Now output the code segment details
       
   218 	iMem.AcquireCodeSegMutex();
       
   219 	TRAPD(err,DumpCodeSegsL(iMem, aDumpFile));
       
   220 	iMem.ReleaseCodeSegMutex();
       
   221 	User::LeaveIfError(err);
       
   222 	}
       
   223 	
       
   224 void DumpCodeSegsL(RMemoryAccess& aMem, RFile& aDumpFile)
       
   225 	{
       
   226 	TCodeSegKernelInfo info;
       
   227 	TPckg<TCodeSegKernelInfo> infoPckg(info);
       
   228 	while (aMem.GetNextCodeSegInfo(infoPckg))
       
   229 		{
       
   230 		// 4 bytes: Code segment run address
       
   231 		AH_DEBUG("Dumping code seg run address");
       
   232 		
       
   233 		User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&info.iRunAddress, 4)));
       
   234 		// 4 bytes: Code segment size
       
   235 		AH_DEBUG("Dumping code seg size");
       
   236 		User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&info.iSize, 4)));
       
   237 		// 4 bytes: Code segment filename length
       
   238 		AH_DEBUG("Dumping code seg filename length");
       
   239 		TInt nameLength = info.iFileName.Length();
       
   240 		User::LeaveIfError(aDumpFile.Write(TPtrC8((TUint8*)&nameLength, 4)));
       
   241 		// 4 bytes: Code segment filename length
       
   242 		AH_DEBUG("Dumping code seg filename length");
       
   243 		User::LeaveIfError(aDumpFile.Write(info.iFileName));
       
   244 		}
       
   245 	}
       
   246 
       
   247 //END nicked