diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Container/CIContainer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Container/CIContainer.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,428 @@ +/* +* 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: +* +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using CrashItemLib.Crash.Base; +using CrashItemLib.Crash.Events; +using CrashItemLib.Crash.Header; +using CrashItemLib.Crash.InfoHW; +using CrashItemLib.Crash.InfoSW; +using CrashItemLib.Crash.Messages; +using CrashItemLib.Crash.Source; +using CrashItemLib.Crash.Summarisable; +using CrashItemLib.Crash.Symbols; +using CrashItemLib.Crash.Traces; +using CrashItemLib.Crash.Reports; +using CrashItemLib.Crash.Registers; +using CrashItemLib.Engine; +using SymbianDebugLib.Engine; + +namespace CrashItemLib.Crash.Container +{ + public sealed class CIContainer : CIElement, ICISymbolManager + { + #region Enumerations + internal enum TCIElementEventType + { + ECIEventChildAdded = 0, + ECIEventChildRemoved, + } + + public enum TStatus + { + EStatusDefault = 0, + EStatusErrorContainer + } + #endregion + + #region Delegates & events + internal delegate void ElementEventHandler( CIContainer aContainer, CIElement aElement, TCIElementEventType aType ); + internal event ElementEventHandler ElementEvents; + #endregion + + #region Static constructors + internal static CIContainer New( CIEngine aEngine, CISource aSource ) + { + CIContainer ret = new CIContainer( aEngine, aSource ); + return ret; + } + + public static CIContainer NewErrorContainer( CIEngine aEngine, CISource aSource ) + { + CIContainer ret = new CIContainer( aEngine, aSource ); + ret.Status = TStatus.EStatusErrorContainer; + return ret; + } + #endregion + + #region Constructors + private CIContainer( CIEngine aEngine, CISource aSource ) + : base( KRootElementId ) + { + iEngine = aEngine; + + // Immediately set up container association (to point to ourself) + // just incase... + base.Container = this; + + // And indicate, that since we *are* the container, we want all our children + // to automatically be "in it" too. + base.IsInContainer = true; + + // Add source descriptor + CISourceElement source = new CISourceElement( this, aSource ); + AddChild( source ); + + // Add other mandatory elements + AddMandatoryElements(); + } + #endregion + + #region API + public IEnumerable GetSummarisableEnumerator() + { + CIElementList list = base.ChildrenByType(); + return list; + } + #endregion + + #region Constants + public const int KRootElementId = CIElementIdProvider.KInitialStartingValue; + #endregion + + #region Properties + public object Tag + { + get { return iTag; } + set { iTag = value; } + } + + public TStatus Status + { + get { return iStatus; } + set { iStatus = value; } + } + + public string[] FileNames + { + get + { + List files = new List(); + if ( iFileNames != null ) + { + files.AddRange( iFileNames ); + } + return files.ToArray(); + } + } + + public override CIEngine Engine + { + get { return iEngine; } + } + + public CISummarisableEntity PrimarySummary + { + get + { + CISummarisableEntity ret = null; + + // The primary summary is the first summary we can locate + // that relates to a crash. + CISummarisableEntityList summaries = Summaries; + foreach ( CISummarisableEntity entity in summaries ) + { + bool isCrash = entity.IsAbnormalTermination; + if ( isCrash ) + { + // Prefer threads to raw stack items. + if ( ret != null ) + { + // If the 'best match' so far is just a stack, then replace it with whatever + // we've just found. This means we could replace a raw stack with another raw + // stack. We could never replace a thread entity with a stack entity though. + if ( ret.IsAvailable( CISummarisableEntity.TElement.EElementThread ) == false ) + { + ret = entity; + } + } + else + { + ret = entity; + } + } + } + + return ret; + } + } + #endregion + + #region Mandatory elements + public CIHeader Header + { + get { return (CIHeader) ChildByType( typeof( CIHeader ) ); } + } + + public CIEventList Events + { + get { return (CIEventList) ChildByType( typeof( CIEventList ) ); } + } + + public CITraceData Traces + { + get { return (CITraceData) ChildByType( typeof( CITraceData ) ); } + } + + public CISourceElement Source + { + get { return (CISourceElement) ChildByType( typeof( CISourceElement ) ); } + } + + public CISymbolDictionary Symbols + { + get { return (CISymbolDictionary) ChildByType( typeof( CISymbolDictionary ) ); } + } + + public CIMessageDictionary Messages + { + get { return (CIMessageDictionary) ChildByType( typeof( CIMessageDictionary ) ); } + } + + public CISummarisableEntityList Summaries + { + get { return (CISummarisableEntityList) ChildByType( typeof( CISummarisableEntityList ) ); } + } + + public CIRegisterListCollection Registers + { + get + { + return (CIRegisterListCollection) ChildByType( typeof( CIRegisterListCollection ) ); + } + } + + public CIReportInfo ReportInfo + { + get { return (CIReportInfo) ChildByType( typeof( CIReportInfo ) ); } + } + #endregion + + #region Internal methods + internal void RunFinalizers( CIElementFinalizationParameters aParams ) + { + Queue mustBeCalledLast = new Queue(); + base.DoFinalize( aParams, mustBeCalledLast, false ); + + // Now call the elements that are to be finalized last + while ( mustBeCalledLast.Count > 0 ) + { + CIElement child = mustBeCalledLast.Dequeue(); + child.DoFinalize( aParams, mustBeCalledLast, true ); + } + } + + internal int GetNextElementId() + { + return Engine.GetNextElementId(); + } + + private void AddMandatoryElements() + { + Type attribType = typeof( CIElementAttributeMandatory ); + Type[] types = Assembly.GetExecutingAssembly().GetTypes(); + // + foreach( Type t in types) + { + // Get all the constructors for the type + if ( !t.IsAbstract && typeof( CIElement ).IsAssignableFrom( t ) ) + { + ConstructorInfo[] ctors = t.GetConstructors( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public ); + foreach ( ConstructorInfo ctor in ctors ) + { + // If the specified ctor is decorated with the "mandatory" attribute + // then it must be a mandatory class, so new an instance up... + object[] attribs = ctor.GetCustomAttributes( attribType, false ); + if ( attribs.Length > 0 ) + { + // Check that it has the expected signature. + // We expect mandatory constructors to take only a single parameter + // which is the container itself, i.e. this object + ParameterInfo[] parameters = ctor.GetParameters(); + if ( parameters.Length == 1 && parameters[ 0 ].ParameterType == this.GetType() ) + { + CIElement element = ctor.Invoke( new object[] { this } ) as CIElement; + if ( element != null ) + { + element.Parent = this; + AddChild( element ); + } + } + } + } + } + } + // + AddChild( new CISymbolDictionary( this ) ); + } + + private void CacheFileNames( DbgEngine aDebugEngine ) + { + if ( iFileNames == null ) + { + iFileNames = new List(); + + CISourceElement source = Source; + foreach ( FileInfo file in source.AllFiles ) + { + iFileNames.Add( file.FullName ); + } + + // Meta-data files + SymbianUtils.FileSystem.FSEntity[] entities = aDebugEngine.FileSystemEntities; + foreach ( SymbianUtils.FileSystem.FSEntity e in entities ) + { + if ( e.IsFile ) + { + FileInfo file = ( (SymbianUtils.FileSystem.FSEntityFile) e ).File; + iFileNames.Add( file.FullName ); + } + } + } + } + #endregion + + #region Internal container event propagation + internal void OnContainerElementRegistered( CIElement aElement ) + { + if ( ElementEvents != null ) + { + ElementEvents( this, aElement, TCIElementEventType.ECIEventChildAdded ); + } + } + + internal void OnContainerElementUnregistered( CIElement aElement ) + { + if ( ElementEvents != null ) + { + ElementEvents( this, aElement, TCIElementEventType.ECIEventChildRemoved ); + } + } + #endregion + + #region From ICISymbolManager + public CISymbolDictionary SymbolDictionary + { + get { return this.Symbols; } + } + #endregion + + #region From CIElement + /// + /// Ensure that we only allow single instances of some objects to be added + /// as direct children. + /// + public override void AddChild( CIElement aChild ) + { + bool exception = false; + // + if ( aChild is CIEventList && Events != null ) + { + exception = true; + } + else if ( aChild is CISymbolDictionary && Symbols != null ) + { + exception = true; + } + else if ( aChild is CIMessageDictionary && Messages != null ) + { + exception = true; + } + else if ( aChild is CISourceElement && Source != null ) + { + exception = true; + } + else if ( aChild is CISummarisableEntityList && Summaries != null ) + { + exception = true; + } + else if ( aChild is CIHeader && Header != null ) + { + exception = true; + } + else if ( aChild is CIReportInfo && ReportInfo != null ) + { + exception = true; + } + else + { + // These aren't mandatory, but there should only be one... + int count = -1; + if ( aChild is CIInfoHW ) + { + count = base.ChildrenByType().Count; + } + else if ( aChild is CIInfoSW ) + { + count = base.ChildrenByType().Count; + } + + if ( count > 1 ) + { + throw new ArgumentException( "An instance of the specified object has already been added to the container" ); + } + } + + if ( exception ) + { + throw new ArgumentException( "Can only add a single instance of " + aChild.GetType() + " to the container" ); + } + + base.AddChild( aChild ); + } + + /// + /// Called by CIElement when an object is *directly* added + /// as a child of the container. + /// + protected override void OnElementAddedToSelf( CIElement aElement ) + { + // The master switch that ensures all elements and their children + // are flagged as in the container. + aElement.IsInContainer = true; + } + + internal override void OnFinalize( CIElementFinalizationParameters aParams ) + { + base.OnFinalize( aParams ); + + // Cache file names + CacheFileNames( aParams.DebugEngine ); + } + #endregion + + #region Data members + private readonly CIEngine iEngine; + private object iTag = null; + private TStatus iStatus = TStatus.EStatusDefault; + private List iFileNames = null; + #endregion + } +}