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