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