crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,432 @@
+/*
+* 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.Text;
+using SymbianStackAlgorithmAccurate.Engine;
+using SymbianStackAlgorithmAccurate.Interfaces;
+using SymbianStackAlgorithmAccurate.Stack;
+using SymbianStackLib.Algorithms;
+using SymbianStackLib.Data.Output;
+using SymbianStackLib.Data.Output.Entry;
+using SymbianStackLib.Data.Source;
+using SymbianStackLib.Interfaces;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianStructuresLib.Debug.Symbols.Constants;
+using SymbianUtils.DataBuffer.Entry;
+using SymbianUtils.Range;
+
+namespace SymbianStackAlgorithmAccurate.Algorithm
+{
+ internal class AccurateAlgorithm : StackAlgorithm, IArmStackInterface
+ {
+ #region Constructors
+ public AccurateAlgorithm( IStackAlgorithmManager aManager, IStackAlgorithmObserver aObserver )
+ : base( aManager, aObserver )
+ {
+ }
+ #endregion
+
+ #region API
+ #endregion
+
+ #region Properties
+ #endregion
+
+ #region From StackAlgorithm
+ public override string Name
+ {
+ get { return "Accurate"; }
+ }
+
+ public override int Priority
+ {
+ get { return 0; }
+ }
+
+ public override bool IsAvailable()
+ {
+ bool ret = base.IsAvailable();
+ //
+ if ( ret )
+ {
+ // We need some registers
+ ret = !base.Engine.Registers.IsEmpty;
+ //
+ if ( ret )
+ {
+ // This algorithm can only work if we have code available
+ // to work with...
+ ret = base.DebugEngineView.Code.IsReady;
+ //
+ if ( ret == false )
+ {
+ base.Trace( "[AccurateAlgorithm] IsAvailable() - code not provided" );
+ }
+ }
+ else
+ {
+ base.Trace( "[AccurateAlgorithm] IsAvailable() - registers not provided" );
+ }
+ }
+ else
+ {
+ base.Trace( "[AccurateAlgorithm] IsAvailable() - symbols not provided" );
+ }
+ //
+ base.Trace( "[AccurateAlgorithm] IsAvailable() - ret: {0}", ret );
+ return ret;
+ }
+ #endregion
+
+ #region From IArmStackInterface
+ uint IArmStackInterface.StackBase
+ {
+ get { return base.Engine.AddressInfo.Base; }
+ }
+
+ uint IArmStackInterface.StackTop
+ {
+ get { return base.Engine.AddressInfo.Top; }
+ }
+
+ uint IArmStackInterface.StackValueAtAddress( uint aAddress )
+ {
+ DataBufferUint entry = base.SourceData[ aAddress ];
+ return entry.Uint;
+ }
+ #endregion
+
+ #region From AsyncReaderBase
+ protected override void HandleReadException( Exception aException )
+ {
+ // If an exception occurred during frame building or
+ // stack reconstruction, then we are aborting the entire operation.
+ //
+ // However, HandleReadcompleted() is always called irrespective
+ // of whether or not an operation succeeded or failed.
+ //
+ // Therefore, to ensure we do not generate a nested exception in
+ // an abort scenario we toggle the 'accurate entry check required'
+ // status flag to false so that we will not complain if the
+ // algorithm did not locate any accurate frames.
+ iAccurateEntryCheckRequired = false;
+ base.Trace( "[AccurateAlgorithm] HandleReadException() - aException: {0}, stack: {1}", aException.Message, aException.StackTrace );
+
+ // Now we can propagate the exception onwards.
+ base.HandleReadException( aException );
+ }
+
+ protected override void HandleReadCompleted()
+ {
+ // If we didn't identify any accurate entries, then we bail out
+ // and let the heuristic algorithm run instead.
+ //
+ // NB: we don't do this unless we succeeded to reconstruct
+ // the entire stack.
+ base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - iAccurateEntryCheckRequired: {0}, iAccurateEntryCount: {1}", iAccurateEntryCheckRequired, iAccurateEntryCount );
+ if ( iAccurateEntryCheckRequired )
+ {
+ if ( iAccurateEntryCount == 0 )
+ {
+ throw new Exception( "Unable to locate any accurate entries" );
+ }
+ }
+
+ // We're an accurate algorithm
+ base.OutputData.IsAccurate = true;
+
+ base.Trace( "[AccurateAlgorithm] HandleReadCompleted() - read ok!" );
+ base.HandleReadCompleted();
+ }
+
+ protected override void HandleReadStarted()
+ {
+ try
+ {
+ base.Trace( "[AccurateAlgorithm] HandleReadStarted() - START" );
+
+ // Indicate that we will throw an exception if we do not
+ // find at least one accurate entry. This is the default behaviour
+ // to ensure we don't result in stack data containing just ghost entries.
+ // We toggle this to false if we abort stack walking due to an exception,
+ // thereby preventing nested exception throwing.
+ iAccurateEntryCheckRequired = true;
+
+ // Create arm engine
+ iArmEngine = new AccurateEngine( base.DebugEngineView, this, base.Manager.Engine );
+
+ // Seed it with the registers
+ iArmEngine.CPU.Registers = base.Engine.Registers;
+
+ // Dump the registers in verbose mode
+ base.Trace( "STACK ENGINE REGISTERS:" );
+ foreach ( ArmRegister reg in base.Engine.Registers )
+ {
+ string symbol = base.DebugEngineView.Symbols.PlainText[ reg.Value ];
+ base.Trace( reg.ToString() + " " + symbol );
+ }
+ //
+ base.Trace( System.Environment.NewLine );
+ base.Trace( "[AccurateAlgorithm] HandleReadStarted() - setup complete." );
+ }
+ finally
+ {
+ base.HandleReadStarted();
+ }
+
+ base.Trace( "[AccurateAlgorithm] HandleReadStarted() - END" );
+ }
+
+ protected override void PerformOperation()
+ {
+ System.Diagnostics.Debug.Assert( iArmEngine != null );
+
+ // First step is to read as many valid stack frames as possible
+ BuildStackFrames();
+
+ // Second step is to try to fill any gaps in the stack data
+ CreateStackOutput();
+ }
+
+ protected override long Size
+ {
+ get
+ {
+ int bytes = base.SourceData.Count;
+ int dWords = bytes / 4;
+ return dWords;
+ }
+ }
+
+ protected override long Position
+ {
+ get
+ {
+ return iDWordIndex;
+ }
+ }
+ #endregion
+
+ #region From DisposableObject
+ protected override void CleanupManagedResources()
+ {
+ try
+ {
+ base.CleanupManagedResources();
+ }
+ finally
+ {
+ if ( iArmEngine != null )
+ {
+ iArmEngine.Dispose();
+ iArmEngine = null;
+ }
+ }
+ }
+ #endregion
+
+ #region Internal methods
+ private ArmStackFrame FrameByStackAddress( uint aAddress )
+ {
+ ArmStackFrame ret = null;
+ //
+ ArmStackFrame[] frames = iArmEngine.StackFrames;
+ foreach ( ArmStackFrame frame in frames )
+ {
+ if ( frame.Address == aAddress )
+ {
+ ret = frame;
+ break;
+ }
+ }
+ //
+ return ret;
+ }
+
+ private ArmStackFrame FrameByRegisterType( TArmRegisterType aRegister )
+ {
+ ArmStackFrame ret = null;
+ //
+ ArmStackFrame[] frames = iArmEngine.StackFrames;
+ foreach ( ArmStackFrame frame in frames )
+ {
+ if ( frame.IsRegisterBasedEntry && frame.AssociatedRegister == aRegister )
+ {
+ ret = frame;
+ break;
+ }
+ }
+ //
+ return ret;
+ }
+
+ private void BuildStackFrames()
+ {
+ bool success = iArmEngine.Process();
+ while ( success )
+ {
+ success = iArmEngine.Process();
+ }
+
+ base.Trace( string.Empty );
+ base.Trace( string.Empty );
+ }
+
+ private void CreateStackOutput()
+ {
+ // Get the source data we need to reconstruct and signal we're about to start
+ StackSourceData sourceData = base.SourceData;
+
+ // Get the output data sink
+ StackOutputData outputData = base.OutputData;
+ outputData.Clear();
+ outputData.AlgorithmName = Name;
+
+ // Get the address range of the stack pointer data
+ AddressRange pointerRange = base.Engine.AddressInfo.StackPointerRange;
+ AddressRange pointerRangeExtended = base.Engine.AddressInfo.StackPointerRangeWithExtensionArea;
+
+ foreach ( DataBufferUint sourceEntry in sourceData.GetUintEnumerator() )
+ {
+ // Check if it is within the stack domain, taking into account
+ // our extended range
+ if ( pointerRangeExtended.Contains( sourceEntry.Address ) )
+ {
+ StackOutputEntry outputEntry = new StackOutputEntry( sourceEntry.Address, sourceEntry.Uint, base.DebugEngineView );
+
+ // Is it the element that corresponds to the current value of SP?
+ bool isCurrentSPEntry = ( outputEntry.AddressRange.Contains( base.Engine.AddressInfo.Pointer ) );
+
+ // Is it within the pure 'stack pointer' address range?
+ bool outsidePureStackPointerRange = !pointerRange.Contains( sourceEntry.Address );
+ outputEntry.IsOutsideCurrentStackRange = outsidePureStackPointerRange;
+
+ // Is it a ghost?
+ if ( outputEntry.Symbol != null )
+ {
+ ArmStackFrame realStackFrame = FrameByStackAddress( sourceEntry.Address );
+ outputEntry.IsAccurate = ( realStackFrame != null );
+ outputEntry.IsGhost = ( realStackFrame == null );
+ }
+
+ // Save entry
+ EmitElement( outputEntry );
+
+ // If we're inside the stack address range, then poke in the PC and LR values
+ if ( isCurrentSPEntry )
+ {
+ outputEntry.IsCurrentStackPointerEntry = true;
+
+ // Working bottom up, so LR should go on the stack first
+ ArmStackFrame stackFrameLR = FrameByRegisterType( TArmRegisterType.EArmReg_LR );
+ if ( stackFrameLR != null )
+ {
+ StackOutputEntry entryLR = new StackOutputEntry( 0, stackFrameLR.Data, base.DebugEngineView );
+ entryLR.IsRegisterBasedEntry = true;
+ entryLR.IsOutsideCurrentStackRange = true;
+ entryLR.AssociatedRegister = stackFrameLR.AssociatedRegister;
+ EmitElement( entryLR );
+ }
+
+ // Then the PC...
+ ArmStackFrame stackFramePC = FrameByRegisterType( TArmRegisterType.EArmReg_PC );
+ if ( stackFramePC != null )
+ {
+ StackOutputEntry entryPC = new StackOutputEntry( 0, stackFramePC.Data, base.DebugEngineView );
+ entryPC.IsRegisterBasedEntry = true;
+ entryPC.IsOutsideCurrentStackRange = true;
+ entryPC.AssociatedRegister = stackFramePC.AssociatedRegister;
+ EmitElement( entryPC );
+ }
+ }
+ }
+ else
+ {
+ // Nope, ignore it...
+ }
+
+ NotifyEvent( TEvent.EReadingProgress );
+ ++iDWordIndex;
+ }
+ }
+
+ private void EmitElement( StackOutputEntry aEntry )
+ {
+ // Debug support
+ if ( base.Engine.Verbose )
+ {
+ StringBuilder line = new StringBuilder( "[AccurateAlgorithm] " );
+ //
+ if ( aEntry.IsCurrentStackPointerEntry )
+ {
+ line.Append( "[C] " );
+ }
+ else if ( aEntry.IsRegisterBasedEntry )
+ {
+ const int KNormalAddressWidth = 10;
+ string prefix = "[ " + aEntry.AssociatedRegisterName;
+ prefix = prefix.PadRight( KNormalAddressWidth - 2 );
+ prefix += " ]";
+ line.Append( prefix );
+ }
+ else if ( aEntry.IsGhost )
+ {
+ line.Append( "[G] " );
+ }
+ else if ( aEntry.IsOutsideCurrentStackRange )
+ {
+ line.Append( " " );
+ }
+ else
+ {
+ line.AppendFormat( "[{0:x8}]", aEntry.Address );
+ }
+
+ line.AppendFormat( " {0:x8} {1}", aEntry.Data, aEntry.DataAsString );
+
+ if ( aEntry.Symbol != null )
+ {
+ string baseAddressOffset = aEntry.Symbol.ToStringOffset( aEntry.Data );
+ line.AppendFormat( "{0} {1}", baseAddressOffset, aEntry.Symbol.Name );
+ }
+ else if ( aEntry.AssociatedBinary != string.Empty )
+ {
+ line.AppendFormat( "{0} {1}", SymbolConstants.KUnknownOffset, aEntry.AssociatedBinary );
+ }
+
+ base.Trace( line.ToString() );
+ }
+
+ // Count the number of accurate entries
+ if ( aEntry.IsAccurate )
+ {
+ ++iAccurateEntryCount;
+ }
+
+ // Flush entry
+ base.StackObserver.StackBuildingElementConstructed( this, aEntry );
+ }
+ #endregion
+
+ #region Data members
+ private AccurateEngine iArmEngine = null;
+ private int iDWordIndex = 0;
+ private bool iAccurateEntryCheckRequired = true;
+ private int iAccurateEntryCount = 0;
+ #endregion
+ }
+}