crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianStackLib/Plugins/Accurate/Instructions/Types/AccInstDataProcessing.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 SymbianInstructionLib.Arm.Instructions.Common;
using SymbianInstructionLib.Arm.Instructions.Arm;
using SymbianInstructionLib.Arm.Instructions.Arm.DataProcessing;
using SymbianInstructionLib.Arm.Instructions.Thumb;
using SymbianInstructionLib.Arm.Instructions.Thumb.DataProcessing;

namespace SymbianStackAlgorithmAccurate.Instructions.Types
{
    internal class AccInstDataProcessing : AccInstruction
    {
        #region Constructors
        public AccInstDataProcessing( IArmInstruction aInstruction )
            : base( aInstruction )
        {
            System.Diagnostics.Debug.Assert( base.Instruction.AIGroup == TArmInstructionGroup.EGroupDataProcessing );
        }
        #endregion

        #region API
        internal override void Process( ArmPrologueHelper aProlog )
        {
            IArmInstruction instruction = base.Instruction;
            
            // Only unconditional instructions are handled
            if ( instruction.AIConditionCode == TArmInstructionCondition.AL )
            {
                // Two heuristically observed requirements:
                //
                // 1) It must be an immediate instruction
                // 2) It must apply with source & destination registers both being SP
                if ( instruction is ArmInstruction )
                {
                    // Aim is to detect modifications to SP (i.e. reservation of stack space)
                    Arm_DataProcessing armDpInst = instruction as Arm_DataProcessing;
                    
                    // 1) Must supply an immediate value
                    if ( armDpInst != null && armDpInst.SuppliesImmediate )
                    {
                        // 2) Must apply to SP
                        if ( armDpInst.Rd == TArmRegisterType.EArmReg_SP &&
                             armDpInst.Rn == TArmRegisterType.EArmReg_SP )
                        {
                            uint immediate = armDpInst.Immediate;
                            HandleDPOperation( armDpInst.OperationType, immediate, aProlog );
                        }
                    }
                }
                else if ( instruction is ThumbInstruction )
                {
                    Thumb_AddOrSubtract thumbDpInst = instruction as Thumb_AddOrSubtract;

                    // 2) Must apply to SP
                    if ( thumbDpInst.Rd == TArmRegisterType.EArmReg_SP )
                    {
                        // 1) Must supply an immediate value
                        if ( thumbDpInst != null && thumbDpInst.SuppliesImmediate )
                        {
                            uint immediate = thumbDpInst.Immediate;
                            HandleDPOperation( thumbDpInst.OperationType, immediate, aProlog );
                        }
                        else if ( thumbDpInst is Thumb_Add_2Regs_High )
                        {
                            // Handle the case where one register supplies the number of
                            // words by which the stack pointer is incremented. Used when 
                            // a large stack allocation is made.
                        }
                    }
                }
                else
                {
                    throw new NotSupportedException( "Instruction type not supported" );
                }
            }
        }
        #endregion

        #region Properties
        public bool AppliesToSP
        {
            get
            {
                bool ret = false;
                IArmInstruction instruction = base.Instruction;

                // Only unconditional instructions are handled
                if ( instruction.AIConditionCode == TArmInstructionCondition.AL )
                {
                    // Two heuristically observed requirements:
                    //
                    // 1) It must be an immediate instruction
                    // 2) It must apply with source & destination registers both being SP
                    if ( instruction is ArmInstruction )
                    {
                        // Aim is to detect modifications to SP (i.e. reservation of stack space)
                        Arm_DataProcessing armDpInst = instruction as Arm_DataProcessing;

                        // 1) Must supply an immediate value
                        if ( armDpInst != null && armDpInst.SuppliesImmediate )
                        {
                            // 2) Must apply to SP
                            if ( armDpInst.Rd == TArmRegisterType.EArmReg_SP &&
                                 armDpInst.Rn == TArmRegisterType.EArmReg_SP )
                            {
                                ret = true;
                            }
                        }
                    }
                    else if ( instruction is ThumbInstruction )
                    {
                        Thumb_AddOrSubtract thumbDpInst = instruction as Thumb_AddOrSubtract;

                        // 2) Must apply to SP
                        if ( thumbDpInst.Rd == TArmRegisterType.EArmReg_SP )
                        {
                            // 1) Must supply an immediate value
                            if ( thumbDpInst != null && thumbDpInst.SuppliesImmediate )
                            {
                                ret = true;
                            }
                            else if ( thumbDpInst is Thumb_Add_2Regs_High )
                            {
                                // Handle the case where one register supplies the number of
                                // words by which the stack pointer is incremented. Used when 
                                // a large stack allocation is made.
                            }
                        }
                    }
                }

                return ret;
            }
        }
        #endregion

        #region Internal methods
        private void HandleDPOperation( TArmDataProcessingType aType, uint aImmediate, ArmPrologueHelper aProlog )
        {
            int wordsPushed = (int) aImmediate / 4;
            //
            switch( aType )
            {
            case TArmDataProcessingType.ADD:
                wordsPushed = -wordsPushed;
                break;
            case TArmDataProcessingType.SUB:
                break;
            default:
                throw new NotSupportedException( "Data processing does not (yet) support instructions of type: " + aType );
            }
            //
            aProlog.AddToNumberOfWordsPushedOnStack( wordsPushed );
        }
        #endregion

        #region Data members
        #endregion
    }
}