crashanalysercmd/Libraries/Engine/CrashDebuggerLib/Structures/NThread/NThread.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/Libraries/Engine/CrashDebuggerLib/Structures/NThread/NThread.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,442 @@
+/*
+* Copyright (c) 2004-2008 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: 
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CrashDebuggerLib.Structures.KernelObjects;
+using CrashDebuggerLib.Structures.Common;
+using CrashDebuggerLib.Structures.Thread;
+using CrashDebuggerLib.Structures.Register;
+using CrashDebuggerLib.Structures.UserContextTable;
+using CrashDebuggerLib.Attributes;
+using SymbianStructuresLib.Debug.Symbols;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianUtils.DataBuffer;
+
+namespace CrashDebuggerLib.Structures.NThread
+{
+    public class NThread : CrashDebuggerAware
+    {
+        #region Enumerations
+        [System.ComponentModel.TypeConverter( typeof( SymbianParserLib.TypeConverters.SymbianEnumConverter ) )]
+        public enum TNThreadState
+        {
+            EUnknown = -1, // Catch all
+            EReady = 0,
+            ESuspended,
+            EWaitFastSemaphore,
+            ESleep,
+            EBlocked,
+            EDead,
+            EWaitDfc
+        }
+
+        public enum TWaitType
+        {
+            EWaitTypeNotWaiting = 0,
+            EWaitTypeUserWaitForRequest,
+            EWaitTypeUserWaitForAnyRequest
+        }
+        #endregion
+
+        #region Constructors
+        public NThread( CrashDebuggerInfo aCrashDebugger, DThread aParentThread )
+            : base( aCrashDebugger )
+        {
+            iParentThread = aParentThread;
+            iRegisters = new RegisterCollection( aCrashDebugger, RegisterCollection.TType.ETypeGeneral, aParentThread.OwningProcess );
+        }
+        #endregion
+
+        #region API
+        public static TNThreadState NStateFromString( string aState )
+        {
+            NThread.TNThreadState ret = NThread.TNThreadState.EUnknown;
+            //
+            switch ( aState.ToUpper() )
+            {
+                case "READY":
+                    ret = NThread.TNThreadState.EReady;
+                    break;
+                case "SUSPENDED":
+                    ret = NThread.TNThreadState.ESuspended;
+                    break;
+                case "WAITFSEM":
+                    ret = NThread.TNThreadState.EWaitFastSemaphore;
+                    break;
+                case "SLEEP":
+                    ret = NThread.TNThreadState.ESleep;
+                    break;
+                case "BLOCKED":
+                    ret = NThread.TNThreadState.EBlocked;
+                    break;
+                case "DEAD":
+                    ret = NThread.TNThreadState.EDead;
+                    break;
+                case "WAITDFC":
+                    ret = NThread.TNThreadState.EWaitDfc;
+                    break;
+                default:
+                case "??":
+                    ret = NThread.TNThreadState.EUnknown;
+                    break;
+            }
+            //
+            return ret;
+        }
+
+        public RegisterCollection GetRegisters( RegisterCollection.TType aType )
+        {
+            RegisterCollection ret = null;
+
+            // Are we the currently executing thread?
+            bool isCurrent = iParentThread.IsCurrent;
+            
+            // If we're dealing with the current thread, and we need to supply
+            // user-land registers, then we'll try to work with the user context
+            // tables so long as we are executing in supervisor mode.
+            if ( aType == RegisterCollection.TType.ETypeUser )
+            {
+                ret = GetUserContextRegisters();
+            }
+            else
+            {
+                // Trying to get non-user registers
+                Cpu.CpuInfo cpuInfo = CrashDebugger.InfoCpu;
+                //
+                if ( isCurrent )
+                {
+                    // Just go entirely with current CPU registers
+                    ret = cpuInfo.GetRegisters();
+                }
+                else
+                {
+                    // Best we can do :(
+                    ret = new RegisterCollection( Registers, aType, iParentThread.OwningProcess );
+
+                    if ( aType == RegisterCollection.TType.ETypeSupervisor )
+                    {
+                        // We know R13_SP because we explicitly are given it
+                        ret[ TArmRegisterType.EArmReg_SP ].Value = SavedSP;
+
+                        // TODO: We also need to get CPSR from somewhere. We just make it
+                        // up at the moment, which is really bad...
+                        ret[ TArmRegisterType.EArmReg_CPSR ].Value = ret[ TArmRegisterType.EArmReg_SPSR ];
+                    }
+                }
+            }
+            //
+            return ret;
+        }
+        #endregion
+
+        #region Properties
+        [PropCat("State")]
+        public TNThreadState NState
+        {
+            get { return iNState; }
+            set { iNState = value; }
+        }
+
+        [PropCat( "Summary", PropCat.TFormatType.EFormatAsHex )]
+        public uint Address
+        {
+            get { return iAddress; }
+            set { iAddress = value; }
+        }
+
+        public uint RequestSemaphoreAddress
+        {
+            get
+            {
+                uint ret = Address;
+                ret += (uint) CrashDebuggerLib.Platform.NKernOffsets.KOffsetOf_iRequestSemaphore_In_NThread;
+                return ret;
+            }
+        }
+
+        public uint WaitObj
+        {
+            get { return iWaitObj; }
+            set { iWaitObj = value; }
+        }
+
+        [PropCat( "Summary" )]
+        public int Priority
+        {
+            get { return iPriority; }
+            set { iPriority = value; }
+        }
+
+        [PropCat( "State", PropCat.TFormatType.EFormatAsHex )]
+        public uint Attributes
+        {
+            get { return iAttributes; }
+            set { iAttributes = value; }
+        }
+
+        [PropCat( "Summary", "Address space" )]
+        public uint AddressSpace
+        {
+            get { return iAddressSpace; }
+            set { iAddressSpace = value; }
+        }
+
+        [PropCat( "Summary", "Supervisor stack pointer", PropCat.TFormatType.EFormatAsHex )]
+        public uint SavedSP
+        {
+            get { return iSavedSP; }
+            set { iSavedSP = value; }
+        }
+
+        [PropCat( "Misc", "Return Value" )]
+        public int ReturnValue
+        {
+            get { return iReturnValue; }
+            set { iReturnValue = value; }
+        }
+
+        [PropCat( "Summary", "Is user thread", PropCat.TFormatType.EFormatAsYesNo )]
+        public bool IsUserThread
+        {
+            get { return iParentThread.IsUserThread; }
+        }
+
+        [PropCat( "State", "Is the current thread", PropCat.TFormatType.EFormatAsYesNo )]
+        public bool IsCurrent
+        {
+            get { return iParentThread.IsCurrent; }
+        }
+
+        public bool HaveUserContext
+        {
+            get
+            {
+                bool haveUserContext = true;
+                //
+                switch ( UserContextType )
+                {
+                case TUserContextType.EContextNone:
+                case TUserContextType.EContextUndefined:
+                case TUserContextType.EContextKernel:
+                    haveUserContext = false;
+                    break;
+                default:
+                    break;
+                }
+                //
+                return haveUserContext;
+            }
+        }
+
+        [PropCat( "State", "User context type" )]
+        public TUserContextType UserContextType
+        {
+            get { return iUserContextType; }
+            set { iUserContextType = value; }
+        }
+
+        [PropCat( "Linked List Info", PropCat.TFormatType.EFormatRecurseInto )]
+        public LinkedListInfo LinkedListInfo
+        {
+            get { return iLinkedListInfo; }
+        }
+
+        [PropCat( "Mutex Info", PropCat.TFormatType.EFormatRecurseInto )]
+        public NThreadMutexInfo MutexInfo
+        {
+            get { return iMutexInfo; }
+        }
+
+        [PropCat( "Timing Info", PropCat.TFormatType.EFormatRecurseInto )]
+        public NThreadTimeInfo TimeInfo
+        {
+            get { return iTimeInfo; }
+            set { iTimeInfo = value; }
+        }
+
+        [PropCat( "Count Info", PropCat.TFormatType.EFormatRecurseInto )]
+        public NThreadCountInfo CountInfo
+        {
+            get { return iCountInfo; }
+            set { iCountInfo = value; }
+        }
+
+        public NThreadExtraContextInfo ExtraContextInfo
+        {
+            get { return iExtraContextInfo; }
+            set { iExtraContextInfo = value; }
+        }
+
+        public RegisterCollection Registers
+        {
+            get { return iRegisters; }
+        }
+
+        public TWaitType WaitType
+        {
+            get
+            {
+                TWaitType ret = TWaitType.EWaitTypeNotWaiting;
+                //
+                RegisterEntry linkReg = Registers[ "R14_USR" ];
+                Symbol symbol = linkReg.Symbol;
+                if ( symbol != null )
+                {
+                    if ( symbol.Name.Contains( "User::WaitForAnyRequest" ) )
+                    {
+                        ret = TWaitType.EWaitTypeUserWaitForAnyRequest;
+                    }
+                    else if ( symbol.Name.Contains( "User::WaitForRequest(TRequestStatus&)" ) )
+                    {
+                        ret = TWaitType.EWaitTypeUserWaitForRequest;
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Internal methods
+        // <summary>
+        // This property returns the return address of the instruction
+        // to resume executing when this thread finishes executing within
+        // the context of an exception handler (typically SVC)
+        // </summary>
+        internal uint UserReturnAddress
+        {
+            get
+            {
+                uint retAddr = 0;
+                //
+                switch ( UserContextType )
+                {
+                case TUserContextType.EContextNone:
+                case TUserContextType.EContextUndefined:
+                case TUserContextType.EContextKernel:
+                    throw new NotSupportedException();
+                default:
+                    {
+                        Thread.ThreadStackData superStackData = iParentThread.StackInfoSupervisor.Data;
+                        SymbianUtils.DataBuffer.Entry.DataBufferUint uintEntry = superStackData.LastRawDataEntry;
+                        retAddr = uintEntry.Uint;
+                    }
+                    break;
+                }
+                //
+                return retAddr;
+            }
+        }
+
+        private RegisterCollection GetUserContextRegisters()
+        {
+            bool isCurrent = IsCurrent;
+            RegisterCollection ret = new RegisterCollection( Registers, RegisterCollection.TType.ETypeUser, iParentThread.OwningProcess );
+
+            // User-land CPSR is stored in SPSR_SVC
+            RegisterEntry spsr = Registers[ TArmRegisterType.EArmReg_SPSR ];
+            ret[ TArmRegisterType.EArmReg_CPSR ].Value = spsr.Value;
+
+            // Get the context table that we'll need to work out the reg positions
+            UserContextTable.UserContextTable table = CrashDebugger.UserContextTableManager[ UserContextType ];
+
+            // Get SP and stack data for supervisor thread
+            uint sp = SavedSP;
+            ThreadStackData spData = iParentThread.StackInfoSupervisor.Data;
+            if ( spData.Info.Data.Size > 0 )
+            {
+                // This is the user side address that will be branched back to once we exit SVC mode...
+                uint retAddr = UserReturnAddress;
+                ret[ TArmRegisterType.EArmReg_PC ].Value = retAddr;
+ 
+                // Now try to get the register values off of the supervisor stack
+                DataBuffer superStackData = spData.Data;
+                foreach ( ArmRegister reg in ret )
+                {
+                    if ( UserContextTable.UserContextTable.IsSupported( reg.RegType ) )
+                    {
+                        UserContextTableEntry uctEntry = table[ reg.RegType ];
+                        if ( uctEntry.IsAvailable( isCurrent ) )
+                        {
+                            ArmRegister savedSp = new ArmRegister( TArmRegisterType.EArmReg_SP, sp );
+                            uint newValue = uctEntry.Process( savedSp, superStackData );
+                            reg.Value = newValue;
+                        }
+                    }
+                }
+            }
+
+            // Getting context of current thread? Some values can be fetched directly
+            // from the registers if they are not available from the stack.
+            if ( isCurrent && table[ TArmRegisterType.EArmReg_SP ].Type == UserContextTableEntry.TType.EOffsetFromSp )
+            {
+                RegisterCollection userRegs = CrashDebugger.InfoCpu[ RegisterCollection.TType.ETypeUser ];
+                //
+                ret[ TArmRegisterType.EArmReg_SP ].Value = userRegs[ TArmRegisterType.EArmReg_SP ];
+                ret[ TArmRegisterType.EArmReg_LR ].Value = userRegs[ TArmRegisterType.EArmReg_LR ];
+            }
+
+            return ret;
+        }
+        #endregion
+
+        #region Internal constants
+        #endregion
+
+        #region Clipboard Support
+        public string ToClipboard()
+        {
+            StringBuilder ret = new StringBuilder();
+            //
+            ret.AppendFormat( "NThread Address: 0x{0:x8}, NState: {1}" + System.Environment.NewLine, Address, NState );
+            //
+            return ret.ToString();
+        }
+        #endregion
+
+        #region From System.Object
+        public override string ToString()
+        {
+            return base.ToString();
+        }
+        #endregion
+
+        #region Data members
+        private readonly RegisterCollection iRegisters;
+        private readonly DThread iParentThread;
+
+        private uint iWaitObj = 0;// object on which this thread is waiting
+        private uint iAddress = 0;
+        private int iPriority = 0;
+        private uint iAttributes = 0;
+        private uint iAddressSpace = 0;
+        private uint iSavedSP = 0;
+        private int iReturnValue = 0;
+        
+        private TNThreadState iNState = TNThreadState.EDead;
+        private TUserContextType iUserContextType = TUserContextType.EContextNone;
+
+        private NThreadMutexInfo iMutexInfo = new NThreadMutexInfo();
+        private NThreadCountInfo iCountInfo = new NThreadCountInfo();
+        private LinkedListInfo iLinkedListInfo = new LinkedListInfo();
+        private NThreadTimeInfo iTimeInfo = new NThreadTimeInfo();
+        private NThreadExtraContextInfo iExtraContextInfo = new NThreadExtraContextInfo();
+        #endregion
+    }
+}