crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Prologue/ArmPrologueHelper.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 SymbianUtils.Tracer;
       
    21 using SymbianDebugLib.PluginAPI.Types.Symbol;
       
    22 using SymbianStructuresLib.Debug.Symbols;
       
    23 using SymbianStructuresLib.Arm;
       
    24 using SymbianStructuresLib.Arm.Registers;
       
    25 using SymbianStructuresLib.Arm.Registers;
       
    26 using SymbianStackAlgorithmAccurate.CPU;
       
    27 using SymbianStackAlgorithmAccurate.Code;
       
    28 using SymbianStackAlgorithmAccurate.Engine;
       
    29 using SymbianStackAlgorithmAccurate.Interfaces;
       
    30 using SymbianStackAlgorithmAccurate.Instructions;
       
    31 
       
    32 namespace SymbianStackAlgorithmAccurate.Prologue
       
    33 {
       
    34     internal class ArmPrologueHelper
       
    35     {
       
    36         #region Constructors
       
    37         public ArmPrologueHelper( AccurateEngine aEngine )
       
    38         {
       
    39             iEngine = aEngine;
       
    40 
       
    41             // Make a new PC register, since we're going to manipulate it...
       
    42             iPC = new ArmRegister( aEngine.CPU.PC );
       
    43 
       
    44             // Create offsets
       
    45             iOffsetValues.AddDefaults();
       
    46             iOffsetValues.SetAll( uint.MaxValue );
       
    47         }
       
    48         #endregion
       
    49 
       
    50         #region API
       
    51         public void Build()
       
    52         {
       
    53             // First, work out how many instructions we need to read from
       
    54             // the code data in order to reach the current PC value.
       
    55             // We currently cap this at 20 instructions.
       
    56             CalculatePrologueInstructionCount();
       
    57 
       
    58             // Get Prologue instructions
       
    59             GetPrologueInstructions();
       
    60 
       
    61             // Update iPC with Prologue starting address - needed for PC-relative
       
    62             // instructions
       
    63             PrepareInitialPCValue();
       
    64 
       
    65             // Process the instructions until exhausted
       
    66             ProcessPrologueInstructions();
       
    67         }
       
    68 
       
    69         public int IncrementNumberOfWordsPushedOnStack( TArmRegisterType aRegister )
       
    70         {
       
    71             uint offset = (uint) iNumberOfWordsPushedOnStack * 4;
       
    72             int ret = iNumberOfWordsPushedOnStack++;
       
    73             iEngine.Trace( "[PLG] IncrementNumberOfWordsPushedOnStack - register: {0}, offset: 0x{1:x4}, DWORDs now on stack: {2:d2}", aRegister, offset, NumberOfWordsPushedOnStack );
       
    74             return ret;
       
    75         }
       
    76 
       
    77         public int AddToNumberOfWordsPushedOnStack( int aExtraWords )
       
    78         {
       
    79             iNumberOfWordsPushedOnStack += aExtraWords;
       
    80             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)",
       
    81                 aExtraWords, 
       
    82                 ( iNumberOfWordsPushedOnStack - aExtraWords ) * 4, 
       
    83                 iNumberOfWordsPushedOnStack - aExtraWords,
       
    84                 iNumberOfWordsPushedOnStack * 4,
       
    85                 iNumberOfWordsPushedOnStack  
       
    86             );
       
    87             //
       
    88             return iNumberOfWordsPushedOnStack;
       
    89         }
       
    90         #endregion
       
    91 
       
    92         #region Properties
       
    93         public int PrologueInstructionCount
       
    94         {
       
    95             get
       
    96             { 
       
    97                 int ret = iPrologueInstructionCount;
       
    98                 //
       
    99                 if ( ret > KMaxPrologueInstructionCount )
       
   100                 {
       
   101                     ret = KMaxPrologueInstructionCount;
       
   102                     iEngine.Trace( "[PLG] Capping the amount of Prologue instructions to read to: " + ret ); 
       
   103                 }
       
   104                 //
       
   105                 return ret;
       
   106             }
       
   107             set
       
   108             {
       
   109                 iPrologueInstructionCount = value;
       
   110             }
       
   111         }
       
   112 
       
   113         public string FunctionName
       
   114         {
       
   115             get { return iFunctionName; }
       
   116         }
       
   117 
       
   118         public TArmInstructionSet FunctionInstructionSet
       
   119         {
       
   120             get
       
   121             {
       
   122                 TArmInstructionSet ret = TArmInstructionSet.EARM;
       
   123                 //
       
   124                 if ( ( FunctionStartingAddress & 0x1 ) == 0x1 )
       
   125                 {
       
   126                     ret = TArmInstructionSet.ETHUMB;
       
   127                 }
       
   128                 //
       
   129                 return ret;
       
   130             }
       
   131         }
       
   132 
       
   133         public uint FunctionStartingAddress
       
   134         {
       
   135             get { return iFunctionStartAddress; }
       
   136         }
       
   137 
       
   138         public uint FunctionStartingAddressWithoutType
       
   139         {
       
   140             get { return iFunctionStartAddress & KInstructionSetMask; }
       
   141         }
       
   142 
       
   143         public uint FunctionOffsetToPC
       
   144         {
       
   145             get
       
   146             {
       
   147                 uint funcAddrWithoutInstructionSetType = FunctionStartingAddressWithoutType;
       
   148                 uint offset = iPC - funcAddrWithoutInstructionSetType;
       
   149                 return offset;
       
   150             }
       
   151         }
       
   152 
       
   153         public ArmRegister ProloguePC
       
   154         {
       
   155             get { return iPC; }
       
   156         }
       
   157 
       
   158         public int NumberOfWordsPushedOnStack
       
   159         {
       
   160             get { return iNumberOfWordsPushedOnStack; }
       
   161             set { iNumberOfWordsPushedOnStack = value; }
       
   162         }
       
   163         #endregion
       
   164 
       
   165         #region Internal methods
       
   166         private void CalculatePrologueInstructionCount()
       
   167         {
       
   168             DbgViewSymbol symbolView = iEngine.DebugEngineView.Symbols;
       
   169 
       
   170             // Get the PC and try to match it to a function
       
   171             SymbolCollection collection = null;
       
   172             Symbol symbol = symbolView.Lookup( iPC, out collection );
       
   173             if ( symbol != null )
       
   174             {
       
   175                 iFunctionStartAddress = symbol.Address;
       
   176                 iFunctionName = symbol.Name;
       
   177                 //
       
   178                 uint offset = FunctionOffsetToPC;
       
   179                 uint instructionSize = SingleInstructionSize;
       
   180                 uint prologueInstructionCount = ( offset / instructionSize );
       
   181                 //
       
   182                 iEngine.Trace( "[PLG] Prologue function: 0x{0:x8} = {1} [+{2:x4}], {3} instructions", iPC.Value, iFunctionName, offset, PrologueInstructionCount );
       
   183                 PrologueInstructionCount = (int) prologueInstructionCount;
       
   184             }
       
   185             else
       
   186             {
       
   187                 // We could not locate the symbol for the corresponding program counter address.
       
   188                 // In this situation, there's nothing we can do - if we cannot work out the offset
       
   189                 // within the function, then we cannot identify how many Prologue instructions to 
       
   190                 // attempt to read.
       
   191                 //
       
   192                 // If the symbol was not found because no code segment claims ownership of this address
       
   193                 // then that might indicate premature dll unload or bad crash data (missing code segments)
       
   194                 if ( collection == null )
       
   195                 {
       
   196                     throw new APESymbolNotFoundCodeSegmentUnavailable( iPC );
       
   197                 }
       
   198                 else
       
   199                 {
       
   200                     throw new APESymbolNotFound( iPC, string.Format( "Code segment \'{0}\' should describe symbol, but none was found for requested program counter address", collection.FileName ) );
       
   201                 }
       
   202             }
       
   203         }
       
   204 
       
   205         private void GetPrologueInstructions()
       
   206         {
       
   207             TArmInstructionSet instSet = CPU.CurrentProcessorMode;
       
   208             uint address = FunctionStartingAddressWithoutType;
       
   209 
       
   210             // Let's get unadulterated instruction counts
       
   211             int instCount = iPrologueInstructionCount;
       
   212             if ( address > 0 && instCount > 0 )
       
   213             {
       
   214                 iInstructions = CodeHelper.LoadInstructions( address, instCount, instSet );
       
   215             }
       
   216             else
       
   217             {
       
   218                 iInstructions = new AccInstructionList();
       
   219             }
       
   220 
       
   221             // Verify that we have the expected number of instructions.
       
   222             // If, for some reason, the code provider does not supply
       
   223             // any Prologue instructions, then we should bail out.
       
   224             int actual = iInstructions.Count;
       
   225             if ( actual != instCount )
       
   226             {
       
   227                 throw new Exception( string.Format( "Prologue instructions unavailable or insufficient @ address: 0x{0:x8} - expected: {1}, received: {2}", FunctionStartingAddressWithoutType, instCount, actual ) );
       
   228             }
       
   229 
       
   230             // Since we fetch all the instructions from a function (leading up to the current address)
       
   231             // we may have lots more instructions that we'd ideally normally expect to see form part
       
   232             // of the function prologue. Normally, we cap the prologue instruction count at ~19 instructions,
       
   233             // so therefore we should disable any instructions beyond this maximum.
       
   234             for ( int i = KMaxPrologueInstructionCount - 1; i < iInstructions.Count; i++ )
       
   235             {
       
   236                 iInstructions[ i ].Ignored = true;
       
   237             }
       
   238 
       
   239             // Run the instructions through the pre-filter. We tell the 
       
   240             // instruction list how many instructions through the current function
       
   241             // we are because this helps to identify whether a branch has been
       
   242             // executed as the last instruction, or whether we artificially limited
       
   243             // the preamble, in which case the branch was "probably" not taken.
       
   244             iInstructions.Prefilter( iPrologueInstructionCount );
       
   245             iInstructions.DebugPrint( iEngine as ITracer );
       
   246         }
       
   247 
       
   248         private void PrepareInitialPCValue()
       
   249         {
       
   250             // Update the program counter so that we skip past the start of
       
   251             // the function. According to Tom G, this is two instructions past
       
   252             // the function entry address
       
   253             uint newPC = FunctionStartingAddress;
       
   254             newPC += (uint) ( 2 * SingleInstructionSize );
       
   255 
       
   256             // Zero the non-address bits for sanity
       
   257             uint clearBitMask = (uint) ( SingleInstructionSize - 1 );
       
   258             newPC &= ~clearBitMask;
       
   259             iPC.Value = newPC;
       
   260 
       
   261             string sym = iEngine.DebugEngineView.Symbols.PlainText[ iPC.Value ];
       
   262             iEngine.Trace( "[PLG] PrepareInitialPCValue - new PC value: 0x{0:x8} = {1}", iPC.Value, sym );
       
   263         }
       
   264 
       
   265         private void ProcessPrologueInstructions()
       
   266         {
       
   267             uint sp = iEngine.CPU[ TArmRegisterType.EArmReg_SP ];
       
   268             iEngine.Trace( "[PLG] ProcessPrologueInstructions - initial PC: 0x{0:x8}, SP: 0x{1:x8}", iPC.Value, sp );
       
   269 
       
   270             // We've got the necessary instructions so continue as normal...
       
   271             int actual = iInstructions.Count;
       
   272             while ( actual > 0 )
       
   273             {
       
   274                 // Get instruction
       
   275                 AccInstruction inst = iInstructions.Deque();
       
   276 
       
   277                 // Don't process any ignored instructions
       
   278                 if ( inst.Ignored == false )
       
   279                 {
       
   280                     iEngine.Trace( "[PLG] ProcessPrologueInstructions - PC: 0x{0:x8}, SP: 0x{1:x8}, I: {2}", iPC.Value, sp + ( iNumberOfWordsPushedOnStack * 4 ), inst.ToString() );
       
   281                     iEngine.SetIndent( 1 );
       
   282  
       
   283                     // Process it to update offsets & register values
       
   284                     inst.Process( this );
       
   285 
       
   286                     // Update Prologue program counter value
       
   287                     iPC.Value += SingleInstructionSize;
       
   288 
       
   289                     // Finished with indentation
       
   290                     iEngine.SetIndent( 0 );
       
   291                 }
       
   292 
       
   293                 // Update count
       
   294                 actual = iInstructions.Count;
       
   295             }
       
   296         }
       
   297         #endregion
       
   298 
       
   299         #region Internal properties
       
   300         internal ArmCpu CPU
       
   301         {
       
   302             get { return iEngine.CPU; }
       
   303         }
       
   304 
       
   305         internal ArmCodeHelper CodeHelper
       
   306         {
       
   307             get { return iEngine.CodeHelper; }
       
   308         }
       
   309 
       
   310         internal ArmRegisterCollection OffsetValues
       
   311         {
       
   312             get { return iOffsetValues; }
       
   313         }
       
   314 
       
   315         private uint SingleInstructionSize
       
   316         {
       
   317             get
       
   318             {
       
   319                 uint size = ArmCpuUtils.InstructionSize( CPU.CurrentProcessorMode );
       
   320                 return size;
       
   321             }
       
   322         }
       
   323         #endregion
       
   324 
       
   325         #region Internal constants
       
   326         private const int KMaxPrologueInstructionCount = 19;
       
   327         private const uint KInstructionSetMask = 0xFFFFFFFE;
       
   328         #endregion
       
   329 
       
   330         #region Data members
       
   331         private readonly AccurateEngine iEngine;
       
   332         private readonly ArmRegister iPC;
       
   333         private int iPrologueInstructionCount = 0;
       
   334         private string iFunctionName = string.Empty;
       
   335         private uint iFunctionStartAddress = 0;
       
   336         private int iNumberOfWordsPushedOnStack = 0;
       
   337         private AccInstructionList iInstructions = new AccInstructionList();
       
   338         private ArmRegisterCollection iOffsetValues = new ArmRegisterCollection();
       
   339         #endregion
       
   340     }
       
   341 }