MethodAnalyzer.java revision e3478f4fd4a52a6dbbcc46b389ad7c8fcc1135ab
1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/* 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Copyright 2013, Google Inc. 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * All rights reserved. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * modification, are permitted provided that the following conditions are 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * met: 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * * Redistributions of source code must retain the above copyright 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * * Redistributions in binary form must reproduce the above 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * in the documentation and/or other materials provided with the 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * distribution. 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * contributors may be used to endorse or promote products derived from 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * this software without specific prior written permission. 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.jf.dexlib2.analysis; 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import com.google.common.collect.ImmutableList; 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.Opcode; 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.*; 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.instruction.*; 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.instruction.formats.*; 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.FieldReference; 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.MethodReference; 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.Reference; 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.iface.reference.TypeReference; 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.immutable.instruction.*; 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.MethodUtil; 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.ReferenceUtil; 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.dexlib2.util.TypeUtils; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.util.BitSetUtils; 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.util.ExceptionWithContext; 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.jf.util.SparseArray; 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import javax.annotation.Nonnull; 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import javax.annotation.Nullable; 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.BitSet; 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import java.util.List; 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/** 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * verify it. 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Before calling the analyze() method, you must have initialized the ClassPath by calling 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * ClassPath.InitializeClassPath 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)public class MethodAnalyzer { 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @Nonnull private final Method method; 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final MethodImplementation methodImpl; 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @Nonnull private final ClassPath classPath; 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @Nullable private final InlineMethodResolver inlineResolver; 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This contains all the AnalyzedInstruction instances, keyed by the code unit address of the instruction 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final SparseArray<AnalyzedInstruction> analyzedInstructions = 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new SparseArray<AnalyzedInstruction>(0); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Which instructions have been analyzed, keyed by instruction index 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final BitSet analyzedState; 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nullable private AnalysisException analysisException = null; 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //register types for this instruction to the parameter types, in order to have them propagate to all of its 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //instruction, etc. 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private final AnalyzedInstruction startOfMethod; 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method, 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nullable InlineMethodResolver inlineResolver) { 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.classPath = classPath; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.inlineResolver = inlineResolver; 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.method = method; 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MethodImplementation methodImpl = method.getImplementation(); 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (methodImpl == null) { 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) throw new IllegalArgumentException("The method has no implementation"); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.methodImpl = methodImpl; 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //have to handle the case this special case of instruction being null, in the main class 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) startOfMethod = new AnalyzedInstruction(null, -1, methodImpl.getRegisterCount()) { 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public boolean setsRegister() { 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public boolean setsWideRegister() { 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public boolean setsRegister(int registerNumber) { 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public int getDestinationRegister() { 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert false; 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return -1; 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) }; 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) buildInstructionList(); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzedState = new BitSet(analyzedInstructions.size()); 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyze(); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void analyze() { 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Method method = this.method; 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MethodImplementation methodImpl = this.methodImpl; 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int totalRegisters = methodImpl.getRegisterCount(); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int parameterRegisters = MethodUtil.getParameterRegisterCount(method); 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int nonParameterRegisters = totalRegisters - parameterRegisters; 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //if this isn't a static method, determine which register is the "this" register and set the type to the 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //current class 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!MethodUtil.isStatic(method)) { 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) nonParameterRegisters--; 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int thisRegister = totalRegisters - parameterRegisters; 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //if this is a constructor, then set the "this" register to an uninitialized reference of the current class 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (MethodUtil.isConstructor(method)) { 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType.getRegisterType(RegisterType.UNINIT, 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) classPath.getClass(method.getDefiningClass()))); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType.getRegisterType(RegisterType.REFERENCE, 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) classPath.getClass(method.getDefiningClass()))); 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) propagateParameterTypes(totalRegisters-parameterRegisters+1); 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) propagateParameterTypes(totalRegisters-parameterRegisters); 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType uninit = RegisterType.getRegisterType(RegisterType.UNINIT, null); 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i=0; i<nonParameterRegisters; i++) { 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, i, uninit); 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BitSet instructionsToAnalyze = new BitSet(analyzedInstructions.size()); 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //make sure all of the "first instructions" are marked for processing 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (AnalyzedInstruction successor: startOfMethod.successors) { 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionsToAnalyze.set(successor.instructionIndex); 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BitSet undeodexedInstructions = new BitSet(analyzedInstructions.size()); 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) do { 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) boolean didSomething = false; 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (!instructionsToAnalyze.isEmpty()) { 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for(int i=instructionsToAnalyze.nextSetBit(0); i>=0; i=instructionsToAnalyze.nextSetBit(i+1)) { 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionsToAnalyze.clear(i); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (analyzedState.get(i)) { 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AnalyzedInstruction instructionToAnalyze = analyzedInstructions.valueAt(i); 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try { 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (instructionToAnalyze.originalInstruction.getOpcode().odexOnly()) { 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //if we had deodexed an odex instruction in a previous pass, we might have more specific 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //register information now, so let's restore the original odexed instruction and 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //re-deodex it 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionToAnalyze.restoreOdexedInstruction(); 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!analyzeInstruction(instructionToAnalyze)) { 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) undeodexedInstructions.set(i); 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) didSomething = true; 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) undeodexedInstructions.clear(i); 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } catch (AnalysisException ex) { 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.analysisException = ex; 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int codeAddress = getInstructionAddress(instructionToAnalyze); 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ex.addContext(String.format("opcode: %s", instructionToAnalyze.instruction.getOpcode().name)); 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ex.addContext(String.format("code address: %d", codeAddress)); 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ex.addContext(String.format("method: %s", ReferenceUtil.getReferenceString(method))); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzedState.set(instructionToAnalyze.getInstructionIndex()); 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (AnalyzedInstruction successor: instructionToAnalyze.successors) { 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionsToAnalyze.set(successor.getInstructionIndex()); 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (analysisException != null) { 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!didSomething) { 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!undeodexedInstructions.isEmpty()) { 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i=undeodexedInstructions.nextSetBit(0); i>=0; i=undeodexedInstructions.nextSetBit(i+1)) { 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionsToAnalyze.set(i); 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } while (true); 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //Now, go through and fix up any unresolvable odex instructions. These are usually odex instructions 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //that operate on a null register, and thus always throw an NPE. They can also be any sort of odex instruction 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //that occurs after an unresolvable odex instruction. We deodex if possible, or replace with an 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //UnresolvableOdexInstruction 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i=0; i< analyzedInstructions.size(); i++) { 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AnalyzedInstruction analyzedInstruction = analyzedInstructions.valueAt(i); 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Instruction instruction = analyzedInstruction.getInstruction(); 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (instruction.getOpcode().odexOnly()) { 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int objectRegisterNumber; 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (instruction.getOpcode().format) { 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format10x: 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzeReturnVoidBarrier(analyzedInstruction, false); 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format21c: 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format22c: 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzePutGetVolatile(analyzedInstruction, false); 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format35c: 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzeInvokeDirectEmpty(analyzedInstruction, false); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format3rc: 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzeInvokeObjectInitRange(analyzedInstruction, false); 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format22cs: 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) objectRegisterNumber = ((Instruction22cs)instruction).getRegisterB(); 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format35mi: 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format35ms: 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) objectRegisterNumber = ((FiveRegisterInstruction)instruction).getRegisterD(); 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format3rmi: 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case Format3rms: 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) objectRegisterNumber = ((RegisterRangeInstruction)instruction).getStartRegister(); 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzedInstruction.setDeodexedInstruction( 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new UnresolvedOdexInstruction(instruction, objectRegisterNumber)); 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void propagateParameterTypes(int parameterStartRegister) { 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int i=0; 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (MethodParameter parameter: method.getParameters()) { 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (TypeUtils.isWideType(parameter)) { 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType.getWideRegisterType(parameter, true)); 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType.getWideRegisterType(parameter, false)); 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType.getRegisterType(classPath, parameter)); 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public int getInstructionAddress(@Nonnull AnalyzedInstruction instruction) { 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return analyzedInstructions.keyAt(instruction.instructionIndex); 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void setDestinationRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull RegisterType registerType) { 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(), 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) registerType); 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int registerNumber, @Nonnull RegisterType registerType) { 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BitSet changedInstructions = new BitSet(analyzedInstructions.size()); 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) { 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions); 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //the next iteration of the while loop. 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //This could also be done recursively, but in large methods it would likely cause very deep recursion, 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //annoying. 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (!changedInstructions.isEmpty()) { 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int instructionIndex=changedInstructions.nextSetBit(0); 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionIndex>=0; 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) changedInstructions.clear(instructionIndex); 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) changedInstructions); 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (registerType.category == RegisterType.LONG_LO) { 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) checkWidePair(registerNumber, analyzedInstruction); 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE); 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (registerType.category == RegisterType.DOUBLE_LO) { 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) checkWidePair(registerNumber, analyzedInstruction); 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE); 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber, 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull BitSet changedInstructions) { 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber); 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (AnalyzedInstruction successor: instruction.successors) { 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState)) { 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) changedInstructions.set(successor.instructionIndex); 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private void buildInstructionList() { 3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int registerCount = methodImpl.getRegisterCount(); 3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions()); 3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzedInstructions.ensureCapacity(instructions.size()); 3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //first, create all the instructions and populate the instructionAddresses array 3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int currentCodeAddress = 0; 3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i=0; i<instructions.size(); i++) { 3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Instruction instruction = instructions.get(i); 3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(instruction, i, registerCount)); 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert analyzedInstructions.indexOfKey(currentCodeAddress) == i; 3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) currentCodeAddress += instruction.getCodeUnits(); 3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception 3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //and is covered by a try block should be set to a list of the first instructions of each exception handler 3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) //for the try block covering the instruction 3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) List<? extends TryBlock> tries = methodImpl.getTryBlocks(); 3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int triesIndex = 0; 3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TryBlock currentTry = null; 3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AnalyzedInstruction[] currentExceptionHandlers = null; 3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][]; 3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (tries != null) { 3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i=0; i< analyzedInstructions.size(); i++) { 3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AnalyzedInstruction instruction = analyzedInstructions.valueAt(i); 3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Opcode instructionOpcode = instruction.instruction.getOpcode(); 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) currentCodeAddress = getInstructionAddress(instruction); 383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) //check if we have gone past the end of the current try 385 if (currentTry != null) { 386 if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) { 387 currentTry = null; 388 triesIndex++; 389 } 390 } 391 392 //check if the next try is applicable yet 393 if (currentTry == null && triesIndex < tries.size()) { 394 TryBlock tryBlock = tries.get(triesIndex); 395 if (tryBlock.getStartCodeAddress() <= currentCodeAddress) { 396 assert(tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress); 397 398 currentTry = tryBlock; 399 400 currentExceptionHandlers = buildExceptionHandlerArray(tryBlock); 401 } 402 } 403 404 //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers 405 //for the current instruction 406 if (currentTry != null && instructionOpcode.canThrow()) { 407 exceptionHandlers[i] = currentExceptionHandlers; 408 } 409 } 410 } 411 412 //finally, populate the successors and predecessors for each instruction. We start at the fake "StartOfMethod" 413 //instruction and follow the execution path. Any unreachable code won't have any predecessors or successors, 414 //and no reachable code will have an unreachable predessor or successor 415 assert analyzedInstructions.size() > 0; 416 BitSet instructionsToProcess = new BitSet(instructions.size()); 417 418 addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess); 419 while (!instructionsToProcess.isEmpty()) { 420 int currentInstructionIndex = instructionsToProcess.nextSetBit(0); 421 instructionsToProcess.clear(currentInstructionIndex); 422 423 AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex); 424 Opcode instructionOpcode = instruction.instruction.getOpcode(); 425 int instructionCodeAddress = getInstructionAddress(instruction); 426 427 if (instruction.instruction.getOpcode().canContinue()) { 428 if (currentInstructionIndex == analyzedInstructions.size() - 1) { 429 throw new AnalysisException("Execution can continue past the last instruction"); 430 } 431 432 AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex+1); 433 addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess); 434 } 435 436 if (instruction.instruction instanceof OffsetInstruction) { 437 OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction; 438 439 if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) { 440 SwitchPayload switchPayload = (SwitchPayload)analyzedInstructions.get(instructionCodeAddress + 441 offsetInstruction.getCodeOffset()).instruction; 442 for (SwitchElement switchElement: switchPayload.getSwitchElements()) { 443 AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + 444 switchElement.getOffset()); 445 446 addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, 447 instructionsToProcess); 448 } 449 } else { 450 int targetAddressOffset = offsetInstruction.getCodeOffset(); 451 AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + 452 targetAddressOffset); 453 addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess); 454 } 455 } 456 } 457 } 458 459 private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, 460 @Nonnull AnalyzedInstruction successor, 461 @Nonnull AnalyzedInstruction[][] exceptionHandlers, 462 @Nonnull BitSet instructionsToProcess) { 463 addPredecessorSuccessor(predecessor, successor, exceptionHandlers, instructionsToProcess, false); 464 } 465 466 private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, 467 @Nonnull AnalyzedInstruction successor, 468 @Nonnull AnalyzedInstruction[][] exceptionHandlers, 469 @Nonnull BitSet instructionsToProcess, boolean allowMoveException) { 470 471 if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) { 472 throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name + 473 " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) + 474 " to the move-exception instruction at address 0x" + 475 Integer.toHexString(getInstructionAddress(successor))); 476 } 477 478 if (!successor.addPredecessor(predecessor)) { 479 return; 480 } 481 482 predecessor.addSuccessor(successor); 483 instructionsToProcess.set(successor.getInstructionIndex()); 484 485 486 //if the successor can throw an instruction, then we need to add the exception handlers as additional 487 //successors to the predecessor (and then apply this same logic recursively if needed) 488 //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually 489 //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other 490 //instruction. But since it doesn't modify any registers, we can treat it like any other instruction. 491 AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex]; 492 if (exceptionHandlersForSuccessor != null) { 493 //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction 494 //can throw an exception 495 assert successor.instruction.getOpcode().canThrow(); 496 497 for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) { 498 addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true); 499 } 500 } 501 } 502 503 @Nonnull 504 private AnalyzedInstruction[] buildExceptionHandlerArray(@Nonnull TryBlock tryBlock) { 505 List<? extends ExceptionHandler> exceptionHandlers = tryBlock.getExceptionHandlers(); 506 507 AnalyzedInstruction[] handlerInstructions = new AnalyzedInstruction[exceptionHandlers.size()]; 508 for (int i=0; i<exceptionHandlers.size(); i++) { 509 handlerInstructions[i] = analyzedInstructions.get(exceptionHandlers.get(i).getHandlerCodeAddress()); 510 } 511 512 return handlerInstructions; 513 } 514 515 /** 516 * @return false if analyzedInstruction is an odex instruction that couldn't be deodexed, due to its 517 * object register being null 518 */ 519 private boolean analyzeInstruction(@Nonnull AnalyzedInstruction analyzedInstruction) { 520 Instruction instruction = analyzedInstruction.instruction; 521 522 switch (instruction.getOpcode()) { 523 case NOP: 524 return true; 525 case MOVE: 526 case MOVE_FROM16: 527 case MOVE_16: 528 case MOVE_WIDE: 529 case MOVE_WIDE_FROM16: 530 case MOVE_WIDE_16: 531 case MOVE_OBJECT: 532 case MOVE_OBJECT_FROM16: 533 case MOVE_OBJECT_16: 534 analyzeMove(analyzedInstruction); 535 return true; 536 case MOVE_RESULT: 537 case MOVE_RESULT_WIDE: 538 case MOVE_RESULT_OBJECT: 539 analyzeMoveResult(analyzedInstruction); 540 return true; 541 case MOVE_EXCEPTION: 542 analyzeMoveException(analyzedInstruction); 543 return true; 544 case RETURN_VOID: 545 case RETURN: 546 case RETURN_WIDE: 547 case RETURN_OBJECT: 548 return true; 549 case RETURN_VOID_BARRIER: 550 analyzeReturnVoidBarrier(analyzedInstruction); 551 return true; 552 case CONST_4: 553 case CONST_16: 554 case CONST: 555 case CONST_HIGH16: 556 analyzeConst(analyzedInstruction); 557 return true; 558 case CONST_WIDE_16: 559 case CONST_WIDE_32: 560 case CONST_WIDE: 561 case CONST_WIDE_HIGH16: 562 analyzeWideConst(analyzedInstruction); 563 return true; 564 case CONST_STRING: 565 case CONST_STRING_JUMBO: 566 analyzeConstString(analyzedInstruction); 567 return true; 568 case CONST_CLASS: 569 analyzeConstClass(analyzedInstruction); 570 return true; 571 case MONITOR_ENTER: 572 case MONITOR_EXIT: 573 return true; 574 case CHECK_CAST: 575 analyzeCheckCast(analyzedInstruction); 576 return true; 577 case INSTANCE_OF: 578 analyzeInstanceOf(analyzedInstruction); 579 return true; 580 case ARRAY_LENGTH: 581 analyzeArrayLength(analyzedInstruction); 582 return true; 583 case NEW_INSTANCE: 584 analyzeNewInstance(analyzedInstruction); 585 return true; 586 case NEW_ARRAY: 587 analyzeNewArray(analyzedInstruction); 588 return true; 589 case FILLED_NEW_ARRAY: 590 case FILLED_NEW_ARRAY_RANGE: 591 return true; 592 case FILL_ARRAY_DATA: 593 return true; 594 case THROW: 595 case GOTO: 596 case GOTO_16: 597 case GOTO_32: 598 return true; 599 case PACKED_SWITCH: 600 case SPARSE_SWITCH: 601 return true; 602 case CMPL_FLOAT: 603 case CMPG_FLOAT: 604 case CMPL_DOUBLE: 605 case CMPG_DOUBLE: 606 case CMP_LONG: 607 analyzeFloatWideCmp(analyzedInstruction); 608 return true; 609 case IF_EQ: 610 case IF_NE: 611 case IF_LT: 612 case IF_GE: 613 case IF_GT: 614 case IF_LE: 615 case IF_EQZ: 616 case IF_NEZ: 617 case IF_LTZ: 618 case IF_GEZ: 619 case IF_GTZ: 620 case IF_LEZ: 621 return true; 622 case AGET: 623 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.INTEGER_TYPE); 624 return true; 625 case AGET_BOOLEAN: 626 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 627 return true; 628 case AGET_BYTE: 629 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BYTE_TYPE); 630 return true; 631 case AGET_CHAR: 632 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.CHAR_TYPE); 633 return true; 634 case AGET_SHORT: 635 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.SHORT_TYPE); 636 return true; 637 case AGET_WIDE: 638 analyzeAgetWide(analyzedInstruction); 639 return true; 640 case AGET_OBJECT: 641 analyzeAgetObject(analyzedInstruction); 642 return true; 643 case APUT: 644 case APUT_BOOLEAN: 645 case APUT_BYTE: 646 case APUT_CHAR: 647 case APUT_SHORT: 648 case APUT_WIDE: 649 case APUT_OBJECT: 650 return true; 651 case IGET: 652 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE); 653 return true; 654 case IGET_BOOLEAN: 655 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 656 return true; 657 case IGET_BYTE: 658 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE); 659 return true; 660 case IGET_CHAR: 661 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE); 662 return true; 663 case IGET_SHORT: 664 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE); 665 return true; 666 case IGET_WIDE: 667 case IGET_OBJECT: 668 analyzeIgetSgetWideObject(analyzedInstruction); 669 return true; 670 case IPUT: 671 case IPUT_BOOLEAN: 672 case IPUT_BYTE: 673 case IPUT_CHAR: 674 case IPUT_SHORT: 675 case IPUT_WIDE: 676 case IPUT_OBJECT: 677 return true; 678 case SGET: 679 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE); 680 return true; 681 case SGET_BOOLEAN: 682 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 683 return true; 684 case SGET_BYTE: 685 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE); 686 return true; 687 case SGET_CHAR: 688 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE); 689 return true; 690 case SGET_SHORT: 691 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE); 692 return true; 693 case SGET_WIDE: 694 case SGET_OBJECT: 695 analyzeIgetSgetWideObject(analyzedInstruction); 696 return true; 697 case SPUT: 698 case SPUT_BOOLEAN: 699 case SPUT_BYTE: 700 case SPUT_CHAR: 701 case SPUT_SHORT: 702 case SPUT_WIDE: 703 case SPUT_OBJECT: 704 return true; 705 case INVOKE_VIRTUAL: 706 case INVOKE_SUPER: 707 return true; 708 case INVOKE_DIRECT: 709 analyzeInvokeDirect(analyzedInstruction); 710 return true; 711 case INVOKE_STATIC: 712 case INVOKE_INTERFACE: 713 case INVOKE_VIRTUAL_RANGE: 714 case INVOKE_SUPER_RANGE: 715 return true; 716 case INVOKE_DIRECT_RANGE: 717 analyzeInvokeDirectRange(analyzedInstruction); 718 return true; 719 case INVOKE_STATIC_RANGE: 720 case INVOKE_INTERFACE_RANGE: 721 return true; 722 case NEG_INT: 723 case NOT_INT: 724 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 725 return true; 726 case NEG_LONG: 727 case NOT_LONG: 728 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 729 return true; 730 case NEG_FLOAT: 731 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 732 return true; 733 case NEG_DOUBLE: 734 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 735 return true; 736 case INT_TO_LONG: 737 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 738 return true; 739 case INT_TO_FLOAT: 740 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 741 return true; 742 case INT_TO_DOUBLE: 743 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 744 return true; 745 case LONG_TO_INT: 746 case DOUBLE_TO_INT: 747 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 748 return true; 749 case LONG_TO_FLOAT: 750 case DOUBLE_TO_FLOAT: 751 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 752 return true; 753 case LONG_TO_DOUBLE: 754 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 755 return true; 756 case FLOAT_TO_INT: 757 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 758 return true; 759 case FLOAT_TO_LONG: 760 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 761 return true; 762 case FLOAT_TO_DOUBLE: 763 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 764 return true; 765 case DOUBLE_TO_LONG: 766 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 767 return true; 768 case INT_TO_BYTE: 769 analyzeUnaryOp(analyzedInstruction, RegisterType.BYTE_TYPE); 770 return true; 771 case INT_TO_CHAR: 772 analyzeUnaryOp(analyzedInstruction, RegisterType.CHAR_TYPE); 773 return true; 774 case INT_TO_SHORT: 775 analyzeUnaryOp(analyzedInstruction, RegisterType.SHORT_TYPE); 776 return true; 777 case ADD_INT: 778 case SUB_INT: 779 case MUL_INT: 780 case DIV_INT: 781 case REM_INT: 782 case SHL_INT: 783 case SHR_INT: 784 case USHR_INT: 785 analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 786 return true; 787 case AND_INT: 788 case OR_INT: 789 case XOR_INT: 790 analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 791 return true; 792 case ADD_LONG: 793 case SUB_LONG: 794 case MUL_LONG: 795 case DIV_LONG: 796 case REM_LONG: 797 case AND_LONG: 798 case OR_LONG: 799 case XOR_LONG: 800 case SHL_LONG: 801 case SHR_LONG: 802 case USHR_LONG: 803 analyzeBinaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false); 804 return true; 805 case ADD_FLOAT: 806 case SUB_FLOAT: 807 case MUL_FLOAT: 808 case DIV_FLOAT: 809 case REM_FLOAT: 810 analyzeBinaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false); 811 return true; 812 case ADD_DOUBLE: 813 case SUB_DOUBLE: 814 case MUL_DOUBLE: 815 case DIV_DOUBLE: 816 case REM_DOUBLE: 817 analyzeBinaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false); 818 return true; 819 case ADD_INT_2ADDR: 820 case SUB_INT_2ADDR: 821 case MUL_INT_2ADDR: 822 case DIV_INT_2ADDR: 823 case REM_INT_2ADDR: 824 case SHL_INT_2ADDR: 825 case SHR_INT_2ADDR: 826 case USHR_INT_2ADDR: 827 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 828 return true; 829 case AND_INT_2ADDR: 830 case OR_INT_2ADDR: 831 case XOR_INT_2ADDR: 832 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 833 return true; 834 case ADD_LONG_2ADDR: 835 case SUB_LONG_2ADDR: 836 case MUL_LONG_2ADDR: 837 case DIV_LONG_2ADDR: 838 case REM_LONG_2ADDR: 839 case AND_LONG_2ADDR: 840 case OR_LONG_2ADDR: 841 case XOR_LONG_2ADDR: 842 case SHL_LONG_2ADDR: 843 case SHR_LONG_2ADDR: 844 case USHR_LONG_2ADDR: 845 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false); 846 return true; 847 case ADD_FLOAT_2ADDR: 848 case SUB_FLOAT_2ADDR: 849 case MUL_FLOAT_2ADDR: 850 case DIV_FLOAT_2ADDR: 851 case REM_FLOAT_2ADDR: 852 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false); 853 return true; 854 case ADD_DOUBLE_2ADDR: 855 case SUB_DOUBLE_2ADDR: 856 case MUL_DOUBLE_2ADDR: 857 case DIV_DOUBLE_2ADDR: 858 case REM_DOUBLE_2ADDR: 859 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false); 860 return true; 861 case ADD_INT_LIT16: 862 case RSUB_INT: 863 case MUL_INT_LIT16: 864 case DIV_INT_LIT16: 865 case REM_INT_LIT16: 866 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 867 return true; 868 case AND_INT_LIT16: 869 case OR_INT_LIT16: 870 case XOR_INT_LIT16: 871 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 872 return true; 873 case ADD_INT_LIT8: 874 case RSUB_INT_LIT8: 875 case MUL_INT_LIT8: 876 case DIV_INT_LIT8: 877 case REM_INT_LIT8: 878 case SHL_INT_LIT8: 879 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 880 return true; 881 case AND_INT_LIT8: 882 case OR_INT_LIT8: 883 case XOR_INT_LIT8: 884 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 885 return true; 886 case SHR_INT_LIT8: 887 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, true), 888 false); 889 return true; 890 case USHR_INT_LIT8: 891 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false), 892 false); 893 return true; 894 895 /*odexed instructions*/ 896 case IGET_VOLATILE: 897 case IPUT_VOLATILE: 898 case SGET_VOLATILE: 899 case SPUT_VOLATILE: 900 case IGET_OBJECT_VOLATILE: 901 case IGET_WIDE_VOLATILE: 902 case IPUT_WIDE_VOLATILE: 903 case SGET_WIDE_VOLATILE: 904 case SPUT_WIDE_VOLATILE: 905 analyzePutGetVolatile(analyzedInstruction); 906 return true; 907 case THROW_VERIFICATION_ERROR: 908 return true; 909 case EXECUTE_INLINE: 910 analyzeExecuteInline(analyzedInstruction); 911 return true; 912 case EXECUTE_INLINE_RANGE: 913 analyzeExecuteInlineRange(analyzedInstruction); 914 return true; 915 case INVOKE_DIRECT_EMPTY: 916 analyzeInvokeDirectEmpty(analyzedInstruction); 917 return true; 918 case INVOKE_OBJECT_INIT_RANGE: 919 analyzeInvokeObjectInitRange(analyzedInstruction); 920 return true; 921 case IGET_QUICK: 922 case IGET_WIDE_QUICK: 923 case IGET_OBJECT_QUICK: 924 case IPUT_QUICK: 925 case IPUT_WIDE_QUICK: 926 case IPUT_OBJECT_QUICK: 927 return analyzeIputIgetQuick(analyzedInstruction); 928 case INVOKE_VIRTUAL_QUICK: 929 return analyzeInvokeVirtualQuick(analyzedInstruction, false, false); 930 case INVOKE_SUPER_QUICK: 931 return analyzeInvokeVirtualQuick(analyzedInstruction, true, false); 932 case INVOKE_VIRTUAL_QUICK_RANGE: 933 return analyzeInvokeVirtualQuick(analyzedInstruction, false, true); 934 case INVOKE_SUPER_QUICK_RANGE: 935 return analyzeInvokeVirtualQuick(analyzedInstruction, true, true); 936 case IPUT_OBJECT_VOLATILE: 937 case SGET_OBJECT_VOLATILE: 938 case SPUT_OBJECT_VOLATILE: 939 analyzePutGetVolatile(analyzedInstruction); 940 return true; 941 default: 942 assert false; 943 return true; 944 } 945 } 946 947 private static final BitSet Primitive32BitCategories = BitSetUtils.bitSetOfIndexes( 948 RegisterType.NULL, 949 RegisterType.ONE, 950 RegisterType.BOOLEAN, 951 RegisterType.BYTE, 952 RegisterType.POS_BYTE, 953 RegisterType.SHORT, 954 RegisterType.POS_SHORT, 955 RegisterType.CHAR, 956 RegisterType.INTEGER, 957 RegisterType.FLOAT); 958 959 private static final BitSet WideLowCategories = BitSetUtils.bitSetOfIndexes( 960 RegisterType.LONG_LO, 961 RegisterType.DOUBLE_LO); 962 963 private static final BitSet WideHighCategories = BitSetUtils.bitSetOfIndexes( 964 RegisterType.LONG_HI, 965 RegisterType.DOUBLE_HI); 966 967 private static final BitSet ReferenceOrUninitCategories = BitSetUtils.bitSetOfIndexes( 968 RegisterType.NULL, 969 RegisterType.UNINIT_REF, 970 RegisterType.UNINIT_THIS, 971 RegisterType.REFERENCE); 972 973 private static final BitSet BooleanCategories = BitSetUtils.bitSetOfIndexes( 974 RegisterType.NULL, 975 RegisterType.ONE, 976 RegisterType.BOOLEAN); 977 978 private void analyzeMove(@Nonnull AnalyzedInstruction analyzedInstruction) { 979 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 980 981 RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 982 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType); 983 } 984 985 private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { 986 AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); 987 if (!previousInstruction.instruction.getOpcode().setsResult()) { 988 throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + 989 "invoke-*/fill-new-array instruction"); 990 } 991 992 RegisterType resultRegisterType; 993 ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction; 994 Reference reference = invokeInstruction.getReference(); 995 996 if (reference instanceof MethodReference) { 997 resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType()); 998 } else { 999 resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference); 1000 } 1001 1002 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType); 1003 } 1004 1005 private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { 1006 int instructionAddress = getInstructionAddress(analyzedInstruction); 1007 1008 RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; 1009 1010 for (TryBlock tryBlock: methodImpl.getTryBlocks()) { 1011 for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { 1012 1013 if (handler.getHandlerCodeAddress() == instructionAddress) { 1014 String type = handler.getExceptionType(); 1015 if (type == null) { 1016 exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, 1017 classPath.getClass("Ljava/lang/Throwable;")); 1018 } else { 1019 exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) 1020 .merge(exceptionType); 1021 } 1022 } 1023 } 1024 } 1025 1026 if (exceptionType.category == RegisterType.UNKNOWN) { 1027 throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); 1028 } 1029 1030 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); 1031 } 1032 1033 private void analyzeReturnVoidBarrier(AnalyzedInstruction analyzedInstruction) { 1034 analyzeReturnVoidBarrier(analyzedInstruction, true); 1035 } 1036 1037 private void analyzeReturnVoidBarrier(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1038 Instruction10x deodexedInstruction = new ImmutableInstruction10x(Opcode.RETURN_VOID); 1039 1040 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1041 1042 if (analyzeResult) { 1043 analyzeInstruction(analyzedInstruction); 1044 } 1045 } 1046 1047 private void analyzeConst(@Nonnull AnalyzedInstruction analyzedInstruction) { 1048 NarrowLiteralInstruction instruction = (NarrowLiteralInstruction)analyzedInstruction.instruction; 1049 1050 //we assume that the literal value is a valid value for the given instruction type, because it's impossible 1051 //to store an invalid literal with the instruction. so we don't need to check the type of the literal 1052 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1053 RegisterType.getRegisterTypeForLiteral(instruction.getNarrowLiteral())); 1054 } 1055 1056 private void analyzeWideConst(@Nonnull AnalyzedInstruction analyzedInstruction) { 1057 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1058 } 1059 1060 private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { 1061 TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); 1062 RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); 1063 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); 1064 } 1065 1066 private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) { 1067 TypeProto classClass = classPath.getClass("Ljava/lang/Class;"); 1068 RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass); 1069 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType); 1070 } 1071 1072 private void analyzeCheckCast(@Nonnull AnalyzedInstruction analyzedInstruction) { 1073 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1074 TypeReference reference = (TypeReference)instruction.getReference(); 1075 RegisterType castRegisterType = RegisterType.getRegisterType(classPath, reference); 1076 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType); 1077 } 1078 1079 private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) { 1080 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 1081 } 1082 1083 private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) { 1084 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.INTEGER_TYPE); 1085 } 1086 1087 private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) { 1088 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1089 1090 int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA(); 1091 RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register); 1092 if (destRegisterType.category != RegisterType.UNKNOWN) { 1093 //the post-instruction destination register will only be set if we have already analyzed this instruction 1094 //at least once. If this is the case, then the uninit reference has already been propagated to all 1095 //successors and nothing else needs to be done. 1096 assert destRegisterType.category == RegisterType.UNINIT_REF; 1097 return; 1098 } 1099 1100 TypeReference typeReference = (TypeReference)instruction.getReference(); 1101 1102 RegisterType classType = RegisterType.getRegisterType(classPath, typeReference); 1103 1104 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1105 RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type)); 1106 } 1107 1108 private void analyzeNewArray(@Nonnull AnalyzedInstruction analyzedInstruction) { 1109 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1110 1111 TypeReference type = (TypeReference)instruction.getReference(); 1112 if (type.getType().charAt(0) != '[') { 1113 throw new AnalysisException("new-array used with non-array type"); 1114 } 1115 1116 RegisterType arrayType = RegisterType.getRegisterType(classPath, type); 1117 1118 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType); 1119 } 1120 1121 private void analyzeFloatWideCmp(@Nonnull AnalyzedInstruction analyzedInstruction) { 1122 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BYTE_TYPE); 1123 } 1124 1125 private void analyze32BitPrimitiveAget(@Nonnull AnalyzedInstruction analyzedInstruction, 1126 @Nonnull RegisterType registerType) { 1127 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); 1128 } 1129 1130 private void analyzeAgetWide(@Nonnull AnalyzedInstruction analyzedInstruction) { 1131 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1132 1133 RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1134 if (arrayRegisterType.category != RegisterType.NULL) { 1135 if (arrayRegisterType.category != RegisterType.REFERENCE || 1136 !(arrayRegisterType.type instanceof ArrayProto)) { 1137 throw new AnalysisException("aget-wide used with non-array register: %s", arrayRegisterType.toString()); 1138 } 1139 ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; 1140 1141 if (arrayProto.dimensions != 1) { 1142 throw new AnalysisException("aget-wide used with multi-dimensional array: %s", 1143 arrayRegisterType.toString()); 1144 } 1145 1146 char arrayBaseType = arrayProto.getElementType().charAt(0); 1147 if (arrayBaseType == 'J') { 1148 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1149 } else if (arrayBaseType == 'D') { 1150 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 1151 } else { 1152 throw new AnalysisException("aget-wide used with narrow array: %s", arrayRegisterType); 1153 } 1154 } else { 1155 // If the array register is null, we can assume that the destination register was meant to be a wide type. 1156 // This is the same behavior as dalvik's verifier 1157 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1158 } 1159 } 1160 1161 private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { 1162 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1163 1164 RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1165 if (arrayRegisterType.category != RegisterType.NULL) { 1166 if (arrayRegisterType.category != RegisterType.REFERENCE || 1167 !(arrayRegisterType.type instanceof ArrayProto)) { 1168 throw new AnalysisException("aget-object used with non-array register: %s", 1169 arrayRegisterType.toString()); 1170 } 1171 1172 ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; 1173 1174 String elementType = arrayProto.getImmediateElementType(); 1175 1176 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1177 RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); 1178 } else { 1179 // If the array register is null, we can assume that the destination register was meant to be a reference 1180 // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier 1181 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); 1182 } 1183 } 1184 1185 private void analyze32BitPrimitiveIgetSget(@Nonnull AnalyzedInstruction analyzedInstruction, 1186 @Nonnull RegisterType registerType) { 1187 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); 1188 } 1189 1190 private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) { 1191 ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction; 1192 1193 FieldReference fieldReference = (FieldReference)referenceInstruction.getReference(); 1194 1195 RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType()); 1196 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType); 1197 } 1198 1199 private void analyzeInvokeDirect(@Nonnull AnalyzedInstruction analyzedInstruction) { 1200 FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction; 1201 analyzeInvokeDirectCommon(analyzedInstruction, instruction.getRegisterC()); 1202 } 1203 1204 private void analyzeInvokeDirectRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1205 RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction; 1206 analyzeInvokeDirectCommon(analyzedInstruction, instruction.getStartRegister()); 1207 } 1208 1209 private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) { 1210 //the only time that an invoke instruction changes a register type is when using invoke-direct on a 1211 //constructor (<init>) method, which changes the uninitialized reference (and any register that the same 1212 //uninit reference has been copied to) to an initialized reference 1213 1214 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1215 1216 MethodReference methodReference = (MethodReference)instruction.getReference(); 1217 1218 if (!methodReference.getName().equals("<init>")) { 1219 return; 1220 } 1221 1222 RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(objectRegister); 1223 1224 if (objectRegisterType.category != RegisterType.UNINIT_REF && 1225 objectRegisterType.category != RegisterType.UNINIT_THIS) { 1226 return; 1227 } 1228 1229 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, objectRegister, 1230 RegisterType.getRegisterType(RegisterType.REFERENCE, objectRegisterType.type)); 1231 1232 for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) { 1233 RegisterType postInstructionRegisterType = analyzedInstruction.postRegisterMap[i]; 1234 if (postInstructionRegisterType.category == RegisterType.UNKNOWN) { 1235 RegisterType preInstructionRegisterType = 1236 analyzedInstruction.getPreInstructionRegisterType(i); 1237 1238 if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || 1239 preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { 1240 RegisterType registerType; 1241 if (preInstructionRegisterType == objectRegisterType) { 1242 registerType = analyzedInstruction.postRegisterMap[objectRegister]; 1243 } else { 1244 registerType = preInstructionRegisterType; 1245 } 1246 1247 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, i, registerType); 1248 } 1249 } 1250 } 1251 } 1252 1253 private void analyzeUnaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1254 @Nonnull RegisterType destRegisterType) { 1255 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1256 } 1257 1258 private void analyzeBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1259 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1260 if (checkForBoolean) { 1261 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1262 1263 RegisterType source1RegisterType = 1264 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1265 RegisterType source2RegisterType = 1266 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC()); 1267 1268 if (BooleanCategories.get(source1RegisterType.category) && 1269 BooleanCategories.get(source2RegisterType.category)) { 1270 destRegisterType = RegisterType.BOOLEAN_TYPE; 1271 } 1272 } 1273 1274 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1275 } 1276 1277 private void analyzeBinary2AddrOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1278 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1279 if (checkForBoolean) { 1280 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1281 1282 RegisterType source1RegisterType = 1283 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA()); 1284 RegisterType source2RegisterType = 1285 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1286 1287 if (BooleanCategories.get(source1RegisterType.category) && 1288 BooleanCategories.get(source2RegisterType.category)) { 1289 destRegisterType = RegisterType.BOOLEAN_TYPE; 1290 } 1291 } 1292 1293 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1294 } 1295 1296 private void analyzeLiteralBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1297 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1298 if (checkForBoolean) { 1299 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1300 1301 RegisterType sourceRegisterType = 1302 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1303 1304 if (BooleanCategories.get(sourceRegisterType.category)) { 1305 int literal = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); 1306 if (literal == 0 || literal == 1) { 1307 destRegisterType = RegisterType.BOOLEAN_TYPE; 1308 } 1309 } 1310 } 1311 1312 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1313 } 1314 1315 private RegisterType getDestTypeForLiteralShiftRight(@Nonnull AnalyzedInstruction analyzedInstruction, boolean signedShift) { 1316 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1317 1318 RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), 1319 Primitive32BitCategories); 1320 long literalShift = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); 1321 1322 if (literalShift == 0) { 1323 return sourceRegisterType; 1324 } 1325 1326 RegisterType destRegisterType; 1327 if (!signedShift) { 1328 destRegisterType = RegisterType.INTEGER_TYPE; 1329 } else { 1330 destRegisterType = sourceRegisterType; 1331 } 1332 1333 literalShift = literalShift & 0x1f; 1334 1335 switch (sourceRegisterType.category) { 1336 case RegisterType.INTEGER: 1337 case RegisterType.FLOAT: 1338 if (!signedShift) { 1339 if (literalShift > 24) { 1340 return RegisterType.POS_BYTE_TYPE; 1341 } 1342 if (literalShift >= 16) { 1343 return RegisterType.CHAR_TYPE; 1344 } 1345 } else { 1346 if (literalShift >= 24) { 1347 return RegisterType.BYTE_TYPE; 1348 } 1349 if (literalShift >= 16) { 1350 return RegisterType.SHORT_TYPE; 1351 } 1352 } 1353 break; 1354 case RegisterType.SHORT: 1355 if (signedShift && literalShift >= 8) { 1356 return RegisterType.BYTE_TYPE; 1357 } 1358 break; 1359 case RegisterType.POS_SHORT: 1360 if (literalShift >= 8) { 1361 return RegisterType.POS_BYTE_TYPE; 1362 } 1363 break; 1364 case RegisterType.CHAR: 1365 if (literalShift > 8) { 1366 return RegisterType.POS_BYTE_TYPE; 1367 } 1368 break; 1369 case RegisterType.BYTE: 1370 break; 1371 case RegisterType.POS_BYTE: 1372 return RegisterType.POS_BYTE_TYPE; 1373 case RegisterType.NULL: 1374 case RegisterType.ONE: 1375 case RegisterType.BOOLEAN: 1376 return RegisterType.NULL_TYPE; 1377 default: 1378 assert false; 1379 } 1380 1381 return destRegisterType; 1382 } 1383 1384 1385 private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { 1386 if (inlineResolver == null) { 1387 throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); 1388 } 1389 1390 Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction; 1391 Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); 1392 1393 Opcode deodexedOpcode; 1394 switch (resolvedMethod.getAccessFlags()) { 1395 case InlineMethodResolver.DIRECT: 1396 deodexedOpcode = Opcode.INVOKE_DIRECT; 1397 break; 1398 case InlineMethodResolver.STATIC: 1399 deodexedOpcode = Opcode.INVOKE_STATIC; 1400 break; 1401 case InlineMethodResolver.VIRTUAL: 1402 deodexedOpcode = Opcode.INVOKE_VIRTUAL; 1403 break; 1404 default: 1405 throw new ExceptionWithContext("Unexpected access flags on resolved inline method: %d, %s", 1406 resolvedMethod.getAccessFlags(), ReferenceUtil.getReferenceString(resolvedMethod)); 1407 } 1408 1409 Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(), 1410 instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), 1411 instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); 1412 1413 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1414 analyzeInstruction(analyzedInstruction); 1415 } 1416 1417 private void analyzeExecuteInlineRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1418 if (inlineResolver == null) { 1419 throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); 1420 } 1421 1422 Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction; 1423 Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); 1424 1425 Opcode deodexedOpcode = null; 1426 switch (resolvedMethod.getAccessFlags()) { 1427 case InlineMethodResolver.DIRECT: 1428 deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE; 1429 break; 1430 case InlineMethodResolver.STATIC: 1431 deodexedOpcode = Opcode.INVOKE_STATIC_RANGE; 1432 break; 1433 case InlineMethodResolver.VIRTUAL: 1434 deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE; 1435 break; 1436 default: 1437 assert false; 1438 } 1439 1440 Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(deodexedOpcode, instruction.getRegisterCount(), 1441 instruction.getStartRegister(), resolvedMethod); 1442 1443 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1444 analyzeInstruction(analyzedInstruction); 1445 } 1446 1447 private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction) { 1448 analyzeInvokeDirectEmpty(analyzedInstruction, true); 1449 } 1450 1451 private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1452 Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction; 1453 1454 Instruction35c deodexedInstruction = new ImmutableInstruction35c(Opcode.INVOKE_DIRECT, 1455 instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), 1456 instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), 1457 instruction.getReference()); 1458 1459 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1460 1461 if (analyzeResult) { 1462 analyzeInstruction(analyzedInstruction); 1463 } 1464 } 1465 1466 private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1467 analyzeInvokeObjectInitRange(analyzedInstruction, true); 1468 } 1469 1470 private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1471 Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction; 1472 1473 Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(Opcode.INVOKE_DIRECT_RANGE, 1474 instruction.getRegisterCount(), instruction.getStartRegister(), instruction.getReference()); 1475 1476 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1477 1478 if (analyzeResult) { 1479 analyzeInstruction(analyzedInstruction); 1480 } 1481 } 1482 1483 private boolean analyzeIputIgetQuick(@Nonnull AnalyzedInstruction analyzedInstruction) { 1484 Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction; 1485 1486 int fieldOffset = instruction.getFieldOffset(); 1487 RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), 1488 ReferenceOrUninitCategories); 1489 1490 if (objectRegisterType.category == RegisterType.NULL) { 1491 return false; 1492 } 1493 1494 TypeProto registerTypeProto = objectRegisterType.type; 1495 assert registerTypeProto != null; 1496 1497 TypeProto classTypeProto = classPath.getClass(registerTypeProto.getType()); 1498 FieldReference field = classTypeProto.getFieldByOffset(fieldOffset); 1499 1500 if (field == null) { 1501 throw new AnalysisException("Could not resolve the field in class %s at offset %d", 1502 objectRegisterType.type.getType(), fieldOffset); 1503 } 1504 1505 String fieldType = field.getType(); 1506 1507 Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, 1508 instruction.getOpcode()); 1509 1510 Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte)instruction.getRegisterA(), 1511 (byte)instruction.getRegisterB(), field); 1512 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1513 1514 analyzeInstruction(analyzedInstruction); 1515 1516 return true; 1517 } 1518 1519 private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper, 1520 boolean isRange) { 1521 int methodIndex; 1522 int objectRegister; 1523 1524 if (isRange) { 1525 Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; 1526 methodIndex = instruction.getVtableIndex(); 1527 objectRegister = instruction.getStartRegister(); 1528 } else { 1529 Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; 1530 methodIndex = instruction.getVtableIndex(); 1531 objectRegister = instruction.getRegisterD(); 1532 } 1533 1534 RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister, 1535 ReferenceOrUninitCategories); 1536 TypeProto objectRegisterTypeProto = objectRegisterType.type; 1537 assert objectRegisterTypeProto != null; 1538 1539 if (objectRegisterType.category == RegisterType.NULL) { 1540 return false; 1541 } 1542 1543 MethodReference resolvedMethod; 1544 if (isSuper) { 1545 // invoke-super is only used for the same class that we're currently in 1546 TypeProto typeProto = classPath.getClass(method.getDefiningClass()); 1547 TypeProto superType; 1548 1549 String superclassType = typeProto.getSuperclass(); 1550 if (superclassType != null) { 1551 superType = classPath.getClass(superclassType); 1552 } else { 1553 // This is either java.lang.Object, or an UnknownClassProto 1554 superType = typeProto; 1555 } 1556 1557 resolvedMethod = superType.getMethodByVtableIndex(methodIndex); 1558 } else{ 1559 resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex); 1560 } 1561 1562 if (resolvedMethod == null) { 1563 throw new AnalysisException("Could not resolve the method in class %s at index %d", 1564 objectRegisterType.type.getType(), methodIndex); 1565 } 1566 1567 Instruction deodexedInstruction; 1568 if (isRange) { 1569 Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; 1570 Opcode opcode; 1571 if (isSuper) { 1572 opcode = Opcode.INVOKE_SUPER_RANGE; 1573 } else { 1574 opcode = Opcode.INVOKE_VIRTUAL_RANGE; 1575 } 1576 1577 deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getRegisterCount(), 1578 instruction.getStartRegister(), resolvedMethod); 1579 } else { 1580 Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; 1581 Opcode opcode; 1582 if (isSuper) { 1583 opcode = Opcode.INVOKE_SUPER; 1584 } else { 1585 opcode = Opcode.INVOKE_VIRTUAL; 1586 } 1587 1588 deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(), 1589 instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), 1590 instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); 1591 } 1592 1593 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1594 analyzeInstruction(analyzedInstruction); 1595 1596 return true; 1597 } 1598 1599 private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) { 1600 return analyzePutGetVolatile(analyzedInstruction, true); 1601 } 1602 1603 private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1604 FieldReference field = (FieldReference)((ReferenceInstruction)analyzedInstruction.instruction).getReference(); 1605 String fieldType = field.getType(); 1606 1607 Opcode originalOpcode = analyzedInstruction.instruction.getOpcode(); 1608 1609 Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, 1610 originalOpcode); 1611 1612 Instruction deodexedInstruction; 1613 1614 if (originalOpcode.isOdexedStaticVolatile()) { 1615 OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction; 1616 deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field); 1617 } else { 1618 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1619 1620 deodexedInstruction = new ImmutableInstruction22c(opcode, instruction.getRegisterA(), 1621 instruction.getRegisterB(), field); 1622 } 1623 1624 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1625 1626 if (analyzeResult) { 1627 analyzeInstruction(analyzedInstruction); 1628 } 1629 return true; 1630 } 1631 1632 @Nonnull 1633 private static RegisterType getAndCheckSourceRegister(@Nonnull AnalyzedInstruction analyzedInstruction, 1634 int registerNumber, BitSet validCategories) { 1635 assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length; 1636 1637 RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber); 1638 1639 checkRegister(registerType, registerNumber, validCategories); 1640 1641 if (validCategories == WideLowCategories) { 1642 checkRegister(registerType, registerNumber, WideLowCategories); 1643 checkWidePair(registerNumber, analyzedInstruction); 1644 1645 RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1); 1646 checkRegister(secondRegisterType, registerNumber+1, WideHighCategories); 1647 } 1648 1649 return registerType; 1650 } 1651 1652 private static void checkRegister(RegisterType registerType, int registerNumber, BitSet validCategories) { 1653 if (!validCategories.get(registerType.category)) { 1654 throw new AnalysisException(String.format("Invalid register type %s for register v%d.", 1655 registerType.toString(), registerNumber)); 1656 } 1657 } 1658 1659 private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) { 1660 if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) { 1661 throw new AnalysisException(String.format("v%d cannot be used as the first register in a wide register" + 1662 "pair because it is the last register.", registerNumber)); 1663 } 1664 } 1665}