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