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