crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Algorithm/AccurateAlgorithm.cs
changeset 0 818e61de6cd1
--- /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
+    }
+}