InstructionMethodItem.java revision c8de336727bfe8e56998332fe97ad5c0e32e50fa
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2010 Ben Gruver (JesusFreke)
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.Format;
30
31import org.jf.baksmali.Adaptors.MethodItem;
32import org.jf.baksmali.Adaptors.ReferenceFormatter;
33import org.jf.baksmali.Adaptors.RegisterFormatter;
34import org.jf.dexlib.Code.Format.Instruction20bc;
35import org.jf.util.IndentingWriter;
36import org.jf.baksmali.Renderers.LongRenderer;
37import org.jf.dexlib.Code.*;
38import org.jf.dexlib.CodeItem;
39import org.jf.dexlib.Item;
40
41import java.io.IOException;
42
43public class InstructionMethodItem<T extends Instruction> extends MethodItem {
44    protected final CodeItem codeItem;
45    protected final T instruction;
46
47    public InstructionMethodItem(CodeItem codeItem, int codeAddress, T instruction) {
48        super(codeAddress);
49        this.codeItem = codeItem;
50        this.instruction = instruction;
51    }
52
53    public double getSortOrder() {
54        //instructions should appear after everything except an "end try" label and .catch directive
55        return 100;
56    }
57
58    @Override
59    public boolean writeTo(IndentingWriter writer) throws IOException {
60        switch (instruction.getFormat()) {
61            case Format10t:
62                writeOpcode(writer);
63                writer.write(' ');
64                writeTargetLabel(writer);
65                return true;
66            case Format10x:
67                writeOpcode(writer);
68                return true;
69            case Format11n:
70                writeOpcode(writer);
71                writer.write(' ');
72                writeFirstRegister(writer);
73                writer.write(", ");
74                writeLiteral(writer);
75                return true;
76            case Format11x:
77                writeOpcode(writer);
78                writer.write(' ');
79                writeFirstRegister(writer);
80                return true;
81            case Format12x:
82                writeOpcode(writer);
83                writer.write(' ');
84                writeFirstRegister(writer);
85                writer.write(", ");
86                writeSecondRegister(writer);
87                return true;
88            case Format20bc:
89                writeOpcode(writer);
90                writer.write(' ');
91                writeVerificationErrorType(writer);
92                writer.write(", ");
93                writeReference(writer);
94                return true;
95            case Format20t:
96            case Format30t:
97                writeOpcode(writer);
98                writer.write(' ');
99                writeTargetLabel(writer);
100                return true;
101            case Format21c:
102            case Format31c:
103            case Format41c:
104                writeOpcode(writer);
105                writer.write(' ');
106                writeFirstRegister(writer);
107                writer.write(", ");
108                writeReference(writer);
109                return true;
110            case Format21h:
111            case Format21s:
112            case Format31i:
113            case Format51l:
114                writeOpcode(writer);
115                writer.write(' ');
116                writeFirstRegister(writer);
117                writer.write(", ");
118                writeLiteral(writer);
119                return true;
120            case Format21t:
121            case Format31t:
122                writeOpcode(writer);
123                writer.write(' ');
124                writeFirstRegister(writer);
125                writer.write(", ");
126                writeTargetLabel(writer);
127                return true;
128            case Format22b:
129            case Format22s:
130                writeOpcode(writer);
131                writer.write(' ');
132                writeFirstRegister(writer);
133                writer.write(", ");
134                writeSecondRegister(writer);
135                writer.write(", ");
136                writeLiteral(writer);
137                return true;
138            case Format22c:
139            case Format52c:
140                writeOpcode(writer);
141                writer.write(' ');
142                writeFirstRegister(writer);
143                writer.write(", ");
144                writeSecondRegister(writer);
145                writer.write(", ");
146                writeReference(writer);
147                return true;
148            case Format22cs:
149                writeOpcode(writer);
150                writer.write(' ');
151                writeFirstRegister(writer);
152                writer.write(", ");
153                writeSecondRegister(writer);
154                writer.write(", ");
155                writeFieldOffset(writer);
156                return true;
157            case Format22t:
158                writeOpcode(writer);
159                writer.write(' ');
160                writeFirstRegister(writer);
161                writer.write(", ");
162                writeSecondRegister(writer);
163                writer.write(", ");
164                writeTargetLabel(writer);
165                return true;
166            case Format22x:
167            case Format32x:
168                writeOpcode(writer);
169                writer.write(' ');
170                writeFirstRegister(writer);
171                writer.write(", ");
172                writeSecondRegister(writer);
173                return true;
174            case Format23x:
175                writeOpcode(writer);
176                writer.write(' ');
177                writeFirstRegister(writer);
178                writer.write(", ");
179                writeSecondRegister(writer);
180                writer.write(", ");
181                writeThirdRegister(writer);
182                return true;
183            case Format35c:
184                writeOpcode(writer);
185                writer.write(' ');
186                writeInvokeRegisters(writer);
187                writer.write(", ");
188                writeReference(writer);
189                return true;
190            case Format35mi:
191                writeOpcode(writer);
192                writer.write(' ');
193                writeInvokeRegisters(writer);
194                writer.write(", ");
195                writeInlineIndex(writer);
196            case Format35ms:
197                writeOpcode(writer);
198                writer.write(' ');
199                writeInvokeRegisters(writer);
200                writer.write(", ");
201                writeVtableIndex(writer);
202                return true;
203            case Format3rc:
204            case Format5rc:
205                writeOpcode(writer);
206                writer.write(' ');
207                writeInvokeRangeRegisters(writer);
208                writer.write(", ");
209                writeReference(writer);
210                return true;
211            case Format3rmi:
212                writeOpcode(writer);
213                writer.write(' ');
214                writeInvokeRangeRegisters(writer);
215                writer.write(", ");
216                writeInlineIndex(writer);
217                return true;
218            case Format3rms:
219                writeOpcode(writer);
220                writer.write(' ');
221                writeInvokeRangeRegisters(writer);
222                writer.write(", ");
223                writeVtableIndex(writer);
224                return true;
225        }
226        assert false;
227        return false;
228    }
229
230    protected void writeOpcode(IndentingWriter writer) throws IOException {
231        writer.write(instruction.opcode.name);
232    }
233
234    protected void writeTargetLabel(IndentingWriter writer) throws IOException {
235        //this method is overrided by OffsetInstructionMethodItem, and should only be called for the formats that
236        //have a target
237        throw new RuntimeException();
238    }
239
240    protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
241        RegisterFormatter.writeTo(writer, codeItem, registerNumber);
242    }
243
244    protected void writeFirstRegister(IndentingWriter writer) throws IOException {
245        writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
246    }
247
248    protected void writeSecondRegister(IndentingWriter writer) throws IOException {
249        writeRegister(writer, ((TwoRegisterInstruction)instruction).getRegisterB());
250    }
251
252    protected void writeThirdRegister(IndentingWriter writer) throws IOException {
253        writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
254    }
255
256    protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
257        FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
258        final int regCount = instruction.getRegCount();
259
260        writer.write('{');
261        switch (regCount) {
262            case 1:
263                writeRegister(writer, instruction.getRegisterD());
264                break;
265            case 2:
266                writeRegister(writer, instruction.getRegisterD());
267                writer.write(", ");
268                writeRegister(writer, instruction.getRegisterE());
269                break;
270            case 3:
271                writeRegister(writer, instruction.getRegisterD());
272                writer.write(", ");
273                writeRegister(writer, instruction.getRegisterE());
274                writer.write(", ");
275                writeRegister(writer, instruction.getRegisterF());
276                break;
277            case 4:
278                writeRegister(writer, instruction.getRegisterD());
279                writer.write(", ");
280                writeRegister(writer, instruction.getRegisterE());
281                writer.write(", ");
282                writeRegister(writer, instruction.getRegisterF());
283                writer.write(", ");
284                writeRegister(writer, instruction.getRegisterG());
285                break;
286            case 5:
287                writeRegister(writer, instruction.getRegisterD());
288                writer.write(", ");
289                writeRegister(writer, instruction.getRegisterE());
290                writer.write(", ");
291                writeRegister(writer, instruction.getRegisterF());
292                writer.write(", ");
293                writeRegister(writer, instruction.getRegisterG());
294                writer.write(", ");
295                writeRegister(writer, instruction.getRegisterA());
296                break;
297        }
298        writer.write('}');
299    }
300
301    protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
302        RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
303
304        int regCount = instruction.getRegCount();
305        if (regCount == 0) {
306            writer.write("{}");
307        } else {
308            int startRegister = instruction.getStartRegister();
309            RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
310        }
311    }
312
313    protected void writeLiteral(IndentingWriter writer) throws IOException {
314        LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
315    }
316
317    protected void writeFieldOffset(IndentingWriter writer) throws IOException {
318        writer.write("field@0x");
319        writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
320    }
321
322    protected void writeInlineIndex(IndentingWriter writer) throws IOException {
323        writer.write("inline@0x");
324        writer.printUnsignedLongAsHex(((OdexedInvokeInline) instruction).getInlineIndex());
325    }
326
327    protected void writeVtableIndex(IndentingWriter writer) throws IOException {
328        writer.write("vtable@0x");
329        writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
330    }
331
332    protected void writeReference(IndentingWriter writer) throws IOException {
333        Item item = ((InstructionWithReference)instruction).getReferencedItem();
334        ReferenceFormatter.writeReference(writer, item);
335    }
336
337    protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
338        VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
339        writer.write(validationErrorType.getName());
340    }
341}
342