20 #include <kern_priv.h> |
20 #include <kern_priv.h> |
21 #include <nkern.h> |
21 #include <nkern.h> |
22 #include <nk_plat.h> |
22 #include <nk_plat.h> |
23 |
23 |
24 #ifdef __MARM__ |
24 #ifdef __MARM__ |
|
25 |
25 #include <arm.h> |
26 #include <arm.h> |
|
27 // Necessary when accessing data members by steam via offsets in order |
|
28 // to prevent potential unaligned data aborts |
|
29 |
|
30 #ifdef __CC_ARM |
|
31 #define UNALIGNED_DATA_MEMBER __packed |
|
32 #endif /* __CC_ARM */ |
|
33 |
|
34 #endif /* __MARM__ */ |
|
35 |
|
36 #ifndef UNALIGNED_DATA_MEMBER |
|
37 #define UNALIGNED_DATA_MEMBER |
26 #endif |
38 #endif |
27 |
|
28 // I've removed UNALIGNED_DATA_MEMBER in preference for just using memcpy to get round the potential unaligned access. -TomS |
|
29 |
39 |
30 // User includes |
40 // User includes |
31 #include "MemSpyDriverLog.h" |
41 #include "MemSpyDriverLog.h" |
32 #include "MemSpyDriverPAndS.h" |
42 #include "MemSpyDriverPAndS.h" |
33 #include "MemSpyDriverDevice.h" |
43 #include "MemSpyDriverDevice.h" |
34 |
44 |
35 // Internal constants |
45 // Internal constants |
36 const TInt KMemSpyLocalThreadDataSizeEstimate = 0x80; // The amount of user stack that MemSpy attempts to scan for the RHeap vTable |
46 const TInt KMemSpyLocalThreadDataSizeEstimate = 0x80; // The amount of user stack that MemSpy attempts to scan for the RHeaep vTable |
37 |
47 |
38 |
48 |
39 |
49 |
40 DMemSpyDriverOSAdaptionDObject::DMemSpyDriverOSAdaptionDObject( DMemSpyDriverOSAdaption& aOSAdaption ) |
50 DMemSpyDriverOSAdaptionDObject::DMemSpyDriverOSAdaptionDObject( DMemSpyDriverOSAdaption& aOSAdaption ) |
41 : iOSAdaption( aOSAdaption ) |
51 : iOSAdaption( aOSAdaption ) |
152 |
162 |
153 TExitType DMemSpyDriverOSAdaptionDThread::GetExitType( DThread& aObject ) const |
163 TExitType DMemSpyDriverOSAdaptionDThread::GetExitType( DThread& aObject ) const |
154 { |
164 { |
155 DThread* dThread = &aObject; |
165 DThread* dThread = &aObject; |
156 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_ExitType; |
166 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_ExitType; |
157 TUint8 exitType = *reinterpret_cast<TUint8*>(pTarget); |
167 UNALIGNED_DATA_MEMBER TExitType* pRet = reinterpret_cast< TExitType* >( pTarget ); |
158 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetExitType() - aObject: 0x%08x, ret: %d", &aObject, (TInt)exitType ) ); |
168 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetExitType() - aObject: 0x%08x, ret: 0x%08x", &aObject, pRet ) ); |
159 return (TExitType)exitType; |
169 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetExitType() - value: %d", *pRet ) ); |
|
170 return *pRet; |
160 } |
171 } |
161 |
172 |
162 |
173 |
163 TUint32 DMemSpyDriverOSAdaptionDThread::GetSupervisorStackBase( DThread& aObject ) const |
174 TUint32 DMemSpyDriverOSAdaptionDThread::GetSupervisorStackBase( DThread& aObject ) const |
164 { |
175 { |
165 DThread* dThread = &aObject; |
176 DThread* dThread = &aObject; |
166 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_SupervisorStackBase; |
177 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_SupervisorStackBase; |
167 |
178 UNALIGNED_DATA_MEMBER TUint32* pRet = reinterpret_cast< TUint32* >( pTarget ); |
168 TUint32 ret; |
179 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackBase() - aObject: 0x%08x, ret: 0x%08x", &aObject, pRet ) ); |
169 memcpy(&ret, (const TAny*)pTarget, sizeof(TUint32)); |
180 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackBase() - 0x%08x: %d", *pRet ) ); |
170 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackBase() - aObject: 0x%08x, ret: 0x%08x", &aObject, ret ) ); |
181 return *pRet; |
171 return ret; |
|
172 } |
182 } |
173 |
183 |
174 |
184 |
175 TInt DMemSpyDriverOSAdaptionDThread::GetSupervisorStackSize( DThread& aObject ) const |
185 TInt DMemSpyDriverOSAdaptionDThread::GetSupervisorStackSize( DThread& aObject ) const |
176 { |
186 { |
177 DThread* dThread = &aObject; |
187 DThread* dThread = &aObject; |
178 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_SupervisorStackSize; |
188 TUint32 pTarget = reinterpret_cast<TUint32>( dThread ) + iOffset_SupervisorStackSize; |
179 |
189 UNALIGNED_DATA_MEMBER TInt* pRet = reinterpret_cast< TInt* >( pTarget ); |
180 TInt ret; |
190 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackSize() - aObject: 0x%08x, ret: 0x%08x", &aObject, pRet ) ); |
181 memcpy(&ret, (const TAny*)pTarget, sizeof(TInt)); |
191 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackSize() - value: %d", *pRet ) ); |
182 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetSupervisorStackSize() - aObject: 0x%08x, ret: %d", &aObject, ret ) ); |
192 return *pRet; |
183 return ret; |
|
184 } |
193 } |
185 |
194 |
186 |
195 |
187 RAllocator* DMemSpyDriverOSAdaptionDThread::GetAllocator( DThread& aObject ) const |
196 RAllocator* DMemSpyDriverOSAdaptionDThread::GetAllocator( DThread& aObject ) const |
188 { |
197 { |
324 { |
332 { |
325 aObject.iOwningProcess->FullName( aName ); |
333 aObject.iOwningProcess->FullName( aName ); |
326 } |
334 } |
327 } |
335 } |
328 |
336 |
329 // TODO re-work this without inspecting the stack. |
337 |
330 // In particular we can get the allocator from the DThread object's iAllocator object |
338 RAllocator* DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress( DThread& aObject, TUint32& aStackAddress ) const |
331 RAllocator* DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress( DThread& aThread, TUint32& aStackAddress ) const |
339 { |
332 { |
340 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - START" ) ); |
333 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - START for aThread 0x%08x with ID %d", &aThread, aThread.iId ) ); |
|
334 // |
341 // |
335 aStackAddress = 0; |
342 aStackAddress = 0; |
336 RAllocator* ret = NULL; |
343 RAllocator* ret = NULL; |
337 |
344 |
338 // We will assume the thread is running and that the user-side stack has been set up |
345 // We will assume the thread is running and that the user-side stack has been set up |
339 // accordingly. |
346 // accordingly. |
340 const TUint32 base = GetUserStackBase( aThread ); |
347 const TUint32 base = GetUserStackBase( aObject ); |
341 const TInt size = GetUserStackSize( aThread ); |
348 const TInt size = GetUserStackSize( aObject ); |
342 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - base: 0x%08x, size: %d, KMemSpyLocalThreadDataSizeEstimate: %d", base, size, KMemSpyLocalThreadDataSizeEstimate ) ); |
349 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - base: 0x%08x, size: %d, KMemSpyLocalThreadDataSizeEstimate: %d", base, size, KMemSpyLocalThreadDataSizeEstimate ) ); |
343 const TUint32 top = base + size; |
350 const TUint32 top = base + size; |
344 |
351 |
345 // This is the RHeap vtable we are looking for |
352 // This is the RHeap vtable we are looking for |
346 const TUint32 rHeapVTable = OSAdaption().Device().RHeapVTable(); |
353 const TUint32 rHeapVTable = OSAdaption().Device().RHeapVTable(); |
354 TUint32 value = 0; |
361 TUint32 value = 0; |
355 TUint32 possibleVTable = 0; |
362 TUint32 possibleVTable = 0; |
356 // |
363 // |
357 TUint32* ptr = reinterpret_cast< TUint32* >( addr ); |
364 TUint32* ptr = reinterpret_cast< TUint32* >( addr ); |
358 // |
365 // |
359 r = Kern::ThreadRawRead( &aThread, ptr, &value, sizeof( value ) ); |
366 r = Kern::ThreadRawRead( &aObject, ptr, &value, sizeof( value ) ); |
360 if ( r == KErrNone ) |
367 if ( r == KErrNone ) |
361 { |
368 { |
362 r = Kern::ThreadRawRead( &aThread, reinterpret_cast< const TAny* >( value ), &possibleVTable, sizeof( possibleVTable ) ); |
369 Kern::ThreadRawRead( &aObject, reinterpret_cast< const TAny* >( value ), &possibleVTable, sizeof( possibleVTable ) ); |
363 } |
370 } |
364 |
371 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - stack[0x%08x] 0x%08x, vTable: 0x%08x (offset: %04d)", addr, value, possibleVTable, top - addr ) ); |
365 if ( r == KErrNone ) |
|
366 { |
|
367 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - stack[0x%08x] 0x%08x, vTable: 0x%08x (offset: %04d)", addr, value, possibleVTable, top - addr ) ); |
|
368 } |
|
369 else |
|
370 { |
|
371 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - stack[0x%08x] 0x%08x, (offset: %04d) read failed: %d", addr, value, top - addr, r ) ); |
|
372 } |
|
373 } |
372 } |
374 #endif |
373 #endif |
375 |
374 |
376 for( TUint32 addr = top - 4; addr >= top - KMemSpyLocalThreadDataSizeEstimate; addr -= 4 ) |
375 for( TUint32 addr = top - 4; addr >= top - KMemSpyLocalThreadDataSizeEstimate; addr -= 4 ) |
377 { |
376 { |
378 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - addr to read from: 0x%08x", addr ) ); |
377 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - addr to read from: 0x%08x", addr ) ); |
379 TUint32 value = 0; |
378 TUint32 value = 0; |
380 // |
379 // |
381 TUint32* ptr = reinterpret_cast< TUint32* >( addr ); |
380 TUint32* ptr = reinterpret_cast< TUint32* >( addr ); |
382 // |
381 // |
383 r = Kern::ThreadRawRead( &aThread, ptr, &value, sizeof( value ) ); |
382 r = Kern::ThreadRawRead( &aObject, ptr, &value, sizeof( value ) ); |
384 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - read from: 0x%08x, result: %d, value: 0x%08x", addr, r, value ) ); |
383 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - read from: 0x%08x, result: %d, value: 0x%08x", addr, r, value ) ); |
385 // |
384 // |
386 if ( r == KErrNone ) |
385 if ( r == KErrNone ) |
387 { |
386 { |
388 // Try and read from the address which is now stored within 'value'. We must do this because |
387 // Try and read from the address which is now stored within 'value'. We must do this because |
389 // the TLD class holds an RAllocator* and we need to ascertain the vTable of the RAllocator* matches the |
388 // the TLD class holds an RAllocator* and we need to ascertain the vTable of the RAllocator* matches the |
390 // only supported vTable that MemSpy understands (RHeap*). |
389 // only supported vTable that MemSpy understands (RHeap*). |
391 TUint32 possibleVTable = 0; |
390 TUint32 possibleVTable = 0; |
392 r = Kern::ThreadRawRead( &aThread, reinterpret_cast< const TAny* >( value ), &possibleVTable, sizeof( possibleVTable ) ); |
391 r = Kern::ThreadRawRead( &aObject, reinterpret_cast< const TAny* >( value ), &possibleVTable, sizeof( possibleVTable ) ); |
393 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - possible vtable read from: 0x%08x, result: %d, possibleVTable: 0x%08x", value, r, possibleVTable ) ); |
392 TRACE( Kern::Printf( "DMemSpyDriverOSAdaptionDThread::GetAllocatorAndStackAddress() - possible vtable read from: 0x%08x, result: %d, possibleVTable: 0x%08x", value, r, possibleVTable ) ); |
394 if ( r == KErrNone && possibleVTable == rHeapVTable ) |
393 if ( r == KErrNone && possibleVTable == rHeapVTable ) |
395 { |
394 { |
396 aStackAddress = addr; |
395 aStackAddress = addr; |
397 ret = reinterpret_cast< RAllocator* >( value ); |
396 ret = reinterpret_cast< RAllocator* >( value ); |
447 { |
446 { |
448 return static_cast< TExitType >( aObject.iExitType ); |
447 return static_cast< TExitType >( aObject.iExitType ); |
449 } |
448 } |
450 |
449 |
451 |
450 |
452 DThread* DMemSpyDriverOSAdaptionDProcess::OpenFirstThread( DProcess& aProcess ) const |
451 DThread* DMemSpyDriverOSAdaptionDProcess::GetFirstThread( DProcess& aObject ) const |
453 { |
452 { |
454 // It appears that the system lock needs to be held while manipulating the iThreadQ |
453 return aObject.FirstThread(); |
455 DThread* result = NULL; |
|
456 NKern::LockSystem(); |
|
457 // We don't use DProcess::FirstThread() as that doesn't appear to do any checking of whether the list is empty, ie if there are no threads at all |
|
458 SDblQueLink* threadLink = aProcess.iThreadQ.First(); |
|
459 if (threadLink != NULL && threadLink != &aProcess.iThreadQ.iA) |
|
460 { |
|
461 result = _LOFF(threadLink,DThread,iProcessLink); |
|
462 if (result->Open() != KErrNone) |
|
463 { |
|
464 result = NULL; |
|
465 } |
|
466 } |
|
467 NKern::UnlockSystem(); |
|
468 return result; |
|
469 } |
454 } |
470 |
455 |
471 |
456 |
472 TUint32 DMemSpyDriverOSAdaptionDProcess::GetSID( DProcess& aObject ) const |
457 TUint32 DMemSpyDriverOSAdaptionDProcess::GetSID( DProcess& aObject ) const |
473 { |
458 { |
584 { |
564 { |
585 return aObject.MaxSize(); |
565 return aObject.MaxSize(); |
586 } |
566 } |
587 |
567 |
588 |
568 |
589 TUint8* DMemSpyDriverOSAdaptionDChunk::GetBase( DChunk& aChunk ) const |
569 TUint8* DMemSpyDriverOSAdaptionDChunk::GetBase( DChunk& aObject ) const |
590 { |
570 { |
591 TUint8* base = aChunk.Base(); |
571 return aObject.Base(); |
592 if (base == 0) |
|
593 { |
|
594 // Under flexible memory model, DChunk::Base() will return NULL (for non-fixed chunks anyway, and that means most of them) |
|
595 // A more useful thing to return is the base address in the owning process |
|
596 DProcess* proc = GetOwningProcess(aChunk); |
|
597 NKern::ThreadEnterCS(); |
|
598 if (proc && proc->Open() == KErrNone) |
|
599 { |
|
600 // Probably shouldn't call ChunkUserBase for a non-user-owned chunk |
|
601 if (!OSAdaption().DProcess().IsKernProcess(*proc)) |
|
602 { |
|
603 DThread* firstThread = OSAdaption().DProcess().OpenFirstThread(*proc); |
|
604 if (firstThread) |
|
605 { |
|
606 base = Kern::ChunkUserBase(&aChunk, firstThread); |
|
607 firstThread->Close(NULL); |
|
608 } |
|
609 } |
|
610 proc->Close(NULL); |
|
611 } |
|
612 NKern::ThreadLeaveCS(); |
|
613 } |
|
614 return base; |
|
615 } |
572 } |
616 |
573 |
617 |
574 |
618 DProcess* DMemSpyDriverOSAdaptionDChunk::GetOwningProcess( DChunk& aObject ) const |
575 DProcess* DMemSpyDriverOSAdaptionDChunk::GetOwningProcess( DChunk& aObject ) const |
619 { |
576 { |