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