Home | History | Annotate | Download | only in Adaptors
      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