• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.dexlib2.analysis;
33 
34 import org.jf.dexlib2.iface.instruction.*;
35 import org.jf.dexlib2.iface.reference.MethodReference;
36 import org.jf.dexlib2.iface.reference.Reference;
37 import org.jf.util.ExceptionWithContext;
38 
39 import javax.annotation.Nonnull;
40 import java.util.*;
41 
42 public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
43     /**
44      * The actual instruction
45      */
46     protected Instruction instruction;
47 
48     /**
49      * The index of the instruction, where the first instruction in the method is at index 0, and so on
50      */
51     protected final int instructionIndex;
52 
53     /**
54      * Instructions that can pass on execution to this one during normal execution
55      */
56     protected final TreeSet<AnalyzedInstruction> predecessors = new TreeSet<AnalyzedInstruction>();
57 
58     /**
59      * Instructions that can execution could pass on to next during normal execution
60      */
61     protected final LinkedList<AnalyzedInstruction> successors = new LinkedList<AnalyzedInstruction>();
62 
63     /**
64      * This contains the register types *before* the instruction has executed
65      */
66     protected final RegisterType[] preRegisterMap;
67 
68     /**
69      * This contains the register types *after* the instruction has executed
70      */
71     protected final RegisterType[] postRegisterMap;
72 
73     /**
74      * When deodexing, we might need to deodex this instruction multiple times, when we merge in new register
75      * information. When this happens, we need to restore the original (odexed) instruction, so we can deodex it again
76      */
77     protected final Instruction originalInstruction;
78 
AnalyzedInstruction(Instruction instruction, int instructionIndex, int registerCount)79     public AnalyzedInstruction(Instruction instruction, int instructionIndex, int registerCount) {
80         this.instruction = instruction;
81         this.originalInstruction = instruction;
82         this.instructionIndex = instructionIndex;
83         this.postRegisterMap = new RegisterType[registerCount];
84         this.preRegisterMap = new RegisterType[registerCount];
85         RegisterType unknown = RegisterType.getRegisterType(RegisterType.UNKNOWN, null);
86         for (int i=0; i<registerCount; i++) {
87             preRegisterMap[i] = unknown;
88             postRegisterMap[i] = unknown;
89         }
90     }
91 
getInstructionIndex()92     public int getInstructionIndex() {
93         return instructionIndex;
94     }
95 
getPredecessorCount()96     public int getPredecessorCount() {
97         return predecessors.size();
98     }
99 
getPredecessors()100     public SortedSet<AnalyzedInstruction> getPredecessors() {
101         return Collections.unmodifiableSortedSet(predecessors);
102     }
103 
addPredecessor(AnalyzedInstruction predecessor)104     protected boolean addPredecessor(AnalyzedInstruction predecessor) {
105         return predecessors.add(predecessor);
106     }
107 
addSuccessor(AnalyzedInstruction successor)108     protected void addSuccessor(AnalyzedInstruction successor) {
109         successors.add(successor);
110     }
111 
setDeodexedInstruction(Instruction instruction)112     protected void setDeodexedInstruction(Instruction instruction) {
113         assert originalInstruction.getOpcode().odexOnly();
114         this.instruction = instruction;
115     }
116 
restoreOdexedInstruction()117     protected void restoreOdexedInstruction() {
118         assert originalInstruction.getOpcode().odexOnly();
119         instruction = originalInstruction;
120     }
121 
getSuccessorCount()122     public int getSuccessorCount() {
123         return successors.size();
124     }
125 
getSuccesors()126     public List<AnalyzedInstruction> getSuccesors() {
127         return Collections.unmodifiableList(successors);
128     }
129 
getInstruction()130     public Instruction getInstruction() {
131         return instruction;
132     }
133 
getOriginalInstruction()134     public Instruction getOriginalInstruction() {
135         return originalInstruction;
136     }
137 
138     /**
139      * Is this instruction a "beginning instruction". A beginning instruction is defined to be an instruction
140      * that can be the first successfully executed instruction in the method. The first instruction is always a
141      * beginning instruction. If the first instruction can throw an exception, and is covered by a try block, then
142      * the first instruction of any exception handler for that try block is also a beginning instruction. And likewise,
143      * if any of those instructions can throw an exception and are covered by try blocks, the first instruction of the
144      * corresponding exception handler is a beginning instruction, etc.
145      *
146      * To determine this, we simply check if the first predecessor is the fake "StartOfMethod" instruction, which has
147      * an instruction index of -1.
148      * @return a boolean value indicating whether this instruction is a beginning instruction
149      */
isBeginningInstruction()150     public boolean isBeginningInstruction() {
151         //if this instruction has no predecessors, it is either the fake "StartOfMethod" instruction or it is an
152         //unreachable instruction.
153         if (predecessors.size() == 0) {
154             return false;
155         }
156 
157         if (predecessors.first().instructionIndex == -1) {
158             return true;
159         }
160         return false;
161     }
162 
163     /*
164      * Merges the given register type into the specified pre-instruction register, and also sets the post-instruction
165      * register type accordingly if it isn't a destination register for this instruction
166      * @param registerNumber Which register to set
167      * @param registerType The register type
168      * @returns true If the post-instruction register type was changed. This might be false if either the specified
169      * register is a destination register for this instruction, or if the pre-instruction register type didn't change
170      * after merging in the given register type
171      */
mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions)172     protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions) {
173         assert registerNumber >= 0 && registerNumber < postRegisterMap.length;
174         assert registerType != null;
175 
176         RegisterType oldRegisterType = preRegisterMap[registerNumber];
177         RegisterType mergedRegisterType = oldRegisterType.merge(registerType);
178 
179         if (mergedRegisterType.equals(oldRegisterType)) {
180             return false;
181         }
182 
183         preRegisterMap[registerNumber] = mergedRegisterType;
184         verifiedInstructions.clear(instructionIndex);
185 
186         if (!setsRegister(registerNumber)) {
187             postRegisterMap[registerNumber] = mergedRegisterType;
188             return true;
189         }
190 
191         return false;
192     }
193 
194     /**
195      * Iterates over the predecessors of this instruction, and merges all the post-instruction register types for the
196      * given register. Any dead, unreachable, or odexed predecessor is ignored
197      * @param registerNumber the register number
198      * @return The register type resulting from merging the post-instruction register types from all predecessors
199      */
200     protected RegisterType mergePreRegisterTypeFromPredecessors(int registerNumber) {
201         RegisterType mergedRegisterType = null;
202         for (AnalyzedInstruction predecessor: predecessors) {
203             RegisterType predecessorRegisterType = predecessor.postRegisterMap[registerNumber];
204             assert predecessorRegisterType != null;
205             mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType);
206         }
207         return mergedRegisterType;
208     }
209 
210     /*
211       * Sets the "post-instruction" register type as indicated.
212       * @param registerNumber Which register to set
213       * @param registerType The "post-instruction" register type
214       * @returns true if the given register type is different than the existing post-instruction register type
215       */
216      protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) {
217          assert registerNumber >= 0 && registerNumber < postRegisterMap.length;
218          assert registerType != null;
219 
220          RegisterType oldRegisterType = postRegisterMap[registerNumber];
221          if (oldRegisterType.equals(registerType)) {
222              return false;
223          }
224 
225          postRegisterMap[registerNumber] = registerType;
226          return true;
227      }
228 
229 
230     protected boolean isInvokeInit() {
231         if (instruction == null || !instruction.getOpcode().canInitializeReference()) {
232             return false;
233         }
234 
235         ReferenceInstruction instruction = (ReferenceInstruction)this.instruction;
236 
237         Reference reference = instruction.getReference();
238         if (reference instanceof MethodReference) {
239             return ((MethodReference)reference).getName().equals("<init>");
240         }
241 
242         return false;
243     }
244 
245     public boolean setsRegister() {
246         return instruction.getOpcode().setsRegister();
247     }
248 
249     public boolean setsWideRegister() {
250         return instruction.getOpcode().setsWideRegister();
251     }
252 
253     public boolean setsRegister(int registerNumber) {
254         //When constructing a new object, the register type will be an uninitialized reference after the new-instance
255         //instruction, but becomes an initialized reference once the <init> method is called. So even though invoke
256         //instructions don't normally change any registers, calling an <init> method will change the type of its
257         //object register. If the uninitialized reference has been copied to other registers, they will be initialized
258         //as well, so we need to check for that too
259         if (isInvokeInit()) {
260             int destinationRegister;
261             if (instruction instanceof FiveRegisterInstruction) {
262                 destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterC();
263             } else {
264                 assert instruction instanceof RegisterRangeInstruction;
265                 RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction;
266                 assert rangeInstruction.getRegisterCount() > 0;
267                 destinationRegister = rangeInstruction.getStartRegister();
268             }
269 
270             if (registerNumber == destinationRegister) {
271                 return true;
272             }
273             RegisterType preInstructionDestRegisterType = getPreInstructionRegisterType(registerNumber);
274             if (preInstructionDestRegisterType.category != RegisterType.UNINIT_REF &&
275                 preInstructionDestRegisterType.category != RegisterType.UNINIT_THIS) {
276 
277                 return false;
278             }
279             //check if the uninit ref has been copied to another register
280             if (getPreInstructionRegisterType(registerNumber).equals(preInstructionDestRegisterType)) {
281                 return true;
282             }
283             return false;
284         }
285 
286         if (!setsRegister()) {
287             return false;
288         }
289         int destinationRegister = getDestinationRegister();
290 
291         if (registerNumber == destinationRegister) {
292             return true;
293         }
294         if (setsWideRegister() && registerNumber == (destinationRegister + 1)) {
295             return true;
296         }
297         return false;
298     }
299 
300     public int getDestinationRegister() {
301         if (!this.instruction.getOpcode().setsRegister()) {
302             throw new ExceptionWithContext("Cannot call getDestinationRegister() for an instruction that doesn't " +
303                     "store a value");
304         }
305         return ((OneRegisterInstruction)instruction).getRegisterA();
306     }
307 
308     public int getRegisterCount() {
309         return postRegisterMap.length;
310     }
311 
312     @Nonnull
313     public RegisterType getPostInstructionRegisterType(int registerNumber) {
314         return postRegisterMap[registerNumber];
315     }
316 
317     @Nonnull
318     public RegisterType getPreInstructionRegisterType(int registerNumber) {
319         return preRegisterMap[registerNumber];
320     }
321 
322     public int compareTo(AnalyzedInstruction analyzedInstruction) {
323         if (instructionIndex < analyzedInstruction.instructionIndex) {
324             return -1;
325         } else if (instructionIndex == analyzedInstruction.instructionIndex) {
326             return 0;
327         } else {
328             return 1;
329         }
330     }
331 }
332 
333