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