160 // b) Make a copy of the heap data |
160 // b) Make a copy of the heap data |
161 // c) Walk copy in order to extract statistics (meta data, i.e. TMemSpyHeapInfo) |
161 // c) Walk copy in order to extract statistics (meta data, i.e. TMemSpyHeapInfo) |
162 // |
162 // |
163 // The driver leaves kernel context with the copy of the kernel heap still associated with MemSpy's process. |
163 // The driver leaves kernel context with the copy of the kernel heap still associated with MemSpy's process. |
164 // The second driver call will copy the chunk data to user side and release the kernel side chunk. |
164 // The second driver call will copy the chunk data to user side and release the kernel side chunk. |
165 const TBool isInit = iKernelHeap.ChunkIsInitialised(); |
165 //const TBool isInit = iKernelHeap.ChunkIsInitialised(); |
166 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - START - isInit: %d", isInit )); |
166 //TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - START - isInit: %d", isInit )); |
167 __ASSERT_ALWAYS( !isInit, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicKernelHeapDataInitError ) ); |
167 //__ASSERT_ALWAYS( !isInit, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicKernelHeapDataInitError ) ); |
168 |
168 |
169 iKernelHeap.Reset(); |
169 iKernelHeap.Reset(); |
170 NKern::ThreadEnterCS(); |
170 NKern::ThreadEnterCS(); |
171 |
|
172 // We must identify if we have a debug kernel allocator |
|
173 const TBool debugAllocator = IsDebugKernel(); |
|
174 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - debugAllocator: %d", debugAllocator ) ); |
|
175 |
171 |
176 TFullName heapChunkName; |
172 TFullName heapChunkName; |
177 TInt r = OpenKernelHeap( iKernelHeap, &heapChunkName ); |
173 TInt r = OpenKernelHeap( iKernelHeap, &heapChunkName ); |
178 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - open err: %d", r)); |
174 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - open err: %d", r)); |
179 |
175 |
180 if ( r == KErrNone ) |
176 if ( r == KErrNone ) |
181 { |
177 { |
182 r = GetHeapInfoKernel( iKernelHeap, debugAllocator, heapChunkName, aInfo, aFreeCells ); |
178 r = GetHeapInfoKernel( iKernelHeap, aInfo, aFreeCells ); |
183 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - base class get heap info: %d", r) ); |
179 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - base class get heap info: %d", r) ); |
184 |
180 |
185 // If everything was okay, we can now return back to user-side, indicating the amount of heap data |
181 // If everything was okay, we can now return back to user-side, indicating the amount of heap data |
186 // that they must prepare to read (in the next operation). |
182 // that they must prepare to read (in the next operation). |
187 if ( r == KErrNone ) |
183 if ( r == KErrNone ) |
188 { |
184 { |
189 // Indicate how big a buffer the user-side must prepare. |
185 // Indicate how big a buffer the user-side must prepare. |
190 r = OSAdaption().DChunk().GetSize( iKernelHeap.Chunk() ); |
186 r = OSAdaption().DChunk().GetSize( iKernelHeap.Chunk() ); |
191 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - user side buffer needs to be: %d", r) ); |
187 TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - user side buffer needs to be: %d", r) ); |
192 } |
188 } |
193 else if ( iKernelHeap.ChunkIsInitialised() ) |
189 else |
194 { |
190 { |
195 // Error scenario - must close heap |
191 // Error scenario - must close heap |
196 iKernelHeap.DisassociateWithKernelChunk(); |
192 iKernelHeap.Close(); |
197 } |
193 } |
198 } |
194 } |
199 |
195 |
200 NKern::ThreadLeaveCS(); |
196 NKern::ThreadLeaveCS(); |
201 |
197 |
302 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser() - END - Not allowing dump of DRM heap - matchType: %d, thread: %O", drmMatchType, thread ); |
302 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser() - END - Not allowing dump of DRM heap - matchType: %d, thread: %O", drmMatchType, thread ); |
303 CloseTempObject(); |
303 CloseTempObject(); |
304 return KErrAccessDenied; |
304 return KErrAccessDenied; |
305 } |
305 } |
306 } |
306 } |
307 |
307 |
308 // Check that the process' thread's are suspended |
308 // Check that the process' thread's are suspended |
309 DThread* thread = (DThread*) TempObject(); |
309 DThread* thread = (DThread*) TempObject(); |
310 if ( SuspensionManager().IsSuspended( *thread ) ) |
310 if ( SuspensionManager().IsSuspended( *thread ) ) |
311 { |
311 { |
312 // Find the chunk with the correct handle |
312 // Open the heap |
313 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - thread: %O", thread) ); |
313 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - thread: %O", thread) ); |
314 RMemSpyDriverRHeapUser heap( OSAdaption() ); |
314 RMemSpyDriverRHeapUser heap( OSAdaption() ); |
315 const TBool allocatorIsReallyRHeap = GetUserHeapHandle( *thread, heap, aParams.iRHeapVTable ); |
315 r = heap.OpenUserHeap(*thread, aParams.iDebugAllocator); |
316 if ( allocatorIsReallyRHeap ) |
316 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - opening heap returned: %d", r) ); |
317 { |
317 if (r == KErrNone) |
318 const TInt chunkHandle = heap.iChunkHandle; |
318 { |
319 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkHandle: 0x%08x, thread: %O", chunkHandle, thread) ); |
319 if ( aParams.iChecksum != 0 ) |
320 |
|
321 NKern::ThreadEnterCS(); |
|
322 NKern::LockSystem(); |
|
323 DChunk* chunk = (DChunk*) Kern::ObjectFromHandle( thread, chunkHandle, EChunk ); |
|
324 NKern::UnlockSystem(); |
|
325 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunk: 0x%08x", chunk ) ); |
|
326 NKern::ThreadLeaveCS(); |
|
327 |
|
328 if ( chunk != NULL ) |
|
329 { |
320 { |
330 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkBase: 0x%08x, size: %8d, maxLen: %8d, chunk: %O", chunk->iBase, chunk->iSize, chunk->iMaxSize, chunk) ); |
321 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - checksum validation requested - expecting: 0x%08x", aParams.iChecksum ) ); |
331 |
322 RMemSpyDriverHeapWalker heapWalker(heap); |
332 // If the client specified a checksum value, then we must walk the heap just to make sure |
323 |
333 // it hasn't changed. Expensive operation, but good for paranoia purposes... |
324 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - starting traversal..." )); |
334 if ( aParams.iChecksum != 0 ) |
325 #if ( defined( TRACE_TYPE_USERHEAP ) && defined( TRACE_TYPE_HEAPWALK ) ) |
|
326 heapWalker.SetPrintDebug(); |
|
327 #endif |
|
328 r = heapWalker.Traverse(); |
|
329 const TUint32 calculatedChecksum = heapWalker.Stats().iFreeCellCRC; |
|
330 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - finished traversal - err: %d, checksum: 0x%08x", r, calculatedChecksum )); |
|
331 |
|
332 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x", calculatedChecksum, aParams.iChecksum )); |
|
333 if ( calculatedChecksum != aParams.iChecksum ) |
335 { |
334 { |
336 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - checksum validation requested - expecting: 0x%08x", aParams.iChecksum ) ); |
335 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x for thread %O", calculatedChecksum, aParams.iChecksum, thread ); |
337 |
336 r = KErrCorrupt; |
338 RMemSpyDriverRHeapUser rHeap( OSAdaption() ); |
|
339 DChunk* userHeapChunk = NULL; |
|
340 r = OpenUserHeap( *thread, aParams.iRHeapVTable, rHeap, userHeapChunk ); |
|
341 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - opening client heap returned: %d", r) ); |
|
342 if ( r == KErrNone ) |
|
343 { |
|
344 TMemSpyHeapWalkerNullObserver observer; |
|
345 RMemSpyDriverHeapWalker heapWalker( rHeap, aParams.iDebugAllocator ); |
|
346 heapWalker.SetObserver( &observer ); |
|
347 |
|
348 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - starting traversal..." )); |
|
349 #if ( defined( TRACE_TYPE_USERHEAP ) && defined( TRACE_TYPE_HEAPWALK ) ) |
|
350 heapWalker.SetPrintDebug(); |
|
351 #endif |
|
352 r = heapWalker.Traverse(); |
|
353 const TUint32 calculatedChecksum = heapWalker.Stats().iFreeCellCRC; |
|
354 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - finished traversal - err: %d, checksum: 0x%08x", r, calculatedChecksum )); |
|
355 |
|
356 // Release resources |
|
357 rHeap.DisassociateWithKernelChunk(); |
|
358 |
|
359 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x", calculatedChecksum, aParams.iChecksum )); |
|
360 if ( calculatedChecksum != aParams.iChecksum ) |
|
361 { |
|
362 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x for thread %O", calculatedChecksum, aParams.iChecksum, thread ); |
|
363 r = KErrCorrupt; |
|
364 } |
|
365 } |
|
366 else |
|
367 { |
|
368 // Couldn't verify checksum in this situation... |
|
369 } |
|
370 } |
337 } |
371 |
338 } |
372 // Get user side (MemSpy) descriptor length info |
339 |
|
340 // Get user side (MemSpy) descriptor length info |
|
341 if ( r == KErrNone ) |
|
342 { |
|
343 TInt destLen = 0; |
|
344 TInt destMax = 0; |
|
345 TUint8* destPtr = NULL; |
|
346 r = Kern::ThreadGetDesInfo( &ClientThread(), aParams.iDes, destLen, destMax, destPtr, ETrue ); |
|
347 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - user side descriptor: 0x%08x (0x%08x), len: %8d, maxLen: %8d, r: %d", aParams.iDes, destPtr, destLen, destMax, r )); |
|
348 destMax = destMax & ~(KPageSize-1); // Round down dest max to page size |
|
349 if (destMax <= 0 || (aParams.iReadAddress & (KPageSize-1))) r = KErrArgument; // If destMax is less than a page or the read address isn't a multiple of page size then we don't want to know |
|
350 |
373 if ( r == KErrNone ) |
351 if ( r == KErrNone ) |
374 { |
352 { |
375 TInt destLen; |
353 const TLinAddr chunkBase = (TLinAddr)OSAdaption().DChunk().GetBase(heap.Chunk()); |
376 TInt destMax; |
354 const TLinAddr chunkMaxAddr = chunkBase + OSAdaption().DChunk().GetMaxSize(heap.Chunk()); |
377 TUint8* destPtr = NULL; |
355 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkBase: 0x%08x", chunkBase) ); |
378 r = Kern::ThreadGetDesInfo( &ClientThread(), aParams.iDes, destLen, destMax, destPtr, ETrue ); |
356 |
379 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - user side descriptor: 0x%08x (0x%08x), len: %8d, maxLen: %8d, r: %d", aParams.iDes, destPtr, destLen, destMax, r )); |
357 TLinAddr readAddress = aParams.iReadAddress; |
380 |
358 if (aParams.iRemaining < 0 ) |
381 if ( r == KErrNone ) |
|
382 { |
359 { |
383 // Calculate start of real heap data (skipping over embedded RHeap object) |
360 // Initial case, start from the bottom |
384 const TUint8* startOfHeapOffset = heap.iBase; |
361 readAddress = chunkBase; |
385 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - startOfHeapOffset: 0x%08x", startOfHeapOffset) ); |
362 aParams.iRemaining = heap.Helper()->CommittedSize(); |
386 |
|
387 // Deal with initial case |
|
388 const TUint heapSize = heap.Size(); |
|
389 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - heapSize: %8d", heapSize) ); |
|
390 if ( aParams.iRemaining < 0 ) |
|
391 { |
|
392 // Initial case, remaining initialised to -1 |
|
393 aParams.iRemaining = heapSize; |
|
394 } |
|
395 |
|
396 // The remaining number of bytes should allow us to calculate the position |
|
397 // to read from. |
|
398 const TInt amountToRead = Min( aParams.iRemaining, destMax ); |
|
399 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - amountToRead: %8d", amountToRead) ); |
|
400 const TInt readOffset = ( heapSize - aParams.iRemaining ); |
|
401 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - readOffset: %8d", readOffset) ); |
|
402 const TAny* readAddress = startOfHeapOffset + readOffset; |
|
403 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - readAddress: 0x%08x", readAddress) ); |
|
404 |
|
405 // Do the read from the heap we are spying on into MemSpy's address space |
|
406 r = Kern::ThreadRawRead( thread, readAddress, destPtr, amountToRead ); |
|
407 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - read result: %d", r) ); |
|
408 // |
|
409 if (r == KErrNone) |
|
410 { |
|
411 // Client takes care of updating descriptor length. |
|
412 r = amountToRead; |
|
413 } |
|
414 else if ( r == KErrBadDescriptor ) |
|
415 { |
|
416 MemSpyDriverUtils::PanicThread( ClientThread(), EPanicBadDescriptor ); |
|
417 } |
|
418 |
|
419 // Update remaining bytes |
|
420 aParams.iRemaining -= amountToRead; |
|
421 aParams.iReadAddress = (TUint) readAddress; |
|
422 } |
363 } |
|
364 |
|
365 // The remaining number of bytes should allow us to calculate the position |
|
366 // to read from. |
|
367 TInt amountToRead = Min( aParams.iRemaining, destMax ); |
|
368 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - amountToRead: %8d", amountToRead) ); |
|
369 |
|
370 // Do the read from the heap we are spying on into MemSpy's address space |
|
371 // TomS: I didn't know you could do this - you live and learn |
|
372 do |
|
373 { |
|
374 r = Kern::ThreadRawRead( thread, (const void*)readAddress, destPtr, amountToRead ); |
|
375 TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - read result: %d", r) ); |
|
376 |
|
377 if (r == KErrBadDescriptor) |
|
378 { |
|
379 // This is not necessarily an error - it could be we've hit an unmapped page |
|
380 if (amountToRead > KPageSize) |
|
381 { |
|
382 // retry reading a single page instead |
|
383 amountToRead = KPageSize; |
|
384 } |
|
385 else |
|
386 { |
|
387 // Try the next page |
|
388 readAddress += KPageSize; |
|
389 } |
|
390 } |
|
391 } while (r == KErrBadDescriptor && readAddress < chunkMaxAddr); |
|
392 // |
|
393 if (r == KErrNone) |
|
394 { |
|
395 // Client takes care of updating descriptor length. |
|
396 r = amountToRead; |
|
397 } |
|
398 |
|
399 // Update remaining bytes |
|
400 aParams.iRemaining -= amountToRead; |
|
401 aParams.iReadAddress = readAddress; |
423 } |
402 } |
424 } |
403 } |
425 else |
404 } |
426 { |
|
427 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunk not found! thread: %O", thread ); |
|
428 r = KErrNotFound; |
|
429 } |
|
430 } |
|
431 else |
405 else |
432 { |
406 { |
433 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - couldnt find heap - vtable mis-match? thread: %O", thread ); |
407 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - couldnt open heap for thread %O, err=%d", thread, r); |
434 r = KErrNotSupported; |
408 r = KErrNotSupported; |
435 } |
409 } |
|
410 heap.Close(); |
436 } |
411 } |
437 else |
412 else |
438 { |
413 { |
439 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - parent process not suspended => KErrAccessDenied - thread: %O", thread ); |
414 Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - parent process not suspended => KErrAccessDenied - thread: %O", thread ); |
440 r = KErrAccessDenied; |
415 r = KErrAccessDenied; |