crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStructuresLib/Debug/Symbols/Utilities/SymbolCollectionHarmoniser.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStructuresLib/Debug/Symbols/Utilities/SymbolCollectionHarmoniser.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,532 @@
+/*
+* 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.Generic;
+using System.Text;
+using SymbianUtils;
+using SymbianStructuresLib.MemoryModel;
+
+namespace SymbianStructuresLib.Debug.Symbols.Utilities
+{
+ public class SymbolCollectionHarmoniser : DisposableObject
+ {
+ #region Enumerations
+ public enum TCollectionType
+ {
+ EXIP = 0,
+ ENotXIP,
+ EPossiblyXIP
+ }
+ #endregion
+
+ #region Constructors
+ public SymbolCollectionHarmoniser( SymbolCollection aCollection )
+ : this( aCollection, TCollectionType.ENotXIP )
+ {
+ }
+
+ public SymbolCollectionHarmoniser( SymbolCollection aCollection, TCollectionType aType )
+ {
+ iCollection = aCollection;
+ iType = aType;
+
+ // If the collection is not XIP, then we can definitely say it is relocatable
+ if ( aType == TCollectionType.ENotXIP )
+ {
+ iCollection.IsFixed = false;
+ }
+ else if ( aType == TCollectionType.EXIP )
+ {
+ iCollection.IsFixed = true;
+ }
+ }
+ #endregion
+
+ #region API
+ public bool Add( Symbol aSymbol )
+ {
+ Debug( aSymbol );
+
+ // Perform pre-filter, which might currently include a blanket ban
+ // on new symbols for this collection
+ bool save = PreFilterBasedUponFlags( aSymbol );
+ if ( save )
+ {
+ // Flags indicate we can accept the symbol, so perform
+ // normal checks based upon symbol meta-data
+ Symbol last = this.LastSymbol;
+ if ( last != null && !last.IsDefault )
+ {
+ if ( aSymbol.Size == 0 )
+ {
+ save = ShouldSaveWhenNewSymbolHasNoSize( last, aSymbol );
+ }
+ else
+ {
+ save = ShouldSaveWhenNewSymbolHasValidSize( last, aSymbol );
+ }
+ }
+ //
+ if ( save )
+ {
+ Collection.Add( aSymbol );
+ }
+ }
+
+ // Perform any final updates
+ PostFilterBasedUponFlags( aSymbol );
+ //
+ return save;
+ }
+ #endregion
+
+ #region Properties
+ public bool DisallowSymbolsOnceReadOnlyLimitReached
+ {
+ get
+ {
+ bool disallow = false;
+
+ // We can only do this once we have one non-default symbol and after
+ // we have set the base address.
+ if ( ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress )
+ {
+ bool isEmpty = Collection.IsEmptyApartFromDefaultSymbol;
+ if ( !isEmpty )
+ {
+ Symbol first = Collection.FirstSymbol;
+ disallow = ( first.Address == 0 );
+ }
+ }
+ //
+ return disallow;
+ }
+ }
+ #endregion
+
+ #region Internal enumerations
+ [Flags]
+ private enum TFlags
+ {
+ EFlagsNone = 0,
+ EFlagsUpdateLengthOfPreviousSymbol = 1,
+ EFlagsDisallowFurtherSymbolsForCollection = 2,
+ EFlagsHaveSetXIPBaseAddress = 4,
+ }
+ #endregion
+
+ #region Internal constants
+ private const uint KMaxAutomaticLengthUpdateDelta = 4 * 1024 * 1024;
+ private const string KSectionNameMarker = "$$";
+ private const string KSectionNameUserBase = "Image$$ER_RO$$Base";
+ private const string KSectionNameUserLimit = "Image$$ER_RO$$Limit";
+ #endregion
+
+ #region Internal properties
+ private SymbolCollection Collection
+ {
+ get { return iCollection; }
+ }
+
+ private Symbol LastSymbol
+ {
+ get
+ {
+ Symbol ret = null;
+ //
+ if ( Collection.Count > 0 )
+ {
+ ret = Collection.LastSymbol;
+ }
+ //
+ return ret;
+ }
+ }
+ #endregion
+
+ #region Internal methods
+ private void Debug( Symbol aSymbol )
+ {
+ }
+
+ private bool PreFilterBasedUponFlags( Symbol aSymbol )
+ {
+ // Do we need to update the length of the previous symbol?
+ if ( ( iFlags & TFlags.EFlagsUpdateLengthOfPreviousSymbol ) == TFlags.EFlagsUpdateLengthOfPreviousSymbol )
+ {
+ FlagBasedUpdateOfLastSymbolLength( aSymbol );
+ }
+
+ // Check for Image$$ER_RO$$Base
+ // This symbol is emitted for user-side code and can be used to work around some maksym problems.
+ string symbolName = aSymbol.Name;
+ if ( symbolName == KSectionNameUserBase )
+ {
+ int count = iCollection.Count;
+ if ( !iCollection.IsEmptyApartFromDefaultSymbol )
+ {
+ // 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, iCollection.FileName ) );
+ iCollection.Clear();
+
+ // At this point, we need to reset the base address because any symbols that have gone
+ // before are invalid.
+ iFlags &= ~TFlags.EFlagsHaveSetXIPBaseAddress;
+ }
+ }
+
+ // Do we need to set the base address for the symbol collection?
+ bool haveSetXIPBase = ( ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress );
+ if ( !haveSetXIPBase && iType != TCollectionType.ENotXIP )
+ {
+ // If we're seeing the first valid symbol, then try to set the base address
+ bool needToSet = true;
+ if ( iType == TCollectionType.EPossiblyXIP )
+ {
+ // Perhaps we're dealing with an XIP collection. In which case, we need to check
+ // with the memory model utility to decide if it really is or not.
+ //
+ // If the symbol address is zero (NULL), then we can't be dealing with an
+ // XIP collection.
+ if ( aSymbol.Address == 0 )
+ {
+ // ROFS
+ needToSet = true;
+ }
+ else
+ {
+ TMemoryModelRegion region = MMUtilities.RegionByAddress( aSymbol.Address );
+ needToSet = ( region == TMemoryModelRegion.EMemoryModelRegionROM );
+ }
+ }
+
+ if ( needToSet )
+ {
+ SetCollectionBaseAddress( aSymbol );
+ }
+ }
+
+ bool disallowNewSymbols = ( iFlags & TFlags.EFlagsDisallowFurtherSymbolsForCollection ) == TFlags.EFlagsDisallowFurtherSymbolsForCollection;
+ return !disallowNewSymbols;
+ }
+
+ private void PostFilterBasedUponFlags( Symbol aSymbol )
+ {
+ string symbolName = aSymbol.Name;
+ if ( symbolName.Contains( KSectionNameMarker ) )
+ {
+ if ( symbolName == KSectionNameUserLimit )
+ {
+ // User data follows - don't update length of previous symbol
+ iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
+
+ // If we're reading a ROFS symbol then most likely we don't want
+ // to allow any more entries since they start to be a little wacky...
+ bool disallow = this.DisallowSymbolsOnceReadOnlyLimitReached;
+ if ( disallow )
+ {
+ iFlags |= TFlags.EFlagsDisallowFurtherSymbolsForCollection;
+ }
+ }
+ else if ( symbolName.Contains( "$$Limit" ) )
+ {
+ // Don't change the length of a limit symbol should we happen to encounter a data item.
+ iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Called when the new proposed symbol has no size.
+ /// </summary>
+ private bool ShouldSaveWhenNewSymbolHasNoSize( Symbol aLastSymbol, Symbol aNewSymbol )
+ {
+ bool save = true;
+ //
+ if ( aLastSymbol.Contains( aNewSymbol.Address ) )
+ {
+ // The new symbol overlaps the previous one. Additionally, the new symbol has a size of zero.
+ //
+ // E.g. #1:
+ //
+ // _E32Dll 0x00008000 ARM Code 40 uc_dll_.o(.emb_text)
+ // Symbian$$CPP$$Exception$$Descriptor 0x00008014 Data 0 uc_dll_.o(.emb_text)
+ //
+ // E.g. #2:
+ //
+ // RArray<unsigned long>::RArray() 0x00009289 Thumb Code 10 abcd.in(t._ZN6RArrayImEC1Ev)
+ // RArray<unsigned long>::RArray__sub_object() 0x00009289 Thumb Code 0 abcd.in(t._ZN6RArrayImEC1Ev)
+ //
+ // => NEW SYMBOL IS DISCARDED
+ //
+ save = false;
+ }
+ else if ( aNewSymbol.Address > aLastSymbol.EndAddress )
+ {
+ // The new symbol has a size of zero, but it doesn't overlap with prior symbol address.
+ //
+ // _E32Dll_Body 0x00008ecd Thumb Code 34 uc_dll.o(.text)
+ // __DLL_Export_Table__ 0x00008f5c ARM Code 0 abcd{000a0000}.exp(ExportTable)
+ // DLL##ExportTableSize 0x00008f60 Data 0 abcd{000a0000}.exp(ExportTable)
+ // DLL##ExportTable 0x00008f64 Data 0 abcd{000a0000}.exp(ExportTable)
+ // CActive::Cancel() 0x00008f9c ARM Code 0 euser{000a0000}-1088.o(StubCode)
+ // aSymbol ==> CActive::SetActive() 0x00008fa4 ARM Code 0 euser{000a0000}-1090.o(StubCode)
+ // CActive::CActive__sub_object(int) 0x00008fac ARM Code 0 euser{000a0000}-1091.o(StubCode)
+ // CActive::~CActive__sub_object() 0x00008fb4 ARM Code 0 euser{000a0000}-1094.o(StubCode)
+ // RArrayBase::At(int) const 0x00008fbc ARM Code 0 euser{000a0000}-1507.o(StubCode)
+ //
+ // => NEW SYMBOL IS SAVED
+ //
+ iFlags |= TFlags.EFlagsUpdateLengthOfPreviousSymbol;
+ }
+ //
+ return save;
+ }
+
+ /// <summary>
+ /// Called when the new symbol has a valid size
+ /// </summary>
+ private bool ShouldSaveWhenNewSymbolHasValidSize( Symbol aLastSymbol, Symbol aNewSymbol )
+ {
+ bool save = true;
+
+ if ( aLastSymbol.Contains( aNewSymbol.Address ) )
+ {
+ // The new symbol and the last symbol somehow overlap.
+ if ( aLastSymbol.Address == aNewSymbol.Address && aLastSymbol.Size == aNewSymbol.Size )
+ {
+ // The symbols start at the same address:
+ //
+ // E.g. #1:
+ //
+ // CABCMonitor::~CABCMonitor() 0x000091a5 Thumb Code 0 abcmonitor.in(i._ZN11CABCMonitorD2Ev)
+ // CABCMonitor::~CABCMonitor__sub_object() 0x000091a5 Thumb Code 8 abcmonitor.in(i._ZN11CABCMonitorD2Ev)
+ //
+ // E.g. #2:
+ //
+ // 8022ab10 0060 Math::DivMod64(long long, long long, long long&)
+ // 8022ab70 0014 Math::UDivMod64(unsigned long long, unsigned long long, unsigned long long&)
+ // 8022ab84 0000 $v0
+ // >>> 8022ab84 0018 TRealX::Set(int)
+ // 8022ab9c 0044 TRealX::operator =(int)
+ //
+ // For example #1, we want to discard the new symbol and keep the original.
+ // For example #2, we want to discard the original symbol and keep the new one.
+ //
+ //
+ if ( !aLastSymbol.IsFunction )
+ {
+ // E.g. #2 => discard old symbol
+ Collection.RemoveAt( Collection.Count - 1 );
+ }
+ else
+ {
+ // E.g. #1 => discard new symbol
+ save = false;
+ }
+ }
+ else if ( aLastSymbol.Address == aNewSymbol.Address && aLastSymbol.Size == 0 )
+ {
+ // E.g. :
+ //
+ // 8342d6b8 0000 Image$$ER_RO$$Base anon$$obj.o(linker$$defined$$symbols)
+ // >>> 8342d6b8 0070 _E32Startup uc_exe_.o(.emb_text)
+ //
+ Collection.RemoveAt( Collection.Count - 1 );
+ }
+ else
+ {
+ // The symbols start at different addresses, but somehow they still overlap.
+ //
+ // E.g.:
+ //
+ // typeinfo name for CABCMonitorCapMapper 0x000094a8 Data 23 accmonitor.in(.constdata__ZTS20CABCMonitorCapMapper)
+ // typeinfo name for CABCMonitorContainer 0x000094bf Data 23 accmonitor.in(.constdata__ZTS20CABCMonitorContainer)
+ //
+ // In this scenario, the size of the 0x94a8 entry (23 bytes) causes it's address to overlap
+ // with the first byte from the entry starting at 0x94bf.
+ //
+ // In this scenario, we make an assumption that the size of the 0x94A8 entry is incorrect/invalid
+ uint overlap = aLastSymbol.AddressRange.Max - aNewSymbol.Address + 1;
+ aLastSymbol.Size = aLastSymbol.Size - overlap;
+ }
+ }
+ else
+ {
+ if ( aLastSymbol.Address > aNewSymbol.Address )
+ {
+
+ }
+ }
+ //
+ return save;
+ }
+
+ private void FlagBasedUpdateOfLastSymbolLength( Symbol aSymbol )
+ {
+ System.Diagnostics.Debug.Assert( ( iFlags & TFlags.EFlagsUpdateLengthOfPreviousSymbol ) == TFlags.EFlagsUpdateLengthOfPreviousSymbol );
+ bool clearFlag = true;
+
+ // Don't set the length of the default symbol!
+ if ( !Collection.IsEmptyApartFromDefaultSymbol )
+ {
+ // Must have some existing symbol.
+ int count = Collection.Count;
+ System.Diagnostics.Debug.Assert( count > 0 );
+
+ // Last symbol must have bad size?
+ Symbol previousSymbol = LastSymbol;
+ 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.
+ if ( aSymbol.Address < previousSymbol.Address )
+ {
+ // Data can confuse us, so skip when the address is earlier. E.g.:
+ //
+ // 83409b88 0000 .ARM.exidx$$Base uc_exe_.o(.ARM.exidx)
+ // 83409f80 0000 .ARM.exidx$$Limit xxx.in(.ARM.exidx)
+ // 83409f80 0000 Image$$ER_RO$$Limit anon$$obj.o(linker$$defined$$symbols)
+ // >> 00400000 0008 AllCapabilities xxx.in(.data)
+ // 00400008 0008 DisabledCapabilities xxx.in(.data)
+ //
+ clearFlag = true;
+ }
+ else
+ {
+ if ( aSymbol.Address == previousSymbol.Address )
+ {
+ if ( aSymbol.Size > 0 )
+ {
+ // Okay, the new symbol has a valid size, the old one didn't.
+ previousSymbol.Size = aSymbol.Size;
+ }
+ else
+ {
+ // Hmm, neither the last or new symbol have a valid size.
+ // Nothing we can do in this case...
+ clearFlag = false;
+ }
+ }
+ else
+ {
+ // Need to work out the length of the previous symbol by comparing the
+ // address of this symbol against it.
+ uint delta = aSymbol.Address - previousSymbol.Address;
+
+ if ( delta > KMaxAutomaticLengthUpdateDelta )
+ {
+ // The delta is huge. Don't allow this kind of update.
+ }
+ else if ( delta > 1 )
+ {
+ // It's okay, this symbol had a later address than the last one
+ // This is normal.
+ previousSymbol.Size = delta - 1;
+ }
+ else
+ {
+ // This is not good. Two symbols both have the same address. In this
+ // situation discard the old symbol and take the new one instead because
+ // in all aspects other than name, they are identical.
+ Collection.RemoveAt( count - 1 );
+ }
+ }
+ }
+ }
+
+ if ( clearFlag )
+ {
+ iFlags &= ~TFlags.EFlagsUpdateLengthOfPreviousSymbol;
+ }
+ }
+
+ private void SetCollectionBaseAddress( Symbol aSymbolToUse )
+ {
+ uint baseAddress = aSymbolToUse.Address;
+ bool haveSet = ( iFlags & TFlags.EFlagsHaveSetXIPBaseAddress ) == TFlags.EFlagsHaveSetXIPBaseAddress;
+ System.Diagnostics.Debug.Assert( haveSet == false );
+
+ // Relocate (changes base address)
+ iCollection.Relocate( baseAddress );
+ iFlags |= TFlags.EFlagsHaveSetXIPBaseAddress;
+
+ // The symbol address needs to be reset to zero (i.e. start of collection)
+ uint symbolSize = aSymbolToUse.Size;
+ aSymbolToUse.OffsetAddress = 0;
+ }
+ #endregion
+
+ #region From DisposableObject
+ protected override void CleanupManagedResources()
+ {
+ try
+ {
+ base.CleanupManagedResources();
+ }
+ finally
+ {
+ // When we aren't sure if we're being used to harmonise an XIP collection
+ // we must check whether the base address has been set to something other than
+ // zero and that the address is in the XIP range.
+ // NB: Other cases are handled in the constructor.
+ if ( iType == TCollectionType.EPossiblyXIP )
+ {
+ if ( !iCollection.IsEmptyApartFromDefaultSymbol )
+ {
+ Symbol first = iCollection.FirstSymbol;
+ uint address = first.Address;
+ if ( address > 0 )
+ {
+ TMemoryModelRegion region = MMUtilities.RegionByAddress( address );
+ bool isFixed = ( region == TMemoryModelRegion.EMemoryModelRegionROM );
+ iCollection.IsFixed = isFixed;
+ }
+ else
+ {
+ // First address is zero, indicates RAM-loaded code and therefore
+ // non-XIP.
+ iCollection.IsFixed = false;
+ }
+ }
+ else
+ {
+ // The collection only contains the default symbol so in that case
+ // it can be thought to be relocatable (although in practise that wouldn't
+ // be very helpful). The main point is that we don't want this collection
+ // to start matching null addresses (quite common when performing symbolic
+ // lookup).
+ iCollection.IsFixed = false;
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Data members
+ private readonly SymbolCollection iCollection;
+ private readonly TCollectionType iType;
+ private TFlags iFlags = TFlags.EFlagsNone;
+ #endregion
+ }
+}