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.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 
     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 = analyzedInstruction.getPredecessorRegisterType(
    160                         predecessor, registerNum);
    161                 if (predecessorRegisterType.category != RegisterType.UNKNOWN &&
    162                         !predecessorRegisterType.equals(mergedRegisterType)) {
    163                     registers.set(registerNum);
    164                 }
    165             }
    166         }
    167     }
    168 
    169     private void addParamRegs(BitSet registers, int registerCount) {
    170         int parameterRegisterCount = methodAnalyzer.getParamRegisterCount();
    171         registers.set(registerCount-parameterRegisterCount, registerCount);
    172     }
    173 
    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 
    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