crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Engine/AccurateEngine.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 * 
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 using System;
       
    18 using System.Collections.Generic;
       
    19 using System.Text;
       
    20 using SymbianDebugLib.Engine;
       
    21 using SymbianDebugLib.PluginAPI.Types.Symbol;
       
    22 using SymbianStackAlgorithmAccurate.Code;
       
    23 using SymbianStackAlgorithmAccurate.CPU;
       
    24 using SymbianStackAlgorithmAccurate.Interfaces;
       
    25 using SymbianStackAlgorithmAccurate.Prologue;
       
    26 using SymbianStackAlgorithmAccurate.Stack;
       
    27 using SymbianStructuresLib.Arm;
       
    28 using SymbianStructuresLib.Arm.Registers;
       
    29 using SymbianUtils;
       
    30 using SymbianUtils.Tracer;
       
    31 
       
    32 namespace SymbianStackAlgorithmAccurate.Engine
       
    33 {
       
    34     internal class AccurateEngine : DisposableObject, ITracer
       
    35     {
       
    36         #region Constructors
       
    37         public AccurateEngine( DbgEngineView aDebugEngineView, IArmStackInterface aStackInterface, ITracer aTracer )
       
    38         {
       
    39             iTracer = aTracer;
       
    40             iDebugEngineView = aDebugEngineView;
       
    41             iStackInterface = aStackInterface;
       
    42             iCodeHelper = new ArmCodeHelper( aDebugEngineView, aTracer );
       
    43         }
       
    44         #endregion
       
    45 
       
    46         #region API
       
    47         public bool Process()
       
    48         {
       
    49             // We need SP, LR, PC, CPSR
       
    50             CheckRequiredRegistersAvailable();
       
    51 
       
    52             // Debug info
       
    53             PrintInitialInfo();
       
    54 
       
    55             // Make initial stack frames for seed registers
       
    56             MakeInitialSeedStackFramesFromRegisterValues();
       
    57 
       
    58             // Get sp
       
    59             ArmRegister sp = CPU[ TArmRegisterType.EArmReg_SP ];
       
    60             uint initialSPValue = sp.Value;
       
    61 
       
    62             // Create Prologue object that will establish the instructions for the
       
    63             // function and also identify operations that might affect SP and LR.
       
    64             ArmPrologueHelper Prologue = new ArmPrologueHelper( this );
       
    65             Prologue.Build();
       
    66             
       
    67             // Create a new stack frame for this function call
       
    68             ArmStackFrame stackFrame = new ArmStackFrame( Prologue );
       
    69 
       
    70             // We save the stack address which contained the popped link register
       
    71             // during the previous cycle. If possible, use that value. If it
       
    72             // hasn't been set, then assume we obtained the link register from the
       
    73             // previous 4 bytes of stack (according to the current value of SP).
       
    74             long stackAddressAssociatedWithCurrentFrame = iLastLinkRegisterStackAddress;
       
    75             if ( stackAddressAssociatedWithCurrentFrame == KLinkRegisterWasNotPushedOnStack )
       
    76             {
       
    77                 // We're always four bytes behind the current SP
       
    78                 stackAddressAssociatedWithCurrentFrame = sp - 4;
       
    79             }
       
    80             stackFrame.Address = (uint) stackAddressAssociatedWithCurrentFrame;
       
    81             stackFrame.Data = iStackInterface.StackValueAtAddress( stackFrame.Address );
       
    82 
       
    83             Trace( "Creating Stack Frame [" + stackFrame.Address.ToString( "x8" ) + "] = 0x" + stackFrame.Data.ToString( "x8" ) + " = " + SymbolString ( stackFrame.Data ) );
       
    84 
       
    85             // Can now adjust stack pointer based upon the number of stack-adjusting
       
    86             // instructions during the Prologue phase.
       
    87             uint stackAdjustment = (uint) ( Prologue.NumberOfWordsPushedOnStack * 4 );
       
    88             sp.Value += stackAdjustment;
       
    89             Trace( "stack adjusted by: 0x" + stackAdjustment.ToString( "x8" ) );
       
    90 
       
    91             // We're hoping that the link register was pushed on the stack somewhere
       
    92             // during the function preamble. If that was the case, then as we processed
       
    93             // each instruction, we'll have updated the register offsets so that we know
       
    94             // the offset to the link register from the perspective of the starting stack
       
    95             // address for the function.
       
    96             uint lrOffsetInWords = Prologue.OffsetValues[ TArmRegisterType.EArmReg_LR ];
       
    97             Trace( string.Format( "LR offset on stack is: 0x{0:x8}", lrOffsetInWords * 4 ) );
       
    98             GetNewLRValue( lrOffsetInWords, Prologue );
       
    99 
       
   100             // Update the PC to point to the new function address (which we obtain
       
   101             // from LR)
       
   102             uint oldPCValue = CPU.PC;
       
   103             ChangePCToLRAddress();
       
   104             uint newPCValue = CPU.PC;
       
   105             Trace( string.Format( "oldPCValue: 0x{0:x8}, newPCValue: 0x{1:x8}, fn: {2}", oldPCValue, newPCValue, SymbolViewText[ newPCValue ] ) );
       
   106 
       
   107             // Decide if we are in thumb or ARM mode after switching functions
       
   108             UpdateInstructionSet( newPCValue );
       
   109 
       
   110             // Return true if we moved to a new function
       
   111             bool gotNewFunction = ( oldPCValue != CPU.PC );
       
   112             Trace( "gotNewFunction: " + gotNewFunction );
       
   113 
       
   114             // Save stack frame
       
   115             SaveStackFrames( stackFrame );
       
   116 
       
   117             // Increment iteration
       
   118             ++iIterationNumber;
       
   119 
       
   120             // Do we have more to do?
       
   121             bool moreToDo = gotNewFunction && ( CPU.PC > 0 );
       
   122 
       
   123             // Done
       
   124             Trace( "moreToDo: " + moreToDo );
       
   125             return moreToDo;
       
   126         }
       
   127         #endregion
       
   128 
       
   129         #region Properties
       
   130         public ArmCpu CPU
       
   131         {
       
   132             get { return iCPU; }
       
   133         }
       
   134 
       
   135         public ArmStackFrame[] StackFrames
       
   136         {
       
   137             get
       
   138             {
       
   139                 return iStackFrames.ToArray();
       
   140             }
       
   141         }
       
   142 
       
   143         internal ArmCodeHelper CodeHelper
       
   144         {
       
   145             get { return iCodeHelper; }
       
   146         }
       
   147 
       
   148         internal DbgEngineView DebugEngineView
       
   149         {
       
   150             get { return iDebugEngineView; }
       
   151         }
       
   152 
       
   153         internal DbgViewSymbol SymbolView
       
   154         {
       
   155             get { return DebugEngineView.Symbols; }
       
   156         }
       
   157 
       
   158         internal DbgSymbolViewText SymbolViewText
       
   159         {
       
   160             get { return SymbolView.PlainText; }
       
   161         }
       
   162         #endregion
       
   163 
       
   164         #region Internal methods
       
   165         private void PrintInitialInfo()
       
   166         {
       
   167             ArmRegister sp = CPU[ TArmRegisterType.EArmReg_SP ];
       
   168             //
       
   169             ArmRegister lr = CPU[ TArmRegisterType.EArmReg_LR ];
       
   170             string lrSymbol = SymbolViewText[ lr ];
       
   171             //
       
   172             ArmRegister pc = CPU[ TArmRegisterType.EArmReg_PC ];
       
   173             string pcSymbol = SymbolViewText[ pc ];
       
   174             //
       
   175             ArmRegister cpsr = CPU[ TArmRegisterType.EArmReg_CPSR ];
       
   176             //
       
   177             Trace( System.Environment.NewLine );
       
   178             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 ) );
       
   179         }
       
   180 
       
   181         private void CheckRequiredRegistersAvailable()
       
   182         {
       
   183             ArmRegisterCollection regs = CPU.Registers;
       
   184 
       
   185             // We need SP, LR, PC, CPSR
       
   186             bool sp = regs.Contains( TArmRegisterType.EArmReg_SP );
       
   187             bool lr = regs.Contains( TArmRegisterType.EArmReg_LR );
       
   188             bool pc = regs.Contains( TArmRegisterType.EArmReg_PC );
       
   189             bool cpsr = regs.Contains( TArmRegisterType.EArmReg_CPSR );
       
   190             //
       
   191             bool available = ( sp && lr && pc && cpsr );
       
   192             if ( !available )
       
   193             {
       
   194                 SymbianUtils.SymDebug.SymDebugger.Break();
       
   195                 throw new ArgumentException( "One or more registers is unavailable" );
       
   196             }
       
   197         }
       
   198 
       
   199         private void MakeInitialSeedStackFramesFromRegisterValues()
       
   200         {
       
   201             if ( !iAlreadySavedInitialRegisterFrames )
       
   202             {
       
   203                 ArmRegisterCollection regs = CPU.Registers;
       
   204 
       
   205                 // Make PC stack frame
       
   206                 ArmStackFrame framePC = new ArmStackFrame( TArmRegisterType.EArmReg_PC );
       
   207                 framePC.Data = regs[ TArmRegisterType.EArmReg_PC ].Value;
       
   208 
       
   209                 // Make LR stack frame
       
   210                 ArmStackFrame frameLR = new ArmStackFrame( TArmRegisterType.EArmReg_LR );
       
   211                 frameLR.Data = regs[ TArmRegisterType.EArmReg_LR ].Value;
       
   212 
       
   213                 // Save 'em
       
   214                 SaveStackFrames( framePC, frameLR );
       
   215 
       
   216                 // Don't do this again
       
   217                 iAlreadySavedInitialRegisterFrames = true;
       
   218             }
       
   219         }
       
   220 
       
   221         private void GetNewLRValue( uint aLinkRegOffsetInWords, ArmPrologueHelper aPrologue )
       
   222         {
       
   223             uint sp = CPU[ TArmRegisterType.EArmReg_SP ];
       
   224             Trace( string.Format( "GetNewLRValue - stack DWORD offset to LR: 0x{0:x8}, sp: 0x{1:x8}", aLinkRegOffsetInWords, sp ) );
       
   225 
       
   226             // If the link register was pushed onto the stack, then get the new value
       
   227             // now...
       
   228             if ( aLinkRegOffsetInWords != uint.MaxValue )
       
   229             {
       
   230                 ArmRegisterCollection regs = aPrologue.OffsetValues;
       
   231                 foreach ( ArmRegister reg in regs )
       
   232                 {
       
   233                     Trace( "GetNewLRValue - reg offsets - " + reg.ToString() );
       
   234                 }
       
   235 
       
   236                 long offsetOnStackToLR = aLinkRegOffsetInWords * 4;
       
   237                 long stackBase = iStackInterface.StackBase;
       
   238                 long stackOffsetToLR = sp - 4 - stackBase - offsetOnStackToLR;
       
   239                 iLastLinkRegisterStackAddress = stackBase + stackOffsetToLR;
       
   240                 uint newLRValue = iStackInterface.StackValueAtAddress( (uint) iLastLinkRegisterStackAddress );
       
   241                 Trace( string.Format( "GetNewLRValue - Fetching LR from stack address: 0x{0:x8} (0x{1:x8})", iLastLinkRegisterStackAddress, newLRValue ) );
       
   242 
       
   243                 uint temp;
       
   244                 string sym;
       
   245                 SymbolViewText.Lookup( newLRValue, out temp, out sym );
       
   246                 Trace( "GetNewLRValue - LR changed to: 0x" + newLRValue.ToString( "x8" ) + " => [ " + sym + " ]" );
       
   247 
       
   248                 CPU[ TArmRegisterType.EArmReg_LR ].Value = newLRValue;
       
   249             }
       
   250             else
       
   251             {
       
   252                 iLastLinkRegisterStackAddress = KLinkRegisterWasNotPushedOnStack;
       
   253                 Trace( "GetNewLRValue - LR not pushed on stack!" );
       
   254             }
       
   255         }
       
   256 
       
   257         private void UpdateInstructionSet( uint aPC )
       
   258         {
       
   259             uint isThumb = aPC & 0x1;
       
   260             if ( isThumb != 0 )
       
   261             {
       
   262                 CPU.CurrentProcessorMode = TArmInstructionSet.ETHUMB;
       
   263             }
       
   264             else
       
   265             {
       
   266                 CPU.CurrentProcessorMode = TArmInstructionSet.EARM;
       
   267             }
       
   268 
       
   269             // Twiddle the first bit to clear any possible non-address value
       
   270             CPU.PC.Value &= 0xFFFFFFFE;
       
   271         }
       
   272 
       
   273         private void ChangePCToLRAddress()
       
   274         {
       
   275             CPU.PC.Value = CPU.LR.Value;
       
   276 
       
   277             // Zero out the LR value as it has just been promoted to PC
       
   278             CPU.LR.Value = 0;
       
   279         }
       
   280 
       
   281         private void SaveStackFrames( params ArmStackFrame[] aFrames )
       
   282         {
       
   283             foreach ( ArmStackFrame frame in aFrames )
       
   284             {
       
   285                 iStackFrames.Add( frame );
       
   286             }
       
   287         }
       
   288 
       
   289         private string SymbolString( uint aAddress )
       
   290         {
       
   291             // Used for debugging
       
   292             uint fnStartAddr = 0;
       
   293             string symbolName = string.Empty;
       
   294             SymbolViewText.Lookup( aAddress, out fnStartAddr, out symbolName );
       
   295             return symbolName;
       
   296         }
       
   297         #endregion
       
   298 
       
   299         #region Internal constants
       
   300         private const long KLinkRegisterWasNotPushedOnStack = -1;
       
   301         #endregion
       
   302 
       
   303         #region From ITracer
       
   304         public void Trace( string aMessage )
       
   305         {
       
   306             StringBuilder t = new StringBuilder();
       
   307             //
       
   308             string pad = string.Empty;
       
   309             //
       
   310             if ( iTraceIndentLevel != 0 )
       
   311             {
       
   312                 pad = pad.PadLeft( iTraceIndentLevel * 4, ' ' );
       
   313             }
       
   314             //
       
   315             t.AppendFormat( "[AIE] {0}{1}", pad, aMessage );
       
   316             iTracer.Trace( t.ToString() );
       
   317         }
       
   318 
       
   319         public void Trace( string aFormat, params object[] aParams )
       
   320         {
       
   321             string t = string.Format( aFormat, aParams );
       
   322             Trace( t );
       
   323         }
       
   324 
       
   325         internal void SetIndent( int aIndentLevel )
       
   326         {
       
   327             iTraceIndentLevel = aIndentLevel;
       
   328         }
       
   329         #endregion
       
   330 
       
   331         #region From DisposableObject
       
   332         protected override void CleanupManagedResources()
       
   333         {
       
   334             try
       
   335             {
       
   336                 base.CleanupManagedResources();
       
   337             }
       
   338             finally
       
   339             {
       
   340                 iStackFrames.Clear();
       
   341                 iStackFrames = null;
       
   342             }
       
   343         }
       
   344         #endregion
       
   345 
       
   346         #region Data members
       
   347         private readonly ITracer iTracer;
       
   348         private readonly DbgEngineView iDebugEngineView;
       
   349         private readonly ArmCodeHelper iCodeHelper;
       
   350         private readonly IArmStackInterface iStackInterface;
       
   351         private long iLastLinkRegisterStackAddress = KLinkRegisterWasNotPushedOnStack;
       
   352         private int iTraceIndentLevel = 0;
       
   353         private int iIterationNumber = 0;
       
   354         private bool iAlreadySavedInitialRegisterFrames = false;
       
   355         private ArmCpu iCPU = new ArmCpu();
       
   356         private List<ArmStackFrame> iStackFrames = new List<ArmStackFrame>();
       
   357         #endregion
       
   358     }
       
   359 }