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