PreInstructionRegisterInfoMethodItem.java revision 7172de2aabc88ee66c0b50d78c731830ed374d18
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/* 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * [The "BSD licence"] 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Copyright (c) 2010 Ben Gruver 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * All rights reserved. 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * modification, are permitted provided that the following conditions 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * are met: 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * documentation and/or other materials provided with the distribution. 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 3. The name of the author may not be used to endorse or promote products 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * derived from this software without specific prior written permission. 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.jf.baksmali.Adaptors; 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.baksmali.baksmaliOptions; 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.analysis.AnalyzedInstruction; 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.analysis.MethodAnalyzer; 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.analysis.RegisterType; 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.dexlib2.iface.instruction.*; 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.jf.util.IndentingWriter; 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import javax.annotation.Nonnull; 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.io.IOException; 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.BitSet; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)public class PreInstructionRegisterInfoMethodItem extends MethodItem { 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private final int registerInfo; 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final MethodAnalyzer methodAnalyzer; 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final RegisterFormatter registerFormatter; 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull private final AnalyzedInstruction analyzedInstruction; 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public PreInstructionRegisterInfoMethodItem(int registerInfo, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull MethodAnalyzer methodAnalyzer, 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull RegisterFormatter registerFormatter, 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Nonnull AnalyzedInstruction analyzedInstruction, 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int codeAddress) { 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) super(codeAddress); 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.registerInfo = registerInfo; 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.methodAnalyzer = methodAnalyzer; 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.registerFormatter = registerFormatter; 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.analyzedInstruction = analyzedInstruction; 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 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