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.rawdex;
18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log;
20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.program.MutatableCode;
21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.IOException;
23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.LinkedList;
24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List;
25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class CodeItem implements RawDexObject {
27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public short registersSize;
28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public short insSize;
29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public short outsSize;
30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public short triesSize;
31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public int debugInfoOff; // NB: this is a special case
32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public int insnsSize;
33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public List<Instruction> insns;
34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public TryItem[] tries;
35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public EncodedCatchHandlerList handlers;
36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private MutatableCode mutatableCode;
38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public static class MethodMetaInfo {
40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public String methodName;
41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public boolean isStatic;
42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    public String shorty;
43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public MethodMetaInfo meta = new MethodMetaInfo();
46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void read(DexRandomAccessFile file) throws IOException {
49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.alignForwards(4);
50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.getOffsetTracker().getNewOffsettable(file, this);
51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    registersSize = file.readUShort();
52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    insSize = file.readUShort();
53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    outsSize = file.readUShort();
54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    triesSize = file.readUShort();
55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    debugInfoOff = file.readUInt();
56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    insnsSize = file.readUInt();
57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    populateInstructionList(file);
58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (triesSize > 0) {
59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((insnsSize % 2) != 0) {
60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Consume padding.
61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        file.readUShort();
62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      tries = new TryItem[triesSize];
64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (int i = 0; i < triesSize; i++) {
65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        (tries[i] = new TryItem()).read(file);
66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      (handlers = new EncodedCatchHandlerList()).read(file);
68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private void populateInstructionList(DexRandomAccessFile file) throws IOException {
72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    insns = new LinkedList<Instruction>();
73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long insnsOffset = file.getFilePointer();
74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (insnsOffset != 0) {
75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      long finger = insnsOffset;
76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      long insnsEnd = insnsOffset + (2 * insnsSize);
77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      while (finger < insnsEnd) {
79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        file.seek(finger);
80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        Instruction newInsn = new Instruction();
81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        newInsn.read(file);
82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        insns.add(newInsn);
83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        finger += (2 * newInsn.getSize());
84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      file.seek(finger);
87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void write(DexRandomAccessFile file) throws IOException {
92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.alignForwards(4);
93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.getOffsetTracker().updatePositionOfNextOffsettable(file);
94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUShort(registersSize);
95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUShort(insSize);
96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUShort(outsSize);
97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUShort(triesSize);
98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // We do not support retaining debug info currently.
99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUInt(0 /*debug_info_off*/);
100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    file.writeUInt(insnsSize);
101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (Instruction insn : insns) {
102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      insn.write(file);
103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (triesSize > 0) {
105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((insnsSize % 2) != 0) {
106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // produce padding
107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        file.writeUShort((short) 0);
108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      for (TryItem tryItem : tries) {
110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        tryItem.write(file);
111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      handlers.write(file);
113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * CodeTranslator should call this to notify a CodeItem about its
118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * mutatable code, so it can always get the "latest" view of its
119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * instructions.
120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void registerMutatableCode(MutatableCode mutatableCode) {
122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    this.mutatableCode = mutatableCode;
123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  @Override
126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (kind == IndexUpdateKind.TYPE_ID && triesSize > 0) {
128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // EncodedCatchHandlerList (well, the EncodedTypeAddrPairs it owns)
129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // are only interested in TYPE_IDs.
130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      handlers.incrementIndex(kind, insertedIdx);
131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (kind == IndexUpdateKind.PROTO_ID) {
134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // The only kind we can't encounter in an instruction.
135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    List<Instruction> insnsToIncrement = insns;
139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // If we have an associated MutatableCode, then it may have created some new insns
141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // that we won't know about yet, during the mutation phase.
142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    //
143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Ask for the latest view of the insns.
144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (mutatableCode != null) {
145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      insnsToIncrement = mutatableCode.requestLatestInstructions();
146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (Instruction insn : insnsToIncrement) {
149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      Opcode opcode = insn.info.opcode;
150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      switch (kind) {
151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case STRING_ID:
152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (opcode == Opcode.CONST_STRING || opcode == Opcode.CONST_STRING_JUMBO) {
153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // STRING@BBBB
154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregB >= insertedIdx) {
155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregB++;
156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case TYPE_ID:
160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (opcode == Opcode.CONST_CLASS
161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              || opcode == Opcode.CHECK_CAST
162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              || opcode == Opcode.NEW_INSTANCE
163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              || opcode == Opcode.FILLED_NEW_ARRAY
164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              || opcode == Opcode.FILLED_NEW_ARRAY_RANGE) {
165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // TYPE@BBBB
166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregB >= insertedIdx) {
167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregB++;
168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          } else if (opcode == Opcode.INSTANCE_OF || opcode == Opcode.NEW_ARRAY) {
170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // TYPE@CCCC
171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregC >= insertedIdx) {
172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregC++;
173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case FIELD_ID:
177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (Opcode.isBetween(opcode, Opcode.SGET, Opcode.SPUT_SHORT)) {
178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // FIELD@BBBB
179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregB >= insertedIdx) {
180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregB++;
181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          } else if (Opcode.isBetween(opcode, Opcode.IGET, Opcode.IPUT_SHORT)) {
183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // FIELD@CCCC
184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregC >= insertedIdx) {
185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregC++;
186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        case METHOD_ID:
190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          if (Opcode.isBetween(opcode, Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_INTERFACE)
191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              || Opcode.isBetween(opcode,
192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle                  Opcode.INVOKE_VIRTUAL_RANGE, Opcode.INVOKE_INTERFACE_RANGE)) {
193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            // METHOD@BBBB
194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            if (insn.vregB >= insertedIdx) {
195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              insn.vregB++;
196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle            }
197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          }
198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          break;
199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        default:
200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          Log.errorAndQuit("Unexpected IndexUpdateKind requested "
201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle              + "in Instruction.incrementIndex()");
202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle}
206