Home | History | Annotate | Download | only in instructions
      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.dx.io.IndexType;
     20 import com.android.dx.io.OpcodeInfo;
     21 import com.android.dx.io.Opcodes;
     22 import com.android.dx.util.DexException;
     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      */
     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      */
     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      */
    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 
    119     public final InstructionCodec getFormat() {
    120         return format;
    121     }
    122 
    123     public final int getOpcode() {
    124         return opcode;
    125     }
    126 
    127     /**
    128      * Gets the opcode, as a code unit.
    129      */
    130     public final short getOpcodeUnit() {
    131         return (short) opcode;
    132     }
    133 
    134     public final int getIndex() {
    135         return index;
    136     }
    137 
    138     /**
    139      * Gets the index, as a code unit.
    140      */
    141     public final short getIndexUnit() {
    142         return (short) index;
    143     }
    144 
    145     public final IndexType getIndexType() {
    146         return indexType;
    147     }
    148 
    149     /**
    150      * Gets the raw target.
    151      */
    152     public final int getTarget() {
    153         return target;
    154     }
    155 
    156     /**
    157      * Gets the target as a relative offset from the given address.
    158      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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 
    247     public abstract int getRegisterCount();
    248 
    249     public int getA() {
    250         return 0;
    251     }
    252 
    253     public int getB() {
    254         return 0;
    255     }
    256 
    257     public int getC() {
    258         return 0;
    259     }
    260 
    261     public int getD() {
    262         return 0;
    263     }
    264 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    477     public abstract DecodedInstruction withIndex(int newIndex);
    478 }
    479