crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Instructions/Types/AccInstDataTransfer.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

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