crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Prologue/ArmPrologueHelper.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Prologue/ArmPrologueHelper.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,341 @@
+/*
+* 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.Tracer;
+using SymbianDebugLib.PluginAPI.Types.Symbol;
+using SymbianStructuresLib.Debug.Symbols;
+using SymbianStructuresLib.Arm;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianStackAlgorithmAccurate.CPU;
+using SymbianStackAlgorithmAccurate.Code;
+using SymbianStackAlgorithmAccurate.Engine;
+using SymbianStackAlgorithmAccurate.Interfaces;
+using SymbianStackAlgorithmAccurate.Instructions;
+
+namespace SymbianStackAlgorithmAccurate.Prologue
+{
+    internal class ArmPrologueHelper
+    {
+        #region Constructors
+        public ArmPrologueHelper( AccurateEngine aEngine )
+        {
+            iEngine = aEngine;
+
+            // Make a new PC register, since we're going to manipulate it...
+            iPC = new ArmRegister( aEngine.CPU.PC );
+
+            // Create offsets
+            iOffsetValues.AddDefaults();
+            iOffsetValues.SetAll( uint.MaxValue );
+        }
+        #endregion
+
+        #region API
+        public void Build()
+        {
+            // First, work out how many instructions we need to read from
+            // the code data in order to reach the current PC value.
+            // We currently cap this at 20 instructions.
+            CalculatePrologueInstructionCount();
+
+            // Get Prologue instructions
+            GetPrologueInstructions();
+
+            // Update iPC with Prologue starting address - needed for PC-relative
+            // instructions
+            PrepareInitialPCValue();
+
+            // Process the instructions until exhausted
+            ProcessPrologueInstructions();
+        }
+
+        public int IncrementNumberOfWordsPushedOnStack( TArmRegisterType aRegister )
+        {
+            uint offset = (uint) iNumberOfWordsPushedOnStack * 4;
+            int ret = iNumberOfWordsPushedOnStack++;
+            iEngine.Trace( "[PLG] IncrementNumberOfWordsPushedOnStack - register: {0}, offset: 0x{1:x4}, DWORDs now on stack: {2:d2}", aRegister, offset, NumberOfWordsPushedOnStack );
+            return ret;
+        }
+
+        public int AddToNumberOfWordsPushedOnStack( int aExtraWords )
+        {
+            iNumberOfWordsPushedOnStack += aExtraWords;
+            iEngine.Trace( "[PLG] AddToNumberOfWordsPushedOnStack     - DWORDs added: {0}, prior SP adjustment: 0x{1:x8} ({2} x DWORDs), new SP adjustment: 0x{3:x8} ({4} x DWORDs)",
+                aExtraWords, 
+                ( iNumberOfWordsPushedOnStack - aExtraWords ) * 4, 
+                iNumberOfWordsPushedOnStack - aExtraWords,
+                iNumberOfWordsPushedOnStack * 4,
+                iNumberOfWordsPushedOnStack  
+            );
+            //
+            return iNumberOfWordsPushedOnStack;
+        }
+        #endregion
+
+        #region Properties
+        public int PrologueInstructionCount
+        {
+            get
+            { 
+                int ret = iPrologueInstructionCount;
+                //
+                if ( ret > KMaxPrologueInstructionCount )
+                {
+                    ret = KMaxPrologueInstructionCount;
+                    iEngine.Trace( "[PLG] Capping the amount of Prologue instructions to read to: " + ret ); 
+                }
+                //
+                return ret;
+            }
+            set
+            {
+                iPrologueInstructionCount = value;
+            }
+        }
+
+        public string FunctionName
+        {
+            get { return iFunctionName; }
+        }
+
+        public TArmInstructionSet FunctionInstructionSet
+        {
+            get
+            {
+                TArmInstructionSet ret = TArmInstructionSet.EARM;
+                //
+                if ( ( FunctionStartingAddress & 0x1 ) == 0x1 )
+                {
+                    ret = TArmInstructionSet.ETHUMB;
+                }
+                //
+                return ret;
+            }
+        }
+
+        public uint FunctionStartingAddress
+        {
+            get { return iFunctionStartAddress; }
+        }
+
+        public uint FunctionStartingAddressWithoutType
+        {
+            get { return iFunctionStartAddress & KInstructionSetMask; }
+        }
+
+        public uint FunctionOffsetToPC
+        {
+            get
+            {
+                uint funcAddrWithoutInstructionSetType = FunctionStartingAddressWithoutType;
+                uint offset = iPC - funcAddrWithoutInstructionSetType;
+                return offset;
+            }
+        }
+
+        public ArmRegister ProloguePC
+        {
+            get { return iPC; }
+        }
+
+        public int NumberOfWordsPushedOnStack
+        {
+            get { return iNumberOfWordsPushedOnStack; }
+            set { iNumberOfWordsPushedOnStack = value; }
+        }
+        #endregion
+
+        #region Internal methods
+        private void CalculatePrologueInstructionCount()
+        {
+            DbgViewSymbol symbolView = iEngine.DebugEngineView.Symbols;
+
+            // Get the PC and try to match it to a function
+            SymbolCollection collection = null;
+            Symbol symbol = symbolView.Lookup( iPC, out collection );
+            if ( symbol != null )
+            {
+                iFunctionStartAddress = symbol.Address;
+                iFunctionName = symbol.Name;
+                //
+                uint offset = FunctionOffsetToPC;
+                uint instructionSize = SingleInstructionSize;
+                uint prologueInstructionCount = ( offset / instructionSize );
+                //
+                iEngine.Trace( "[PLG] Prologue function: 0x{0:x8} = {1} [+{2:x4}], {3} instructions", iPC.Value, iFunctionName, offset, PrologueInstructionCount );
+                PrologueInstructionCount = (int) prologueInstructionCount;
+            }
+            else
+            {
+                // We could not locate the symbol for the corresponding program counter address.
+                // In this situation, there's nothing we can do - if we cannot work out the offset
+                // within the function, then we cannot identify how many Prologue instructions to 
+                // attempt to read.
+                //
+                // If the symbol was not found because no code segment claims ownership of this address
+                // then that might indicate premature dll unload or bad crash data (missing code segments)
+                if ( collection == null )
+                {
+                    throw new APESymbolNotFoundCodeSegmentUnavailable( iPC );
+                }
+                else
+                {
+                    throw new APESymbolNotFound( iPC, string.Format( "Code segment \'{0}\' should describe symbol, but none was found for requested program counter address", collection.FileName ) );
+                }
+            }
+        }
+
+        private void GetPrologueInstructions()
+        {
+            TArmInstructionSet instSet = CPU.CurrentProcessorMode;
+            uint address = FunctionStartingAddressWithoutType;
+
+            // Let's get unadulterated instruction counts
+            int instCount = iPrologueInstructionCount;
+            if ( address > 0 && instCount > 0 )
+            {
+                iInstructions = CodeHelper.LoadInstructions( address, instCount, instSet );
+            }
+            else
+            {
+                iInstructions = new AccInstructionList();
+            }
+
+            // Verify that we have the expected number of instructions.
+            // If, for some reason, the code provider does not supply
+            // any Prologue instructions, then we should bail out.
+            int actual = iInstructions.Count;
+            if ( actual != instCount )
+            {
+                throw new Exception( string.Format( "Prologue instructions unavailable or insufficient @ address: 0x{0:x8} - expected: {1}, received: {2}", FunctionStartingAddressWithoutType, instCount, actual ) );
+            }
+
+            // Since we fetch all the instructions from a function (leading up to the current address)
+            // we may have lots more instructions that we'd ideally normally expect to see form part
+            // of the function prologue. Normally, we cap the prologue instruction count at ~19 instructions,
+            // so therefore we should disable any instructions beyond this maximum.
+            for ( int i = KMaxPrologueInstructionCount - 1; i < iInstructions.Count; i++ )
+            {
+                iInstructions[ i ].Ignored = true;
+            }
+
+            // Run the instructions through the pre-filter. We tell the 
+            // instruction list how many instructions through the current function
+            // we are because this helps to identify whether a branch has been
+            // executed as the last instruction, or whether we artificially limited
+            // the preamble, in which case the branch was "probably" not taken.
+            iInstructions.Prefilter( iPrologueInstructionCount );
+            iInstructions.DebugPrint( iEngine as ITracer );
+        }
+
+        private void PrepareInitialPCValue()
+        {
+            // Update the program counter so that we skip past the start of
+            // the function. According to Tom G, this is two instructions past
+            // the function entry address
+            uint newPC = FunctionStartingAddress;
+            newPC += (uint) ( 2 * SingleInstructionSize );
+
+            // Zero the non-address bits for sanity
+            uint clearBitMask = (uint) ( SingleInstructionSize - 1 );
+            newPC &= ~clearBitMask;
+            iPC.Value = newPC;
+
+            string sym = iEngine.DebugEngineView.Symbols.PlainText[ iPC.Value ];
+            iEngine.Trace( "[PLG] PrepareInitialPCValue - new PC value: 0x{0:x8} = {1}", iPC.Value, sym );
+        }
+
+        private void ProcessPrologueInstructions()
+        {
+            uint sp = iEngine.CPU[ TArmRegisterType.EArmReg_SP ];
+            iEngine.Trace( "[PLG] ProcessPrologueInstructions - initial PC: 0x{0:x8}, SP: 0x{1:x8}", iPC.Value, sp );
+
+            // We've got the necessary instructions so continue as normal...
+            int actual = iInstructions.Count;
+            while ( actual > 0 )
+            {
+                // Get instruction
+                AccInstruction inst = iInstructions.Deque();
+
+                // Don't process any ignored instructions
+                if ( inst.Ignored == false )
+                {
+                    iEngine.Trace( "[PLG] ProcessPrologueInstructions - PC: 0x{0:x8}, SP: 0x{1:x8}, I: {2}", iPC.Value, sp + ( iNumberOfWordsPushedOnStack * 4 ), inst.ToString() );
+                    iEngine.SetIndent( 1 );
+ 
+                    // Process it to update offsets & register values
+                    inst.Process( this );
+
+                    // Update Prologue program counter value
+                    iPC.Value += SingleInstructionSize;
+
+                    // Finished with indentation
+                    iEngine.SetIndent( 0 );
+                }
+
+                // Update count
+                actual = iInstructions.Count;
+            }
+        }
+        #endregion
+
+        #region Internal properties
+        internal ArmCpu CPU
+        {
+            get { return iEngine.CPU; }
+        }
+
+        internal ArmCodeHelper CodeHelper
+        {
+            get { return iEngine.CodeHelper; }
+        }
+
+        internal ArmRegisterCollection OffsetValues
+        {
+            get { return iOffsetValues; }
+        }
+
+        private uint SingleInstructionSize
+        {
+            get
+            {
+                uint size = ArmCpuUtils.InstructionSize( CPU.CurrentProcessorMode );
+                return size;
+            }
+        }
+        #endregion
+
+        #region Internal constants
+        private const int KMaxPrologueInstructionCount = 19;
+        private const uint KInstructionSetMask = 0xFFFFFFFE;
+        #endregion
+
+        #region Data members
+        private readonly AccurateEngine iEngine;
+        private readonly ArmRegister iPC;
+        private int iPrologueInstructionCount = 0;
+        private string iFunctionName = string.Empty;
+        private uint iFunctionStartAddress = 0;
+        private int iNumberOfWordsPushedOnStack = 0;
+        private AccInstructionList iInstructions = new AccInstructionList();
+        private ArmRegisterCollection iOffsetValues = new ArmRegisterCollection();
+        #endregion
+    }
+}