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; }
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!"); } }
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); }
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"); } } }
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); }
internal abstract void Process(ArmPrologueHelper aProlog);
internal ArmStackFrame(ArmPrologueHelper aPrologEntry) { iPrologEntry = aPrologEntry; }