InstructionMethodItem.java revision 4d3b3311e19f479cef271ff374a0ea512bd3cbc1
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                return true;
197            case Format35ms:
198                writeOpcode(writer);
199                writer.write(' ');
200                writeInvokeRegisters(writer);
201                writer.write(", ");
202                writeVtableIndex(writer);
203                return true;
204            case Format3rc:
205            case Format5rc:
206                writeOpcode(writer);
207                writer.write(' ');
208                writeInvokeRangeRegisters(writer);
209                writer.write(", ");
210                writeReference(writer);
211                return true;
212            case Format3rmi:
213                writeOpcode(writer);
214                writer.write(' ');
215                writeInvokeRangeRegisters(writer);
216                writer.write(", ");
217                writeInlineIndex(writer);
218                return true;
219            case Format3rms:
220                writeOpcode(writer);
221                writer.write(' ');
222                writeInvokeRangeRegisters(writer);
223                writer.write(", ");
224                writeVtableIndex(writer);
225                return true;
226        }
227        assert false;
228        return false;
229    }
230
231    protected void writeOpcode(IndentingWriter writer) throws IOException {
232        writer.write(instruction.opcode.name);
233    }
234
235    protected void writeTargetLabel(IndentingWriter writer) throws IOException {
236        //this method is overrided by OffsetInstructionMethodItem, and should only be called for the formats that
237        //have a target
238        throw new RuntimeException();
239    }
240
241    protected void writeRegister(IndentingWriter writer, int registerNumber) throws IOException {
242        RegisterFormatter.writeTo(writer, codeItem, registerNumber);
243    }
244
245    protected void writeFirstRegister(IndentingWriter writer) throws IOException {
246        writeRegister(writer, ((SingleRegisterInstruction)instruction).getRegisterA());
247    }
248
249    protected void writeSecondRegister(IndentingWriter writer) throws IOException {
250        writeRegister(writer, ((TwoRegisterInstruction)instruction).getRegisterB());
251    }
252
253    protected void writeThirdRegister(IndentingWriter writer) throws IOException {
254        writeRegister(writer, ((ThreeRegisterInstruction)instruction).getRegisterC());
255    }
256
257    protected void writeInvokeRegisters(IndentingWriter writer) throws IOException {
258        FiveRegisterInstruction instruction = (FiveRegisterInstruction)this.instruction;
259        final int regCount = instruction.getRegCount();
260
261        writer.write('{');
262        switch (regCount) {
263            case 1:
264                writeRegister(writer, instruction.getRegisterD());
265                break;
266            case 2:
267                writeRegister(writer, instruction.getRegisterD());
268                writer.write(", ");
269                writeRegister(writer, instruction.getRegisterE());
270                break;
271            case 3:
272                writeRegister(writer, instruction.getRegisterD());
273                writer.write(", ");
274                writeRegister(writer, instruction.getRegisterE());
275                writer.write(", ");
276                writeRegister(writer, instruction.getRegisterF());
277                break;
278            case 4:
279                writeRegister(writer, instruction.getRegisterD());
280                writer.write(", ");
281                writeRegister(writer, instruction.getRegisterE());
282                writer.write(", ");
283                writeRegister(writer, instruction.getRegisterF());
284                writer.write(", ");
285                writeRegister(writer, instruction.getRegisterG());
286                break;
287            case 5:
288                writeRegister(writer, instruction.getRegisterD());
289                writer.write(", ");
290                writeRegister(writer, instruction.getRegisterE());
291                writer.write(", ");
292                writeRegister(writer, instruction.getRegisterF());
293                writer.write(", ");
294                writeRegister(writer, instruction.getRegisterG());
295                writer.write(", ");
296                writeRegister(writer, instruction.getRegisterA());
297                break;
298        }
299        writer.write('}');
300    }
301
302    protected void writeInvokeRangeRegisters(IndentingWriter writer) throws IOException {
303        RegisterRangeInstruction instruction = (RegisterRangeInstruction)this.instruction;
304
305        int regCount = instruction.getRegCount();
306        if (regCount == 0) {
307            writer.write("{}");
308        } else {
309            int startRegister = instruction.getStartRegister();
310            RegisterFormatter.writeRegisterRange(writer, codeItem, startRegister, startRegister+regCount-1);
311        }
312    }
313
314    protected void writeLiteral(IndentingWriter writer) throws IOException {
315        LongRenderer.writeSignedIntOrLongTo(writer, ((LiteralInstruction)instruction).getLiteral());
316    }
317
318    protected void writeFieldOffset(IndentingWriter writer) throws IOException {
319        writer.write("field@0x");
320        writer.printUnsignedLongAsHex(((OdexedFieldAccess) instruction).getFieldOffset());
321    }
322
323    protected void writeInlineIndex(IndentingWriter writer) throws IOException {
324        writer.write("inline@0x");
325        writer.printUnsignedLongAsHex(((OdexedInvokeInline) instruction).getInlineIndex());
326    }
327
328    protected void writeVtableIndex(IndentingWriter writer) throws IOException {
329        writer.write("vtable@0x");
330        writer.printUnsignedLongAsHex(((OdexedInvokeVirtual) instruction).getVtableIndex());
331    }
332
333    protected void writeReference(IndentingWriter writer) throws IOException {
334        Item item = ((InstructionWithReference)instruction).getReferencedItem();
335        ReferenceFormatter.writeReference(writer, item);
336    }
337
338    protected void writeVerificationErrorType(IndentingWriter writer) throws IOException {
339        VerificationErrorType validationErrorType = ((Instruction20bc)instruction).getValidationErrorType();
340        writer.write(validationErrorType.getName());
341    }
342}
343