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