crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Engine/AccurateEngine.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Engine/AccurateEngine.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,359 @@
+/*
+* 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 SymbianDebugLib.Engine;
+using SymbianDebugLib.PluginAPI.Types.Symbol;
+using SymbianStackAlgorithmAccurate.Code;
+using SymbianStackAlgorithmAccurate.CPU;
+using SymbianStackAlgorithmAccurate.Interfaces;
+using SymbianStackAlgorithmAccurate.Prologue;
+using SymbianStackAlgorithmAccurate.Stack;
+using SymbianStructuresLib.Arm;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianUtils;
+using SymbianUtils.Tracer;
+
+namespace SymbianStackAlgorithmAccurate.Engine
+{
+    internal class AccurateEngine : DisposableObject, ITracer
+    {
+        #region Constructors
+        public AccurateEngine( DbgEngineView aDebugEngineView, IArmStackInterface aStackInterface, ITracer aTracer )
+        {
+            iTracer = aTracer;
+            iDebugEngineView = aDebugEngineView;
+            iStackInterface = aStackInterface;
+            iCodeHelper = new ArmCodeHelper( aDebugEngineView, aTracer );
+        }
+        #endregion
+
+        #region API
+        public bool Process()
+        {
+            // We need SP, LR, PC, CPSR
+            CheckRequiredRegistersAvailable();
+
+            // Debug info
+            PrintInitialInfo();
+
+            // Make initial stack frames for seed registers
+            MakeInitialSeedStackFramesFromRegisterValues();
+
+            // Get sp
+            ArmRegister sp = CPU[ TArmRegisterType.EArmReg_SP ];
+            uint initialSPValue = sp.Value;
+
+            // Create Prologue object that will establish the instructions for the
+            // function and also identify operations that might affect SP and LR.
+            ArmPrologueHelper Prologue = new ArmPrologueHelper( this );
+            Prologue.Build();
+            
+            // Create a new stack frame for this function call
+            ArmStackFrame stackFrame = new ArmStackFrame( Prologue );
+
+            // We save the stack address which contained the popped link register
+            // during the previous cycle. If possible, use that value. If it
+            // hasn't been set, then assume we obtained the link register from the
+            // previous 4 bytes of stack (according to the current value of SP).
+            long stackAddressAssociatedWithCurrentFrame = iLastLinkRegisterStackAddress;
+            if ( stackAddressAssociatedWithCurrentFrame == KLinkRegisterWasNotPushedOnStack )
+            {
+                // We're always four bytes behind the current SP
+                stackAddressAssociatedWithCurrentFrame = sp - 4;
+            }
+            stackFrame.Address = (uint) stackAddressAssociatedWithCurrentFrame;
+            stackFrame.Data = iStackInterface.StackValueAtAddress( stackFrame.Address );
+
+            Trace( "Creating Stack Frame [" + stackFrame.Address.ToString( "x8" ) + "] = 0x" + stackFrame.Data.ToString( "x8" ) + " = " + SymbolString ( stackFrame.Data ) );
+
+            // Can now adjust stack pointer based upon the number of stack-adjusting
+            // instructions during the Prologue phase.
+            uint stackAdjustment = (uint) ( Prologue.NumberOfWordsPushedOnStack * 4 );
+            sp.Value += stackAdjustment;
+            Trace( "stack adjusted by: 0x" + stackAdjustment.ToString( "x8" ) );
+
+            // We're hoping that the link register was pushed on the stack somewhere
+            // during the function preamble. If that was the case, then as we processed
+            // each instruction, we'll have updated the register offsets so that we know
+            // the offset to the link register from the perspective of the starting stack
+            // address for the function.
+            uint lrOffsetInWords = Prologue.OffsetValues[ TArmRegisterType.EArmReg_LR ];
+            Trace( string.Format( "LR offset on stack is: 0x{0:x8}", lrOffsetInWords * 4 ) );
+            GetNewLRValue( lrOffsetInWords, Prologue );
+
+            // Update the PC to point to the new function address (which we obtain
+            // from LR)
+            uint oldPCValue = CPU.PC;
+            ChangePCToLRAddress();
+            uint newPCValue = CPU.PC;
+            Trace( string.Format( "oldPCValue: 0x{0:x8}, newPCValue: 0x{1:x8}, fn: {2}", oldPCValue, newPCValue, SymbolViewText[ newPCValue ] ) );
+
+            // Decide if we are in thumb or ARM mode after switching functions
+            UpdateInstructionSet( newPCValue );
+
+            // Return true if we moved to a new function
+            bool gotNewFunction = ( oldPCValue != CPU.PC );
+            Trace( "gotNewFunction: " + gotNewFunction );
+
+            // Save stack frame
+            SaveStackFrames( stackFrame );
+
+            // Increment iteration
+            ++iIterationNumber;
+
+            // Do we have more to do?
+            bool moreToDo = gotNewFunction && ( CPU.PC > 0 );
+
+            // Done
+            Trace( "moreToDo: " + moreToDo );
+            return moreToDo;
+        }
+        #endregion
+
+        #region Properties
+        public ArmCpu CPU
+        {
+            get { return iCPU; }
+        }
+
+        public ArmStackFrame[] StackFrames
+        {
+            get
+            {
+                return iStackFrames.ToArray();
+            }
+        }
+
+        internal ArmCodeHelper CodeHelper
+        {
+            get { return iCodeHelper; }
+        }
+
+        internal DbgEngineView DebugEngineView
+        {
+            get { return iDebugEngineView; }
+        }
+
+        internal DbgViewSymbol SymbolView
+        {
+            get { return DebugEngineView.Symbols; }
+        }
+
+        internal DbgSymbolViewText SymbolViewText
+        {
+            get { return SymbolView.PlainText; }
+        }
+        #endregion
+
+        #region Internal methods
+        private void PrintInitialInfo()
+        {
+            ArmRegister sp = CPU[ TArmRegisterType.EArmReg_SP ];
+            //
+            ArmRegister lr = CPU[ TArmRegisterType.EArmReg_LR ];
+            string lrSymbol = SymbolViewText[ lr ];
+            //
+            ArmRegister pc = CPU[ TArmRegisterType.EArmReg_PC ];
+            string pcSymbol = SymbolViewText[ pc ];
+            //
+            ArmRegister cpsr = CPU[ TArmRegisterType.EArmReg_CPSR ];
+            //
+            Trace( System.Environment.NewLine );
+            Trace( string.Format( "[{5:d2}] SP: 0x{0:x8}, LR: 0x{1:x8} [{2}], PC: 0x{3:x8} [{4}], isThumb: {6}", sp.Value, lr.Value, lrSymbol, pc.Value, pcSymbol, iIterationNumber, CPU.CurrentProcessorMode == TArmInstructionSet.ETHUMB ) );
+        }
+
+        private void CheckRequiredRegistersAvailable()
+        {
+            ArmRegisterCollection regs = CPU.Registers;
+
+            // We need SP, LR, PC, CPSR
+            bool sp = regs.Contains( TArmRegisterType.EArmReg_SP );
+            bool lr = regs.Contains( TArmRegisterType.EArmReg_LR );
+            bool pc = regs.Contains( TArmRegisterType.EArmReg_PC );
+            bool cpsr = regs.Contains( TArmRegisterType.EArmReg_CPSR );
+            //
+            bool available = ( sp && lr && pc && cpsr );
+            if ( !available )
+            {
+                SymbianUtils.SymDebug.SymDebugger.Break();
+                throw new ArgumentException( "One or more registers is unavailable" );
+            }
+        }
+
+        private void MakeInitialSeedStackFramesFromRegisterValues()
+        {
+            if ( !iAlreadySavedInitialRegisterFrames )
+            {
+                ArmRegisterCollection regs = CPU.Registers;
+
+                // Make PC stack frame
+                ArmStackFrame framePC = new ArmStackFrame( TArmRegisterType.EArmReg_PC );
+                framePC.Data = regs[ TArmRegisterType.EArmReg_PC ].Value;
+
+                // Make LR stack frame
+                ArmStackFrame frameLR = new ArmStackFrame( TArmRegisterType.EArmReg_LR );
+                frameLR.Data = regs[ TArmRegisterType.EArmReg_LR ].Value;
+
+                // Save 'em
+                SaveStackFrames( framePC, frameLR );
+
+                // Don't do this again
+                iAlreadySavedInitialRegisterFrames = true;
+            }
+        }
+
+        private void GetNewLRValue( uint aLinkRegOffsetInWords, ArmPrologueHelper aPrologue )
+        {
+            uint sp = CPU[ TArmRegisterType.EArmReg_SP ];
+            Trace( string.Format( "GetNewLRValue - stack DWORD offset to LR: 0x{0:x8}, sp: 0x{1:x8}", aLinkRegOffsetInWords, sp ) );
+
+            // If the link register was pushed onto the stack, then get the new value
+            // now...
+            if ( aLinkRegOffsetInWords != uint.MaxValue )
+            {
+                ArmRegisterCollection regs = aPrologue.OffsetValues;
+                foreach ( ArmRegister reg in regs )
+                {
+                    Trace( "GetNewLRValue - reg offsets - " + reg.ToString() );
+                }
+
+                long offsetOnStackToLR = aLinkRegOffsetInWords * 4;
+                long stackBase = iStackInterface.StackBase;
+                long stackOffsetToLR = sp - 4 - stackBase - offsetOnStackToLR;
+                iLastLinkRegisterStackAddress = stackBase + stackOffsetToLR;
+                uint newLRValue = iStackInterface.StackValueAtAddress( (uint) iLastLinkRegisterStackAddress );
+                Trace( string.Format( "GetNewLRValue - Fetching LR from stack address: 0x{0:x8} (0x{1:x8})", iLastLinkRegisterStackAddress, newLRValue ) );
+
+                uint temp;
+                string sym;
+                SymbolViewText.Lookup( newLRValue, out temp, out sym );
+                Trace( "GetNewLRValue - LR changed to: 0x" + newLRValue.ToString( "x8" ) + " => [ " + sym + " ]" );
+
+                CPU[ TArmRegisterType.EArmReg_LR ].Value = newLRValue;
+            }
+            else
+            {
+                iLastLinkRegisterStackAddress = KLinkRegisterWasNotPushedOnStack;
+                Trace( "GetNewLRValue - LR not pushed on stack!" );
+            }
+        }
+
+        private void UpdateInstructionSet( uint aPC )
+        {
+            uint isThumb = aPC & 0x1;
+            if ( isThumb != 0 )
+            {
+                CPU.CurrentProcessorMode = TArmInstructionSet.ETHUMB;
+            }
+            else
+            {
+                CPU.CurrentProcessorMode = TArmInstructionSet.EARM;
+            }
+
+            // Twiddle the first bit to clear any possible non-address value
+            CPU.PC.Value &= 0xFFFFFFFE;
+        }
+
+        private void ChangePCToLRAddress()
+        {
+            CPU.PC.Value = CPU.LR.Value;
+
+            // Zero out the LR value as it has just been promoted to PC
+            CPU.LR.Value = 0;
+        }
+
+        private void SaveStackFrames( params ArmStackFrame[] aFrames )
+        {
+            foreach ( ArmStackFrame frame in aFrames )
+            {
+                iStackFrames.Add( frame );
+            }
+        }
+
+        private string SymbolString( uint aAddress )
+        {
+            // Used for debugging
+            uint fnStartAddr = 0;
+            string symbolName = string.Empty;
+            SymbolViewText.Lookup( aAddress, out fnStartAddr, out symbolName );
+            return symbolName;
+        }
+        #endregion
+
+        #region Internal constants
+        private const long KLinkRegisterWasNotPushedOnStack = -1;
+        #endregion
+
+        #region From ITracer
+        public void Trace( string aMessage )
+        {
+            StringBuilder t = new StringBuilder();
+            //
+            string pad = string.Empty;
+            //
+            if ( iTraceIndentLevel != 0 )
+            {
+                pad = pad.PadLeft( iTraceIndentLevel * 4, ' ' );
+            }
+            //
+            t.AppendFormat( "[AIE] {0}{1}", pad, aMessage );
+            iTracer.Trace( t.ToString() );
+        }
+
+        public void Trace( string aFormat, params object[] aParams )
+        {
+            string t = string.Format( aFormat, aParams );
+            Trace( t );
+        }
+
+        internal void SetIndent( int aIndentLevel )
+        {
+            iTraceIndentLevel = aIndentLevel;
+        }
+        #endregion
+
+        #region From DisposableObject
+        protected override void CleanupManagedResources()
+        {
+            try
+            {
+                base.CleanupManagedResources();
+            }
+            finally
+            {
+                iStackFrames.Clear();
+                iStackFrames = null;
+            }
+        }
+        #endregion
+
+        #region Data members
+        private readonly ITracer iTracer;
+        private readonly DbgEngineView iDebugEngineView;
+        private readonly ArmCodeHelper iCodeHelper;
+        private readonly IArmStackInterface iStackInterface;
+        private long iLastLinkRegisterStackAddress = KLinkRegisterWasNotPushedOnStack;
+        private int iTraceIndentLevel = 0;
+        private int iIterationNumber = 0;
+        private bool iAlreadySavedInitialRegisterFrames = false;
+        private ArmCpu iCPU = new ArmCpu();
+        private List<ArmStackFrame> iStackFrames = new List<ArmStackFrame>();
+        #endregion
+    }
+}