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