crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Instructions/Types/AccInstDataTransfer.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Instructions/Types/AccInstDataTransfer.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,172 @@
+/*
+* 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 System.IO;
+using SymbianUtils.BasicTypes;
+using SymbianStackAlgorithmAccurate.CPU;
+using SymbianStackAlgorithmAccurate.Prologue;
+using SymbianStructuresLib.Arm;
+using SymbianStructuresLib.Arm.Instructions;
+using SymbianStructuresLib.Arm.Registers;
+using SymbianStructuresLib.Arm.Registers.VFP;
+using SymbianInstructionLib.Arm.Instructions.Common;
+using SymbianInstructionLib.Arm.Instructions.Arm;
+using SymbianInstructionLib.Arm.Instructions.Arm.DataTransfer;
+using SymbianInstructionLib.Arm.Instructions.Thumb;
+using SymbianInstructionLib.Arm.Instructions.Thumb.DataTransfer;
+
+namespace SymbianStackAlgorithmAccurate.Instructions.Types
+{
+ internal class AccInstDataTransfer : AccInstruction
+ {
+ #region Constructors
+ public AccInstDataTransfer( IArmInstruction aInstruction )
+ : base( aInstruction )
+ {
+ System.Diagnostics.Debug.Assert( base.Instruction.AIGroup == TArmInstructionGroup.EGroupDataTransfer );
+ }
+ #endregion
+
+ #region API
+ internal override void Process( ArmPrologueHelper aProlog )
+ {
+ IArmInstruction instruction = base.Instruction;
+
+ // Only unconditional instructions are handled
+ if ( instruction.AIConditionCode == TArmInstructionCondition.AL )
+ {
+ if ( instruction is ArmInstruction )
+ {
+ ArmInstruction armInst = (ArmInstruction) instruction;
+ //
+ if ( armInst is Arm_LoadOrStoreMultiple )
+ {
+ Arm_LoadOrStoreMultiple lsmInstruction = (Arm_LoadOrStoreMultiple) instruction;
+
+ // We're looking for store operations
+ if ( lsmInstruction.DataTransferType == TArmDataTransferType.EStore )
+ {
+ // We're looking for LSM's that involve SP.
+ if ( lsmInstruction.BaseRegister == TArmRegisterType.EArmReg_SP )
+ {
+ if ( lsmInstruction is Arm_LoadOrStoreMultiple_GP )
+ {
+ Arm_LoadOrStoreMultiple_GP gpLsmInstruction = (Arm_LoadOrStoreMultiple_GP) lsmInstruction;
+ HandleDTOperation( aProlog, gpLsmInstruction.Registers );
+ }
+ else if ( lsmInstruction is Arm_LoadOrStoreMultiple_VFP )
+ {
+ Arm_LoadOrStoreMultiple_VFP vfpLsmInstruction = (Arm_LoadOrStoreMultiple_VFP) lsmInstruction;
+ HandleDTOperation( aProlog, vfpLsmInstruction.Registers );
+ }
+ }
+ }
+ }
+ }
+ else if ( instruction is ThumbInstruction )
+ {
+ ThumbInstruction thumbInst = (ThumbInstruction) instruction;
+ //
+ if ( thumbInst is Thumb_LoadOrStoreMultiple )
+ {
+ // Special case that loads or stores multiple registers
+ Thumb_LoadOrStoreMultiple lsmThumb = (Thumb_LoadOrStoreMultiple) thumbInst;
+ if ( lsmThumb.DataTransferType == TArmDataTransferType.EStore && lsmThumb.Rd == TArmRegisterType.EArmReg_SP )
+ {
+ HandleDTOperation( aProlog, lsmThumb.Registers );
+ }
+ else
+ {
+ }
+ }
+ else if ( thumbInst is Thumb_LDR_RelativeToPC )
+ {
+ // When the Prologue needs to establish a working stack slurry, then often
+ // the scratch registers are used to build up a large subtraction from SP.
+ HandleDTLoad( aProlog, thumbInst as Thumb_LDR_RelativeToPC );
+ }
+ }
+ else
+ {
+ throw new NotSupportedException( "Instruction type not supported" );
+ }
+ }
+ }
+ #endregion
+
+ #region Properties
+ #endregion
+
+ #region Internal methods
+ private void HandleDTOperation( ArmPrologueHelper aProlog, TArmRegisterType[] aRegisterList )
+ {
+ int count = aRegisterList.Length;
+ for ( int i = 0; i < count; i++ )
+ {
+ TArmRegisterType register = aRegisterList[ i ];
+ int push = aProlog.IncrementNumberOfWordsPushedOnStack( register );
+ aProlog.OffsetValues[ register ].Value = (uint) push;
+ }
+ }
+
+ private void HandleDTOperation( ArmPrologueHelper aProlog, TArmRegisterTypeVFP[] aRegisterList )
+ {
+ int numberOfRegisters = aRegisterList.Length;
+ if ( numberOfRegisters > 0 )
+ {
+ // The size of the register varies... but the list will be consistent.
+ TArmRegisterTypeVFP first = aRegisterList[ 0 ];
+ //
+ int numberOfBitsPerRegister = ArmVectorFloatingPointUtils.RegisterSizeInBits( first );
+ int numberOfBytesPerRegister = numberOfBitsPerRegister / 8;
+ int totalNumberOfBytes = numberOfBytesPerRegister * numberOfRegisters;
+ int numberOfWords = totalNumberOfBytes / 4;
+ //
+ aProlog.AddToNumberOfWordsPushedOnStack( numberOfWords );
+ }
+ }
+
+ private void HandleDTLoad( ArmPrologueHelper aProlog, Thumb_LoadOrStore_Immediate8 aInstruction )
+ {
+ // E.g:
+ //
+ // LDR R0, [PC, #40] ; Load R0 from PC + 0x40 (= address of the LDR instruction + 8 + 0x40)
+ //
+ TArmRegisterType reg = aInstruction.Rd;
+ uint immed = aInstruction.Immediate * 4u;
+
+ // PC = Is the program counter. Its value is used to calculate the memory
+ // address. Bit 1 of the PC value is forced to zero for the purpose of
+ // this calculation, so the address is always word-aligned.
+ uint pcAddress = aProlog.ProloguePC & 0xFFFFFFFC;
+ pcAddress = pcAddress + immed;
+
+ // Read code value at specified address
+ uint value = aProlog.CodeHelper.LoadData( pcAddress );
+
+ // Set the register
+ aProlog.CPU[ reg ].Value = value;
+ }
+ #endregion
+
+ #region Data members
+ #endregion
+ }
+}
+