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.baksmali.BaksmaliOptions; 32 import org.jf.dexlib2.analysis.AnalyzedInstruction; 33 import org.jf.dexlib2.analysis.MethodAnalyzer; 34 import org.jf.dexlib2.analysis.RegisterType; 35 import org.jf.dexlib2.iface.instruction.*; 36 import org.jf.util.IndentingWriter; 37 38 import javax.annotation.Nonnull; 39 import java.io.IOException; 40 import java.util.BitSet; 41 42 public 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 PreInstructionRegisterInfoMethodItem(int registerInfo, @Nonnull MethodAnalyzer methodAnalyzer, @Nonnull RegisterFormatter registerFormatter, @Nonnull AnalyzedInstruction analyzedInstruction, int codeAddress)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 getSortOrder()61 public double getSortOrder() { 62 return 99.9; 63 } 64 65 @Override writeTo(IndentingWriter writer)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 addArgsRegs(BitSet registers)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 addMergeRegs(BitSet registers, int registerCount)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 = analyzedInstruction.getPredecessorRegisterType( 160 predecessor, registerNum); 161 if (predecessorRegisterType.category != RegisterType.UNKNOWN && 162 !predecessorRegisterType.equals(mergedRegisterType)) { 163 registers.set(registerNum); 164 } 165 } 166 } 167 } 168 addParamRegs(BitSet registers, int registerCount)169 private void addParamRegs(BitSet registers, int registerCount) { 170 int parameterRegisterCount = methodAnalyzer.getParamRegisterCount(); 171 registers.set(registerCount-parameterRegisterCount, registerCount); 172 } 173 writeFullMerge(IndentingWriter writer, int registerNum)174 private void writeFullMerge(IndentingWriter writer, int registerNum) throws IOException { 175 registerFormatter.writeTo(writer, registerNum); 176 writer.write('='); 177 analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer); 178 writer.write(":merge{"); 179 180 boolean first = true; 181 182 for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) { 183 RegisterType predecessorRegisterType = analyzedInstruction.getPredecessorRegisterType( 184 predecessor, registerNum); 185 186 if (!first) { 187 writer.write(','); 188 } 189 190 if (predecessor.getInstructionIndex() == -1) { 191 //the fake "StartOfMethod" instruction 192 writer.write("Start:"); 193 } else { 194 writer.write("0x"); 195 writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor)); 196 writer.write(':'); 197 } 198 predecessorRegisterType.writeTo(writer); 199 200 first = false; 201 } 202 writer.write('}'); 203 } 204 writeRegisterInfo(IndentingWriter writer, BitSet registers, BitSet fullMergeRegisters)205 private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, 206 BitSet fullMergeRegisters) throws IOException { 207 boolean firstRegister = true; 208 boolean previousWasFullMerge = false; 209 int registerNum = registers.nextSetBit(0); 210 if (registerNum < 0) { 211 return false; 212 } 213 214 writer.write('#'); 215 for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) { 216 boolean fullMerge = fullMergeRegisters!=null && fullMergeRegisters.get(registerNum); 217 if (fullMerge) { 218 if (!firstRegister) { 219 writer.write('\n'); 220 writer.write('#'); 221 } 222 writeFullMerge(writer, registerNum); 223 previousWasFullMerge = true; 224 } else { 225 if (previousWasFullMerge) { 226 writer.write('\n'); 227 writer.write('#'); 228 previousWasFullMerge = false; 229 } 230 231 RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum); 232 233 registerFormatter.writeTo(writer, registerNum); 234 writer.write('='); 235 236 registerType.writeTo(writer); 237 writer.write(';'); 238 } 239 240 firstRegister = false; 241 } 242 return true; 243 } 244 } 245