1 /* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 package org.jf.baksmali.Adaptors; 30 31 import org.jf.util.IndentingWriter; 32 import org.jf.baksmali.baksmali; 33 import org.jf.baksmali.main; 34 import org.jf.dexlib.ClassDataItem; 35 import org.jf.dexlib.Code.Analysis.AnalyzedInstruction; 36 import org.jf.dexlib.Code.Analysis.MethodAnalyzer; 37 import org.jf.dexlib.Code.Analysis.RegisterType; 38 import org.jf.dexlib.Code.*; 39 import org.jf.dexlib.Util.AccessFlags; 40 41 import java.io.IOException; 42 import java.util.BitSet; 43 44 public class PreInstructionRegisterInfoMethodItem extends MethodItem { 45 private final AnalyzedInstruction analyzedInstruction; 46 private final MethodAnalyzer methodAnalyzer; 47 48 public PreInstructionRegisterInfoMethodItem(AnalyzedInstruction analyzedInstruction, MethodAnalyzer methodAnalyzer, 49 int codeAddress) { 50 super(codeAddress); 51 this.analyzedInstruction = analyzedInstruction; 52 this.methodAnalyzer = methodAnalyzer; 53 } 54 55 @Override 56 public double getSortOrder() { 57 return 99.9; 58 } 59 60 @Override 61 public boolean writeTo(IndentingWriter writer) throws IOException { 62 int registerInfo = baksmali.registerInfo; 63 int registerCount = analyzedInstruction.getRegisterCount(); 64 BitSet registers = new BitSet(registerCount); 65 66 if ((registerInfo & main.ALL) != 0) { 67 registers.set(0, registerCount); 68 } else { 69 if ((registerInfo & main.ALLPRE) != 0) { 70 registers.set(0, registerCount); 71 } else { 72 if ((registerInfo & main.ARGS) != 0) { 73 addArgsRegs(registers); 74 } 75 if ((registerInfo & main.MERGE) != 0) { 76 addMergeRegs(registers, registerCount); 77 } else if ((registerInfo & main.FULLMERGE) != 0 && 78 (analyzedInstruction.isBeginningInstruction())) { 79 addParamRegs(registers, registerCount); 80 } 81 } 82 } 83 84 boolean printedSomething = false; 85 if ((registerInfo & main.FULLMERGE) != 0) { 86 printedSomething = writeFullMergeRegs(writer, registers, registerCount); 87 } 88 89 printedSomething |= writeRegisterInfo(writer, registers, printedSomething); 90 91 return printedSomething; 92 } 93 94 private void addArgsRegs(BitSet registers) { 95 if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) { 96 RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction(); 97 98 registers.set(instruction.getStartRegister(), 99 instruction.getStartRegister() + instruction.getRegCount()); 100 } else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) { 101 FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction(); 102 int regCount = instruction.getRegCount(); 103 switch (regCount) { 104 case 5: 105 registers.set(instruction.getRegisterA()); 106 //fall through 107 case 4: 108 registers.set(instruction.getRegisterG()); 109 //fall through 110 case 3: 111 registers.set(instruction.getRegisterF()); 112 //fall through 113 case 2: 114 registers.set(instruction.getRegisterE()); 115 //fall through 116 case 1: 117 registers.set(instruction.getRegisterD()); 118 } 119 } else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) { 120 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction(); 121 registers.set(instruction.getRegisterA()); 122 registers.set(instruction.getRegisterB()); 123 registers.set(instruction.getRegisterC()); 124 } else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) { 125 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction(); 126 registers.set(instruction.getRegisterA()); 127 registers.set(instruction.getRegisterB()); 128 } else if (analyzedInstruction.getInstruction() instanceof SingleRegisterInstruction) { 129 SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.getInstruction(); 130 registers.set(instruction.getRegisterA()); 131 } 132 } 133 134 private void addMergeRegs(BitSet registers, int registerCount) { 135 if (analyzedInstruction.isBeginningInstruction()) { 136 addParamRegs(registers, registerCount); 137 } 138 139 if (analyzedInstruction.getPredecessorCount() <= 1) { 140 //in the common case of an instruction that only has a single predecessor which is the previous 141 //instruction, the pre-instruction registers will always match the previous instruction's 142 //post-instruction registers 143 return; 144 } 145 146 for (int registerNum=0; registerNum<registerCount; registerNum++) { 147 RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 148 149 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 150 if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) { 151 registers.set(registerNum); 152 continue; 153 } 154 } 155 } 156 } 157 158 private void addParamRegs(BitSet registers, int registerCount) { 159 ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod(); 160 int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount(); 161 if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) { 162 parameterRegisterCount++; 163 } 164 165 registers.set(registerCount-parameterRegisterCount, registerCount); 166 } 167 168 private boolean writeFullMergeRegs(IndentingWriter writer, BitSet registers, int registerCount) 169 throws IOException { 170 if (analyzedInstruction.getPredecessorCount() <= 1) { 171 return false; 172 } 173 174 ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod(); 175 176 boolean firstRegister = true; 177 178 for (int registerNum=0; registerNum<registerCount; registerNum++) { 179 RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 180 boolean addRegister = false; 181 182 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 183 RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); 184 if (predecessorRegisterType.category != RegisterType.Category.Unknown && 185 predecessorRegisterType != mergedRegisterType) { 186 187 addRegister = true; 188 break; 189 } 190 } 191 192 if (!addRegister) { 193 continue; 194 } 195 196 if (firstRegister) { 197 firstRegister = false; 198 } else { 199 writer.write('\n'); 200 } 201 202 writer.write('#'); 203 RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum); 204 writer.write('='); 205 analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer); 206 writer.write(":merge{"); 207 208 boolean first = true; 209 210 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 211 RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); 212 213 if (!first) { 214 writer.write(','); 215 } 216 217 if (predecessor.getInstructionIndex() == -1) { 218 //the fake "StartOfMethod" instruction 219 writer.write("Start:"); 220 } else { 221 writer.write("0x"); 222 writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor)); 223 writer.write(':'); 224 } 225 predecessorRegisterType.writeTo(writer); 226 227 first = false; 228 } 229 writer.write('}'); 230 231 registers.clear(registerNum); 232 } 233 return !firstRegister; 234 } 235 236 private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, 237 boolean addNewline) throws IOException { 238 ClassDataItem.EncodedMethod encodedMethod = methodAnalyzer.getMethod(); 239 240 int registerNum = registers.nextSetBit(0); 241 if (registerNum < 0) { 242 return false; 243 } 244 245 if (addNewline) { 246 writer.write('\n'); 247 } 248 writer.write('#'); 249 for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) { 250 251 RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 252 253 RegisterFormatter.writeTo(writer, encodedMethod.codeItem, registerNum); 254 writer.write('='); 255 256 if (registerType == null) { 257 writer.write("null"); 258 } else { 259 registerType.writeTo(writer); 260 } 261 writer.write(';'); 262 } 263 return true; 264 } 265 } 266