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