AnalyzedInstruction.java revision c9be5e13034da9827b5598a6257376164745b827
1package org.jf.dexlib.Code.Analysis; 2 3import org.jf.dexlib.Code.*; 4import org.jf.dexlib.Item; 5import org.jf.dexlib.ItemType; 6import org.jf.dexlib.MethodIdItem; 7import org.jf.dexlib.Util.ExceptionWithContext; 8 9import java.util.LinkedList; 10 11public class AnalyzedInstruction { 12 /** 13 * The actual instruction 14 */ 15 public final Instruction instruction; 16 17 /** 18 * The index of the instruction, where the first instruction in the method is at index 0, and so on 19 */ 20 protected final int instructionIndex; 21 22 /** 23 * Instructions that can pass on execution to this one during normal execution 24 */ 25 protected final LinkedList<AnalyzedInstruction> predecessors = new LinkedList<AnalyzedInstruction>(); 26 27 /** 28 * Instructions that can execution could pass on to next during normal execution 29 */ 30 protected final LinkedList<AnalyzedInstruction> successors = new LinkedList<AnalyzedInstruction>(); 31 32 /** 33 * This contains the register types *after* the instruction has executed 34 */ 35 protected final RegisterType[] postRegisterMap; 36 37 /** 38 * This is set to true when this instruction follows an odexed instruction that couldn't be deodexed. In this case 39 * the unodexable instruction is guaranteed to throw an NPE, so anything following it is dead, up until a non-dead 40 * code path merges in. And more importantly, the code following the unodexable instruction isn't verifiable in 41 * some cases, if it depends on the return/field type of the unodexeable instruction. Meaning that if the "dead" 42 * code was left in, dalvik would reject it because it couldn't verify the register types. In some cases, this 43 * dead code could be left in without ill-effect, but it's easier to always remove it, which is always valid. Since 44 * it is dead code, removing it won't have any effect. 45 */ 46 protected boolean dead = false; 47 48 public AnalyzedInstruction(Instruction instruction, int instructionIndex, int registerCount) { 49 this.instruction = instruction; 50 this.instructionIndex = instructionIndex; 51 this.postRegisterMap = new RegisterType[registerCount]; 52 RegisterType unknown = RegisterType.getRegisterType(RegisterType.Category.Unknown, null); 53 for (int i=0; i<registerCount; i++) { 54 postRegisterMap[i] = unknown; 55 } 56 } 57 58 public int getInstructionIndex() { 59 return instructionIndex; 60 } 61 62 public int getPredecessorCount() { 63 return predecessors.size(); 64 } 65 66 protected void addPredecessor(AnalyzedInstruction predecessor) { 67 predecessors.add(predecessor); 68 } 69 70 /** 71 * @return true if the successor was added or false if it wasn't added because it already existed 72 */ 73 protected boolean addSuccessor(AnalyzedInstruction successor) { 74 for (AnalyzedInstruction instruction: successors) { 75 if (instruction == successor) { 76 return false; 77 } 78 } 79 successors.add(successor); 80 return true; 81 } 82 83 /* 84 * Sets the "post-instruction" register type as indicated. This should only be used to set 85 * the method parameter types for the "start of method" instruction, or to set the register 86 * type of the destination register during verification. The change to the register type 87 * will 88 * @param registerNumber Which register to set 89 * @param registerType The "post-instruction" register type 90 */ 91 protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) { 92 assert registerNumber >= 0 && registerNumber < postRegisterMap.length; 93 assert registerType != null; 94 95 RegisterType oldRegisterType = postRegisterMap[registerNumber]; 96 if (oldRegisterType == registerType) { 97 return false; 98 } 99 100 postRegisterMap[registerNumber] = registerType; 101 return true; 102 } 103 104 protected RegisterType getMergedRegisterTypeFromPredecessors(int registerNumber) { 105 RegisterType mergedRegisterType = null; 106 for (AnalyzedInstruction predecessor: predecessors) { 107 RegisterType predecessorRegisterType = predecessor.postRegisterMap[registerNumber]; 108 assert predecessorRegisterType != null; 109 mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType); 110 } 111 return mergedRegisterType; 112 } 113 114 protected boolean isInvokeInit() { 115 if (instruction == null || 116 (instruction.opcode != Opcode.INVOKE_DIRECT && instruction.opcode != Opcode.INVOKE_DIRECT_RANGE)) { 117 return false; 118 } 119 120 //TODO: check access flags instead of name? 121 122 InstructionWithReference instruction = (InstructionWithReference)this.instruction; 123 Item item = instruction.getReferencedItem(); 124 assert item.getItemType() == ItemType.TYPE_METHOD_ID_ITEM; 125 MethodIdItem method = (MethodIdItem)item; 126 127 if (!method.getMethodName().getStringValue().equals("<init>")) { 128 return false; 129 } 130 131 return true; 132 } 133 134 public boolean setsRegister() { 135 return instruction.opcode.setsRegister(); 136 } 137 138 public boolean setsWideRegister() { 139 return instruction.opcode.setsWideRegister(); 140 } 141 142 public boolean setsRegister(int registerNumber) { 143 144 //When constructing a new object, the register type will be an uninitialized reference after the new-instance 145 //instruction, but becomes an initialized reference once the <init> method is called. So even though invoke 146 //instructions don't normally change any registers, calling an <init> method will change the type of its 147 //object register. If the uninitialized reference has been copied to other registers, they will be initialized 148 //as well, so we need to check for that too 149 if (isInvokeInit()) { 150 int destinationRegister; 151 if (instruction instanceof FiveRegisterInstruction) { 152 destinationRegister = ((FiveRegisterInstruction)instruction).getRegisterD(); 153 } else { 154 assert instruction instanceof RegisterRangeInstruction; 155 RegisterRangeInstruction rangeInstruction = (RegisterRangeInstruction)instruction; 156 assert rangeInstruction.getRegCount() > 0; 157 destinationRegister = rangeInstruction.getStartRegister(); 158 } 159 160 if (registerNumber == destinationRegister) { 161 return true; 162 } 163 RegisterType preInstructionDestRegisterType = getMergedRegisterTypeFromPredecessors(registerNumber); 164 if (preInstructionDestRegisterType.category != RegisterType.Category.UninitRef && 165 preInstructionDestRegisterType.category != RegisterType.Category.UninitThis) { 166 167 return false; 168 } 169 //check if the uninit ref has been copied to another register 170 if (getMergedRegisterTypeFromPredecessors(registerNumber) == preInstructionDestRegisterType) { 171 return true; 172 } 173 return false; 174 } 175 176 if (!setsRegister()) { 177 return false; 178 } 179 int destinationRegister = getDestinationRegister(); 180 181 if (registerNumber == destinationRegister) { 182 return true; 183 } 184 if (setsWideRegister() && registerNumber == (destinationRegister + 1)) { 185 return true; 186 } 187 return false; 188 } 189 190 public int getDestinationRegister() { 191 if (!this.instruction.opcode.setsRegister()) { 192 throw new ExceptionWithContext("Cannot call getDestinationRegister() for an instruction that doesn't " + 193 "store a value"); 194 } 195 return ((SingleRegisterInstruction)instruction).getRegisterA(); 196 } 197 198 public int getRegisterCount() { 199 return postRegisterMap.length; 200 } 201 202 public RegisterType getPostInstructionRegisterType(int registerNumber) { 203 return postRegisterMap[registerNumber]; 204 } 205 206 public RegisterType getPreInstructionRegisterType(int registerNumber) { 207 //if the specific register is not a destination register, then the stored post-instruction register type will 208 //be the same as the pre-instruction regsiter type, so we can use that. 209 //otherwise, we need to merge the predecessor's post-instruction register types 210 211 if (this.setsRegister(registerNumber)) { 212 return getMergedRegisterTypeFromPredecessors(registerNumber); 213 } else { 214 return postRegisterMap[registerNumber]; 215 } 216 } 217} 218 219