analyzetool/kerneleventhandler/src/analyzetoolchannel.cpp
branchRCL_3
changeset 13 da2cedce4920
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/analyzetool/kerneleventhandler/src/analyzetoolchannel.cpp	Tue May 25 14:22:58 2010 +0300
@@ -0,0 +1,1019 @@
+/*
+* 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 DAnalyzeToolChannel.
+*
+*/
+
+
+// INCLUDE FILES
+#include "analyzetoolchannel.h"
+#include "analyzetooldevice.h"
+#include "analyzetooleventhandler.h"
+
+#include <kernel/kern_priv.h>
+#ifdef __WINSCW__
+#include <emulator.h>
+#endif // __WINSCW__
+
+#include "atlog.h"
+
+// ================= MEMBER FUNCTIONS =========================================
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::DoCreate()
+// Creates the logical channel.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::DoCreate( TInt /*aUnit*/, 
+    const TDesC8* /*aInfo*/, const TVersion &aVer )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::DoCreate()" );
+
+    // Check client version.
+    if ( !Kern::QueryVersionSupported( KAnalyzeToolLddVersion(), aVer ) )
+        {
+        return KErrNotSupported;
+        }
+     
+    TInt error = Kern::DynamicDfcQCreate( iOwnDfcQ, 
+                                          KAnalyzeToolThreadPriority, 
+                                          KAnalyzeToolThreadName );
+
+    if ( KErrNone != error )
+        {
+        return error;
+        }
+
+    SetDfcQ( iOwnDfcQ );
+    
+    iMsgQ.Receive();
+   
+    // Create the event handler
+    iEventHandler = new DAnalyzeToolEventHandler( iOwnDfcQ );
+
+    // Check that everything is OK
+    if ( !iEventHandler )
+        {
+        return KErrNoMemory;
+        }
+    
+    // 2nd stage constructor for event handler
+    return iEventHandler->Create( iDevice, Kern::CurrentProcess().iId );
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::DAnalyzeToolChannel()
+// Constructor.
+// -----------------------------------------------------------------------------
+//
+DAnalyzeToolChannel::DAnalyzeToolChannel()
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::DAnalyzeToolChannel()" );
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::~DAnalyzeToolChannel()
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+DAnalyzeToolChannel::~DAnalyzeToolChannel()
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::~DAnalyzeToolChannel()" );
+    
+    if ( iEventHandler )
+        {
+        // Cancel all processing that we may be doing
+        DoCancel();
+        
+        // Client code should use Close() instead the operator delete 
+        // to destroy the event handler. 
+        TInt error( iEventHandler->Close() );
+        if ( KErrNone != error )
+            {
+            LOGSTR2( "ATDD iEventHandler->Close(%d)", error );
+            }
+        }
+    #ifdef __WINSCW__
+        iCodeSeg.Close();
+    #endif // __WINSCW__
+    
+    // Destroy the queqe
+    if ( iOwnDfcQ )
+        {
+        iOwnDfcQ->Destroy();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::DoControl()
+// Handles a client request.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::DoControl( TInt aFunction, 
+                                     TAny* a1, 
+                                     TAny* /*a2*/, 
+                                     TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::Request()" );
+    
+    TInt ret( KErrNone );
+
+    // Check the requested function
+    switch (aFunction)
+        {
+        case RAnalyzeTool::EGetProcessInfo:
+            ret = GetProcessInfo( a1, aMessage );
+            break;
+            
+        case RAnalyzeTool::EGetCodesegInfo:
+            ret = GetCodesegInfo( a1, aMessage );
+            break;
+
+        case RAnalyzeTool::EGetLibraryInfo:
+            ret = GetLibraryInfo( a1, aMessage );
+            break;
+            
+        case RAnalyzeTool::ECancelLibraryEvent:
+            iEventHandler->CancelInformLibraryEvent();
+            break;
+            
+        case RAnalyzeTool::ECurrentClientCount:
+            ret = ClientCount( a1, aMessage );
+            break;
+
+        case RAnalyzeTool::EMainThreadAlloctor:
+            ret = MainThreadAllocator( a1, aMessage );
+            break;
+        
+        case RAnalyzeTool::EThreadStack:
+             ret = ThreadStack( a1, aMessage );
+             break;
+             
+        case RAnalyzeTool::EGetProcessHandle:
+            ret = GetProcessHandleInfo( a1, aMessage );
+            break;
+        
+        case RAnalyzeTool::EGetCurrentHandles:
+            ret = GetCurrentHandleCount( a1, aMessage );
+            break;
+        case RAnalyzeTool::EGetMemoryModel:
+            ret = GetMemoryModel( a1, aMessage );
+            break;
+            
+        // Unsupported function. Panic
+        default:
+            Kern::PanicCurrentThread( KClientPanic, EPanicUnsupportedRequest );
+            break;
+        }
+        
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::DoRequest()
+// Handles a client asynchronous request.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::DoRequest( TInt aFunction, 
+                                     TRequestStatus* aStatus, 
+                                     TAny* a1, 
+                                     TAny* /*a2*/,
+                                     TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::DoRequest()" );
+    
+    // Check the requested function
+    switch (aFunction)
+        {
+        case RAnalyzeTool::ELibraryEvent:
+            iEventHandler->InformLibraryEvent( aStatus, a1, aMessage );
+            break;
+            
+        // Unsupported function. Panic
+        default:
+            aMessage.PanicClient( KClientPanic, EPanicUnsupportedRequest );
+            break;
+        }
+        
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::DoCancel()
+// Cancels outstanding asynchronous request.
+// -----------------------------------------------------------------------------
+//
+void DAnalyzeToolChannel::DoCancel()
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::DoCancel()" );
+    
+    iEventHandler->CancelInformLibraryEvent();
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::HandleMsg()
+// Processes a message for this logical channel.
+// -----------------------------------------------------------------------------
+//
+void DAnalyzeToolChannel::HandleMsg(TMessageBase* aMsg)
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::HandleMsg()" );
+
+    TThreadMessage& message = *(TThreadMessage*)aMsg;
+
+    // Get message type
+    TInt id = message.iValue;
+
+    // Decode the message type and dispatch it to the relevent handler function...
+    if ( id == (TInt) ECloseMsg )
+        {
+        // Channel Close
+        DoCancel();
+        message.Complete( KErrNone, EFalse );
+        }
+    else if ( id == KMaxTInt )
+        {
+        // DoCancel
+        DoCancel();
+        message.Complete( KErrNone, ETrue );
+        }
+    else if ( id < 0 )
+        {
+        // DoRequest
+        TRequestStatus* status = (TRequestStatus*) message.Ptr0();
+        TInt error = DoRequest( ~id, status, message.Ptr1(), message.Ptr2(), message );
+        if ( KErrNone != error )
+            {
+            Kern::RequestComplete( message.Client(), status, error);
+            }
+        message.Complete(KErrNone, ETrue );
+        }
+    else
+        {
+        // DoControl
+        TInt ret = DoControl( id, message.Ptr0(), message.Ptr1(), message );
+        message.Complete( ret, ETrue );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetProcessInfo()
+// Acquires current process information
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetProcessInfo( TAny* aProcessInfo, 
+                                          TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetProcessInfo()" );
+
+    // Variable for reading parameters from user side
+    TProcessIdentityParamsBuf params;
+    
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), aProcessInfo, params, 0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess& process = *Kern::ProcessFromId( params().iProcessId );  
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == &process )
+        {        
+        return KErrNotFound;
+        }
+    
+    // Temporary variable for collecting information from the process
+    TProcessIdentityParamsBuf info;
+    
+    // Collect needed information from the process
+    process.AppendName( info().iProcessName );//lint !e64 !e1514
+    
+    // Gets the current thread
+    Kern::Containers()[ EThread ]->Wait(); 
+    DThread& thread = *Kern::ThreadFromId( params().iThreadId );
+    Kern::Containers()[ EThread ]->Signal();
+   
+    if ( NULL == &thread )
+        {
+        return KErrNotFound;
+        }     
+    
+    // Stack address of the main thread
+    info().iStackAddress = thread.iUserStackRunAddress;
+    info().iStackSize    = thread.iUserStackSize;  
+    
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+        
+    // Collect needed information from the process
+    info().iDynamicCount = process.iDynamicCode.Count();
+
+    // Temporary queue for acquiring the count of codesegments
+    SDblQue queue;
+
+    // Acquire the count of codesegments
+    TInt codesegCount = process.TraverseCodeSegs( &queue, 
+                                                  NULL, 
+                                                  DCodeSeg::EMarkDebug, 
+                                                  DProcess::ETraverseFlagAdd );
+    
+    #ifndef __WINSCW__
+        info().iCodesegCount = codesegCount;    
+    #else
+    // Reset codesegment array
+    iCodeSeg.Reset();
+    
+    if ( codesegCount > 0 )
+        {
+        SDblQueLink* link = queue.iA.iNext;
+        TCodesegInfo codeinfo;
+        // Iterate through codesegments
+        for ( TInt i = 0; i < codesegCount; ++i, link = link->iNext )
+            {
+            DWin32CodeSeg* codeseg = 
+                (DWin32CodeSeg*)_LOFF( link, DCodeSeg, iTempLink );
+
+            // Aqcuire codeseg information
+            codeinfo.iFileEntryPoint = codeseg->iFileEntryPoint;
+            codeinfo.iSize = codeseg->iSize;
+            codeinfo.iFullName.Copy( codeseg->iRootName );
+            codeinfo.iRunAddress = codeseg->iRunAddress;
+            iCodeSeg.Append( codeinfo );
+            }
+        }
+    
+    // Add dependency codesegments
+    DWin32CodeSeg* pcodeSeg = (DWin32CodeSeg*)process.iCodeSeg;
+    
+    // Get dependency codesegments
+    GetModuleDependencies( pcodeSeg->iModuleHandle );
+    
+    // Set codesegment count
+    info().iCodesegCount = iCodeSeg.Count();
+    #endif
+    
+    // Removes all code segments from a queue and clear specified mark(s)
+    DCodeSeg::EmptyQueue( queue, DCodeSeg::EMarkDebug );
+
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+
+    // Writes a descriptor to a thread's process.
+    error = Kern::ThreadDesWrite( aMessage.Client(), aProcessInfo, info, 0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        return error;
+        } 
+   
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetCodesegInfo()
+// Acquires codeseg information.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetCodesegInfo( TAny* aCodesegInfo, 
+                                          TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetCodesegInfo()" );
+
+    // Temporary variable for collecting information from the codeseg
+    TCodesegInfoBuf params;
+
+    TInt error( KErrArgument );
+    
+    // Reads a descriptor from a thread's process.
+    error = Kern::ThreadDesRead( aMessage.Client(), aCodesegInfo, params, 0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+
+    if ( params().iIndex < 0 )
+        {
+        return KErrArgument;
+        }
+    
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess& process = *Kern::ProcessFromId( params().iProcessId );
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == &process )
+        {
+        return KErrNotFound;
+        }
+    
+    // Temporary variable for collecting information 
+    TCodesegInfoBuf output;
+
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+
+    #ifndef __WINSCW__
+    // Temporary queue for acquiring the codesegments
+    SDblQue queue;
+    
+    // Acquire the codesegments
+    TInt actcount = process.TraverseCodeSegs( &queue, 
+                                              NULL, 
+                                              DCodeSeg::EMarkDebug, 
+                                              DProcess::ETraverseFlagAdd );
+    if ( actcount >= params().iIndex )
+        {
+        LOGSTR1( "ATDD DAnalyzeToolChannel::GetCodesegInfo() - actcount >= params.iIndex" );
+        SDblQueLink* link = queue.iA.iNext;
+        
+        // Iterate through codesegments
+        for (TInt i = 0; i < actcount; ++i, link = link->iNext)
+            {
+            DCodeSeg* codeseg = _LOFF( link, DCodeSeg, iTempLink );
+
+            // Is the codesegments which information client wants
+            if ( i == params().iIndex )
+                {
+                // Aqcuire codeseg information
+                output().iFileEntryPoint = codeseg->iFileEntryPoint;
+                output().iSize = codeseg->iSize;
+                output().iFullName.Copy( codeseg->iRootName );
+                output().iRunAddress = codeseg->iRunAddress;
+                error = codeseg->GetMemoryInfo( output().iMemoryInfo, &process );
+                
+                if ( KErrNone == error )
+                    {
+                    // Writes a descriptor to a thread's process.
+                    error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                                  aCodesegInfo, 
+                                                  output, 
+                                                  0 );   
+                    if ( KErrNone != error )
+                        {
+                        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+                        } 
+                    }
+                break;
+                }
+            }
+        }
+    // Removes all code segments from a queue and clear specified mark(s).
+    DCodeSeg::EmptyQueue( queue, DCodeSeg::EMarkDebug );
+    
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+    
+    return error;
+    #else // WINSCW
+    
+    if ( iCodeSeg.Count() > params().iIndex )
+        {
+        // Aqcuire codeseg information
+        output().iSize = iCodeSeg[params().iIndex].iSize;
+        output().iFullName.Copy( iCodeSeg[params().iIndex].iFullName );
+        output().iRunAddress = iCodeSeg[params().iIndex].iRunAddress;
+        
+        // Writes a descriptor to a thread's process.
+        error = Kern::ThreadDesWrite( aMessage.Client(), aCodesegInfo, output, 0 ); 
+        
+        if ( KErrNone != error )
+            {
+            LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+            }
+        }
+    
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+    
+    return error;
+    #endif
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetLibraryInfo()
+// Acquires library information.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetLibraryInfo( TAny* aLibraryInfo, 
+                                          TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetLibraryInfo()" );
+
+    // Temporary variable for reading informationfrom the user side
+    TLibraryInfoBuf params;
+
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), aLibraryInfo, params, 0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+
+    if ( params().iIndex < 0 )
+        {
+        return KErrArgument;
+        }
+   
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess& process = *Kern::ProcessFromId( params().iProcessId );
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == &process )
+        {
+        return KErrNotFound;
+        }
+    
+    // Temporary variable for collecting information from the library
+    TLibraryInfoBuf output;
+        
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+
+    // Iterate to find the right library
+    if ( params().iIndex < process.iDynamicCode.Count() )
+        {
+        // Acquire entry to the codeseg
+        SCodeSegEntry entry = process.iDynamicCode[ params().iIndex ];
+        
+        // Acquire library information
+        entry.iLib->AppendName( output().iLibraryName );//lint !e64 !e1514
+        output().iRunAddress = entry.iSeg->iRunAddress;
+        output().iSize = entry.iSeg->iSize;
+        
+        // Writes a descriptor to a thread's process.
+        error = Kern::ThreadDesWrite( aMessage.Client(), aLibraryInfo, output, 0 ); 
+        
+        if ( KErrNone != error )
+            {
+            LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+            } 
+        
+        // Exits thread critical section and releases code segment mutex.
+        Kern::EndAccessCode();
+        
+        return error;
+        }
+    else
+        {
+        // Exits thread critical section and releases code segment mutex.
+        Kern::EndAccessCode();
+        
+        return KErrArgument;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::MainThreadAllocator()
+// Acquires information about process main thread RAllocator
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::MainThreadAllocator( TAny* aMainThreadParams, 
+                                               TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::MainThreadAllocator()" );
+
+    // Temporary variable for reading client side parameters
+    TMainThreadParamsBuf params;
+
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), 
+                                      aMainThreadParams, 
+                                      params, 
+                                      0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+    
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess& process = *Kern::ProcessFromId( params().iProcessId );
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == &process )
+        {
+        return KErrNotFound;
+        }
+
+    // Gets the current process
+    Kern::AccessCode();
+
+    // Temporary variable for collecting information from the RAllocator
+    TMainThreadParamsBuf output;
+
+    // Aqcuire a reference to the main thread RAllocator
+    output().iAllocator = process.FirstThread()->iAllocator;
+
+    // Is this only thread in the process
+    output().iAlone = process.iThreadQ.First()->Alone();
+
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+
+    // Writes a descriptor to a thread's process.
+    error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                  aMainThreadParams, 
+                                  output, 
+                                  0 ); 
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        } 
+
+    return error;
+    }    
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::ThreadStack()
+// Acquires main thread stack address
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::ThreadStack( TAny* aThreadStack, 
+                                       TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::ThreadStack()" );
+
+    // Temporary variable for reading client side parameters
+    TThreadParamsBuf params;
+
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), 
+                                      aThreadStack, 
+                                      params, 
+                                      0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+    
+    // Gets the current process
+    Kern::Containers()[ EThread ]->Wait();
+    DThread& thread = *Kern::ThreadFromId( params().iThreadId );
+    Kern::Containers()[ EThread ]->Signal();
+    
+    if ( NULL == &thread )
+        {
+        return KErrNotFound;
+        }
+    
+    // Gets the current process
+    Kern::AccessCode();
+
+    // Temporary variable for collecting information from the RAllocator
+    TThreadParamsBuf output;
+
+    // Stack address of the main thread
+    output().iStackAddress = thread.iUserStackRunAddress;
+    output().iStackSize    = thread.iUserStackSize;
+
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+
+    // Writes a descriptor to a thread's process.
+    error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                  aThreadStack, 
+                                  output, 
+                                  0 ); 
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        } 
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetProcessHandleInfo()
+// Acquires information about process global handles
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetProcessHandleInfo( TAny* aProcessHandleInfo,
+                                                TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetProcessHandleInfo()" );
+
+    // Temporary variable for collecting information from the codeseg
+    TProcessHandleInfoBuf params;
+
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), 
+                                      aProcessHandleInfo, 
+                                      params, 
+                                      0 );  
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess& process = *Kern::ProcessFromId( params().iProcessId );
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == &process )
+        {
+        return KErrNotFound;
+        }
+    
+    // Variable holding wanted information
+    TProcessHandleInfoBuf output;
+
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+
+    // Get the process thread queue.
+    SDblQue queue = process.iThreadQ;
+    error = KErrNotFound;
+        
+    // Tests whether this doubly linked list is empty.
+    if ( !queue.IsEmpty() )
+        {
+        // Gets a pointer to the first item in this doubly linked list.
+        SDblQueLink* link = queue.First();
+        DThread* thread = _LOFF( link, DThread, iProcessLink );
+
+        if ( thread )
+            {
+            
+#ifdef MCL_ROBJECTIX
+            TInt threadHandles( thread->iHandles.ActiveCount() );
+#else
+            TInt threadHandles( thread->iHandles->ActiveCount() );
+#endif
+            
+            // Aqcuire thread information
+            //thread->AppendName( output.iThreadName );
+            output().iUserStackRunAddress = thread->iUserStackRunAddress;
+            output().iUserStackSize = thread->iUserStackSize;
+            output().iThreadHandleCount = threadHandles;
+            
+#ifdef MCL_ROBJECTIX
+            RObjectIx objectIx = process.iHandles;
+            output().iProcessHandleCount = objectIx.ActiveCount();
+#else
+            DObjectIx* objectIx = process.iHandles;
+            output().iProcessHandleCount = objectIx->ActiveCount();
+#endif
+                        
+            // Writes a descriptor to a thread's process.
+            error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                          aProcessHandleInfo, 
+                                          output, 
+                                          0 ); 
+            
+            if ( KErrNone != error )
+                {
+                LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+                } 
+            }
+        }
+
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetCurrentHandleCount()
+// Acquires a process's current handle count
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetCurrentHandleCount( TAny* aProcessHandles,
+                                                 TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetCurrentHandleCount()" );
+
+    // Temporary variable for collecting information from the codeseg
+    TATProcessHandlesBuf params;
+    
+    // Reads a descriptor from a thread's process.
+    TInt error = Kern::ThreadDesRead( aMessage.Client(), 
+                                      aProcessHandles, 
+                                      params, 
+                                      0 );
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesRead error %d", error );
+        return error;
+        } 
+    
+    // Gets the current process
+    Kern::Containers()[ EProcess ]->Wait();
+    DProcess* process = Kern::ProcessFromId( params().iProcessId );
+    Kern::Containers()[ EProcess ]->Signal();
+    
+    if ( NULL == process )
+        {
+        return KErrNotFound;
+        }
+
+    // Variable holding wanted information
+    TATProcessHandlesBuf output;
+    
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+    
+    SDblQue queue = process->iThreadQ;
+    SDblQueLink* link = queue.First();
+    TInt threadHandles( 0 );
+    
+    // Iterate through current processes's threads
+    while ( link != queue.Last() )
+        {
+        DThread* thread = _LOFF( link, DThread, iProcessLink );
+        
+#ifdef MCL_ROBJECTIX
+        threadHandles += thread->iHandles.ActiveCount();
+#else
+        threadHandles += thread->iHandles->ActiveCount();
+#endif
+        
+        link = link->iNext;
+        }
+
+    if ( link == queue.Last() )
+        {
+        DThread* thread = _LOFF( link, DThread, iProcessLink );
+
+#ifdef MCL_ROBJECTIX
+        threadHandles += thread->iHandles.ActiveCount();
+#else
+        threadHandles += thread->iHandles->ActiveCount();
+#endif
+        }
+    
+    output().iCurrentHandleCount = threadHandles;
+    
+    // Writes a descriptor to a thread's process.
+    error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                  aProcessHandles, 
+                                  output, 
+                                  0 ); 
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        } 
+    
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::ClientCount()
+// Acquires the count of current device driver users.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::ClientCount( TAny* aClientCount,
+                                       TThreadMessage& aMessage )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::ClientCount()" );
+    
+    // Enters thread critical section and acquires code segment mutex.
+    Kern::AccessCode();
+    
+    // Variable holding wanted information
+    TClientCountBuf output;
+    
+    // Get the number of DLogicalChannelBase objects currently in existence which
+    // have been created from this LDD.
+    output().iClientCount = DLogicalChannelBase::iDevice->iOpenChannels;
+    LOGSTR2( "ATDD > iOpenChannels count: %d", output().iClientCount ); 
+    
+    // Writes a descriptor to a thread's process.
+    TInt error = Kern::ThreadDesWrite( aMessage.Client(), 
+                                       aClientCount, 
+                                       output, 
+                                       0 ); 
+    
+    if ( KErrNone != error )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        } 
+    
+    // Exits thread critical section and releases code segment mutex.
+    Kern::EndAccessCode();
+    
+    return error;
+    }
+
+#ifdef __WINSCW__
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetModuleDependencies()
+// Get module dependencies
+// -----------------------------------------------------------------------------
+//
+void DAnalyzeToolChannel::GetModuleDependencies( HMODULE aModule )
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetModuleDependencies()" );
+
+    Emulator::TModule etm( aModule );
+    TUint32 dllSize( 0 );
+    // Temporary variable for collecting information from the codeseg
+    TCodesegInfo info;
+    TBool found( EFalse );
+    
+    const IMAGE_IMPORT_DESCRIPTOR* imports = etm.Imports();
+    while( imports->Characteristics != 0 )
+        {
+        // Reset flag
+        found = EFalse;
+        
+        // Get dll name
+        const TUint8* nameAddr = ( const TUint8* )( imports->Name + ( TInt )etm.iBase );
+        TPtrC8 namePtr( nameAddr );     
+        
+        // Get dll run address
+        Emulator::TModule imp_etm( ( PCSTR )etm.Translate( imports->Name ) );        
+        const TUint8* runAddr = ( const TUint8* )imp_etm.iBase;
+        
+        // Get dll size
+        const IMAGE_NT_HEADERS32* ntHeader = imp_etm.NtHeader();
+        dllSize = ntHeader->OptionalHeader.SizeOfImage;       
+        
+        // Check if DLL already exists in codesegment list
+        for( TInt i = 0; i < iCodeSeg.Count(); i++ )
+            {
+            if ( iCodeSeg[i].iFullName.Compare( namePtr ) == KErrNone )
+                {
+                found = ETrue;
+                break;
+                }
+            }
+        
+        if ( !found )
+            {
+            info.iSize = dllSize;
+            info.iFullName.Copy( namePtr );
+            info.iRunAddress = (TUint32) runAddr;  
+            // Append codesegment to array
+            iCodeSeg.Append( info );
+            }
+        imports++;
+        }
+    }
+  
+#endif // __WINSCW__
+
+// -----------------------------------------------------------------------------
+// DAnalyzeToolChannel::GetMemoryModel()
+// Acquires memory model system uses.
+// -----------------------------------------------------------------------------
+//
+TInt DAnalyzeToolChannel::GetMemoryModel(TAny* aMemoryModel,
+                                        TThreadMessage& aMessage)
+    {
+    LOGSTR1( "ATDD DAnalyzeToolChannel::GetMemoryModel()" );
+   
+    // Model buffer.
+    TATMemoryModelBuf model;
+    // Get current model.
+    model().iMemoryModel = (TUint32) Kern::HalFunction( EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL );
+    model().iMemoryModel &= EMemModelTypeMask; // Mask out other stuff.
+    // Write it to client side.
+    TInt error = Kern::ThreadDesWrite( aMessage.Client(),
+                                        aMemoryModel,
+                                        model,
+                                        0);
+    if ( error != KErrNone )
+        {
+        LOGSTR2( "ATDD ThreadDesWrite error %d", error );
+        }
+    return error;
+    }
+// End of File