DexBackedInstruction.java revision 1c3a283ac327b8c673321999c5817996872b7fcc
1/*
2 * Copyright 2012, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked.instruction;
33
34import org.jf.dexlib2.dexbacked.DexReader;
35import org.jf.dexlib2.Opcode;
36import org.jf.dexlib2.iface.instruction.Instruction;
37import org.jf.dexlib2.iface.instruction.formats.*;
38import org.jf.dexlib2.immutable.instruction.*;
39import org.jf.util.ExceptionWithContext;
40import org.jf.util.NibbleUtils;
41
42import javax.annotation.Nonnull;
43
44public abstract class DexBackedInstruction {
45    @Nonnull
46    public static Instruction readFrom(@Nonnull DexReader reader) {
47        int opcodeValue = reader.readUbyte();
48        if (opcodeValue == 0) {
49            reader.moveRelative(-1);
50            opcodeValue = reader.readUshort();
51            if (opcodeValue == 0) {
52                // if we've got a real nop, and not a payload instruction, back up a byte,
53                // so that the reader is positioned just after the single opcode byte, for consistency
54                reader.moveRelative(-1);
55            }
56        }
57
58        Opcode opcode = Opcode.getOpcodeByValue(opcodeValue);
59
60        //TODO: handle unexpected/unknown opcodes
61
62        switch (opcode.format) {
63            case Format10t:
64                return instruction10t(opcode, reader);
65            case Format10x:
66                return instruction10x(opcode, reader);
67            case Format11n:
68                return instruction11n(opcode, reader);
69            case Format11x:
70                return instruction11x(opcode, reader);
71            case Format12x:
72                return instruction12x(opcode, reader);
73            case Format20t:
74                return instruction20t(opcode, reader);
75            case Format21c:
76                return instruction21c(opcode, reader);
77            case Format21ih:
78                return instruction21ih(opcode, reader);
79            case Format21lh:
80                return instruction21lh(opcode, reader);
81            case Format21s:
82                return instruction21s(opcode, reader);
83            case Format21t:
84                return instruction21t(opcode, reader);
85            case Format22b:
86                return instruction22b(opcode, reader);
87            case Format22c:
88                return instruction22c(opcode, reader);
89            case Format22s:
90                return instruction22s(opcode, reader);
91            case Format22t:
92                return instruction22t(opcode, reader);
93            case Format22x:
94                return instruction22x(opcode, reader);
95            case Format23x:
96                return instruction23x(opcode, reader);
97            case Format30t:
98                return instruction30t(opcode, reader);
99            case Format31c:
100                return instruction31c(opcode, reader);
101            case Format31i:
102                return instruction31i(opcode, reader);
103            case Format31t:
104                return instruction31t(opcode, reader);
105            case Format32x:
106                return instruction32x(opcode, reader);
107            case Format35c:
108                return instruction35c(opcode, reader);
109            case Format3rc:
110                return instruction3rc(opcode, reader);
111            case Format51l:
112                return instruction51l(opcode, reader);
113            case PackedSwitchPayload:
114                return packedSwitchPayload(reader);
115            case SparseSwitchPayload:
116                return sparseSwitchPayload(reader);
117            case ArrayPayload:
118                return arrayPayload(reader);
119            //TODO: temporary, until we get all instructions implemented
120            default:
121                throw new ExceptionWithContext("Unexpected opcode format: %s", opcode.format.toString());
122        }
123    }
124
125    @Nonnull
126    private static Instruction10t instruction10t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
127        int offset = reader.readByte();
128        return new ImmutableInstruction10t(opcode, offset);
129    }
130
131    @Nonnull
132    private static Instruction10x instruction10x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
133        reader.skipByte();
134        return new ImmutableInstruction10x(opcode);
135    }
136
137    @Nonnull
138    private static Instruction11n instruction11n(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
139        int b = reader.readUbyte();
140        int registerA = NibbleUtils.extractLowUnsignedNibble(b);
141        int literal = NibbleUtils.extractHighSignedNibble(b);
142        return new ImmutableInstruction11n(opcode, registerA, literal);
143    }
144
145    @Nonnull
146    private static Instruction11x instruction11x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
147        int registerA = reader.readUbyte();
148        return new ImmutableInstruction11x(opcode, registerA);
149    }
150
151    @Nonnull
152    private static Instruction12x instruction12x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
153        int b = reader.readUbyte();
154        int registerA = NibbleUtils.extractLowUnsignedNibble(b);
155        int registerB = NibbleUtils.extractHighUnsignedNibble(b);
156        return new ImmutableInstruction12x(opcode, registerA, registerB);
157    }
158
159    @Nonnull
160    private static Instruction20t instruction20t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
161        reader.skipByte();
162        int offset = reader.readShort();
163        return new ImmutableInstruction20t(opcode, offset);
164    }
165
166    @Nonnull
167    private static Instruction21c instruction21c(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
168        int registerA = reader.readUbyte();
169        int referenceIndex = reader.readUshort();
170        String reference = reader.getReference(opcode.referenceType, referenceIndex);
171        return new ImmutableInstruction21c(opcode, registerA, reference);
172    }
173
174    @Nonnull
175    private static Instruction21ih instruction21ih(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
176        int registerA = reader.readUbyte();
177        int literalHat = reader.readShort();
178        return new ImmutableInstruction21ih(opcode, registerA, literalHat << 16);
179    }
180
181    @Nonnull
182    private static Instruction21lh instruction21lh(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
183        int registerA = reader.readUbyte();
184        int literalHat = reader.readShort();
185        return new ImmutableInstruction21lh(opcode, registerA, ((long)literalHat) << 48);
186    }
187
188    @Nonnull
189    private static Instruction21s instruction21s(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
190        int registerA = reader.readUbyte();
191        int literal = reader.readShort();
192        return new ImmutableInstruction21s(opcode, registerA, literal);
193    }
194
195    @Nonnull
196    private static Instruction21t instruction21t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
197        int registerA = reader.readUbyte();
198        int offset = reader.readShort();
199        return new ImmutableInstruction21t(opcode, registerA, offset);
200    }
201
202    @Nonnull
203    private static Instruction22b instruction22b(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
204        int registerA = reader.readUbyte();
205        int registerB = reader.readUbyte();
206        int literal = reader.readByte();
207        return new ImmutableInstruction22b(opcode, registerA, registerB, literal);
208    }
209
210    @Nonnull
211    private static Instruction22c instruction22c(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
212        int b = reader.readUbyte();
213        int registerA = NibbleUtils.extractLowUnsignedNibble(b);
214        int registerB = NibbleUtils.extractHighUnsignedNibble(b);
215
216        int referenceIndex = reader.readUshort();
217        String reference = reader.getReference(opcode.referenceType, referenceIndex);
218        return new ImmutableInstruction22c(opcode, registerA, registerB, reference);
219    }
220
221    @Nonnull
222    private static Instruction22s instruction22s(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
223        int b = reader.readUbyte();
224        int registerA = NibbleUtils.extractLowUnsignedNibble(b);
225        int registerB = NibbleUtils.extractHighUnsignedNibble(b);
226        int literal = reader.readShort();
227        return new ImmutableInstruction22s(opcode, registerA, registerB, literal);
228    }
229
230    @Nonnull
231    private static Instruction22t instruction22t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
232        int b = reader.readUbyte();
233        int registerA = NibbleUtils.extractLowUnsignedNibble(b);
234        int registerB = NibbleUtils.extractHighUnsignedNibble(b);
235        int offset = reader.readShort();
236        return new ImmutableInstruction22t(opcode, registerA, registerB, offset);
237    }
238
239    @Nonnull
240    private static Instruction22x instruction22x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
241        int registerA = reader.readUbyte();
242        int registerB = reader.readUshort();
243        return new ImmutableInstruction22x(opcode, registerA, registerB);
244    }
245
246    @Nonnull
247    private static Instruction23x instruction23x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
248        int registerA = reader.readUbyte();
249        int registerB = reader.readUbyte();
250        int registerC = reader.readUbyte();
251        return new ImmutableInstruction23x(opcode, registerA, registerB, registerC);
252    }
253
254    @Nonnull
255    private static Instruction30t instruction30t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
256        reader.skipByte();
257        int offset = reader.readInt();
258        return new ImmutableInstruction30t(opcode, offset);
259    }
260
261    @Nonnull
262    private static Instruction31c instruction31c(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
263        int registerA = reader.readUbyte();
264        int referenceIndex = reader.readSmallUint();
265        String reference = reader.getReference(opcode.referenceType, referenceIndex);
266        return new ImmutableInstruction31c(opcode, registerA, reference);
267    }
268
269    @Nonnull
270    private static Instruction31i instruction31i(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
271        int registerA = reader.readUbyte();
272        int literal = reader.readInt();
273        return new ImmutableInstruction31i(opcode, registerA, literal);
274    }
275
276    @Nonnull
277    private static Instruction31t instruction31t(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
278        int registerA = reader.readUbyte();
279        int offset = reader.readInt();
280        return new ImmutableInstruction31t(opcode, registerA, offset);
281    }
282
283    @Nonnull
284    private static Instruction32x instruction32x(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
285        reader.skipByte();
286        int registerA = reader.readUshort();
287        int registerB = reader.readUshort();
288        return new ImmutableInstruction32x(opcode, registerA, registerB);
289    }
290
291    @Nonnull
292    private static Instruction35c instruction35c(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
293        int b = reader.readUbyte();
294        int registerCount = NibbleUtils.extractHighUnsignedNibble(b);
295        int registerG = NibbleUtils.extractLowUnsignedNibble(b);
296
297        int referenceIndex = reader.readUshort();
298        String reference = reader.getReference(opcode.referenceType, referenceIndex);
299
300        b = reader.readUbyte();
301        int registerC = NibbleUtils.extractLowUnsignedNibble(b);
302        int registerD = NibbleUtils.extractHighUnsignedNibble(b);
303
304        b = reader.readUbyte();
305        int registerE = NibbleUtils.extractLowUnsignedNibble(b);
306        int registerF = NibbleUtils.extractHighUnsignedNibble(b);
307
308        return new ImmutableInstruction35c(opcode, registerCount, registerC, registerD,
309                registerE, registerF, registerG, reference);
310    }
311
312    @Nonnull
313    private static Instruction3rc instruction3rc(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
314        int registerCount = reader.readUbyte();
315        int referenceIndex = reader.readUshort();
316        String reference = reader.getReference(opcode.referenceType, referenceIndex);
317        int startRegister = reader.readUshort();
318        return new ImmutableInstruction3rc(opcode, startRegister, registerCount, reference);
319    }
320
321    @Nonnull
322    private static Instruction51l instruction51l(@Nonnull Opcode opcode, @Nonnull DexReader reader) {
323        int registerA = reader.readUbyte();
324        long literal = reader.readLong();
325        return new ImmutableInstruction51l(opcode, registerA, literal);
326    }
327
328    @Nonnull
329    private static DexBackedPackedSwitchPayload packedSwitchPayload(@Nonnull DexReader reader) {
330        // the reader is currently positioned after the 2-byte "opcode"
331        int instructionStartOffset = reader.getOffset() - 2;
332        DexBackedPackedSwitchPayload instruction =
333                new DexBackedPackedSwitchPayload(reader.getDexBuffer(), instructionStartOffset);
334        reader.setOffset(instructionStartOffset + instruction.getCodeUnits() * 2);
335        return instruction;
336    }
337
338    @Nonnull
339    private static DexBackedSparseSwitchPayload sparseSwitchPayload(@Nonnull DexReader reader) {
340        // the reader is currently positioned after the 2-byte "opcode"
341        int instructionStartOffset = reader.getOffset() - 2;
342        DexBackedSparseSwitchPayload instruction =
343                new DexBackedSparseSwitchPayload(reader.getDexBuffer(), instructionStartOffset);
344        reader.setOffset(instructionStartOffset + instruction.getCodeUnits() * 2);
345        return instruction;
346    }
347
348    @Nonnull
349    private static DexBackedArrayPayload arrayPayload(@Nonnull DexReader reader) {
350        // the reader is currently positioned after the 2-byte "opcode"
351        int instructionStartOffset = reader.getOffset() - 2;
352        DexBackedArrayPayload instruction = new DexBackedArrayPayload(reader.getDexBuffer(), instructionStartOffset);
353        reader.setOffset(instructionStartOffset + instruction.getCodeUnits() * 2);
354        return instruction;
355    }
356}
357