Пример #1
0
        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");
                }
            }
        }
        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;
        }
Пример #5
0
        private void GetNewLRValue(uint aLinkRegOffsetInWords, ArmPrologueHelper aPrologue)
        {
            uint sp = CPU[TArmRegisterType.EArmReg_SP];

            Trace(string.Format("GetNewLRValue - stack DWORD offset to LR: 0x{0:x8}, sp: 0x{1:x8}", aLinkRegOffsetInWords, sp));

            // If the link register was pushed onto the stack, then get the new value
            // now...
            if (aLinkRegOffsetInWords != uint.MaxValue)
            {
                ArmRegisterCollection regs = aPrologue.OffsetValues;
                foreach (ArmRegister reg in regs)
                {
                    Trace("GetNewLRValue - reg offsets - " + reg.ToString());
                }

                long offsetOnStackToLR = aLinkRegOffsetInWords * 4;
                long stackBase         = iStackInterface.StackBase;
                long stackOffsetToLR   = sp - 4 - stackBase - offsetOnStackToLR;
                iLastLinkRegisterStackAddress = stackBase + stackOffsetToLR;
                uint newLRValue = iStackInterface.StackValueAtAddress((uint)iLastLinkRegisterStackAddress);
                Trace(string.Format("GetNewLRValue - Fetching LR from stack address: 0x{0:x8} (0x{1:x8})", iLastLinkRegisterStackAddress, newLRValue));

                uint   temp;
                string sym;
                SymbolViewText.Lookup(newLRValue, out temp, out sym);
                Trace("GetNewLRValue - LR changed to: 0x" + newLRValue.ToString("x8") + " => [ " + sym + " ]");

                CPU[TArmRegisterType.EArmReg_LR].Value = newLRValue;
            }
            else
            {
                iLastLinkRegisterStackAddress = KLinkRegisterWasNotPushedOnStack;
                Trace("GetNewLRValue - LR not pushed on stack!");
            }
        }
Пример #6
0
        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);
        }
Пример #7
0
 internal override void Process(ArmPrologueHelper aProlog)
 {
 }
        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");
                }
            }
        }
Пример #9
0
        public bool Process()
        {
            // We need SP, LR, PC, CPSR
            CheckRequiredRegistersAvailable();

            // Debug info
            PrintInitialInfo();

            // Make initial stack frames for seed registers
            MakeInitialSeedStackFramesFromRegisterValues();

            // Get sp
            ArmRegister sp             = CPU[TArmRegisterType.EArmReg_SP];
            uint        initialSPValue = sp.Value;

            // Create Prologue object that will establish the instructions for the
            // function and also identify operations that might affect SP and LR.
            ArmPrologueHelper Prologue = new ArmPrologueHelper(this);

            Prologue.Build();

            // Create a new stack frame for this function call
            ArmStackFrame stackFrame = new ArmStackFrame(Prologue);

            // We save the stack address which contained the popped link register
            // during the previous cycle. If possible, use that value. If it
            // hasn't been set, then assume we obtained the link register from the
            // previous 4 bytes of stack (according to the current value of SP).
            long stackAddressAssociatedWithCurrentFrame = iLastLinkRegisterStackAddress;

            if (stackAddressAssociatedWithCurrentFrame == KLinkRegisterWasNotPushedOnStack)
            {
                // We're always four bytes behind the current SP
                stackAddressAssociatedWithCurrentFrame = sp - 4;
            }
            stackFrame.Address = (uint)stackAddressAssociatedWithCurrentFrame;
            stackFrame.Data    = iStackInterface.StackValueAtAddress(stackFrame.Address);

            Trace("Creating Stack Frame [" + stackFrame.Address.ToString("x8") + "] = 0x" + stackFrame.Data.ToString("x8") + " = " + SymbolString(stackFrame.Data));

            // Can now adjust stack pointer based upon the number of stack-adjusting
            // instructions during the Prologue phase.
            uint stackAdjustment = (uint)(Prologue.NumberOfWordsPushedOnStack * 4);

            sp.Value += stackAdjustment;
            Trace("stack adjusted by: 0x" + stackAdjustment.ToString("x8"));

            // We're hoping that the link register was pushed on the stack somewhere
            // during the function preamble. If that was the case, then as we processed
            // each instruction, we'll have updated the register offsets so that we know
            // the offset to the link register from the perspective of the starting stack
            // address for the function.
            uint lrOffsetInWords = Prologue.OffsetValues[TArmRegisterType.EArmReg_LR];

            Trace(string.Format("LR offset on stack is: 0x{0:x8}", lrOffsetInWords * 4));
            GetNewLRValue(lrOffsetInWords, Prologue);

            // Update the PC to point to the new function address (which we obtain
            // from LR)
            uint oldPCValue = CPU.PC;

            ChangePCToLRAddress();
            uint newPCValue = CPU.PC;

            Trace(string.Format("oldPCValue: 0x{0:x8}, newPCValue: 0x{1:x8}, fn: {2}", oldPCValue, newPCValue, SymbolViewText[newPCValue]));

            // Decide if we are in thumb or ARM mode after switching functions
            UpdateInstructionSet(newPCValue);

            // Return true if we moved to a new function
            bool gotNewFunction = (oldPCValue != CPU.PC);

            Trace("gotNewFunction: " + gotNewFunction);

            // Save stack frame
            SaveStackFrames(stackFrame);

            // Increment iteration
            ++iIterationNumber;

            // Do we have more to do?
            bool moreToDo = gotNewFunction && (CPU.PC > 0);

            // Done
            Trace("moreToDo: " + moreToDo);
            return(moreToDo);
        }
Пример #10
0
 internal abstract void Process(ArmPrologueHelper aProlog);
Пример #11
0
 internal ArmStackFrame(ArmPrologueHelper aPrologEntry)
 {
     iPrologEntry = aPrologEntry;
 }