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.CodeItem;
21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.EncodedCatchHandler;
22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.EncodedTypeAddrPair;
23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Instruction;
24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.Opcode;
25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.TryItem;
26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.formats.ContainsTarget;
27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.rawdex.formats.RawInsnHelper;
28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList;
30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Collections;
31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Comparator;
32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.HashMap;
33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.LinkedList;
34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List;
35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Map;
36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/**
38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Translates from a CodeItem (the raw list of Instructions) to MutatableCode
39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * (graph of Instructions, using MInsns and subclasses) and vice-versa.
40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */
41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class CodeTranslator {
42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a raw DEX file's CodeItem, produce a MutatableCode object, that CodeMutators
45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * are designed to operate on.
46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param codeItemIdx Used to make sure the correct CodeItem is updated later after mutation.
47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return A new MutatableCode object, which contains all relevant information
48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   *         obtained from the CodeItem.
49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public MutatableCode codeItemToMutatableCode(Program program, CodeItem codeItem,
51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int codeItemIdx, int mutatableCodeIdx) {
52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Log.debug("Translating CodeItem " + codeItemIdx
53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        + " (" + codeItem.meta.methodName + ") to MutatableCode");
54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    MutatableCode mutatableCode = new MutatableCode(program);
56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.registerMutatableCode(mutatableCode);
58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.name = codeItem.meta.methodName;
60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.shorty = codeItem.meta.shorty;
61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.isStatic = codeItem.meta.isStatic;
62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.codeItemIdx = codeItemIdx;
64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.mutatableCodeIdx = mutatableCodeIdx;
66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.registersSize = codeItem.registersSize;
68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.insSize = codeItem.insSize;
69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.outsSize = codeItem.outsSize;
70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.triesSize = codeItem.triesSize;
71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Temporary map from bytecode offset -> instruction.
73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Map<Integer,MInsn> insnLocationMap = new HashMap<Integer,MInsn>();
74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    List<Instruction> inputInsns = codeItem.insns;
76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Create the MInsns.
78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int loc = 0;
79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (Instruction insn : inputInsns) {
80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      MInsn mInsn = null;
81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (isInstructionSwitch(insn)) {
83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mInsn = new MSwitchInsn();
84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (isInstructionBranch(insn)) {
85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mInsn = new MBranchInsn();
86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (isInstructionFillArrayData(insn)) {
87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mInsn = new MInsnWithData();
88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else {
89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mInsn = new MInsn();
90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mInsn.insn = insn;
93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Populate the temporary map.
95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      insnLocationMap.put(loc, mInsn);
96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Populate the proper list of mutatable instructions.
98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mutatableCode.addInstructionToEnd(mInsn);
99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Calculate the offsets for each instruction.
101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mInsn.location = loc;
102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mInsn.locationUpdated = false;
103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      loc += mInsn.insn.getSize();
105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now make branch/switch instructions point at the right target instructions.
108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn instanceof MSwitchInsn) {
110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        readSwitchInstruction((MSwitchInsn) mInsn, insnLocationMap);
111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (mInsn instanceof MInsnWithData) {
112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int targetLoc = mInsn.location + (int) containsTarget.getTarget(mInsn.insn);
114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ((MInsnWithData)mInsn).dataTarget = insnLocationMap.get(targetLoc);
115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (((MInsnWithData)mInsn).dataTarget == null) {
116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit("Bad offset calculation in data-target insn");
117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (mInsn instanceof MBranchInsn) {
119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int targetLoc = mInsn.location + (int) containsTarget.getTarget(mInsn.insn);
121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ((MBranchInsn)mInsn).target = insnLocationMap.get(targetLoc);
122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (((MBranchInsn)mInsn).target == null) {
123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit("Bad offset calculation in branch insn");
124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now create try blocks.
129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (mutatableCode.triesSize > 0) {
130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      readTryBlocks(codeItem, mutatableCode, insnLocationMap);
131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return mutatableCode;
134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a MutatableCode item that may have been mutated, update the original CodeItem
138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * correctly, to allow valid DEX to be written back to the output file.
139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void mutatableCodeToCodeItem(CodeItem codeItem, MutatableCode mutatableCode) {
141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Log.debug("Translating MutatableCode " + mutatableCode.name
142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        + " to CodeItem " + mutatableCode.codeItemIdx);
143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // We must first align any data instructions at the end of the code
145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // before we recalculate any offsets.
146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // This also updates their sizes...
147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    alignDataInstructions(mutatableCode);
148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Validate that the tracked locations for instructions are valid.
150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Also mark locations as no longer being updated.
151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int loc = 0;
152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn.insn.justRaw) {
154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // All just_raw instructions need alignment!
155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if ((loc % 2) != 0) {
156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          loc++;
157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn.location != loc) {
160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.errorAndQuit(String.format("%s does not have expected location 0x%x",
161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            mInsn, loc));
162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mInsn.locationUpdated = false;
164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      loc += mInsn.insn.getSize();
165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // This new list will be attached to the CodeItem at the end...
168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    List<Instruction> outputInsns = new LinkedList<Instruction>();
169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Go through our new list of MInsns, adding them to the new
171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // list of instructions that will be attached to the CodeItem.
172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Also recalculate offsets for branches.
173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn instanceof MSwitchInsn) {
175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        updateSwitchInstruction((MSwitchInsn)mInsn, mutatableCode);
176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (mInsn instanceof MInsnWithData) {
177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn target = ((MInsnWithData) mInsn).dataTarget;
178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int dataOffset = target.location - mInsn.location;
179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        containsTarget.setTarget(mInsn.insn, dataOffset);
181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (mInsn instanceof MBranchInsn) {
182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn target = ((MBranchInsn) mInsn).target;
183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int branchOffset = target.location - mInsn.location;
184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        ContainsTarget containsTarget = (ContainsTarget) mInsn.insn.info.format;
185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        containsTarget.setTarget(mInsn.insn, branchOffset);
186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      outputInsns.add(mInsn.insn);
188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Calculate the new insns_size.
191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int newInsnsSize = 0;
192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (Instruction insn : outputInsns) {
193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      newInsnsSize += insn.getSize();
194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (mutatableCode.triesSize > 0) {
197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      updateTryBlocks(codeItem, mutatableCode);
198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.insnsSize = newInsnsSize;
201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.insns = outputInsns;
202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.registersSize = mutatableCode.registersSize;
203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.insSize = mutatableCode.insSize;
204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.outsSize = mutatableCode.outsSize;
205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    codeItem.triesSize = mutatableCode.triesSize;
206959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
207959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
208959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
209959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * The TryItem specifies an offset into the EncodedCatchHandlerList for a given CodeItem,
210959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * but we only have an array of the EncodedCatchHandlers that the List contains.
211959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * This function produces a map that offers a way to find out the index into our array,
212959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * from the try handler's offset.
213959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
214959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private Map<Short,Integer> createTryHandlerOffsetToIndexMap(CodeItem codeItem) {
215959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Create a sorted set of offsets.
216959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    List<Short> uniqueOffsets = new ArrayList<Short>();
217959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (TryItem tryItem : codeItem.tries) {
218959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int index = 0;
219959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      while (true) {
220959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if ((index == uniqueOffsets.size())
221959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            || (uniqueOffsets.get(index) > tryItem.handlerOff)) {
222959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          // First condition means we're at the end of the set (or we're inserting
223959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          //   into an empty set)
224959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          // Second condition means that the offset belongs here
225959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          // ...so insert it here, pushing the element currently in this position to the
226959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          //    right, if it exists
227959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          uniqueOffsets.add(index, tryItem.handlerOff);
228959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
229959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        } else if (uniqueOffsets.get(index) == tryItem.handlerOff) {
230959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          // We've already seen it, and we're making a set, not a list.
231959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
232959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        } else {
233959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          // Keep searching.
234959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          index++;
235959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
236959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
237959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
238959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now we have an (implicit) index -> offset mapping!
239959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
240959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now create the reverse mapping.
241959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Map<Short,Integer> offsetIndexMap = new HashMap<Short,Integer>();
242959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < uniqueOffsets.size(); i++) {
243959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      offsetIndexMap.put(uniqueOffsets.get(i), i);
244959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
245959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
246959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return offsetIndexMap;
247959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
248959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
249959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void readTryBlocks(CodeItem codeItem, MutatableCode mutatableCode,
250959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Map<Integer,MInsn> insnLocationMap) {
251959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    mutatableCode.mutatableTries = new LinkedList<MTryBlock>();
252959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
253959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Map<Short,Integer> offsetIndexMap = createTryHandlerOffsetToIndexMap(codeItem);
254959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
255959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Read each TryItem into a MutatableTryBlock.
256959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (TryItem tryItem : codeItem.tries) {
257959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      MTryBlock mTryBlock = new MTryBlock();
258959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
259959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the MInsns that form the start and end of the try block.
260959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int startLocation = tryItem.startAddr;
261959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mTryBlock.startInsn = insnLocationMap.get(startLocation);
26202de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov
26302de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      // The instructions vary in size, so we have to find the last instruction in the block in a
26402de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      // few tries.
26502de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      int endLocation = tryItem.startAddr + tryItem.insnCount - 1;
266959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mTryBlock.endInsn = insnLocationMap.get(endLocation);
26702de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      while ((mTryBlock.endInsn == null) && (endLocation >= startLocation)) {
26802de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov        endLocation--;
26902de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov        mTryBlock.endInsn = insnLocationMap.get(endLocation);
27002de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      }
271959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
272959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Sanity checks.
273959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mTryBlock.startInsn == null) {
274959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.errorAndQuit(String.format(
275959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            "Couldn't find a mutatable insn at start offset 0x%x",
276959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            startLocation));
277959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
278959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mTryBlock.endInsn == null) {
279959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.errorAndQuit(String.format(
280959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            "Couldn't find a mutatable insn at end offset 0x%x",
281959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            endLocation));
282959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
283959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
284959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the EncodedCatchHandler.
285959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int handlerIdx = offsetIndexMap.get(tryItem.handlerOff);
286959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      EncodedCatchHandler encodedCatchHandler = codeItem.handlers.list[handlerIdx];
287959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
288959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Do we have a catch all? If so, associate the MInsn that's there.
289959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (encodedCatchHandler.size <= 0) {
290959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mTryBlock.catchAllHandler =
291959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            insnLocationMap.get(encodedCatchHandler.catchAllAddr);
292959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Sanity check.
293959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (mTryBlock.catchAllHandler == null) {
294959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit(
295959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              String.format("Couldn't find a mutatable insn at catch-all offset 0x%x",
296959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                  encodedCatchHandler.catchAllAddr));
297959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
298959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
299959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Do we have explicitly-typed handlers? This will remain empty if not.
300959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mTryBlock.handlers = new LinkedList<MInsn>();
301959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
302959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Associate all the explicitly-typed handlers.
303959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 0; i < Math.abs(encodedCatchHandler.size); i++) {
304959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        EncodedTypeAddrPair handler = encodedCatchHandler.handlers[i];
305959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn handlerInsn = insnLocationMap.get(handler.addr);
306959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Sanity check.
307959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (handlerInsn == null) {
308959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit(String.format(
309959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              "Couldn't find a mutatable instruction at handler offset 0x%x",
310959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              handler.addr));
311959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
312959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mTryBlock.handlers.add(handlerInsn);
313959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
314959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
315959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Now finally add the new MutatableTryBlock into this MutatableCode's list!
316959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      mutatableCode.mutatableTries.add(mTryBlock);
317959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
318959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
319959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
320959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void updateTryBlocks(CodeItem codeItem, MutatableCode mutatableCode) {
321959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
322959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // TODO: Support ability to add extra try blocks/handlers?
323959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
324959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MTryBlock mTryBlock : mutatableCode.mutatableTries) {
325959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mTryBlock.startInsn.location > mTryBlock.endInsn.location) {
326959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Mutation has put this try block's end insn before its start insn. Fix this.
327959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn tempInsn = mTryBlock.startInsn;
328959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mTryBlock.startInsn = mTryBlock.endInsn;
329959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        mTryBlock.endInsn = tempInsn;
330959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
331959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
332959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
333959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // First, manipulate the try blocks if they overlap.
334959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < mutatableCode.mutatableTries.size() - 1; i++) {
335959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      MTryBlock first = mutatableCode.mutatableTries.get(i);
336959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      MTryBlock second = mutatableCode.mutatableTries.get(i + 1);
337959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
338959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Do they overlap?
339959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (first.endInsn.location > second.startInsn.location) {
340959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
341959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.debug("Found overlap in TryBlocks, moving 2nd TryBlock...");
342959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.debug("1st TryBlock goes from " + first.startInsn + " to "  + first.endInsn);
343959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.debug("2nd TryBlock goes from " + second.startInsn + " to "  + second.endInsn);
344959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
345959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Find the first instruction that comes after that does not overlap
346959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // with the first try block.
347959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn newInsn = second.startInsn;
348959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int ptr = mutatableCode.getInstructionIndex(newInsn);
349959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        while (first.endInsn.location > newInsn.location) {
350959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          ptr++;
351959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          newInsn = mutatableCode.getInstructionAt(ptr);
352959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
353959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        second.startInsn = newInsn;
354959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
355959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.debug("Now 2nd TryBlock goes from " + second.startInsn + " to "  + second.endInsn);
356959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
357959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
358959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
359959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Map<Short,Integer> offsetIndexMap = createTryHandlerOffsetToIndexMap(codeItem);
360959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
361959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int tryItemIdx = 0;
362959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MTryBlock mTryBlock : mutatableCode.mutatableTries) {
363959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      TryItem tryItem = codeItem.tries[tryItemIdx];
364959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
365959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      tryItem.startAddr = mTryBlock.startInsn.location;
36602de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      int insnCount = mTryBlock.endInsn.location - mTryBlock.startInsn.location +
36702de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov          mTryBlock.endInsn.insn.getSize();
36802de20038ae0b75d809c33eb0b36127dff7e7220Branislav Rankov      tryItem.insnCount = (short) insnCount;
369959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
370959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the EncodedCatchHandler.
371959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      EncodedCatchHandler encodedCatchHandler =
372959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          codeItem.handlers.list[offsetIndexMap.get(tryItem.handlerOff)];
373959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
374959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (encodedCatchHandler.size <= 0) {
375959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        encodedCatchHandler.catchAllAddr = mTryBlock.catchAllHandler.location;
376959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
377959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 0; i < Math.abs(encodedCatchHandler.size); i++) {
378959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsn handlerInsn = mTryBlock.handlers.get(i);
379959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        EncodedTypeAddrPair handler = encodedCatchHandler.handlers[i];
380959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        handler.addr = handlerInsn.location;
381959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
382959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      tryItemIdx++;
383959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
384959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
385959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
386959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
387959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a switch instruction, find the associated data's raw[] form, and update
388959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * the targets of the switch instruction to point to the correct instructions.
389959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
390959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void readSwitchInstruction(MSwitchInsn switchInsn,
391959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Map<Integer,MInsn> insnLocationMap) {
392959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Find the data.
393959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    ContainsTarget containsTarget = (ContainsTarget) switchInsn.insn.info.format;
394959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int dataLocation = switchInsn.location + (int) containsTarget.getTarget(switchInsn.insn);
395959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    switchInsn.dataTarget = insnLocationMap.get(dataLocation);
396959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (switchInsn.dataTarget == null) {
397959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Log.errorAndQuit("Bad offset calculation for data target in switch insn");
398959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
399959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
400959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now read the data.
401959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Instruction dataInsn = switchInsn.dataTarget.insn;
402959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
403959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int rawPtr = 2;
404959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
405959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int targetsSize = (int) RawInsnHelper.getUnsignedShortFromTwoBytes(dataInsn.rawBytes, rawPtr);
406959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    rawPtr += 2;
407959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
408959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int[] keys = new int[targetsSize];
409959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int[] targets = new int[targetsSize];
410959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
411959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (dataInsn.rawType == 1) {
412959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      switchInsn.packed = true;
413959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Dealing with a packed-switch.
414959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Read the first key.
415959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      keys[0] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes, rawPtr);
416959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      rawPtr += 4;
417959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Calculate the rest of the keys.
418959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 1; i < targetsSize; i++) {
419959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        keys[i] = keys[i - 1] + 1;
420959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
421959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    } else if (dataInsn.rawType == 2) {
422959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Dealing with a sparse-switch.
423959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Read all of the keys.
424959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 0; i < targetsSize; i++) {
425959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        keys[i] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes,
426959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            rawPtr);
427959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        rawPtr += 4;
428959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
429959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
430959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
431959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now read the targets.
432959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < targetsSize; i++) {
433959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      targets[i] = (int) RawInsnHelper.getUnsignedIntFromFourBytes(dataInsn.rawBytes,
434959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          rawPtr);
435959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      rawPtr += 4;
436959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
437959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
438959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Store the keys.
439959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    switchInsn.keys = keys;
440959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
441959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Convert our targets[] offsets into pointers to MInsns.
442959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int target : targets) {
443959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int targetLocation = switchInsn.location + target;
444959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      MInsn targetInsn = insnLocationMap.get(targetLocation);
445959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      switchInsn.targets.add(targetInsn);
446959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (targetInsn == null) {
447959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.errorAndQuit("Bad offset calculation for target in switch insn");
448959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
449959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
450959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
451959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
452959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
453959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Given a mutatable switch instruction, which may have had some of its branch
454959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * targets moved, update all the target offsets in the raw[] form of the instruction.
455959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
456959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void updateSwitchInstruction(MSwitchInsn switchInsn, MutatableCode mutatableCode) {
457959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Update the offset to the data instruction
458959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    MInsn dataTarget = switchInsn.dataTarget;
459959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int dataOffset = dataTarget.location - switchInsn.location;
460959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    ContainsTarget containsTarget = (ContainsTarget) switchInsn.insn.info.format;
461959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    containsTarget.setTarget(switchInsn.insn, dataOffset);
462959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
463959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int targetsSize = switchInsn.targets.size();
464959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
465959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int[] keys = switchInsn.keys;
466959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int[] targets = new int[targetsSize];
467959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
468959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Calculate the new offsets.
469959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int targetIdx = 0;
470959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn target : switchInsn.targets) {
471959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      targets[targetIdx] = target.location - switchInsn.location;
472959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      targetIdx++;
473959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
474959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
475959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Now write the data back to the raw bytes.
476959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Instruction dataInsn = switchInsn.dataTarget.insn;
477959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
478959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int rawPtr = 2;
479959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
480959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Write out the size.
481959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    RawInsnHelper.writeUnsignedShortToTwoBytes(dataInsn.rawBytes, rawPtr, targetsSize);
482959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    rawPtr += 2;
483959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
484959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Write out the keys.
485959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (switchInsn.packed) {
486959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Only write out one key - the first.
487959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, keys[0]);
488959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      rawPtr += 4;
489959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    } else {
490959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Write out all the keys.
491959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 0; i < targetsSize; i++) {
492959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, keys[i]);
493959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        rawPtr += 4;
494959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
495959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
496959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
497959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Write out all the targets.
498959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < targetsSize; i++) {
499959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      RawInsnHelper.writeUnsignedIntToFourBytes(dataInsn.rawBytes, rawPtr, targets[i]);
500959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      rawPtr += 4;
501959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
502959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
503959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
504959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
505959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * After mutation, data instructions may no longer be 4-byte aligned.
506959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * If this is the case, insert nops to align them all.
507959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * This makes a number of assumptions about data currently:
508959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * - data is always at the end of method insns
509959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * - all data instructions are stored contiguously
510959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
511959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void alignDataInstructions(MutatableCode mutatableCode) {
512959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Find all the switch data instructions.
513959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    List<MInsn> dataInsns = new ArrayList<MInsn>();
514959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
515959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Update raw sizes of the data instructions as well.
516959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (MInsn mInsn : mutatableCode.getInstructions()) {
517959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (mInsn instanceof MSwitchInsn) {
518959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Update the raw size of the instruction.
519959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MSwitchInsn switchInsn = (MSwitchInsn) mInsn;
520959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        int targetsSize = switchInsn.targets.size();
521959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Instruction dataInsn = switchInsn.dataTarget.insn;
522959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (switchInsn.packed) {
523959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          dataInsn.rawSize = (targetsSize * 2) + 4;
524959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        } else {
525959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          dataInsn.rawSize = (targetsSize * 4) + 2;
526959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
527959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        dataInsns.add(switchInsn.dataTarget);
528959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else if (mInsn instanceof MInsnWithData) {
529959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        MInsnWithData insnWithData =
530959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            (MInsnWithData) mInsn;
531959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        dataInsns.add(insnWithData.dataTarget);
532959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
533959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
534959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
535959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Only need to align switch data instructions if there are any!
536959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (!dataInsns.isEmpty()) {
537959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
538959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Log.debug("Found data instructions, checking alignment...");
539959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
540959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Sort data_insns by location.
541959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Collections.sort(dataInsns, new Comparator<MInsn>() {
542959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        @Override
543959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        public int compare(MInsn first, MInsn second) {
544959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (first.location < second.location) {
545959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            return -1;
546959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          } else if (first.location > second.location) {
547959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            return 1;
548959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
549959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          return 0;
550959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
551959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      });
552959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
553959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      boolean performedAlignment = false;
554959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
555959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Go through all the data insns, and insert an alignment nop if they're unaligned.
556959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (MInsn dataInsn : dataInsns) {
557959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if (dataInsn.location % 2 != 0) {
558959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.debug("Aligning data instruction with a nop.");
559959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          int alignmentNopIdx = mutatableCode.getInstructionIndex(dataInsn);
560959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          MInsn nop = new MInsn();
561959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          nop.insn = new Instruction();
562959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          nop.insn.info = Instruction.getOpcodeInfo(Opcode.NOP);
563959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          mutatableCode.insertInstructionAt(nop, alignmentNopIdx);
564959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          performedAlignment = true;
565959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
566959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
567959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
568959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (!performedAlignment) {
569959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Log.debug("Alignment okay.");
570959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
571959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
572959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
573959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
574959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
575959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Determine if a particular instruction is a branch instruction, based on opcode.
576959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
577959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private boolean isInstructionBranch(Instruction insn) {
578959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Opcode opcode = insn.info.opcode;
579959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (Opcode.isBetween(opcode, Opcode.IF_EQ, Opcode.IF_LEZ)
580959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        || Opcode.isBetween(opcode, Opcode.GOTO, Opcode.GOTO_32)) {
581959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return true;
582959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
583959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return false;
584959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
585959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
586959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
587959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Determine if a particular instruction is a switch instruction, based on opcode.
588959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
589959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private boolean isInstructionSwitch(Instruction insn) {
590959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Opcode opcode = insn.info.opcode;
591959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (Opcode.isBetween(opcode, Opcode.PACKED_SWITCH, Opcode.SPARSE_SWITCH)) {
592959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return true;
593959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
594959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return false;
595959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
596959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
597959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private boolean isInstructionFillArrayData(Instruction insn) {
598959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return (insn.info.opcode == Opcode.FILL_ARRAY_DATA);
599959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
600959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle}
601