--- /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
+}