PreInstructionRegisterInfoMethodItem.java revision c91b03ba45ccacfa7b0ad52592a42e8fd8c18da1
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 29package org.jf.baksmali.Adaptors; 30 31import org.jf.baksmali.baksmali; 32import org.jf.baksmali.main; 33import org.jf.dexlib2.analysis.AnalyzedInstruction; 34import org.jf.dexlib2.analysis.MethodAnalyzer; 35import org.jf.dexlib2.analysis.RegisterType; 36import org.jf.dexlib2.iface.instruction.*; 37import org.jf.util.IndentingWriter; 38 39import javax.annotation.Nonnull; 40import java.io.IOException; 41import java.util.BitSet; 42 43public class PreInstructionRegisterInfoMethodItem extends MethodItem { 44 @Nonnull private final MethodAnalyzer methodAnalyzer; 45 @Nonnull private final RegisterFormatter registerFormatter; 46 @Nonnull private final AnalyzedInstruction analyzedInstruction; 47 48 public PreInstructionRegisterInfoMethodItem(@Nonnull MethodAnalyzer methodAnalyzer, 49 @Nonnull RegisterFormatter registerFormatter, 50 @Nonnull AnalyzedInstruction analyzedInstruction, 51 int codeAddress) { 52 super(codeAddress); 53 this.methodAnalyzer = methodAnalyzer; 54 this.registerFormatter = registerFormatter; 55 this.analyzedInstruction = analyzedInstruction; 56 } 57 58 @Override 59 public double getSortOrder() { 60 return 99.9; 61 } 62 63 @Override 64 public boolean writeTo(IndentingWriter writer) throws IOException { 65 int registerInfo = baksmali.registerInfo; 66 int registerCount = analyzedInstruction.getRegisterCount(); 67 BitSet registers = new BitSet(registerCount); 68 69 if ((registerInfo & main.ALL) != 0) { 70 registers.set(0, registerCount); 71 } else { 72 if ((registerInfo & main.ALLPRE) != 0) { 73 registers.set(0, registerCount); 74 } else { 75 if ((registerInfo & main.ARGS) != 0) { 76 addArgsRegs(registers); 77 } 78 if ((registerInfo & main.MERGE) != 0) { 79 addMergeRegs(registers, registerCount); 80 } else if ((registerInfo & main.FULLMERGE) != 0 && 81 (analyzedInstruction.isBeginningInstruction())) { 82 addParamRegs(registers, registerCount); 83 } 84 } 85 } 86 87 boolean printedSomething = false; 88 if ((registerInfo & main.FULLMERGE) != 0) { 89 printedSomething = writeFullMergeRegs(writer, registers, registerCount); 90 } 91 92 printedSomething |= writeRegisterInfo(writer, registers, printedSomething); 93 94 return printedSomething; 95 } 96 97 private void addArgsRegs(BitSet registers) { 98 if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) { 99 RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction(); 100 101 registers.set(instruction.getStartRegister(), 102 instruction.getStartRegister() + instruction.getRegisterCount()); 103 } else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) { 104 FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction(); 105 int regCount = instruction.getRegisterCount(); 106 switch (regCount) { 107 case 5: 108 registers.set(instruction.getRegisterG()); 109 //fall through 110 case 4: 111 registers.set(instruction.getRegisterF()); 112 //fall through 113 case 3: 114 registers.set(instruction.getRegisterE()); 115 //fall through 116 case 2: 117 registers.set(instruction.getRegisterD()); 118 //fall through 119 case 1: 120 registers.set(instruction.getRegisterC()); 121 } 122 } else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) { 123 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction(); 124 registers.set(instruction.getRegisterA()); 125 registers.set(instruction.getRegisterB()); 126 registers.set(instruction.getRegisterC()); 127 } else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) { 128 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction(); 129 registers.set(instruction.getRegisterA()); 130 registers.set(instruction.getRegisterB()); 131 } else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) { 132 OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction(); 133 registers.set(instruction.getRegisterA()); 134 } 135 } 136 137 private void addMergeRegs(BitSet registers, int registerCount) { 138 if (analyzedInstruction.isBeginningInstruction()) { 139 addParamRegs(registers, registerCount); 140 } 141 142 if (analyzedInstruction.getPredecessorCount() <= 1) { 143 //in the common case of an instruction that only has a single predecessor which is the previous 144 //instruction, the pre-instruction registers will always match the previous instruction's 145 //post-instruction registers 146 return; 147 } 148 149 for (int registerNum=0; registerNum<registerCount; registerNum++) { 150 RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 151 152 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 153 if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) { 154 registers.set(registerNum); 155 } 156 } 157 } 158 } 159 160 private void addParamRegs(BitSet registers, int registerCount) { 161 int parameterRegisterCount = methodAnalyzer.getParamRegisterCount(); 162 registers.set(registerCount-parameterRegisterCount, registerCount); 163 } 164 165 private boolean writeFullMergeRegs(IndentingWriter writer, BitSet registers, int registerCount) 166 throws IOException { 167 if (analyzedInstruction.getPredecessorCount() <= 1) { 168 return false; 169 } 170 171 boolean firstRegister = true; 172 173 for (int registerNum=0; registerNum<registerCount; registerNum++) { 174 RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 175 boolean addRegister = false; 176 177 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 178 RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); 179 if (predecessorRegisterType.category != RegisterType.UNKNOWN && 180 predecessorRegisterType != mergedRegisterType) { 181 182 addRegister = true; 183 break; 184 } 185 } 186 187 if (!addRegister) { 188 continue; 189 } 190 191 if (firstRegister) { 192 firstRegister = false; 193 } else { 194 writer.write('\n'); 195 } 196 197 writer.write('#'); 198 registerFormatter.writeTo(writer, registerNum); 199 writer.write('='); 200 analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer); 201 writer.write(":merge{"); 202 203 boolean first = true; 204 205 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 206 RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); 207 208 if (!first) { 209 writer.write(','); 210 } 211 212 if (predecessor.getInstructionIndex() == -1) { 213 //the fake "StartOfMethod" instruction 214 writer.write("Start:"); 215 } else { 216 writer.write("0x"); 217 writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor)); 218 writer.write(':'); 219 } 220 predecessorRegisterType.writeTo(writer); 221 222 first = false; 223 } 224 writer.write('}'); 225 226 registers.clear(registerNum); 227 } 228 return !firstRegister; 229 } 230 231 private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, boolean addNewline) throws IOException { 232 int registerNum = registers.nextSetBit(0); 233 if (registerNum < 0) { 234 return false; 235 } 236 237 if (addNewline) { 238 writer.write('\n'); 239 } 240 241 writer.write('#'); 242 for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) { 243 244 RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 245 246 registerFormatter.writeTo(writer, registerNum); 247 writer.write('='); 248 249 registerType.writeTo(writer); 250 writer.write(';'); 251 } 252 return true; 253 } 254} 255