PreInstructionRegisterInfoMethodItem.java revision 3f05570b6bb8249f545ced73a1beb7f996c5227d
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
29package org.jf.baksmali.Adaptors;
30
31import org.jf.baksmali.baksmaliOptions;
32import org.jf.dexlib2.analysis.AnalyzedInstruction;
33import org.jf.dexlib2.analysis.MethodAnalyzer;
34import org.jf.dexlib2.analysis.RegisterType;
35import org.jf.dexlib2.iface.instruction.*;
36import org.jf.util.IndentingWriter;
37
38import javax.annotation.Nonnull;
39import java.io.IOException;
40import java.util.BitSet;
41
42public 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
70        if ((registerInfo & baksmaliOptions.ALL) != 0) {
71            registers.set(0, registerCount);
72        } else {
73            if ((registerInfo & baksmaliOptions.ALLPRE) != 0) {
74                registers.set(0, registerCount);
75            } else {
76                if ((registerInfo & baksmaliOptions.ARGS) != 0) {
77                    addArgsRegs(registers);
78                }
79                if ((registerInfo & baksmaliOptions.MERGE) != 0) {
80                    addMergeRegs(registers, registerCount);
81                } else if ((registerInfo & baksmaliOptions.FULLMERGE) != 0 &&
82                        (analyzedInstruction.isBeginningInstruction())) {
83                    addParamRegs(registers, registerCount);
84                }
85            }
86        }
87
88        boolean printedSomething = false;
89        if ((registerInfo & baksmaliOptions.FULLMERGE) != 0) {
90            printedSomething = writeFullMergeRegs(writer, registers, registerCount);
91        }
92
93        printedSomething |= writeRegisterInfo(writer, registers, printedSomething);
94
95        return printedSomething;
96    }
97
98    private void addArgsRegs(BitSet registers) {
99        if (analyzedInstruction.getInstruction() instanceof RegisterRangeInstruction) {
100            RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.getInstruction();
101
102            registers.set(instruction.getStartRegister(),
103                    instruction.getStartRegister() + instruction.getRegisterCount());
104        } else if (analyzedInstruction.getInstruction() instanceof FiveRegisterInstruction) {
105            FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.getInstruction();
106            int regCount = instruction.getRegisterCount();
107            switch (regCount) {
108                case 5:
109                    registers.set(instruction.getRegisterG());
110                    //fall through
111                case 4:
112                    registers.set(instruction.getRegisterF());
113                    //fall through
114                case 3:
115                    registers.set(instruction.getRegisterE());
116                    //fall through
117                case 2:
118                    registers.set(instruction.getRegisterD());
119                    //fall through
120                case 1:
121                    registers.set(instruction.getRegisterC());
122            }
123        } else if (analyzedInstruction.getInstruction() instanceof ThreeRegisterInstruction) {
124            ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.getInstruction();
125            registers.set(instruction.getRegisterA());
126            registers.set(instruction.getRegisterB());
127            registers.set(instruction.getRegisterC());
128        } else if (analyzedInstruction.getInstruction() instanceof TwoRegisterInstruction) {
129            TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.getInstruction();
130            registers.set(instruction.getRegisterA());
131            registers.set(instruction.getRegisterB());
132        } else if (analyzedInstruction.getInstruction() instanceof OneRegisterInstruction) {
133            OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.getInstruction();
134            registers.set(instruction.getRegisterA());
135        }
136    }
137
138    private void addMergeRegs(BitSet registers, int registerCount) {
139        if (analyzedInstruction.isBeginningInstruction()) {
140            addParamRegs(registers, registerCount);
141        }
142
143        if (analyzedInstruction.getPredecessorCount() <= 1) {
144            //in the common case of an instruction that only has a single predecessor which is the previous
145            //instruction, the pre-instruction registers will always match the previous instruction's
146            //post-instruction registers
147            return;
148        }
149
150        for (int registerNum=0; registerNum<registerCount; registerNum++) {
151            RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
152
153            for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
154                if (!predecessor.getPostInstructionRegisterType(registerNum).equals(mergedRegisterType)) {
155                    registers.set(registerNum);
156                }
157            }
158        }
159    }
160
161    private void addParamRegs(BitSet registers, int registerCount) {
162        int parameterRegisterCount = methodAnalyzer.getParamRegisterCount();
163        registers.set(registerCount-parameterRegisterCount, registerCount);
164    }
165
166    private boolean writeFullMergeRegs(IndentingWriter writer, BitSet registers, int registerCount)
167                                    throws IOException {
168        if (analyzedInstruction.getPredecessorCount() <= 1) {
169            return false;
170        }
171
172        boolean firstRegister = true;
173
174        for (int registerNum=0; registerNum<registerCount; registerNum++) {
175            RegisterType mergedRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
176            boolean addRegister = false;
177
178            for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
179                RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
180                if (predecessorRegisterType.category != RegisterType.UNKNOWN &&
181                        !predecessorRegisterType.equals(mergedRegisterType)) {
182
183                    addRegister = true;
184                    break;
185                }
186            }
187
188            if (!addRegister) {
189                continue;
190            }
191
192            if (firstRegister) {
193                firstRegister = false;
194            } else {
195                writer.write('\n');
196            }
197
198            writer.write('#');
199            registerFormatter.writeTo(writer, registerNum);
200            writer.write('=');
201            analyzedInstruction.getPreInstructionRegisterType(registerNum).writeTo(writer);
202            writer.write(":merge{");
203
204            boolean first = true;
205
206            for (AnalyzedInstruction predecessor: analyzedInstruction.getPredecessors()) {
207                RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum);
208
209                if (!first) {
210                    writer.write(',');
211                }
212
213                if (predecessor.getInstructionIndex() == -1) {
214                    //the fake "StartOfMethod" instruction
215                    writer.write("Start:");
216                } else {
217                    writer.write("0x");
218                    writer.printUnsignedLongAsHex(methodAnalyzer.getInstructionAddress(predecessor));
219                    writer.write(':');
220                }
221                predecessorRegisterType.writeTo(writer);
222
223                first = false;
224            }
225            writer.write('}');
226
227            registers.clear(registerNum);
228        }
229        return !firstRegister;
230    }
231
232    private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers, boolean addNewline) throws IOException {
233        int registerNum = registers.nextSetBit(0);
234        if (registerNum < 0) {
235            return false;
236        }
237
238        if (addNewline) {
239            writer.write('\n');
240        }
241
242        writer.write('#');
243        for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) {
244
245            RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNum);
246
247            registerFormatter.writeTo(writer, registerNum);
248            writer.write('=');
249
250            registerType.writeTo(writer);
251            writer.write(';');
252        }
253        return true;
254    }
255}
256