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