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 32package org.jf.dexlib2.analysis; 33 34import org.jf.dexlib2.iface.instruction.*; 35import org.jf.dexlib2.iface.reference.MethodReference; 36import org.jf.dexlib2.iface.reference.Reference; 37import org.jf.util.ExceptionWithContext; 38 39import javax.annotation.Nonnull; 40import java.util.*; 41 42public 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 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 92 public int getInstructionIndex() { 93 return instructionIndex; 94 } 95 96 public int getPredecessorCount() { 97 return predecessors.size(); 98 } 99 100 public SortedSet<AnalyzedInstruction> getPredecessors() { 101 return Collections.unmodifiableSortedSet(predecessors); 102 } 103 104 protected boolean addPredecessor(AnalyzedInstruction predecessor) { 105 return predecessors.add(predecessor); 106 } 107 108 protected void addSuccessor(AnalyzedInstruction successor) { 109 successors.add(successor); 110 } 111 112 protected void setDeodexedInstruction(Instruction instruction) { 113 assert originalInstruction.getOpcode().odexOnly(); 114 this.instruction = instruction; 115 } 116 117 protected void restoreOdexedInstruction() { 118 assert originalInstruction.getOpcode().odexOnly(); 119 instruction = originalInstruction; 120 } 121 122 public int getSuccessorCount() { 123 return successors.size(); 124 } 125 126 public List<AnalyzedInstruction> getSuccesors() { 127 return Collections.unmodifiableList(successors); 128 } 129 130 public Instruction getInstruction() { 131 return instruction; 132 } 133 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 */ 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 */ 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