--- /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
+ }
+}