crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbolLib/Sources/Symbol/File/SymbolsForBinary.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbolLib/Sources/Symbol/File/SymbolsForBinary.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,611 @@
+/*
+* 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.IO;
+using System.Collections;
+using System.Collections.Generic;
+using SymbianUtils;
+using SymbianUtils.Range;
+using SymbolLib.Generics;
+using SymbolLib.Sources.Symbol.Symbol;
+
+namespace SymbolLib.Sources.Symbol.File
+{
+    public class SymbolsForBinary : GenericSymbolCollection
+	{
+		#region Construct & destruct
+        public SymbolsForBinary( string aHostFileName )
+            : base( aHostFileName )
+		{
+            // Add default unknown entry
+            SymbolSymbol nullEntry = SymbolSymbol.NewUnknown( this );
+            iEntries.Add( nullEntry );
+		}
+		#endregion
+
+        #region Properties
+        internal GenericSymbol InternalLastSymbol
+        {
+            get
+            {
+                // We don't want to return the last symbol
+                GenericSymbol ret = base.LastSymbol;
+                //
+                if ( ret != null && ret.IsUnknownSymbol )
+                {
+                    ret = null;
+                }
+                //
+                return ret;
+            }
+        }
+        #endregion
+
+        #region API
+        internal void Add( GenericSymbolEngine aEngine, GenericSymbol aSymbol, bool aAllowNonRomSymbols )
+        {
+            System.Diagnostics.Debug.Assert( aSymbol is SymbolSymbol );
+ 
+            // Check for Image$$ER_RO$$Base or Image$$ER_RO$$Limit. 
+            // This symbol is emitted for user-side code and can be used to work around some maksym problems.
+            string symbolName = aSymbol.Symbol;
+            if ( symbolName.StartsWith( KSymbolNameImageBaseOrLimitPrefix ) )
+            {
+                bool isBase = symbolName.Contains( "Base" );
+
+                // If we've just seen the base entry, but we already have some stored symbols, then
+                // probably this is a maksym problem that we must try to work around.
+                if ( isBase )
+                {
+                    int count = iEntries.Count;
+                    if ( count > 0 && !iEntries[ 0 ].IsUnknownSymbol )
+                    {
+                        // Discard all the entries we've seen so far because most likely
+                        // they are invalid.
+                        System.Diagnostics.Debug.WriteLine( string.Format( "Discarding {0} invalid symbols for library: {1}", count, base.HostBinaryFileName ) );
+                        iEntries.Clear();
+
+                        // At this point, we need to reset the base address because any symbols that have gone 
+                        // before are invalid.
+                        iFlags &= ~TFlags.EFlagsHaveSeenFirstSymbol;
+                    }
+                }
+                else
+                {
+                    // Reached the limit - stop storing symbols at this point as everything else is likely data.
+                    iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
+                }
+            }
+
+            // Don't save the entry if we're in disabled state.
+            bool newAdditionsDisabled = ( iFlags & TFlags.EFlagsDisallowFurtherSymbolsForCollection ) == TFlags.EFlagsDisallowFurtherSymbolsForCollection;
+            if ( !newAdditionsDisabled )
+            {
+                // Whether or not we keep the entry
+                bool addEntry = false;
+
+                // Set base address
+                UpdateCollectionBaseAddressBasedUponFirstSymbol( aSymbol );
+
+                GenericSymbol lastSymbol = InternalLastSymbol;
+                if ( lastSymbol != null )
+                {
+                    if ( lastSymbol.Address > aSymbol.Address )
+                    {
+                        // Work-around for maksym problem where it fails to parse some MAP files correctly.
+                    }
+                    else
+                    {
+                        // If we have a last symbol, and it's address is prior to that of the new symbol, we can
+                        // try to update the last symbol's size (if it needs it updating - the method will check that).
+                        UpdateLengthOfPreviousSymbol( aSymbol );
+  
+                        // Check to see if we already have a symbol within this address range
+                        bool overlappingSymbol = LastSymbolSharesSameAddressRange( aSymbol );
+                        if ( overlappingSymbol )
+                        {
+                            // They overlap - which one do we keep? 
+                            addEntry = FilterOutCommonAddressEntry( lastSymbol, aSymbol );
+                        }
+                        else
+                        {
+                            addEntry = TakeEntry( aSymbol, aAllowNonRomSymbols );
+                        }
+                    }
+                }
+                else
+                {
+                    addEntry = TakeEntry( aSymbol, aAllowNonRomSymbols );
+                }
+
+                // If we need to keep the symbol, then save it now...
+                if ( addEntry )
+                {
+                    DoAddEntry( aSymbol );
+                }
+            }
+        }
+
+        internal void Fixup( long aNewBaseAddress )
+        {
+            BaseAddress = aNewBaseAddress;
+            if ( aNewBaseAddress != 0 )
+            {
+                iFlags |= TFlags.EFlagsHaveDoneFixup;
+            }
+
+            base.RebuildAddressRange();
+        }
+        #endregion
+
+        #region From GenericSymbolCollection
+        public override void WriteToStream( StreamWriter aWriter )
+        {
+            if ( ( iFlags & TFlags.EFlagsHaveDoneFixup ) == TFlags.EFlagsHaveDoneFixup )
+            {
+                long originalBaseAddress = BaseAddress;
+                try
+                {
+                    // For fixed up symbol collections, i.e. those with a base address of zero
+                    // that have subsequently been fixed up at runtime (rofs) then we
+                    // must ensure we write base addresses of zero again when externalising
+                    // the symbol data.
+                    BaseAddress = 0;
+                    base.WriteToStream( aWriter );
+                }
+                finally
+                {
+                    BaseAddress = originalBaseAddress;
+                }
+            }
+            else
+            {
+                base.WriteToStream( aWriter );
+            }
+        }
+
+        public override void Add( GenericSymbolEngine aEngine, GenericSymbol aSymbol )
+        {
+            Add( aEngine, aSymbol, true );
+        }
+
+		public override void Remove( GenericSymbol aSymbol )
+		{
+			iEntries.Remove( aSymbol );
+		}
+
+		public override void RemoveAt( int aIndex )
+		{
+			iEntries.RemoveAt( aIndex );
+		}
+
+        public override int Count
+        {
+            get
+            {
+                return iEntries.Count;
+            }
+        }
+
+        public override void Sort()
+        {
+            iEntries.Sort( new GenericSymbolComparer() );
+#if PROFILING
+            System.DateTime startTime = DateTime.Now;
+            System.DateTime endTime = DateTime.Now;
+            long tickDuration = ( ( endTime.Ticks - startTime.Ticks ) / 100 );
+            System.Diagnostics.Debug.WriteLine( "SORT TIME " + tickDuration.ToString( "d6" ) );
+#endif
+        }
+
+        public override GenericSymbol SymbolForAddress( long aAddress )
+        {
+#if DEBUG
+            int x = 0;
+            if ( x > 0 )
+            {
+                base.Dump( aAddress );
+            }
+#endif
+            GenericSymbol ret = null;
+            //
+            AddressFindingComparer comparer = new AddressFindingComparer();
+            SymbolSymbol temp = SymbolSymbol.NewUnknown( (uint) aAddress, 0, string.Empty );
+            int pos = iEntries.BinarySearch( temp, comparer );
+            if ( pos >= 0 && pos < iEntries.Count )
+            {
+                ret = iEntries[ pos ];
+                System.Diagnostics.Debug.Assert( ret.AddressRange.Contains( aAddress ) );
+            }
+            //
+            return ret;
+        }
+
+        public override IEnumerator CreateEnumerator()
+        {
+            IEnumerator<GenericSymbol> self = (IEnumerator<GenericSymbol>) this;
+            return self;
+        }
+
+        public override IEnumerator<GenericSymbol> CreateGenericEnumerator()
+        {
+            foreach ( GenericSymbol sym in iEntries )
+            {
+                yield return sym;
+            }
+        }
+
+        public override GenericSymbol this[ int aIndex ]
+        {
+            get
+            {
+                return iEntries[ aIndex ];
+            }
+        }
+        #endregion
+
+        #region Internal enumerations
+        [Flags]
+		private enum TFlags
+		{
+			EFlagsNone = 0,
+			EFlagsCalculateLengthOfPreviousSymbol = 1,
+			EFlagsDisallowFurtherSymbolsForCollection = 2,
+			EFlagsHaveSeenFirstSymbol = 4,
+            EFlagsHaveDoneFixup = 8
+		}
+		#endregion
+
+        #region Internal constants
+        private const string KSymbolNameImageBaseOrLimitPrefix = "Image$$ER_RO$$";
+        private const long KMaxDifferenceBetweenConsecutiveSymbols = 1024 * 64;
+        #endregion
+
+        #region Internal methods
+        private void UpdateCollectionBaseAddressBasedUponFirstSymbol( GenericSymbol aSymbol )
+        {
+            // If we are not processing the first Symbol in the collection, then we
+            // can rely on the base address being set. Otherwise, we are
+            // defining the base address itself.
+            if ( !( ( iFlags & TFlags.EFlagsHaveSeenFirstSymbol ) == TFlags.EFlagsHaveSeenFirstSymbol ) )
+            {
+                // Set collection base address to symbol starting address
+                BaseAddress = aSymbol.Address;
+
+                // Since this is the first symbol in the collection, and we're going to use
+                // its address as the offset (base) address for the entire collection, 
+                // if we just set the collection base address to the symbol's address and
+                // the continue, this entry will be double offset (the new offset for the collection
+                // + the offset of the symbol itself). We must therefore set the symbol's offset
+                // address to zero.
+                SymbolSymbol realSymbol = (SymbolSymbol) aSymbol;
+                realSymbol.ResetOffsetAddress( 0 );
+
+                // Make sure we set a flag so that we don't attempt to do this again.
+                iFlags |= TFlags.EFlagsHaveSeenFirstSymbol;
+            }
+        }
+
+        private void UpdateLengthOfPreviousSymbol( GenericSymbol aNewSymbol )
+        {
+            bool clearFlag = false;
+            //
+            if ( ( iFlags & TFlags.EFlagsCalculateLengthOfPreviousSymbol ) == TFlags.EFlagsCalculateLengthOfPreviousSymbol )
+            {
+                // Must have some existing symbol.
+                System.Diagnostics.Debug.Assert( Count > 0 );
+
+                // Last symbol must have bad size?
+                GenericSymbol previousSymbol = InternalLastSymbol;
+                System.Diagnostics.Debug.Assert( previousSymbol.Size == 0 );
+
+                // The new symbol must be exactly the same address as the last symbol
+                // (in which case, the new symbol must have a valid size or else we're
+                // unable to do anything sensible with it) 
+                //
+                // OR
+                //
+                // The new symbol must be after the last symbol. It cannot be before.
+                System.Diagnostics.Debug.Assert( aNewSymbol.Address >= previousSymbol.Address );
+                if ( aNewSymbol.Address == previousSymbol.Address )
+                {
+                    if ( aNewSymbol.Size > 0 )
+                    {
+                        // Okay, the new symbol has a valid size, the old one didn't.
+                        clearFlag = true;
+                        previousSymbol.Size = aNewSymbol.Size;
+                    }
+                    else
+                    {
+                        // Hmm, neither the last or new symbol have a valid size.
+                        // Nothing we can do in this case...
+                    }
+                }
+                else
+                {
+                    // Need to work out the length of the previous symbol by comparing the
+                    // address of this symbol against it.
+                    //
+                    // Only do this if the region type hasn't changed.
+                    MemoryModel.TMemoryModelRegion previousType = MemoryModel.RegionByAddress( previousSymbol.Address, aNewSymbol.MemoryModelType );
+                    MemoryModel.TMemoryModelRegion regionType = MemoryModel.RegionByAddress( aNewSymbol.Address, aNewSymbol.MemoryModelType );
+                    if ( regionType == previousType )
+                    {
+                        // If this new symbol and the old symbol have the same address, then
+                        // also check the size of the previous symbol. If it was zero, then discard it
+                        // and keep this new entry. Otherwise, discard this new one instead.
+                        long delta = aNewSymbol.Address - previousSymbol.Address;
+                        if ( delta > 1 )
+                        {
+                            // It's okay, this symbol had a later address than the last one
+                            // This is normal.
+                            previousSymbol.Size = delta;
+                        }
+                        else
+                        {
+                            // This is not good. Two symbols both have the same address.
+                            iEntries.Remove( previousSymbol );
+                        }
+                    }
+
+                    clearFlag = true;
+                }
+            }
+
+            if ( clearFlag )
+            {
+                iFlags &= ~TFlags.EFlagsCalculateLengthOfPreviousSymbol;
+            }
+        }
+
+        private void DoAddEntry( GenericSymbol aSymbol )
+        {
+            // Make sure we remove the null symbol if this is the first 'valid' symbol for
+            // the collection.
+            if ( OnlyContainsDefaultSymbol )
+            {
+                RemoveAt( 0 );
+            }
+
+            // If the symbol has no size, then try to work it out next time around
+            if ( aSymbol.Size == 0 )
+            {
+                iFlags |= TFlags.EFlagsCalculateLengthOfPreviousSymbol;
+            }
+
+            // Save it
+            iEntries.Add( aSymbol );
+        }
+
+        private bool LastSymbolSharesSameAddressRange( GenericSymbol aSymbol )
+        {
+            bool ret = false;
+            //
+            GenericSymbol last = InternalLastSymbol;
+            if ( last != null && last.FallsWithinDomain( aSymbol.Address ) )
+            {
+                ret = true;
+            }
+            //
+            return ret;
+        }
+
+        private bool FilterOutCommonAddressEntry( GenericSymbol aLast, GenericSymbol aNew )
+        {
+            bool acceptNew = false;
+            //
+            if ( aLast.IsUnknownSymbol )
+            {
+                // Always discard the unknown symbol in preference of anything better
+                iEntries.Remove( aLast );
+                acceptNew = true;
+            }
+            else if ( aNew.Size > 0 )
+            {
+                if ( aLast.Size == 0 )
+                {
+                    // New is 'better' because it contains proper sizing information
+                    iEntries.Remove( aLast );
+                    acceptNew = true;
+                }
+                else if ( aLast.Size < aNew.Size )
+                {
+                    // New is 'better' because it is bigger
+                    iEntries.Remove( aLast );
+                    acceptNew = true;
+                }
+                else if ( aLast.Size == aNew.Size )
+                {
+                    // Both the same size. Take symbols over everything else.
+                    if ( aNew.IsSymbol && !aLast.IsSymbol )
+                    {
+                        // Keep the symbol (new)
+                        iEntries.Remove( aLast );
+                        acceptNew = true;
+                    }
+                    else if ( !aNew.IsSymbol && aLast.IsSymbol )
+                    {
+                        // Keep the symbol (last)
+                        acceptNew = false;
+                    }
+                    else
+                    {
+                        // Take higher priority...
+                        if ( aNew.AddressType > aLast.AddressType )
+                        {
+                            iEntries.Remove( aLast );
+                            acceptNew = true;
+                        }
+                        else
+                        {
+                            acceptNew = false;
+                        }
+                    }
+                }
+            }
+            else if ( aLast.Size > 0 )
+            {
+                // Last is 'better' because the new entry doesn't have any size
+                acceptNew = false;
+            }
+            else if ( aLast.Size == 0 && aNew.Size == 0 )
+            {
+                // Both entries have no size and the same address. We cannot
+                // accept both, therefore we make an arbitrary decision about
+                // which to keep.
+                if ( aLast.IsSubObject && !aNew.IsSubObject )
+                {
+                    // Discard the sub object (last)
+                    iEntries.Remove( aLast );
+                    acceptNew = true;
+                }
+                else if ( aNew.IsSubObject && !aLast.IsSubObject )
+                {
+                    // Discard the sub object (new)
+                    acceptNew = false;
+                }
+                else if ( aNew.IsSymbol && !aLast.IsSymbol )
+                {
+                    // Keep the symbol (new)
+                    iEntries.Remove( aLast );
+                    acceptNew = true;
+                }
+                else if ( !aNew.IsSymbol && aLast.IsSymbol )
+                {
+                    // Keep the symbol (last)
+                    acceptNew = false;
+                }
+                else
+                {
+                    // Couldn't make a good decision. Junk the new entry
+                    acceptNew = false;
+                }
+            }
+            //
+            return acceptNew;
+        }
+
+        private bool IsEntryReallyData( GenericSymbol aSymbol )
+        {
+            bool isData = false;
+
+            // Check to see if its from a data=<something> IBY entry...
+            string baseName = Path.GetFileName( HostBinaryFileName ).ToLower();
+            string symbolName = aSymbol.Symbol.ToLower();
+
+            if ( symbolName == baseName && aSymbol.Size == 0 )
+            {
+                // Its from a data entry
+                isData = true;
+
+                // Data entries only consist of a single symbol (the data itself)
+                iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
+            }
+
+            return isData;
+        }
+
+        private bool TakeEntry( GenericSymbol aSymbol, bool aAllowNonRomSymbols )
+        {
+            bool take = IsEntryReallyData( aSymbol );
+
+            if ( !take )
+            {
+                // We'll take the entry if all we have at the moment is
+                // the default entry or then no entries at all.
+                if ( OnlyContainsDefaultSymbol || iEntries.Count == 0 )
+                {
+                    take = true;
+                }
+                else
+                {
+                    GenericSymbol last = LastSymbol;
+                    System.Diagnostics.Debug.Assert( last != null );
+                    GenericSymbol.TAddressType addressType = aSymbol.AddressType;
+                    //
+                    switch ( addressType )
+                    {
+                    // We always take these...
+                    case GenericSymbol.TAddressType.EAddressTypeROMSymbol:
+                        take = true;
+                        break;
+
+                    // We sometimes take these...
+                    case GenericSymbol.TAddressType.EAddressTypeRAMSymbol:
+                        take = aAllowNonRomSymbols;
+                        break;
+
+                    case GenericSymbol.TAddressType.EAddressTypeLabel:
+                        take = true;
+                        break;
+                    case GenericSymbol.TAddressType.EAddressTypeSubObject:
+                        take = ( aSymbol.Size > 0 ) || ( last.EndAddress < aSymbol.Address );
+                        break;
+
+                    // We never take these
+                    default:
+                    case GenericSymbol.TAddressType.EAddressTypeReadOnlySymbol:
+                    case GenericSymbol.TAddressType.EAddressTypeUnknown:
+                    case GenericSymbol.TAddressType.EAddressTypeKernelGlobalVariable:
+                        break;
+                    }
+                }
+            }
+            //
+            return take;
+        }
+
+        private bool OnlyContainsDefaultSymbol
+        {
+            get
+            {
+                bool ret = ( Count == 1 && this[ 0 ].IsUnknownSymbol );
+                return ret;
+            }
+        }
+        #endregion
+
+        #region Data members
+        private TFlags iFlags = TFlags.EFlagsNone;
+        private List<GenericSymbol> iEntries = new List<GenericSymbol>( 200 );
+        #endregion
+    }
+
+    #region Internal classes
+    internal class AddressFindingComparer : IComparer<GenericSymbol>
+    {
+        public int Compare( GenericSymbol aLeft, GenericSymbol aRight )
+        {
+            int ret = -1;
+            //
+            AddressRange lr = aLeft.AddressRange;
+            AddressRange rr = aRight.AddressRange;
+            //
+            if ( lr.Contains( rr ) || rr.Contains( lr ) )
+            {
+                ret = 0;
+            }
+            else
+            {
+                ret = lr.CompareTo( rr );
+            }
+            //
+            return ret;
+        }
+    }
+    #endregion
+}