crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbolLib/Sources/Symbol/Engine/SymbolFileEngine.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbolLib/Sources/Symbol/Engine/SymbolFileEngine.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,541 @@
+/*
+* 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.Text;
+using System.Threading;
+using System.Collections;
+using System.Collections.Generic;
+using SymbianUtils;
+using SymbianUtils.Range;
+using SymbianUtils.Tracer;
+using SymbianUtils.FileSystem;
+using SymbianUtils.FileSystem.Utilities;
+using SymbolLib.Generics;
+using SymbolLib.CodeSegDef;
+using SymbolLib.Sources.Symbol.Symbol;
+using SymbolLib.Sources.Symbol.File;
+using SymbolLib.Sources.Symbol.Parser;
+using SymbolLib.Sources.Symbol.Collection;
+
+namespace SymbolLib.Sources.Symbol.Engine
+{
+ internal class SymbolFileEngine : GenericSymbolEngine, SymbolCollectionCreator, SymbolEntryCreator
+ {
+ #region Events
+ public event AsyncReaderBase.Observer Observer;
+ #endregion
+
+ #region Enumerations
+ public enum TActivationType
+ {
+ EImmediate,
+ EOnDemand
+ }
+ #endregion
+
+ #region Constructors
+ public SymbolFileEngine( ITracer aTracer, TActivationType aActivationType, bool aAllowNonRomSymbols )
+ : base( aTracer )
+ {
+ iAllowNonRomSymbols = aAllowNonRomSymbols;
+ iActivationType = aActivationType;
+ }
+ #endregion
+
+ #region API
+ public static bool IsSymbolFile( string aFileName )
+ {
+ string extension = Path.GetExtension( aFileName ).ToLower();
+ return ( extension == KSymbolFileExtensionPrimary );
+ }
+
+ public SymbolsForBinary ReadFirstCollection( string aFileName )
+ {
+ bool isValid = false;
+ return ReadFirstCollection( aFileName, out isValid );
+ }
+
+ public SymbolsForBinary ReadFirstCollection( string aFileName, out bool aIsSymbolFile )
+ {
+ iCurrentBinary = null;
+ iSymbolFileName = aFileName;
+ //
+ iParser = new SymbolFileParser( this, this, aFileName, this );
+ iParser.CollectionCompleted += new SymbolLib.Sources.Symbol.Parser.SymbolFileParser.CollectionCompletedHandler( Parser_CollectionCompletedSingleOnly );
+ iParser.SymbolCreated += new SymbolLib.Sources.Symbol.Parser.SymbolFileParser.SymbolCreatedHandler( Parser_SymbolCreated );
+ iParser.Read( TSynchronicity.ESynchronous );
+ //
+ SymbolsForBinary ret = null;
+ if ( iAllSymbols.Count > 0 )
+ {
+ ret = iAllSymbols[ 0 ];
+ aIsSymbolFile = true;
+ }
+
+ // Did we see any collections whatsoever (all be they data or code?)
+ aIsSymbolFile = iParser.ContainedAtLeastOneCollectionFileName;
+
+ return ret;
+ }
+
+ public void LoadFromFile( string aSymbolFileName, TSynchronicity aSynchronicity )
+ {
+ iSymbolFileName = aSymbolFileName;
+ //
+ iParser = new SymbolFileParser( this, this, aSymbolFileName, this );
+ iParser.Tag = this;
+ iParser.iObserver += new SymbianUtils.AsyncReaderBase.Observer( ParserEventHandler );
+ iParser.CollectionCompleted += new SymbolLib.Sources.Symbol.Parser.SymbolFileParser.CollectionCompletedHandler( Parser_CollectionCompleted );
+ iParser.SymbolCreated += new SymbolLib.Sources.Symbol.Parser.SymbolFileParser.SymbolCreatedHandler( Parser_SymbolCreated );
+ iParser.Read( aSynchronicity );
+ }
+
+ public bool IsLoaded( CodeSegDefinition aDefinition )
+ {
+ // In ROM, variation might mean that the file name
+ // doesn't match the definition name from the actual run-time code
+ // segments loaded by a process...
+ //
+ // If we don't find a file name match, but we do find an address match
+ // then we'll treat it as "good enough"
+ bool activated = false;
+ string searchingFor = aDefinition.ImageFileName.ToLower();
+ string searchingForWithoutExtension = FSUtilities.StripAllExtensions( searchingFor );
+
+ // Try to promote a symbol
+ foreach ( SymbolsForBinary file in iActivatedSymbols )
+ {
+ string entryName = System.IO.Path.GetFileName( file.HostBinaryFileName ).ToLower();
+ if ( entryName == searchingFor )
+ {
+ activated = true;
+ break;
+ }
+ else if ( file.AddressRangeStart == aDefinition.AddressStart && file.AddressRangeEnd == aDefinition.AddressEnd )
+ {
+ // E.g: ROM.symbol says: "From \epoc32\release\armv5\urel\xxx.22.dll"
+ // runtime code seg says: "xxx.dll"
+ // We must use the base address instead...
+
+ activated = true;
+ break;
+ }
+ else
+ {
+ // Try a fuzzy match
+ string entryNameWithoutExtension = FSUtilities.StripAllExtensions( entryName );
+ if ( entryNameWithoutExtension.Contains( searchingForWithoutExtension ) )
+ {
+ // Also make sure the base addresses are the same
+ if ( file.AddressRangeStart == aDefinition.AddressStart )
+ {
+ // Fuzzy match
+ activated = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return activated;
+ }
+
+ public bool Load( CodeSegDefinition aDefinition )
+ {
+ bool activated = false;
+ string searchingFor = aDefinition.EnvironmentFileName.ToLower();
+ if ( string.IsNullOrEmpty( searchingFor ) )
+ {
+ // Try to use on-target name instead, if valid
+ searchingFor = aDefinition.ImageFileName.ToLower();
+ }
+
+ // Try to promote a symbol
+ foreach( SymbolsForBinary file in iIdleSymbols )
+ {
+ string entryName = System.IO.Path.GetFileName( file.HostBinaryFileName ).ToLower();
+ if ( entryName == searchingFor )
+ {
+#if DEBUG
+ System.Diagnostics.Debug.WriteLine( " LOAD {S}: " + aDefinition.ToString() );
+#endif
+
+ // Fix up the symbols in this collection
+ file.Fixup( aDefinition.AddressStart );
+
+ // Update ranges
+ iRange.UpdateMin( file.AddressRangeStart );
+ iRange.UpdateMax( file.AddressRangeEnd );
+
+ // Housekeeping
+ iActivatedSymbols.Add( file );
+ iIdleSymbols.Remove( file );
+ iActivatedSymbols.Sort();
+
+ // Even though the symbols for this binary may not be explicitly referenced
+ // they are definitely required by the callee, therefore we tag them
+ // immediately.
+ file.Tagged = true;
+
+ // Indicate we loaded the code seg from a symbol file
+ aDefinition.Source = CodeSegDefinition.TSourceType.ESourceWasSymbolFile;
+
+ activated = true;
+ break;
+ }
+ }
+
+ return activated;
+ }
+
+ public bool Unload( CodeSegDefinition aDefinition )
+ {
+ bool suspended = false;
+ string searchingFor = aDefinition.EnvironmentFileName.ToLower();
+
+ // Try to promote a symbol
+ foreach( SymbolsForBinary file in iActivatedSymbols )
+ {
+ string entryName = System.IO.Path.GetFileName( file.HostBinaryFileName ).ToLower();
+ if ( entryName == searchingFor )
+ {
+#if DEBUG
+ System.Diagnostics.Debug.WriteLine( " UNLOAD {S}: " + aDefinition.ToString() );
+#endif
+ //
+ iActivatedSymbols.Remove( file );
+ iIdleSymbols.Add( file );
+ //
+ iRange.UpdateMin( file.AddressRangeStart );
+ iRange.UpdateMax( file.AddressRangeEnd );
+ //
+ suspended = true;
+
+ // NB: We don't untag the file since it was obviously needed at
+ // some point.
+ break;
+ }
+ }
+
+ return suspended;
+ }
+
+ public void UnloadAll()
+ {
+ iActivatedSymbols.Clear();
+ iIdleSymbols.Clear();
+ //
+ foreach( SymbolsForBinary file in iAllSymbols )
+ {
+ iIdleSymbols.Add( file );
+ }
+ }
+ #endregion
+
+ #region Properties
+ public string SymbolFileName
+ {
+ get { return iSymbolFileName; }
+ }
+
+ public bool AllowNonRomSymbols
+ {
+ get { return iAllowNonRomSymbols; }
+ }
+
+ public int Progress
+ {
+ get
+ {
+ int prog = 0;
+ //
+ if ( iParser != null )
+ {
+ prog = iParser.Progress;
+ }
+ //
+ return prog;
+ }
+ }
+
+ public string[] BinaryFileNames
+ {
+ get
+ {
+ List<string> fileNames = new List<string>( AllSymbols.Count );
+ //
+ foreach ( GenericSymbolCollection collection in AllSymbols )
+ {
+ fileNames.Add( collection.HostBinaryFileName );
+ }
+ //
+ return fileNames.ToArray();
+ }
+ }
+
+ public SymbolsForBinaryCollection AllSymbols
+ {
+ get { return iAllSymbols; }
+ }
+ #endregion
+
+ #region From GenericSymbolEngine
+ public override void Reset()
+ {
+ iActivatedSymbols.Clear();
+ iIdleSymbols.Clear();
+ iAllSymbols.Clear();
+ iSymbolFileName = string.Empty;
+ iCurrentBinary = null;
+ iRange = new AddressRange();
+ }
+
+ public override bool IsLoaded( string aFileName )
+ {
+ return ( aFileName.ToLower() == iSymbolFileName.ToLower() );
+ }
+
+ public override bool IsReady
+ {
+ get
+ {
+ bool ready = ( SymbolFileName.Length > 0 );
+ //
+ if ( ready && iParser != null )
+ {
+ ready = iParser.IsReady;
+ }
+ //
+ return ready;
+ }
+ }
+
+ public override GenericSymbolCollection this[ int aIndex ]
+ {
+ get
+ {
+ return iActivatedSymbols[ aIndex ];
+ }
+ }
+
+ public override void SaveTaggedCollections( string aFileName )
+ {
+ // We override this so that we search through 'iAllSymbols' rather
+ // than just the activated symbols (which would be the case if we
+ // used the base class version of this method).
+ using ( StreamWriter writer = new StreamWriter( aFileName, false ) )
+ {
+ foreach ( GenericSymbolCollection collection in iAllSymbols )
+ {
+ if ( collection.Tagged )
+ {
+ System.Diagnostics.Debug.WriteLine( "STORING: " + collection.HostBinaryFileName );
+ collection.WriteToStream( writer );
+ }
+ }
+ }
+ }
+
+ public override AddressRange Range
+ {
+ get
+ {
+ return iRange;
+ }
+ }
+
+ internal override void UnloadUntagged()
+ {
+
+ }
+ #endregion
+
+ #region From IGenericSymbolCollectionStatisticsInterface
+ public override int NumberOfCollections
+ {
+ get { return iActivatedSymbols.Count; }
+ }
+ #endregion
+
+ #region AsyncReaderBase observer
+ private void ParserEventHandler( SymbianUtils.AsyncReaderBase.TEvent aEvent, SymbianUtils.AsyncReaderBase aObject )
+ {
+ if ( Observer != null )
+ {
+ Observer( aEvent, aObject );
+ }
+
+ if ( aEvent == AsyncReaderBase.TEvent.EReadingComplete )
+ {
+ iActivatedSymbols.Sort();
+ iParser = null;
+ }
+ }
+ #endregion
+
+ #region Parser observer - for normal parsing
+ private bool Parser_CollectionCompleted( SymbolsForBinary aCollection )
+ {
+ // Check whether the collection contains any item. If it doesn't, ditch it.
+ // Remove empty collections or sort completed ones.
+ bool takeCollection = false;
+ int count = aCollection.Count;
+ if ( count > 0 )
+ {
+ // Check whether the collection contains at least 2 symbols, and if not
+ // does the one and only symbol just have a length of zero?
+ if ( count == 1 )
+ {
+ GenericSymbol symbol = aCollection.FirstSymbol;
+ takeCollection = ( symbol.Size > 0 ) || symbol.IsUnknownSymbol;
+ }
+ else
+ {
+ takeCollection = true;
+ }
+ }
+
+ // If its okay to take the collection, let's sort it and activate if necessary.
+ if ( takeCollection )
+ {
+#if INSPECT_SYMBOL_DATA
+ using ( StreamWriter writer = new StreamWriter( @"C:\Temp\OldSymbols\" + Path.GetFileName( aCollection.HostBinaryFileName ) + ".symbol" ) )
+ {
+ aCollection.WriteToStream( writer );
+ }
+#endif
+ // All the symbol collections - whether they are loaded or idle.
+ iAllSymbols.Add( aCollection );
+
+ // Then put the collection in the correct container depending on
+ // activation type.
+ if ( iActivationType == TActivationType.EImmediate )
+ {
+ aCollection.Sort();
+ iActivatedSymbols.Add( aCollection );
+ //
+ iRange.UpdateMin( aCollection.AddressRangeStart );
+ iRange.UpdateMax( aCollection.AddressRangeEnd );
+ }
+ else if ( iActivationType == TActivationType.EOnDemand )
+ {
+ ThreadPool.QueueUserWorkItem( new WaitCallback( SortCollection ), aCollection );
+ iIdleSymbols.Add( aCollection );
+ }
+ }
+ else
+ {
+ //System.Diagnostics.Debug.WriteLine( "Discarded Symbol Collection: " + aCollection.TargetBinary );
+ //System.Diagnostics.Debug.WriteLine( " " );
+ }
+
+ iCurrentBinary = null;
+ return SymbolFileParser.KCollectionCompletedAndContinueParsing;
+ }
+
+ private void Parser_SymbolCreated( SymbolSymbol aSymbol )
+ {
+ // 1) We accept symbols with an address of zero, providing that their size is greater
+ // than zero.
+ //
+ // 2) We accept symbols with an address greater than zero, irrespective of their size.
+ if ( ( aSymbol.Address >= 0 || aSymbol.Size > 0 ) || // 1
+ ( aSymbol.Address == 0 && aSymbol.Size > 0 ) // 2
+ )
+ {
+ iCurrentBinary.Add( this, aSymbol, AllowNonRomSymbols );
+ }
+ else
+ {
+ System.Diagnostics.Debug.WriteLine( " Discarded symbol: " + aSymbol );
+ }
+ }
+ #endregion
+
+ #region Parser observer - for peeking at a symbol file's first collection
+ private bool Parser_CollectionCompletedSingleOnly( SymbolLib.Sources.Symbol.File.SymbolsForBinary aCollection )
+ {
+ // Call our standard function to handle the collection
+ Parser_CollectionCompleted( aCollection );
+
+ // Indicate no more parsing required
+ bool ret = SymbolFileParser.KCollectionCompletedAndContinueParsing;
+ if ( aCollection.Count > 0 && iAllSymbols.Count > 0 )
+ {
+ ret = SymbolFileParser.KCollectionCompletedAndAbortParsing;
+ }
+ //
+ return ret;
+ }
+ #endregion
+
+ #region SymbolCollectionCreator interface
+ public SymbolsForBinary CreateCollection( string aHostFileName )
+ {
+ iCurrentBinary = new SymbolsForBinary( aHostFileName );
+ iCurrentBinary.SourceFile = SymbolFileName;
+ return iCurrentBinary;
+ }
+ #endregion
+
+ #region SymbolEntryCreator interface
+ public SymbolSymbol CreateSymbol()
+ {
+ return SymbolSymbol.New( iCurrentBinary );
+ }
+ #endregion
+
+ #region Internal methods
+ private void CalculateRange()
+ {
+ iRange.Reset();
+ //
+ foreach( SymbolsForBinary file in iActivatedSymbols )
+ {
+ iRange.UpdateMin( file.AddressRangeStart );
+ iRange.UpdateMax( file.AddressRangeEnd );
+ }
+ }
+
+ private void SortCollection( object aCollection )
+ {
+ SymbolsForBinary symbols = aCollection as SymbolsForBinary;
+ if ( symbols != null )
+ {
+ symbols.Sort();
+ }
+ }
+ #endregion
+
+ #region Internal constants
+ private const string KSymbolFileExtensionPrimary = ".symbol";
+ #endregion
+
+ #region Data members
+ private readonly TActivationType iActivationType;
+ private readonly bool iAllowNonRomSymbols;
+ private string iSymbolFileName = string.Empty;
+ private SymbolsForBinary iCurrentBinary = null;
+ private SymbolFileParser iParser = null;
+ private AddressRange iRange = new AddressRange();
+ private SymbolsForBinaryCollection iAllSymbols = new SymbolsForBinaryCollection();
+ private SymbolsForBinaryCollection iIdleSymbols = new SymbolsForBinaryCollection();
+ private SymbolsForBinaryCollection iActivatedSymbols = new SymbolsForBinaryCollection();
+ #endregion
+ }
+}