• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.io.instructions;
18 
19 import com.android.dex.DexException;
20 import com.android.dx.io.IndexType;
21 import com.android.dx.io.OpcodeInfo;
22 import com.android.dx.io.Opcodes;
23 import com.android.dx.util.Hex;
24 import java.io.EOFException;
25 
26 /**
27  * A decoded Dalvik instruction. This consists of a format codec, a
28  * numeric opcode, an optional index type, and any additional
29  * arguments of the instruction. The additional arguments (if any) are
30  * represented as uninterpreted data.
31  *
32  * <p><b>Note:</b> The names of the arguments are <i>not</i> meant to
33  * match the names given in the Dalvik instruction format
34  * specification, specification which just names fields (somewhat)
35  * arbitrarily alphabetically from A. In this class, non-register
36  * fields are given descriptive names and register fields are
37  * consistently named alphabetically.</p>
38  */
39 public abstract class DecodedInstruction {
40     /** non-null; instruction format / codec */
41     private final InstructionCodec format;
42 
43     /** opcode number */
44     private final int opcode;
45 
46     /** constant index argument */
47     private final int index;
48 
49     /** null-ok; index type */
50     private final IndexType indexType;
51 
52     /**
53      * target address argument. This is an absolute address, not just
54      * a signed offset. <b>Note:</b> The address is unsigned, even
55      * though it is stored in an {@code int}.
56      */
57     private final int target;
58 
59     /**
60      * literal value argument; also used for special verification error
61      * constants (format 20bc) as well as should-be-zero values
62      * (formats 10x, 20t, 30t, and 32x)
63      */
64     private final long literal;
65 
66     /**
67      * Decodes an instruction from the given input source.
68      */
decode(CodeInput in)69     public static DecodedInstruction decode(CodeInput in) throws EOFException {
70         int opcodeUnit = in.read();
71         int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
72         InstructionCodec format = OpcodeInfo.getFormat(opcode);
73 
74         return format.decode(opcodeUnit, in);
75     }
76 
77     /**
78      * Decodes an array of instructions. The result has non-null
79      * elements at each offset that represents the start of an
80      * instruction.
81      */
decodeAll(short[] encodedInstructions)82     public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
83         int size = encodedInstructions.length;
84         DecodedInstruction[] decoded = new DecodedInstruction[size];
85         ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
86 
87         try {
88             while (in.hasMore()) {
89                 decoded[in.cursor()] = DecodedInstruction.decode(in);
90             }
91         } catch (EOFException ex) {
92             throw new DexException(ex);
93         }
94 
95         return decoded;
96     }
97 
98     /**
99      * Constructs an instance.
100      */
DecodedInstruction(InstructionCodec format, int opcode, int index, IndexType indexType, int target, long literal)101     public DecodedInstruction(InstructionCodec format, int opcode,
102             int index, IndexType indexType, int target, long literal) {
103         if (format == null) {
104             throw new NullPointerException("format == null");
105         }
106 
107         if (!Opcodes.isValidShape(opcode)) {
108             throw new IllegalArgumentException("invalid opcode");
109         }
110 
111         this.format = format;
112         this.opcode = opcode;
113         this.index = index;
114         this.indexType = indexType;
115         this.target = target;
116         this.literal = literal;
117     }
118 
getFormat()119     public final InstructionCodec getFormat() {
120         return format;
121     }
122 
getOpcode()123     public final int getOpcode() {
124         return opcode;
125     }
126 
127     /**
128      * Gets the opcode, as a code unit.
129      */
getOpcodeUnit()130     public final short getOpcodeUnit() {
131         return (short) opcode;
132     }
133 
getIndex()134     public final int getIndex() {
135         return index;
136     }
137 
138     /**
139      * Gets the index, as a code unit.
140      */
getIndexUnit()141     public final short getIndexUnit() {
142         return (short) index;
143     }
144 
getIndexType()145     public final IndexType getIndexType() {
146         return indexType;
147     }
148 
149     /**
150      * Gets the raw target.
151      */
getTarget()152     public final int getTarget() {
153         return target;
154     }
155 
156     /**
157      * Gets the target as a relative offset from the given address.
158      */
getTarget(int baseAddress)159     public final int getTarget(int baseAddress) {
160         return target - baseAddress;
161     }
162 
163     /**
164      * Gets the target as a relative offset from the given base
165      * address, as a code unit. This will throw if the value is out of
166      * the range of a signed code unit.
167      */
getTargetUnit(int baseAddress)168     public final short getTargetUnit(int baseAddress) {
169         int relativeTarget = getTarget(baseAddress);
170 
171         if (relativeTarget != (short) relativeTarget) {
172             throw new DexException("Target out of range: "
173                     + Hex.s4(relativeTarget));
174         }
175 
176         return (short) relativeTarget;
177     }
178 
179     /**
180      * Gets the target as a relative offset from the given base
181      * address, masked to be a byte in size. This will throw if the
182      * value is out of the range of a signed byte.
183      */
getTargetByte(int baseAddress)184     public final int getTargetByte(int baseAddress) {
185         int relativeTarget = getTarget(baseAddress);
186 
187         if (relativeTarget != (byte) relativeTarget) {
188             throw new DexException("Target out of range: "
189                     + Hex.s4(relativeTarget));
190         }
191 
192         return relativeTarget & 0xff;
193     }
194 
getLiteral()195     public final long getLiteral() {
196         return literal;
197     }
198 
199     /**
200      * Gets the literal value, masked to be an int in size. This will
201      * throw if the value is out of the range of a signed int.
202      */
getLiteralInt()203     public final int getLiteralInt() {
204         if (literal != (int) literal) {
205             throw new DexException("Literal out of range: " + Hex.u8(literal));
206         }
207 
208         return (int) literal;
209     }
210 
211     /**
212      * Gets the literal value, as a code unit. This will throw if the
213      * value is out of the range of a signed code unit.
214      */
getLiteralUnit()215     public final short getLiteralUnit() {
216         if (literal != (short) literal) {
217             throw new DexException("Literal out of range: " + Hex.u8(literal));
218         }
219 
220         return (short) literal;
221     }
222 
223     /**
224      * Gets the literal value, masked to be a byte in size. This will
225      * throw if the value is out of the range of a signed byte.
226      */
getLiteralByte()227     public final int getLiteralByte() {
228         if (literal != (byte) literal) {
229             throw new DexException("Literal out of range: " + Hex.u8(literal));
230         }
231 
232         return (int) literal & 0xff;
233     }
234 
235     /**
236      * Gets the literal value, masked to be a nibble in size. This
237      * will throw if the value is out of the range of a signed nibble.
238      */
getLiteralNibble()239     public final int getLiteralNibble() {
240         if ((literal < -8) || (literal > 7)) {
241             throw new DexException("Literal out of range: " + Hex.u8(literal));
242         }
243 
244         return (int) literal & 0xf;
245     }
246 
getRegisterCount()247     public abstract int getRegisterCount();
248 
getA()249     public int getA() {
250         return 0;
251     }
252 
getB()253     public int getB() {
254         return 0;
255     }
256 
getC()257     public int getC() {
258         return 0;
259     }
260 
getD()261     public int getD() {
262         return 0;
263     }
264 
getE()265     public int getE() {
266         return 0;
267     }
268 
269     /**
270      * Gets the register count, as a code unit. This will throw if the
271      * value is out of the range of an unsigned code unit.
272      */
getRegisterCountUnit()273     public final short getRegisterCountUnit() {
274         int registerCount = getRegisterCount();
275 
276         if ((registerCount & ~0xffff) != 0) {
277             throw new DexException("Register count out of range: "
278                     + Hex.u8(registerCount));
279         }
280 
281         return (short) registerCount;
282     }
283 
284     /**
285      * Gets the A register number, as a code unit. This will throw if the
286      * value is out of the range of an unsigned code unit.
287      */
getAUnit()288     public final short getAUnit() {
289         int a = getA();
290 
291         if ((a & ~0xffff) != 0) {
292             throw new DexException("Register A out of range: " + Hex.u8(a));
293         }
294 
295         return (short) a;
296     }
297 
298     /**
299      * Gets the A register number, as a byte. This will throw if the
300      * value is out of the range of an unsigned byte.
301      */
getAByte()302     public final short getAByte() {
303         int a = getA();
304 
305         if ((a & ~0xff) != 0) {
306             throw new DexException("Register A out of range: " + Hex.u8(a));
307         }
308 
309         return (short) a;
310     }
311 
312     /**
313      * Gets the A register number, as a nibble. This will throw if the
314      * value is out of the range of an unsigned nibble.
315      */
getANibble()316     public final short getANibble() {
317         int a = getA();
318 
319         if ((a & ~0xf) != 0) {
320             throw new DexException("Register A out of range: " + Hex.u8(a));
321         }
322 
323         return (short) a;
324     }
325 
326     /**
327      * Gets the B register number, as a code unit. This will throw if the
328      * value is out of the range of an unsigned code unit.
329      */
getBUnit()330     public final short getBUnit() {
331         int b = getB();
332 
333         if ((b & ~0xffff) != 0) {
334             throw new DexException("Register B out of range: " + Hex.u8(b));
335         }
336 
337         return (short) b;
338     }
339 
340     /**
341      * Gets the B register number, as a byte. This will throw if the
342      * value is out of the range of an unsigned byte.
343      */
getBByte()344     public final short getBByte() {
345         int b = getB();
346 
347         if ((b & ~0xff) != 0) {
348             throw new DexException("Register B out of range: " + Hex.u8(b));
349         }
350 
351         return (short) b;
352     }
353 
354     /**
355      * Gets the B register number, as a nibble. This will throw if the
356      * value is out of the range of an unsigned nibble.
357      */
getBNibble()358     public final short getBNibble() {
359         int b = getB();
360 
361         if ((b & ~0xf) != 0) {
362             throw new DexException("Register B out of range: " + Hex.u8(b));
363         }
364 
365         return (short) b;
366     }
367 
368     /**
369      * Gets the C register number, as a code unit. This will throw if the
370      * value is out of the range of an unsigned code unit.
371      */
getCUnit()372     public final short getCUnit() {
373         int c = getC();
374 
375         if ((c & ~0xffff) != 0) {
376             throw new DexException("Register C out of range: " + Hex.u8(c));
377         }
378 
379         return (short) c;
380     }
381 
382     /**
383      * Gets the C register number, as a byte. This will throw if the
384      * value is out of the range of an unsigned byte.
385      */
getCByte()386     public final short getCByte() {
387         int c = getC();
388 
389         if ((c & ~0xff) != 0) {
390             throw new DexException("Register C out of range: " + Hex.u8(c));
391         }
392 
393         return (short) c;
394     }
395 
396     /**
397      * Gets the C register number, as a nibble. This will throw if the
398      * value is out of the range of an unsigned nibble.
399      */
getCNibble()400     public final short getCNibble() {
401         int c = getC();
402 
403         if ((c & ~0xf) != 0) {
404             throw new DexException("Register C out of range: " + Hex.u8(c));
405         }
406 
407         return (short) c;
408     }
409 
410     /**
411      * Gets the D register number, as a code unit. This will throw if the
412      * value is out of the range of an unsigned code unit.
413      */
getDUnit()414     public final short getDUnit() {
415         int d = getD();
416 
417         if ((d & ~0xffff) != 0) {
418             throw new DexException("Register D out of range: " + Hex.u8(d));
419         }
420 
421         return (short) d;
422     }
423 
424     /**
425      * Gets the D register number, as a byte. This will throw if the
426      * value is out of the range of an unsigned byte.
427      */
getDByte()428     public final short getDByte() {
429         int d = getD();
430 
431         if ((d & ~0xff) != 0) {
432             throw new DexException("Register D out of range: " + Hex.u8(d));
433         }
434 
435         return (short) d;
436     }
437 
438     /**
439      * Gets the D register number, as a nibble. This will throw if the
440      * value is out of the range of an unsigned nibble.
441      */
getDNibble()442     public final short getDNibble() {
443         int d = getD();
444 
445         if ((d & ~0xf) != 0) {
446             throw new DexException("Register D out of range: " + Hex.u8(d));
447         }
448 
449         return (short) d;
450     }
451 
452     /**
453      * Gets the E register number, as a nibble. This will throw if the
454      * value is out of the range of an unsigned nibble.
455      */
getENibble()456     public final short getENibble() {
457         int e = getE();
458 
459         if ((e & ~0xf) != 0) {
460             throw new DexException("Register E out of range: " + Hex.u8(e));
461         }
462 
463         return (short) e;
464     }
465 
466     /**
467      * Encodes this instance to the given output.
468      */
encode(CodeOutput out)469     public final void encode(CodeOutput out) {
470         format.encode(this, out);
471     }
472 
473     /**
474      * Returns an instance just like this one, except with the index replaced
475      * with the given one.
476      */
withIndex(int newIndex)477     public abstract DecodedInstruction withIndex(int newIndex);
478 
479     /** Update the instruction with a new 45cc or 4rcc proto index. */
withProtoIndex(int newIndex, int newProtoIndex)480     public DecodedInstruction withProtoIndex(int newIndex, int newProtoIndex) {
481         throw new IllegalStateException(getClass().toString());
482     }
483 
484     /** Returns a 45cc or 4rcc proto index. */
getProtoIndex()485     public short getProtoIndex() {
486         throw new IllegalStateException(getClass().toString());
487     }
488 }
489