diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/Libraries/Engine/CrashDebuggerLib/Structures/NThread/NThread.cs --- /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 + // + // 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) + // + 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 + } +}