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