1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/* 2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project 3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License"); 5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License. 6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at 7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * http://www.apache.org/licenses/LICENSE-2.0 9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software 11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS, 12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and 14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License. 15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.program; 18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log; 20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Instruction; 21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Opcode; 22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList; 24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Collections; 25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.LinkedList; 26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List; 27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/** 29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * A class that represents a CodeItem in a way that is more amenable to mutation. 30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class MutatableCode { 32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * To ensure we update the correct CodeItem in the raw DEX file. 34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int codeItemIdx; 36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This is an index into the Program's list of MutatableCodes. 39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int mutatableCodeIdx; 41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Number of registers this code uses. 44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public short registersSize; 46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Number of ins this code has. 49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public short insSize; 51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Number of outs this code has. 54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public short outsSize; 56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Number of tries this code has. 59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public short triesSize; 61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * CodeTranslator is responsible for creating this, and 64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * converting it back to a list of Instructions. 65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private List<MInsn> mutatableInsns; 67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * CodeTranslator is responsible for creating this, and 70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * converting it back to the correct form for CodeItems. 71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public List<MTryBlock> mutatableTries; 73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * The name of the method this code represents. 76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public String name; 78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public String shorty; 79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public boolean isStatic; 80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * The Program that owns this MutatableCode. 83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Currently used to get the size of constant pools for 84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * PoolIndexChanger/RandomInstructionGenerator 85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Program program; 87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private short originalInVReg; 89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private short tempVRegsAllocated; 90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private short initialTempVReg; 91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private boolean vregsNeedCopying; 92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int numMoveInsnsGenerated; 93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public MutatableCode(Program program) { 95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle this.program = program; 96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle this.mutatableInsns = new LinkedList<MInsn>(); 97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Call this to update all instructions after the provided mInsn, to have their 101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * locations adjusted by the provided offset. It will also mark that they have been updated. 102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void updateInstructionLocationsAfter(MInsn mInsn, int offset) { 104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle boolean updating = false; 105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsnChecking : mutatableInsns) { 106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (updating) { 107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mInsnChecking.locationUpdated = true; 108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mInsnChecking.location += offset; 109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mInsnChecking == mInsn) { 111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updating = true; 112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void recalculateLocations() { 119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int loc = 0; 120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsn : mutatableInsns) { 121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mInsn.location = loc; 122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle loc += mInsn.insn.getSize(); 123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public List<MInsn> getInstructions() { 127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return Collections.unmodifiableList(mutatableInsns); 128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int getInstructionCount() { 131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return mutatableInsns.size(); 132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int getInstructionIndex(MInsn mInsn) { 135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return mutatableInsns.indexOf(mInsn); 136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public MInsn getInstructionAt(int idx) { 139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return mutatableInsns.get(idx); 140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void addInstructionToEnd(MInsn mInsn) { 143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.add(mInsn); 144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void insertInstructionAfter(MInsn toBeInserted, int insertionIdx) { 147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if ((insertionIdx + 1) < mutatableInsns.size()) { 148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertInstructionAt(toBeInserted, insertionIdx + 1); 149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Appending to end. 151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn finalInsn = mutatableInsns.get(mutatableInsns.size() - 1); 152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle toBeInserted.location = finalInsn.location + finalInsn.insn.getSize(); 153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.add(toBeInserted); 154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Has same semantics as List.add() 159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void insertInstructionAt(MInsn toBeInserted, int insertionIdx) { 161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn currentInsn = mutatableInsns.get(insertionIdx); 162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle toBeInserted.location = currentInsn.location; 163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.add(insertionIdx , toBeInserted); 164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateInstructionLocationsAfter(toBeInserted, toBeInserted.insn.getSize()); 165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Checks if any MTryBlock's instruction refs pointed at the 'before' MInsn, 169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * and points them to the 'after' MInsn, if so. 'twoWay' will check if 'after' 170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * was pointed to, and point refs to the 'before' insn. 171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * (one-way is used when deleting instructions, 172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * two-way is used when swapping instructions.) 173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void updateTryBlocksWithReplacementInsn(MInsn before, MInsn after, 175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle boolean twoWay) { 176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (triesSize > 0) { 177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MTryBlock mTryBlock : mutatableTries) { 178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mTryBlock.startInsn == before) { 179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's first instruction was updated"); 180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.startInsn = after; 181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (twoWay && mTryBlock.startInsn == after) { 182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's first instruction was updated"); 183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.startInsn = before; 184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mTryBlock.endInsn == before) { 186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's last instruction was updated"); 187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.endInsn = after; 188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (twoWay && mTryBlock.endInsn == after) { 189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's last instruction was updated"); 190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.endInsn = before; 191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mTryBlock.catchAllHandler == before) { 193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's catch-all instruction was updated"); 194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.catchAllHandler = after; 195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (twoWay && mTryBlock.catchAllHandler == after) { 196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's catch-all instruction was updated"); 197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.catchAllHandler = before; 198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle List<Integer> matchesIndicesToChange = new ArrayList<Integer>(); 201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle List<Integer> replacementIndicesToChange = null; 202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (twoWay) { 203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle replacementIndicesToChange = new ArrayList<Integer>(); 204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 206959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int idx = 0; 207959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn handler : mTryBlock.handlers) { 208959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (handler == before) { 209959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle matchesIndicesToChange.add(idx); 210959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's handler instruction was updated"); 211959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (twoWay && handler == after) { 212959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle replacementIndicesToChange.add(idx); 213959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Try block's handler instruction was updated"); 214959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 215959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle idx++; 216959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 217959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 218959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int idxToChange : matchesIndicesToChange) { 219959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.handlers.set(idxToChange, after); 220959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 221959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 222959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (twoWay) { 223959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int idxToChange : replacementIndicesToChange) { 224959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mTryBlock.handlers.set(idxToChange, before); 225959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 226959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 227959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 228959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 229959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 230959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 231959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 232959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * The actual implementation of deleteInstruction called by 233959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the single-argument deleteInstructions. 234959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 235959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void deleteInstructionFull(MInsn toBeDeleted, int toBeDeletedIdx) { 236959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Make sure we update all locations afterwards first. 237959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateInstructionLocationsAfter(toBeDeleted, -(toBeDeleted.insn.getSize())); 238959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 239959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Remove it. 240959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.remove(toBeDeletedIdx); 241959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 242959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Update any branch instructions that branched to the instruction we just deleted! 243959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 244959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // First, pick the replacement target. 245959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int replacementTargetIdx = toBeDeletedIdx; 246959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (replacementTargetIdx == mutatableInsns.size()) { 247959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle replacementTargetIdx--; 248959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 249959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn replacementTarget = mutatableInsns.get(replacementTargetIdx); 250959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 251959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsn : mutatableInsns) { 252959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mInsn instanceof MBranchInsn) { 253959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Check if this branch insn points at the insn we just deleted. 254959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MBranchInsn branchInsn = (MBranchInsn) mInsn; 255959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn target = branchInsn.target; 256959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (target == toBeDeleted) { 257959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug(branchInsn + " was pointing at the deleted instruction, updated."); 258959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle branchInsn.target = replacementTarget; 259959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 260959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (mInsn instanceof MSwitchInsn) { 261959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Check if any of this switch insn's targets points at the insn we just deleted. 262959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MSwitchInsn switchInsn = (MSwitchInsn) mInsn; 263959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle List<Integer> indicesToChange = new ArrayList<Integer>(); 264959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int idx = 0; 265959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn target : switchInsn.targets) { 266959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (target == toBeDeleted) { 267959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle indicesToChange.add(idx); 268959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug(switchInsn + "[" + idx 269959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + "] was pointing at the deleted instruction, updated."); 270959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 271959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle idx++; 272959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 273959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int idxToChange : indicesToChange) { 274959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle switchInsn.targets.remove(idxToChange); 275959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle switchInsn.targets.add(idxToChange, replacementTarget); 276959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 277959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 278959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 279959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 280959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Now update the try blocks. 281959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateTryBlocksWithReplacementInsn(toBeDeleted, replacementTarget, false); 282959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 283959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 284959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 285959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Delete the provided MInsn. 286959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 287959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void deleteInstruction(MInsn toBeDeleted) { 288959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle deleteInstructionFull(toBeDeleted, mutatableInsns.indexOf(toBeDeleted)); 289959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 290959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 291959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 292959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Delete the MInsn at the provided index. 293959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 294959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void deleteInstruction(int toBeDeletedIdx) { 295959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle deleteInstructionFull(mutatableInsns.get(toBeDeletedIdx), toBeDeletedIdx); 296959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 297959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 298959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void swapInstructionsByIndex(int aIdx, int bIdx) { 299959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn aInsn = mutatableInsns.get(aIdx); 300959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn bInsn = mutatableInsns.get(bIdx); 301959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 302959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.set(aIdx, bInsn); 303959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mutatableInsns.set(bIdx, aInsn); 304959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 305959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateTryBlocksWithReplacementInsn(aInsn, bInsn, true); 306959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 307959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle recalculateLocations(); 308959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 309959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 310959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 311959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Some mutators may require the use of temporary registers. For instance, 312959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to easily add in printing of values without having to look for registers 313959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * that aren't currently live. 314959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * The idea is to allocate these registers at the top of the set of registers. 315959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Because this will then shift where the arguments to the method are, we then 316959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * change the start of the method to copy the arguments to the method 317959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * into the place where the rest of the method's code expects them to be. 318959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Call allocateTemporaryVRegs(n), then use getTemporaryVReg(n), 319959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * and then make sure finishedUsingTemporaryVRegs() is called! 320959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 321959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void allocateTemporaryVRegs(int count) { 322959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (count > tempVRegsAllocated) { 323959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (tempVRegsAllocated == 0) { 324959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Allocating temporary vregs for method..."); 325959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle initialTempVReg = registersSize; 326959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle originalInVReg = (short) (registersSize - insSize); 327959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 328959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Extending allocation of temporary vregs for method..."); 329959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 330959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle registersSize = (short) (initialTempVReg + count); 331959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (outsSize < count) { 332959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle outsSize = (short) count; 333959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 334959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle vregsNeedCopying = true; 335959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle tempVRegsAllocated = (short) count; 336959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 337959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 338959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 339959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public int getTemporaryVReg(int number) { 340959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (number >= tempVRegsAllocated) { 341959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Not allocated enough temporary vregs!"); 342959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 343959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return initialTempVReg + number; 344959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 345959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 346959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void finishedUsingTemporaryVRegs() { 347959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (tempVRegsAllocated > 0 && vregsNeedCopying) { 348959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Just delete all the move instructions and generate again, if we already have some. 349959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle while (numMoveInsnsGenerated > 0) { 350959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle deleteInstruction(0); 351959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle numMoveInsnsGenerated--; 352959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 353959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 354959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Moving 'in' vregs to correct locations after allocating temporary vregs"); 355959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 356959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int shortyIdx = 0; 357959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (isStatic) { 358959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle shortyIdx = 1; 359959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 360959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 361959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int insertionCounter = 0; 362959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 363959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Insert copy insns that move all the in VRs down. 364959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < insSize; i++) { 365959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MInsn moveInsn = new MInsn(); 366959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn = new Instruction(); 367959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn.vregA = originalInVReg + i; 368959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn.vregB = originalInVReg + i + tempVRegsAllocated; 369959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 370959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle char type = 'L'; 371959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (shortyIdx > 0) { 372959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle type = shorty.charAt(shortyIdx); 373959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 374959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle shortyIdx++; 375959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 376959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (type == 'L') { 377959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_OBJECT_16); 378959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (type == 'D' || type == 'J') { 379959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_WIDE_16); 380959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle i++; 381959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 382959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle moveInsn.insn.info = Instruction.getOpcodeInfo(Opcode.MOVE_16); 383959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 384959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 385959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertInstructionAt(moveInsn, insertionCounter); 386959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertionCounter++; 387959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Temp vregs creation, Added instruction " + moveInsn); 388959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle numMoveInsnsGenerated++; 389959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 390959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 391959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle vregsNeedCopying = false; 392959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 393959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 394959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 395959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 396959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * When we insert new Field/Type/MethodIds into the DEX file, this may shunt some Ids 397959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * into a new position in the table. If this happens, every reference to the Ids must 398959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * be updated! Because CodeItems have their Instructions wrapped into a graph of MInsns 399959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * during mutation, they don't have a view of all their instructions during mutation, 400959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * and so if they are asked to update their instructions' indices into the tables, they 401959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * must call this method to get the actual list of instructions they currently own. 402959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 403959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public List<Instruction> requestLatestInstructions() { 404959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle List<Instruction> latestInsns = new ArrayList<Instruction>(); 405959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MInsn mInsn : mutatableInsns) { 406959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle latestInsns.add(mInsn.insn); 407959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 408959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return latestInsns; 409959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 410959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle} 411