diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Prologue/ArmPrologueHelper.cs --- /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 + } +}