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