memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanThreadAndProcess.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:57:15 +0200
changeset 0 a03f92240627
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* 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:
*
*/

#include "MemSpyDriverLogChanThreadAndProcess.h"

// System includes
#include <platform.h>
#include <memspy/driver/memspydriverobjectsshared.h>
#include <memspy/driver/memspydriverpanics.h>

// Shared includes
#include "MemSpyDriverOpCodes.h"
#include "MemSpyDriverObjectsInternal.h"

// User includes
#include "MemSpyDriverUtils.h"
#include "MemSpyDriverOSAdaption.h"
#include "MemSpyDriverSuspensionManager.h"

// Constants
const TBool KMemSpyDriverAllowDeadOpenRequests = ETrue;
const TInt KMemSpyDriverLogChanThreadAndProcessXferBufferSize = 512;


DMemSpyDriverLogChanThreadAndProcess::DMemSpyDriverLogChanThreadAndProcess( DMemSpyDriverDevice& aDevice, DThread& aThread )
:   DMemSpyDriverLogChanBase( aDevice, aThread )
    {
    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::DMemSpyDriverLogChanThreadAndProcess() - this: 0x%08x", this ));
    }


DMemSpyDriverLogChanThreadAndProcess::~DMemSpyDriverLogChanThreadAndProcess()
	{
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::~DMemSpyDriverLogChanThreadAndProcess() - START - this: 0x%08x", this ));

	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::~DMemSpyDriverLogChanThreadAndProcess() - END - this: 0x%08x", this ));
	}


TInt DMemSpyDriverLogChanThreadAndProcess::Construct()
	{
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::Construct() - START - this: 0x%08x", this ));
    
    const TInt ret = BaseConstruct( KMemSpyDriverLogChanThreadAndProcessXferBufferSize );

	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::Construct() - END - this: 0x%08x, err: %d", this, ret ));
    return ret;
	}


TInt DMemSpyDriverLogChanThreadAndProcess::Request( TInt aFunction, TAny* a1, TAny* a2 )
	{
	TInt r = DMemSpyDriverLogChanBase::Request( aFunction, a1, a2 );
    if  ( r == KErrNone )
        {
	    switch( aFunction )
		    {
	    case EMemSpyDriverOpCodeThreadAndProcessGetInfoThread:
		    r = GetInfoThread( (TUint)a1, (TMemSpyDriverInternalThreadInfoParams*) a2);
		    break;
	    case EMemSpyDriverOpCodeThreadAndProcessGetInfoProcess:
		    r = GetInfoProcess( (TUint)a1, (TMemSpyDriverProcessInfo*) a2);
		    break;
        case EMemSpyDriverOpCodeThreadAndProcessEndThread:
            r = EndThread( (TUint) a1, (TExitType) ((TUint) a2) );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessOpenThread:
            r = OpenThread( (TUint) a1 );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessOpenProcess:
            r = OpenProcess( (TUint) a1 );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessSuspendAllThreads:
            r = SuspendAllThreadsInProcess( (TUint) a1 );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessResumeAllThreads:
            r = ResumeAllThreadsInProcess( (TUint) a1 );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessGetThreads:
            r = GetThreadsForProcess( (TUint) a1, (TDes8*) a2 );
            break;
        case EMemSpyDriverOpCodeThreadAndProcessSetPriorityThread:
            r = SetPriority( (TUint) a1, (TThreadPriority) ((TUint) a2) );
            break;

        default:
            r = KErrNotSupported;
		    break;
		    }
        }
    //
    return r;
	}


TBool DMemSpyDriverLogChanThreadAndProcess::IsHandler( TInt aFunction ) const
    {
    return ( aFunction > EMemSpyDriverOpCodeThreadAndProcessBase && aFunction < EMemSpyDriverOpCodeThreadAndProcessEnd );
    }






TInt DMemSpyDriverLogChanThreadAndProcess::GetInfoThread( TUint aTid, TMemSpyDriverInternalThreadInfoParams* aParams )
	{
    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - START"));

    TMemSpyDriverInternalThreadInfoParams params;
    TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, &params, sizeof(TMemSpyDriverInternalThreadInfoParams) );
    if  ( r != KErrNone )
        {
    	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - END - params read error: %d", r));
        return r;
        }

	r = OpenTempObject( aTid, EThread );
	if  ( r == KErrNone )
		{
		DThread* dThread = (DThread*) TempObject();
  	    NKern::ThreadEnterCS();

        // Get DThread adaptor. This is a means of querying DThread internals
        // without accessing them directly. Takes into account possible differences
        // between compile time and run time
        DMemSpyDriverOSAdaptionDThread& dThreadAdaptor = OSAdaption().DThread();

        // Saved CPU registers for thread. Need to get NThread to do this.
        NThread* nThread = dThreadAdaptor.GetNThread( *dThread );
    	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting regs..." ));
        MemSpyDriverUtils::GetThreadRegisters( nThread, params.iCpu );
		
        // Name
    	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting full name..." ));
		dThread->FullName( params.iFullName );

        // User framework
    	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting allocator..." ));
        params.iAllocator = dThreadAdaptor.GetAllocator( *dThread );

        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting scheduler..." ));
        params.iScheduler = dThreadAdaptor.GetActiveScheduler( *dThread );

        // User stack information - rest comes from user side API calls
        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting user stack pointer..." ));
        params.iStackInfo.iUserStackPointer = params.iCpu.iRn[ 12 ];

        // Supervisor stack information
        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - getting supervisor stack..." ));
        params.iStackInfo.iSupervisorStackPointer = 0;
        params.iStackInfo.iSupervisorStackHighWatermark = 0;
        params.iStackInfo.iSupervisorStackBase = dThreadAdaptor.GetSupervisorStackBase( *dThread );
        params.iStackInfo.iSupervisorStackSize = dThreadAdaptor.GetSupervisorStackSize( *dThread );
 
        // Write back to user-side
        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - writing to user side..." ));
        r = Kern::ThreadRawWrite( &ClientThread(), aParams, &params, sizeof(TMemSpyDriverInternalThreadInfoParams) );
	    NKern::ThreadLeaveCS();
		CloseTempObject();
		}

    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoThread() - END - ret: %d", r));
    return r;
	}


TInt DMemSpyDriverLogChanThreadAndProcess::GetInfoProcess( TUint aPid, TMemSpyDriverProcessInfo* aParams )
	{
    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoProcess() - START"));

    TMemSpyDriverProcessInfo params;
    TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, &params, sizeof(TMemSpyDriverProcessInfo) );
    if  ( r != KErrNone )
        {
    	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoProcess() - END - params read error: %d", r));
        return r;
        }

	r = OpenTempObject( aPid, EProcess );
	if  ( r == KErrNone )
		{
        DMemSpyDriverOSAdaptionDProcess& processAdaptor = OSAdaption().DProcess();
  
        DProcess* process = (DProcess*) TempObject();
  	    NKern::ThreadEnterCS();
		//
        params.iFlags = processAdaptor.GetFlags( *process );
        params.iGeneration = processAdaptor.GetGeneration( *process );
        params.iSecurityInfo = processAdaptor.GetSecurityInfo( *process );

        // Write back to user-side
        r = Kern::ThreadRawWrite( &ClientThread(), aParams, &params, sizeof(TMemSpyDriverProcessInfo) );
	    NKern::ThreadLeaveCS();
		CloseTempObject();
		}

    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::GetInfoProcess() - END - ret: %d", r));
    return r;
	}









TInt DMemSpyDriverLogChanThreadAndProcess::EndThread( TUint aId, TExitType aType )
    {
    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::EndThread() - START - aId: %d, aType: %d", aId, aType ));

	TInt r = OpenTempObject( aId, EThread );
	if  ( r == KErrNone )
		{
        DThread* thread = (DThread*) TempObject();
        //
        const TInt reason = MapToMemSpyExitReason( aType );
        Kern::ThreadKill( thread, aType, reason, KMemSpyClientPanic );
        //
	    CloseTempObject();
        }
    else
        {
        r = KErrNotFound;
        }

	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::EndThread() - END - r: %d", r));
	return r;
    }






















TInt DMemSpyDriverLogChanThreadAndProcess::OpenThread( TUint aId )
    {
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - START - aId: %d", aId));

	TInt r = OpenTempObject( aId, EThread, KMemSpyDriverAllowDeadOpenRequests );
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - done open temp object, r: %d", r ));
	if  ( r == KErrNone )
		{
        NKern::ThreadEnterCS();
        DThread* threadToOpen = (DThread*) TempObject();
        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - thread exit type: %d", threadToOpen->iExitType ));

        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - making handle..." ));
        r = Kern::MakeHandleAndOpen( &ClientThread(), threadToOpen );
	    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - handle: %d",r ));
    	NKern::ThreadLeaveCS();

        // Balance reference count, handle is still open and mapped into our process since we opened
        // it above via MakeHandleAndOpen
	    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - closing temp object..." ));
	    CloseTempObject();
	    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - closed temp object" ));
        }
    else
        {
        r = KErrNotFound;
        }

	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenThread() - END - r: %d", r));
	return r;
    }


TInt DMemSpyDriverLogChanThreadAndProcess::OpenProcess( TUint aId )
    {
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenProcess() - START - aId: %d", aId));

	TInt r = OpenTempObject( aId, EProcess, KMemSpyDriverAllowDeadOpenRequests );
	if  ( r == KErrNone )
		{
        NKern::ThreadEnterCS();
        DProcess* processToOpen = (DProcess*) TempObject();
        r = Kern::MakeHandleAndOpen( &ClientThread(), processToOpen );
    	NKern::ThreadLeaveCS();

        // Balance reference count, handle is still open and mapped into our process since we opened
        // it above via MakeHandleAndOpen
	    CloseTempObject();
        }
    else
        {
        r = KErrNotFound;
        }

	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::OpenProcess() - END - r: %d", r));
	return r;
    }





























TInt DMemSpyDriverLogChanThreadAndProcess::SuspendAllThreadsInProcess( TUint aPid )
    {
	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::SuspendAllThreadsInProcess() - START - aPid: %d", aPid ));

    DMemSpySuspensionManager& susMan = SuspensionManager();
    const TInt err = susMan.SuspendAllThreadsInProcess( aPid, ClientThread() );

	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::SuspendAllThreadsInProcess() - END - aPid: %d, err: %d", aPid, err ));
	return err;
    }


TInt DMemSpyDriverLogChanThreadAndProcess::ResumeAllThreadsInProcess( TUint aPid )
    {
	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::ResumeAllThreadsInProcess() - START - aPid: %d", aPid ));

    DMemSpySuspensionManager& susMan = SuspensionManager();
    const TInt err = susMan.ResumeAllThreadsInProcess( aPid, ClientThread() );

	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::ResumeAllThreadsInProcess() - END - aPid: %d, err: %d", aPid, err ));
	return err;
    }


TInt DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess( TUint aPid, TDes8* aBufferSink )
    {
	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - START - aPid: %d", aPid ) );

    // We open the source thread or process, just to ensure it doesn't die underneath us...
    TInt r = OpenTempObject( aPid, EProcess );
    if  ( r == KErrNone )
		{
		DProcess& process = TempObjectAsProcess();

        // Open stream
        RMemSpyMemStreamWriter stream = OpenXferStream();
        TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - stream remaining: %d", stream.Remaining() ) ); 

        // Save marker pos for the thread count - we'll update it after the loop
        TInt count = 0;
        TInt32* pCountMarkerThread = stream.WriteInt32( 0 );

        DMemSpyDriverOSAdaptionDProcess& processAdaptor = OSAdaption().DProcess();
        SDblQue& threadQueue = processAdaptor.GetThreadQueue( process );
        SDblQueLink* pLink = threadQueue.First();
		while( pLink != & threadQueue.iA && !stream.IsFull() )
			{
			DThread* pT = processAdaptor.GetThread( pLink );
            //
            if  ( pT )
                {
                const TUint tid = OSAdaption().DThread().GetId( *pT );
                TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - id: %d (0x%04x)", tid, tid ) );
                stream.WriteUint32( tid );
                }

            pLink = pLink->iNext;
			++count;
            }
 
        if  ( stream.IsFull() )
            {
            Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - STREAM FULL - id: %d (0x%04x), thread: %O", process.iId, process.iId, &process );
            }

        // Now write the count
        *pCountMarkerThread = count;

        // Tidy up
        r = stream.WriteAndClose( aBufferSink );
        TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - r: %d, count: %d", r, count ));

        CloseTempObject();
        }

	TRACE( Kern::Printf( "DMemSpyDriverLogChanThreadAndProcess::GetThreadsForProcess() - END - aPid: %d, err: %d", aPid, r ));
	return r;
    }


TInt DMemSpyDriverLogChanThreadAndProcess::SetPriority( TUint aId, TThreadPriority aPriority )
    {
    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::SetPriority(T) - START - aId: %d, aPriority: %d", aId, aPriority ));

	TInt r = OpenTempObject( aId, EThread );
	TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::SetPriority(T) - done open temp object, r: %d", r ));
	if  ( r == KErrNone )
		{
        // Map user side thread priority to kernel-side absolute thread priority (typically 0-63)
        const TInt kernelThreadPri = MemSpyDriverUtils::MapToAbsoluteThreadPriority( aPriority );
        TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::SetPriority(T) - user: %d, kernel absolute: %d", aPriority, kernelThreadPri ));

        if  ( kernelThreadPri > 0 && kernelThreadPri < KNumPriorities )
            {
            NKern::ThreadEnterCS();
            DThread& thread = TempObjectAsThread();
            r = Kern::SetThreadPriority( kernelThreadPri, &thread );
            TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::SetPriority(T) - Kern::SetThreadPriority() returned: %d", r ));
    	    NKern::ThreadLeaveCS();
            }
        else
            {
            // Error
            r = kernelThreadPri;
            }

        CloseTempObject();
        }

    TRACE( Kern::Printf("DMemSpyDriverLogChanThreadAndProcess::SetPriority(T) - END - r: %d", r));
	return r;
    }






TInt DMemSpyDriverLogChanThreadAndProcess::MapToMemSpyExitReason( TExitType aType )
    {
    TInt ret = 0;
    //
    switch( aType )
        {
    default:
    case EExitKill:
        ret = EPanicForcedKill;
        break;
    case EExitTerminate:
        ret = EPanicForcedTerminate;
        break;
    case EExitPanic:
        ret = EPanicForcedPanic;
        break;
        }
    //
    return ret;
    }