crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianSymbolLib/SourceManagement/Source/SymSource.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* 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 SymbianUtils;
using SymbianUtils.Range;
using SymbianStructuresLib.Debug.Symbols;
using SymbianStructuresLib.Debug.Symbols.Interfaces;
using SymbianStructuresLib.CodeSegments;
using SymbianStructuresLib.Debug.Common.FileName;
using SymbianSymbolLib.SourceManagement.Provisioning;

namespace SymbianSymbolLib.SourceManagement.Source
{
    public class SymSource : DisposableObject, IEnumerable<SymbolCollection>, ISymbolCollectionRelocationHandler
    {
        #region Delegates & events
        public delegate void EventHandlerFunction( TEvent aEvent, SymSource aSource, object aData );
        public event EventHandlerFunction EventHandler;
        #endregion

        #region Enumerations
        public enum TEvent
        {
            EReadingStarted = 0,
            EReadingProgress,
            EReadingComplete
        }

        public enum TTimeToRead
        {
            EReadWhenPriming = 0,
            EReadWhenNeeded // i.e. relocated
        }
        #endregion

        #region Constructors
        public SymSource( string aURI, SymSourceProvider aProvider )
        {
            iURI = aURI;
            iProvider = aProvider;
        }

        public SymSource( string aURI, SymSourceProvider aProvider, SymbolCollection aCollection )
            : this( aURI, aProvider )
        {
            Add( aCollection );
        }
        #endregion

        #region API
        public virtual void Read( TSynchronicity aSynchronicity )
        {
            iProvider.ReadSource( this, aSynchronicity );
        }

        public virtual void Add( SymbolCollection aCollection )
        {
            // We want to be told if the collection changes it's relocation state.
            aCollection.RelocationStatusChanged += new SymbolCollection.RelocationStatusChangeHandler( Collection_RelocationStatusChanged );

            lock ( iCollectionsAll )
            {
                iCollectionsAll.Add( aCollection );
            }

            CategoriseCollection( aCollection );
        }

        public virtual void Remove( SymbolCollection aCollection )
        {
            aCollection.RelocationStatusChanged -= new SymbolCollection.RelocationStatusChangeHandler( Collection_RelocationStatusChanged );
            //
            lock ( iCollectionsAll )
            {
                iCollectionsAll.Remove( aCollection );
            }
            lock ( iAlwaysActivatedCollections )
            {
                iAlwaysActivatedCollections.Remove( aCollection );
            }
        }

        public virtual bool Contains( uint aAddress )
        {
            lock ( iAlwaysActivatedCollections )
            {
                return iAlwaysActivatedCollections.Contains( aAddress );
            }
        }

        public virtual Symbol Lookup( uint aAddress, out SymbolCollection aCollection )
        {
            lock ( iAlwaysActivatedCollections )
            {
                aCollection = null;
                //
                Symbol ret = iAlwaysActivatedCollections.Lookup( aAddress, out aCollection );
                return ret;
            }
        }

        protected virtual void OnAddedToCollection( SymSourceCollection aCollection )
        {
            ++iReferenceCount;
        }

        protected virtual void OnRemovedFromCollection( SymSourceCollection aCollection )
        {
            if ( --iReferenceCount <= 0 )
            {
                this.Dispose();
            }
        }

        protected virtual void OnPrepareForRelocation( SymbolCollection aCollection, uint aOldBase, uint aNewBase )
        {
            // If we read our data during priming, then we don't need to do anything... otherwise, we should
            // read the data now.
            if ( TimeToRead == TTimeToRead.EReadWhenNeeded )
            {
                this.Read( TSynchronicity.ESynchronous );
            }
        }
        #endregion

        #region API - framework
        public void ReportEvent( TEvent aEvent )
        {
            if ( aEvent == TEvent.EReadingComplete )
            {
                iAlwaysActivatedCollections.BuildLookupCache();
            }

            ReportEvent( aEvent, null );
        }

        public void ReportEvent( TEvent aEvent, object aData )
        {
            if ( EventHandler != null )
            {
                EventHandler( aEvent, this, aData );
            }
        }
        #endregion

        #region Event handlers
        private void Collection_RelocationStatusChanged( SymbolCollection aCollection )
        {
            CategoriseCollection( aCollection );
        }
        #endregion

        #region Properties
        public int Count
        {
            get
            {
                lock ( iCollectionsAll )
                {
                    return iCollectionsAll.Count;
                }
            }
        }

        public string URI
        {
            get
            {
                lock ( iURI )
                {
                    return iURI;
                }
            }
            set
            {
                lock ( iURI )
                {
                    iURI = value;
                }
            }

        }

        public string FileName
        {
            get { return iProvider.GetFileName( this ); }
        }

        public TTimeToRead TimeToRead
        {
            get { return iTimeToRead; }
            set
            {
                iTimeToRead = value;
            }
        }

        public SymSourceProvider Provider
        {
            get
            {
                lock ( iProvider )
                {
                    return iProvider;
                }
            }
        }

        public SymbolCollection this[ int aIndex ]
        {
            get 
            {
                lock ( iCollectionsAll )
                {
                    return iCollectionsAll[ aIndex ];
                }
            }
        }

        public virtual SymbolCollection this[ CodeSegDefinition aCodeSegment ]
        {
            get
            {
                lock ( iCollectionsAll )
                {
                    SymbolCollection ret = iCollectionsAll[ aCodeSegment ];
                    return ret;
                }
            }
        }

        public virtual SymbolCollection this[ PlatformFileName aFileName ]
        {
            get
            {
                lock ( iCollectionsAll )
                {
                    SymbolCollection ret = iCollectionsAll[ aFileName ];
                    return ret;
                }
            }
        }
        #endregion

        #region Internal methods
        internal int CountActivated
        {
            get
            {
                lock ( iAlwaysActivatedCollections )
                {
                    return iAlwaysActivatedCollections.Count;
                }
            }
        }

        internal void AddedToCollection( SymSourceCollection aCollection )
        {
            OnAddedToCollection( aCollection );
        }

        internal void RemovedFromCollection( SymSourceCollection aCollection )
        {
            OnRemovedFromCollection( aCollection );
        }

        private void CategoriseCollection( SymbolCollection aCollection )
        {
            // Reset state
            lock ( iAlwaysActivatedCollections )
            {
                iAlwaysActivatedCollections.Remove( aCollection );
                aCollection.IfaceRelocationHandler = null;
            }

            // Collections which do not move from their pre-determined base address
            // are transparently "activated" which means that they will be queried
            // automatically during symbolic look up.
            if ( aCollection.IsFixed )
            {
                lock ( iAlwaysActivatedCollections )
                {
                    iAlwaysActivatedCollections.Add( aCollection );
                }
            }
            else
            {
                aCollection.IfaceRelocationHandler = this;
            }
        }
        #endregion
    
        #region From ISymbolCollectionRelocationHandler
        public void PrepareForRelocation( SymbolCollection aCollection, uint aOldBase, uint aNewBase )
        {
            OnPrepareForRelocation( aCollection, aOldBase, aNewBase );
        }
        #endregion

        #region From IEnumerable<SymbolCollection>
        public IEnumerator<SymbolCollection> GetEnumerator()
        {
            lock ( iCollectionsAll )
            {
                foreach ( SymbolCollection col in iCollectionsAll )
                {
                    yield return col;
                }
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            lock ( iCollectionsAll )
            {
                foreach ( SymbolCollection col in iCollectionsAll )
                {
                    yield return col;
                }
            }
        }
        #endregion

        #region From DisposableObject
        protected override void CleanupManagedResources()
        {
            try
            {
                base.CleanupManagedResources();
            }
            finally
            {
                int count = iCollectionsAll.Count;
                for ( int i = count - 1; i >= 0; i-- )
                {
                    SymbolCollection col = iCollectionsAll[ i ];
                    Remove( col );
                    col.Dispose();
                }

                // These should both be empty in any case
                iCollectionsAll.Clear();
                iAlwaysActivatedCollections.Clear();
            }
        }
        #endregion

        #region From System.Object
        public override string ToString()
        {
            return URI;
        }

        public override int GetHashCode()
        {
            return URI.GetHashCode();
        }

        public override bool Equals( object aObject )
        {
            if ( aObject is SymSource )
            {
                SymSource other = (SymSource) aObject;
                bool ret = ( string.Compare( other.URI, this.URI, StringComparison.CurrentCultureIgnoreCase ) == 0 );
                return ret;
            }
            //
            return base.Equals( aObject );
        }
        #endregion

        #region Data members
        private readonly SymSourceProvider iProvider;
        private string iURI = string.Empty;
        private int iReferenceCount = 0;
        private TTimeToRead iTimeToRead = TTimeToRead.EReadWhenPriming;
        private SymbolCollectionList iCollectionsAll = new SymbolCollectionList();
        private SymbolCollectionList iAlwaysActivatedCollections = new SymbolCollectionList();
        #endregion
    }
}