MethodAnalyzer.java revision 02f1d6cc1a7db4305f8fa3dbb97e47696ad751d9
1/* 2 * Copyright 2013, 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.analysis; 33 34import com.google.common.collect.ImmutableList; 35import org.jf.dexlib2.Opcode; 36import org.jf.dexlib2.iface.*; 37import org.jf.dexlib2.iface.instruction.*; 38import org.jf.dexlib2.iface.instruction.formats.*; 39import org.jf.dexlib2.iface.reference.FieldReference; 40import org.jf.dexlib2.iface.reference.MethodReference; 41import org.jf.dexlib2.iface.reference.Reference; 42import org.jf.dexlib2.iface.reference.TypeReference; 43import org.jf.dexlib2.immutable.instruction.*; 44import org.jf.dexlib2.util.MethodUtil; 45import org.jf.dexlib2.util.ReferenceUtil; 46import org.jf.dexlib2.util.TypeUtils; 47import org.jf.util.BitSetUtils; 48import org.jf.util.ExceptionWithContext; 49import org.jf.util.SparseArray; 50 51import javax.annotation.Nonnull; 52import javax.annotation.Nullable; 53import java.util.BitSet; 54import java.util.List; 55 56/** 57 * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types 58 * for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification 59 * are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and 60 * there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then 61 * verify it. 62 * 63 * Before calling the analyze() method, you must have initialized the ClassPath by calling 64 * ClassPath.InitializeClassPath 65 */ 66public class MethodAnalyzer { 67 @Nonnull private final Method method; 68 @Nonnull private final MethodImplementation methodImpl; 69 70 private final int paramRegisterCount; 71 72 @Nonnull private final ClassPath classPath; 73 @Nullable private final InlineMethodResolver inlineResolver; 74 75 // This contains all the AnalyzedInstruction instances, keyed by the code unit address of the instruction 76 @Nonnull private final SparseArray<AnalyzedInstruction> analyzedInstructions = 77 new SparseArray<AnalyzedInstruction>(0); 78 79 // Which instructions have been analyzed, keyed by instruction index 80 @Nonnull private final BitSet analyzedState; 81 82 @Nullable private AnalysisException analysisException = null; 83 84 //This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the 85 //register types for this instruction to the parameter types, in order to have them propagate to all of its 86 //successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first 87 //instruction, etc. 88 private final AnalyzedInstruction startOfMethod; 89 90 public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method, 91 @Nullable InlineMethodResolver inlineResolver) { 92 this.classPath = classPath; 93 this.inlineResolver = inlineResolver; 94 95 this.method = method; 96 97 MethodImplementation methodImpl = method.getImplementation(); 98 if (methodImpl == null) { 99 throw new IllegalArgumentException("The method has no implementation"); 100 } 101 102 this.methodImpl = methodImpl; 103 104 //override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't 105 //have to handle the case this special case of instruction being null, in the main class 106 startOfMethod = new AnalyzedInstruction(null, -1, methodImpl.getRegisterCount()) { 107 public boolean setsRegister() { 108 return false; 109 } 110 111 @Override 112 public boolean setsWideRegister() { 113 return false; 114 } 115 116 @Override 117 public boolean setsRegister(int registerNumber) { 118 return false; 119 } 120 121 @Override 122 public int getDestinationRegister() { 123 assert false; 124 return -1; 125 } 126 }; 127 128 buildInstructionList(); 129 130 analyzedState = new BitSet(analyzedInstructions.size()); 131 paramRegisterCount = MethodUtil.getParameterRegisterCount(method); 132 analyze(); 133 } 134 135 private void analyze() { 136 Method method = this.method; 137 MethodImplementation methodImpl = this.methodImpl; 138 139 int totalRegisters = methodImpl.getRegisterCount(); 140 int parameterRegisters = paramRegisterCount; 141 142 int nonParameterRegisters = totalRegisters - parameterRegisters; 143 144 //if this isn't a static method, determine which register is the "this" register and set the type to the 145 //current class 146 if (!MethodUtil.isStatic(method)) { 147 int thisRegister = totalRegisters - parameterRegisters; 148 149 //if this is a constructor, then set the "this" register to an uninitialized reference of the current class 150 if (MethodUtil.isConstructor(method)) { 151 setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, 152 RegisterType.getRegisterType(RegisterType.UNINIT_THIS, 153 classPath.getClass(method.getDefiningClass()))); 154 } else { 155 setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister, 156 RegisterType.getRegisterType(RegisterType.REFERENCE, 157 classPath.getClass(method.getDefiningClass()))); 158 } 159 160 propagateParameterTypes(totalRegisters-parameterRegisters+1); 161 } else { 162 propagateParameterTypes(totalRegisters-parameterRegisters); 163 } 164 165 RegisterType uninit = RegisterType.getRegisterType(RegisterType.UNINIT, null); 166 for (int i=0; i<nonParameterRegisters; i++) { 167 setPostRegisterTypeAndPropagateChanges(startOfMethod, i, uninit); 168 } 169 170 BitSet instructionsToAnalyze = new BitSet(analyzedInstructions.size()); 171 172 //make sure all of the "first instructions" are marked for processing 173 for (AnalyzedInstruction successor: startOfMethod.successors) { 174 instructionsToAnalyze.set(successor.instructionIndex); 175 } 176 177 BitSet undeodexedInstructions = new BitSet(analyzedInstructions.size()); 178 179 do { 180 boolean didSomething = false; 181 182 while (!instructionsToAnalyze.isEmpty()) { 183 for(int i=instructionsToAnalyze.nextSetBit(0); i>=0; i=instructionsToAnalyze.nextSetBit(i+1)) { 184 instructionsToAnalyze.clear(i); 185 if (analyzedState.get(i)) { 186 continue; 187 } 188 AnalyzedInstruction instructionToAnalyze = analyzedInstructions.valueAt(i); 189 try { 190 if (instructionToAnalyze.originalInstruction.getOpcode().odexOnly()) { 191 //if we had deodexed an odex instruction in a previous pass, we might have more specific 192 //register information now, so let's restore the original odexed instruction and 193 //re-deodex it 194 instructionToAnalyze.restoreOdexedInstruction(); 195 } 196 197 if (!analyzeInstruction(instructionToAnalyze)) { 198 undeodexedInstructions.set(i); 199 continue; 200 } else { 201 didSomething = true; 202 undeodexedInstructions.clear(i); 203 } 204 } catch (AnalysisException ex) { 205 this.analysisException = ex; 206 int codeAddress = getInstructionAddress(instructionToAnalyze); 207 ex.codeAddress = codeAddress; 208 ex.addContext(String.format("opcode: %s", instructionToAnalyze.instruction.getOpcode().name)); 209 ex.addContext(String.format("code address: %d", codeAddress)); 210 ex.addContext(String.format("method: %s", ReferenceUtil.getReferenceString(method))); 211 break; 212 } 213 214 analyzedState.set(instructionToAnalyze.getInstructionIndex()); 215 216 for (AnalyzedInstruction successor: instructionToAnalyze.successors) { 217 instructionsToAnalyze.set(successor.getInstructionIndex()); 218 } 219 } 220 if (analysisException != null) { 221 break; 222 } 223 } 224 225 if (!didSomething) { 226 break; 227 } 228 229 if (!undeodexedInstructions.isEmpty()) { 230 for (int i=undeodexedInstructions.nextSetBit(0); i>=0; i=undeodexedInstructions.nextSetBit(i+1)) { 231 instructionsToAnalyze.set(i); 232 } 233 } 234 } while (true); 235 236 //Now, go through and fix up any unresolvable odex instructions. These are usually odex instructions 237 //that operate on a null register, and thus always throw an NPE. They can also be any sort of odex instruction 238 //that occurs after an unresolvable odex instruction. We deodex if possible, or replace with an 239 //UnresolvableOdexInstruction 240 for (int i=0; i< analyzedInstructions.size(); i++) { 241 AnalyzedInstruction analyzedInstruction = analyzedInstructions.valueAt(i); 242 243 Instruction instruction = analyzedInstruction.getInstruction(); 244 245 if (instruction.getOpcode().odexOnly()) { 246 int objectRegisterNumber; 247 switch (instruction.getOpcode().format) { 248 case Format10x: 249 analyzeReturnVoidBarrier(analyzedInstruction, false); 250 continue; 251 case Format21c: 252 case Format22c: 253 analyzePutGetVolatile(analyzedInstruction, false); 254 continue; 255 case Format35c: 256 analyzeInvokeDirectEmpty(analyzedInstruction, false); 257 continue; 258 case Format3rc: 259 analyzeInvokeObjectInitRange(analyzedInstruction, false); 260 continue; 261 case Format22cs: 262 objectRegisterNumber = ((Instruction22cs)instruction).getRegisterB(); 263 break; 264 case Format35mi: 265 case Format35ms: 266 objectRegisterNumber = ((FiveRegisterInstruction)instruction).getRegisterD(); 267 break; 268 case Format3rmi: 269 case Format3rms: 270 objectRegisterNumber = ((RegisterRangeInstruction)instruction).getStartRegister(); 271 break; 272 default: 273 continue; 274 } 275 276 analyzedInstruction.setDeodexedInstruction( 277 new UnresolvedOdexInstruction(instruction, objectRegisterNumber)); 278 } 279 } 280 } 281 282 private void propagateParameterTypes(int parameterStartRegister) { 283 int i=0; 284 for (MethodParameter parameter: method.getParameters()) { 285 if (TypeUtils.isWideType(parameter)) { 286 setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 287 RegisterType.getWideRegisterType(parameter, true)); 288 setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 289 RegisterType.getWideRegisterType(parameter, false)); 290 } else { 291 setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, 292 RegisterType.getRegisterType(classPath, parameter)); 293 } 294 } 295 } 296 297 public List<AnalyzedInstruction> getAnalyzedInstructions() { 298 return analyzedInstructions.getValues(); 299 } 300 301 @Nullable 302 public AnalysisException getAnalysisException() { 303 return analysisException; 304 } 305 306 public int getParamRegisterCount() { 307 return paramRegisterCount; 308 } 309 310 public int getInstructionAddress(@Nonnull AnalyzedInstruction instruction) { 311 return analyzedInstructions.keyAt(instruction.instructionIndex); 312 } 313 314 private void setDestinationRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, 315 @Nonnull RegisterType registerType) { 316 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, analyzedInstruction.getDestinationRegister(), 317 registerType); 318 } 319 320 private void setPostRegisterTypeAndPropagateChanges(@Nonnull AnalyzedInstruction analyzedInstruction, 321 int registerNumber, @Nonnull RegisterType registerType) { 322 323 BitSet changedInstructions = new BitSet(analyzedInstructions.size()); 324 325 if (!analyzedInstruction.setPostRegisterType(registerNumber, registerType)) { 326 return; 327 } 328 329 propagateRegisterToSuccessors(analyzedInstruction, registerNumber, changedInstructions); 330 331 //Using a for loop inside the while loop optimizes for the common case of the successors of an instruction 332 //occurring after the instruction. Any successors that occur prior to the instruction will be picked up on 333 //the next iteration of the while loop. 334 //This could also be done recursively, but in large methods it would likely cause very deep recursion, 335 //which requires the user to specify a larger stack size. This isn't really a problem, but it is slightly 336 //annoying. 337 while (!changedInstructions.isEmpty()) { 338 for (int instructionIndex=changedInstructions.nextSetBit(0); 339 instructionIndex>=0; 340 instructionIndex=changedInstructions.nextSetBit(instructionIndex+1)) { 341 342 changedInstructions.clear(instructionIndex); 343 344 propagateRegisterToSuccessors(analyzedInstructions.valueAt(instructionIndex), registerNumber, 345 changedInstructions); 346 } 347 } 348 349 if (registerType.category == RegisterType.LONG_LO) { 350 checkWidePair(registerNumber, analyzedInstruction); 351 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.LONG_HI_TYPE); 352 } else if (registerType.category == RegisterType.DOUBLE_LO) { 353 checkWidePair(registerNumber, analyzedInstruction); 354 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, registerNumber+1, RegisterType.DOUBLE_HI_TYPE); 355 } 356 } 357 358 private void propagateRegisterToSuccessors(@Nonnull AnalyzedInstruction instruction, int registerNumber, 359 @Nonnull BitSet changedInstructions) { 360 RegisterType postRegisterType = instruction.getPostInstructionRegisterType(registerNumber); 361 for (AnalyzedInstruction successor: instruction.successors) { 362 if (successor.mergeRegister(registerNumber, postRegisterType, analyzedState)) { 363 changedInstructions.set(successor.instructionIndex); 364 } 365 } 366 } 367 368 private void buildInstructionList() { 369 int registerCount = methodImpl.getRegisterCount(); 370 371 ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions()); 372 373 analyzedInstructions.ensureCapacity(instructions.size()); 374 375 //first, create all the instructions and populate the instructionAddresses array 376 int currentCodeAddress = 0; 377 for (int i=0; i<instructions.size(); i++) { 378 Instruction instruction = instructions.get(i); 379 analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(instruction, i, registerCount)); 380 assert analyzedInstructions.indexOfKey(currentCodeAddress) == i; 381 currentCodeAddress += instruction.getCodeUnits(); 382 } 383 384 //next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception 385 //and is covered by a try block should be set to a list of the first instructions of each exception handler 386 //for the try block covering the instruction 387 List<? extends TryBlock> tries = methodImpl.getTryBlocks(); 388 int triesIndex = 0; 389 TryBlock currentTry = null; 390 AnalyzedInstruction[] currentExceptionHandlers = null; 391 AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][]; 392 393 if (tries != null) { 394 for (int i=0; i< analyzedInstructions.size(); i++) { 395 AnalyzedInstruction instruction = analyzedInstructions.valueAt(i); 396 Opcode instructionOpcode = instruction.instruction.getOpcode(); 397 currentCodeAddress = getInstructionAddress(instruction); 398 399 //check if we have gone past the end of the current try 400 if (currentTry != null) { 401 if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) { 402 currentTry = null; 403 triesIndex++; 404 } 405 } 406 407 //check if the next try is applicable yet 408 if (currentTry == null && triesIndex < tries.size()) { 409 TryBlock tryBlock = tries.get(triesIndex); 410 if (tryBlock.getStartCodeAddress() <= currentCodeAddress) { 411 assert(tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress); 412 413 currentTry = tryBlock; 414 415 currentExceptionHandlers = buildExceptionHandlerArray(tryBlock); 416 } 417 } 418 419 //if we're inside a try block, and the instruction can throw an exception, then add the exception handlers 420 //for the current instruction 421 if (currentTry != null && instructionOpcode.canThrow()) { 422 exceptionHandlers[i] = currentExceptionHandlers; 423 } 424 } 425 } 426 427 //finally, populate the successors and predecessors for each instruction. We start at the fake "StartOfMethod" 428 //instruction and follow the execution path. Any unreachable code won't have any predecessors or successors, 429 //and no reachable code will have an unreachable predessor or successor 430 assert analyzedInstructions.size() > 0; 431 BitSet instructionsToProcess = new BitSet(instructions.size()); 432 433 addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess); 434 while (!instructionsToProcess.isEmpty()) { 435 int currentInstructionIndex = instructionsToProcess.nextSetBit(0); 436 instructionsToProcess.clear(currentInstructionIndex); 437 438 AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex); 439 Opcode instructionOpcode = instruction.instruction.getOpcode(); 440 int instructionCodeAddress = getInstructionAddress(instruction); 441 442 if (instruction.instruction.getOpcode().canContinue()) { 443 if (currentInstructionIndex == analyzedInstructions.size() - 1) { 444 throw new AnalysisException("Execution can continue past the last instruction"); 445 } 446 447 AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex+1); 448 addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess); 449 } 450 451 if (instruction.instruction instanceof OffsetInstruction) { 452 OffsetInstruction offsetInstruction = (OffsetInstruction)instruction.instruction; 453 454 if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) { 455 SwitchPayload switchPayload = (SwitchPayload)analyzedInstructions.get(instructionCodeAddress + 456 offsetInstruction.getCodeOffset()).instruction; 457 for (SwitchElement switchElement: switchPayload.getSwitchElements()) { 458 AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + 459 switchElement.getOffset()); 460 461 addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, 462 instructionsToProcess); 463 } 464 } else if (instructionOpcode != Opcode.FILL_ARRAY_DATA) { 465 int targetAddressOffset = offsetInstruction.getCodeOffset(); 466 AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + 467 targetAddressOffset); 468 addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess); 469 } 470 } 471 } 472 } 473 474 private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, 475 @Nonnull AnalyzedInstruction successor, 476 @Nonnull AnalyzedInstruction[][] exceptionHandlers, 477 @Nonnull BitSet instructionsToProcess) { 478 addPredecessorSuccessor(predecessor, successor, exceptionHandlers, instructionsToProcess, false); 479 } 480 481 private void addPredecessorSuccessor(@Nonnull AnalyzedInstruction predecessor, 482 @Nonnull AnalyzedInstruction successor, 483 @Nonnull AnalyzedInstruction[][] exceptionHandlers, 484 @Nonnull BitSet instructionsToProcess, boolean allowMoveException) { 485 486 if (!allowMoveException && successor.instruction.getOpcode() == Opcode.MOVE_EXCEPTION) { 487 throw new AnalysisException("Execution can pass from the " + predecessor.instruction.getOpcode().name + 488 " instruction at code address 0x" + Integer.toHexString(getInstructionAddress(predecessor)) + 489 " to the move-exception instruction at address 0x" + 490 Integer.toHexString(getInstructionAddress(successor))); 491 } 492 493 if (!successor.addPredecessor(predecessor)) { 494 return; 495 } 496 497 predecessor.addSuccessor(successor); 498 instructionsToProcess.set(successor.getInstructionIndex()); 499 500 501 //if the successor can throw an instruction, then we need to add the exception handlers as additional 502 //successors to the predecessor (and then apply this same logic recursively if needed) 503 //Technically, we should handle the monitor-exit instruction as a special case. The exception is actually 504 //thrown *after* the instruction executes, instead of "before" the instruction executes, lke for any other 505 //instruction. But since it doesn't modify any registers, we can treat it like any other instruction. 506 AnalyzedInstruction[] exceptionHandlersForSuccessor = exceptionHandlers[successor.instructionIndex]; 507 if (exceptionHandlersForSuccessor != null) { 508 //the item for this instruction in exceptionHandlersForSuccessor should only be set if this instruction 509 //can throw an exception 510 assert successor.instruction.getOpcode().canThrow(); 511 512 for (AnalyzedInstruction exceptionHandler: exceptionHandlersForSuccessor) { 513 addPredecessorSuccessor(predecessor, exceptionHandler, exceptionHandlers, instructionsToProcess, true); 514 } 515 } 516 } 517 518 @Nonnull 519 private AnalyzedInstruction[] buildExceptionHandlerArray(@Nonnull TryBlock tryBlock) { 520 List<? extends ExceptionHandler> exceptionHandlers = tryBlock.getExceptionHandlers(); 521 522 AnalyzedInstruction[] handlerInstructions = new AnalyzedInstruction[exceptionHandlers.size()]; 523 for (int i=0; i<exceptionHandlers.size(); i++) { 524 handlerInstructions[i] = analyzedInstructions.get(exceptionHandlers.get(i).getHandlerCodeAddress()); 525 } 526 527 return handlerInstructions; 528 } 529 530 /** 531 * @return false if analyzedInstruction is an odex instruction that couldn't be deodexed, due to its 532 * object register being null 533 */ 534 private boolean analyzeInstruction(@Nonnull AnalyzedInstruction analyzedInstruction) { 535 Instruction instruction = analyzedInstruction.instruction; 536 537 switch (instruction.getOpcode()) { 538 case NOP: 539 return true; 540 case MOVE: 541 case MOVE_FROM16: 542 case MOVE_16: 543 case MOVE_WIDE: 544 case MOVE_WIDE_FROM16: 545 case MOVE_WIDE_16: 546 case MOVE_OBJECT: 547 case MOVE_OBJECT_FROM16: 548 case MOVE_OBJECT_16: 549 analyzeMove(analyzedInstruction); 550 return true; 551 case MOVE_RESULT: 552 case MOVE_RESULT_WIDE: 553 case MOVE_RESULT_OBJECT: 554 analyzeMoveResult(analyzedInstruction); 555 return true; 556 case MOVE_EXCEPTION: 557 analyzeMoveException(analyzedInstruction); 558 return true; 559 case RETURN_VOID: 560 case RETURN: 561 case RETURN_WIDE: 562 case RETURN_OBJECT: 563 return true; 564 case RETURN_VOID_BARRIER: 565 analyzeReturnVoidBarrier(analyzedInstruction); 566 return true; 567 case CONST_4: 568 case CONST_16: 569 case CONST: 570 case CONST_HIGH16: 571 analyzeConst(analyzedInstruction); 572 return true; 573 case CONST_WIDE_16: 574 case CONST_WIDE_32: 575 case CONST_WIDE: 576 case CONST_WIDE_HIGH16: 577 analyzeWideConst(analyzedInstruction); 578 return true; 579 case CONST_STRING: 580 case CONST_STRING_JUMBO: 581 analyzeConstString(analyzedInstruction); 582 return true; 583 case CONST_CLASS: 584 analyzeConstClass(analyzedInstruction); 585 return true; 586 case MONITOR_ENTER: 587 case MONITOR_EXIT: 588 return true; 589 case CHECK_CAST: 590 analyzeCheckCast(analyzedInstruction); 591 return true; 592 case INSTANCE_OF: 593 analyzeInstanceOf(analyzedInstruction); 594 return true; 595 case ARRAY_LENGTH: 596 analyzeArrayLength(analyzedInstruction); 597 return true; 598 case NEW_INSTANCE: 599 analyzeNewInstance(analyzedInstruction); 600 return true; 601 case NEW_ARRAY: 602 analyzeNewArray(analyzedInstruction); 603 return true; 604 case FILLED_NEW_ARRAY: 605 case FILLED_NEW_ARRAY_RANGE: 606 return true; 607 case FILL_ARRAY_DATA: 608 return true; 609 case THROW: 610 case GOTO: 611 case GOTO_16: 612 case GOTO_32: 613 return true; 614 case PACKED_SWITCH: 615 case SPARSE_SWITCH: 616 return true; 617 case CMPL_FLOAT: 618 case CMPG_FLOAT: 619 case CMPL_DOUBLE: 620 case CMPG_DOUBLE: 621 case CMP_LONG: 622 analyzeFloatWideCmp(analyzedInstruction); 623 return true; 624 case IF_EQ: 625 case IF_NE: 626 case IF_LT: 627 case IF_GE: 628 case IF_GT: 629 case IF_LE: 630 case IF_EQZ: 631 case IF_NEZ: 632 case IF_LTZ: 633 case IF_GEZ: 634 case IF_GTZ: 635 case IF_LEZ: 636 return true; 637 case AGET: 638 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.INTEGER_TYPE); 639 return true; 640 case AGET_BOOLEAN: 641 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 642 return true; 643 case AGET_BYTE: 644 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.BYTE_TYPE); 645 return true; 646 case AGET_CHAR: 647 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.CHAR_TYPE); 648 return true; 649 case AGET_SHORT: 650 analyze32BitPrimitiveAget(analyzedInstruction, RegisterType.SHORT_TYPE); 651 return true; 652 case AGET_WIDE: 653 analyzeAgetWide(analyzedInstruction); 654 return true; 655 case AGET_OBJECT: 656 analyzeAgetObject(analyzedInstruction); 657 return true; 658 case APUT: 659 case APUT_BOOLEAN: 660 case APUT_BYTE: 661 case APUT_CHAR: 662 case APUT_SHORT: 663 case APUT_WIDE: 664 case APUT_OBJECT: 665 return true; 666 case IGET: 667 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE); 668 return true; 669 case IGET_BOOLEAN: 670 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 671 return true; 672 case IGET_BYTE: 673 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE); 674 return true; 675 case IGET_CHAR: 676 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE); 677 return true; 678 case IGET_SHORT: 679 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE); 680 return true; 681 case IGET_WIDE: 682 case IGET_OBJECT: 683 analyzeIgetSgetWideObject(analyzedInstruction); 684 return true; 685 case IPUT: 686 case IPUT_BOOLEAN: 687 case IPUT_BYTE: 688 case IPUT_CHAR: 689 case IPUT_SHORT: 690 case IPUT_WIDE: 691 case IPUT_OBJECT: 692 return true; 693 case SGET: 694 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.INTEGER_TYPE); 695 return true; 696 case SGET_BOOLEAN: 697 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 698 return true; 699 case SGET_BYTE: 700 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.BYTE_TYPE); 701 return true; 702 case SGET_CHAR: 703 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.CHAR_TYPE); 704 return true; 705 case SGET_SHORT: 706 analyze32BitPrimitiveIgetSget(analyzedInstruction, RegisterType.SHORT_TYPE); 707 return true; 708 case SGET_WIDE: 709 case SGET_OBJECT: 710 analyzeIgetSgetWideObject(analyzedInstruction); 711 return true; 712 case SPUT: 713 case SPUT_BOOLEAN: 714 case SPUT_BYTE: 715 case SPUT_CHAR: 716 case SPUT_SHORT: 717 case SPUT_WIDE: 718 case SPUT_OBJECT: 719 return true; 720 case INVOKE_VIRTUAL: 721 case INVOKE_SUPER: 722 return true; 723 case INVOKE_DIRECT: 724 analyzeInvokeDirect(analyzedInstruction); 725 return true; 726 case INVOKE_STATIC: 727 case INVOKE_INTERFACE: 728 case INVOKE_VIRTUAL_RANGE: 729 case INVOKE_SUPER_RANGE: 730 return true; 731 case INVOKE_DIRECT_RANGE: 732 analyzeInvokeDirectRange(analyzedInstruction); 733 return true; 734 case INVOKE_STATIC_RANGE: 735 case INVOKE_INTERFACE_RANGE: 736 return true; 737 case NEG_INT: 738 case NOT_INT: 739 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 740 return true; 741 case NEG_LONG: 742 case NOT_LONG: 743 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 744 return true; 745 case NEG_FLOAT: 746 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 747 return true; 748 case NEG_DOUBLE: 749 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 750 return true; 751 case INT_TO_LONG: 752 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 753 return true; 754 case INT_TO_FLOAT: 755 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 756 return true; 757 case INT_TO_DOUBLE: 758 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 759 return true; 760 case LONG_TO_INT: 761 case DOUBLE_TO_INT: 762 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 763 return true; 764 case LONG_TO_FLOAT: 765 case DOUBLE_TO_FLOAT: 766 analyzeUnaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE); 767 return true; 768 case LONG_TO_DOUBLE: 769 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 770 return true; 771 case FLOAT_TO_INT: 772 analyzeUnaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE); 773 return true; 774 case FLOAT_TO_LONG: 775 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 776 return true; 777 case FLOAT_TO_DOUBLE: 778 analyzeUnaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 779 return true; 780 case DOUBLE_TO_LONG: 781 analyzeUnaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE); 782 return true; 783 case INT_TO_BYTE: 784 analyzeUnaryOp(analyzedInstruction, RegisterType.BYTE_TYPE); 785 return true; 786 case INT_TO_CHAR: 787 analyzeUnaryOp(analyzedInstruction, RegisterType.CHAR_TYPE); 788 return true; 789 case INT_TO_SHORT: 790 analyzeUnaryOp(analyzedInstruction, RegisterType.SHORT_TYPE); 791 return true; 792 case ADD_INT: 793 case SUB_INT: 794 case MUL_INT: 795 case DIV_INT: 796 case REM_INT: 797 case SHL_INT: 798 case SHR_INT: 799 case USHR_INT: 800 analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 801 return true; 802 case AND_INT: 803 case OR_INT: 804 case XOR_INT: 805 analyzeBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 806 return true; 807 case ADD_LONG: 808 case SUB_LONG: 809 case MUL_LONG: 810 case DIV_LONG: 811 case REM_LONG: 812 case AND_LONG: 813 case OR_LONG: 814 case XOR_LONG: 815 case SHL_LONG: 816 case SHR_LONG: 817 case USHR_LONG: 818 analyzeBinaryOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false); 819 return true; 820 case ADD_FLOAT: 821 case SUB_FLOAT: 822 case MUL_FLOAT: 823 case DIV_FLOAT: 824 case REM_FLOAT: 825 analyzeBinaryOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false); 826 return true; 827 case ADD_DOUBLE: 828 case SUB_DOUBLE: 829 case MUL_DOUBLE: 830 case DIV_DOUBLE: 831 case REM_DOUBLE: 832 analyzeBinaryOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false); 833 return true; 834 case ADD_INT_2ADDR: 835 case SUB_INT_2ADDR: 836 case MUL_INT_2ADDR: 837 case DIV_INT_2ADDR: 838 case REM_INT_2ADDR: 839 case SHL_INT_2ADDR: 840 case SHR_INT_2ADDR: 841 case USHR_INT_2ADDR: 842 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 843 return true; 844 case AND_INT_2ADDR: 845 case OR_INT_2ADDR: 846 case XOR_INT_2ADDR: 847 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 848 return true; 849 case ADD_LONG_2ADDR: 850 case SUB_LONG_2ADDR: 851 case MUL_LONG_2ADDR: 852 case DIV_LONG_2ADDR: 853 case REM_LONG_2ADDR: 854 case AND_LONG_2ADDR: 855 case OR_LONG_2ADDR: 856 case XOR_LONG_2ADDR: 857 case SHL_LONG_2ADDR: 858 case SHR_LONG_2ADDR: 859 case USHR_LONG_2ADDR: 860 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.LONG_LO_TYPE, false); 861 return true; 862 case ADD_FLOAT_2ADDR: 863 case SUB_FLOAT_2ADDR: 864 case MUL_FLOAT_2ADDR: 865 case DIV_FLOAT_2ADDR: 866 case REM_FLOAT_2ADDR: 867 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.FLOAT_TYPE, false); 868 return true; 869 case ADD_DOUBLE_2ADDR: 870 case SUB_DOUBLE_2ADDR: 871 case MUL_DOUBLE_2ADDR: 872 case DIV_DOUBLE_2ADDR: 873 case REM_DOUBLE_2ADDR: 874 analyzeBinary2AddrOp(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE, false); 875 return true; 876 case ADD_INT_LIT16: 877 case RSUB_INT: 878 case MUL_INT_LIT16: 879 case DIV_INT_LIT16: 880 case REM_INT_LIT16: 881 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 882 return true; 883 case AND_INT_LIT16: 884 case OR_INT_LIT16: 885 case XOR_INT_LIT16: 886 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 887 return true; 888 case ADD_INT_LIT8: 889 case RSUB_INT_LIT8: 890 case MUL_INT_LIT8: 891 case DIV_INT_LIT8: 892 case REM_INT_LIT8: 893 case SHL_INT_LIT8: 894 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, false); 895 return true; 896 case AND_INT_LIT8: 897 case OR_INT_LIT8: 898 case XOR_INT_LIT8: 899 analyzeLiteralBinaryOp(analyzedInstruction, RegisterType.INTEGER_TYPE, true); 900 return true; 901 case SHR_INT_LIT8: 902 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, true), 903 false); 904 return true; 905 case USHR_INT_LIT8: 906 analyzeLiteralBinaryOp(analyzedInstruction, getDestTypeForLiteralShiftRight(analyzedInstruction, false), 907 false); 908 return true; 909 910 /*odexed instructions*/ 911 case IGET_VOLATILE: 912 case IPUT_VOLATILE: 913 case SGET_VOLATILE: 914 case SPUT_VOLATILE: 915 case IGET_OBJECT_VOLATILE: 916 case IGET_WIDE_VOLATILE: 917 case IPUT_WIDE_VOLATILE: 918 case SGET_WIDE_VOLATILE: 919 case SPUT_WIDE_VOLATILE: 920 analyzePutGetVolatile(analyzedInstruction); 921 return true; 922 case THROW_VERIFICATION_ERROR: 923 return true; 924 case EXECUTE_INLINE: 925 analyzeExecuteInline(analyzedInstruction); 926 return true; 927 case EXECUTE_INLINE_RANGE: 928 analyzeExecuteInlineRange(analyzedInstruction); 929 return true; 930 case INVOKE_DIRECT_EMPTY: 931 analyzeInvokeDirectEmpty(analyzedInstruction); 932 return true; 933 case INVOKE_OBJECT_INIT_RANGE: 934 analyzeInvokeObjectInitRange(analyzedInstruction); 935 return true; 936 case IGET_QUICK: 937 case IGET_WIDE_QUICK: 938 case IGET_OBJECT_QUICK: 939 case IPUT_QUICK: 940 case IPUT_WIDE_QUICK: 941 case IPUT_OBJECT_QUICK: 942 return analyzeIputIgetQuick(analyzedInstruction); 943 case INVOKE_VIRTUAL_QUICK: 944 return analyzeInvokeVirtualQuick(analyzedInstruction, false, false); 945 case INVOKE_SUPER_QUICK: 946 return analyzeInvokeVirtualQuick(analyzedInstruction, true, false); 947 case INVOKE_VIRTUAL_QUICK_RANGE: 948 return analyzeInvokeVirtualQuick(analyzedInstruction, false, true); 949 case INVOKE_SUPER_QUICK_RANGE: 950 return analyzeInvokeVirtualQuick(analyzedInstruction, true, true); 951 case IPUT_OBJECT_VOLATILE: 952 case SGET_OBJECT_VOLATILE: 953 case SPUT_OBJECT_VOLATILE: 954 analyzePutGetVolatile(analyzedInstruction); 955 return true; 956 default: 957 assert false; 958 return true; 959 } 960 } 961 962 private static final BitSet Primitive32BitCategories = BitSetUtils.bitSetOfIndexes( 963 RegisterType.NULL, 964 RegisterType.ONE, 965 RegisterType.BOOLEAN, 966 RegisterType.BYTE, 967 RegisterType.POS_BYTE, 968 RegisterType.SHORT, 969 RegisterType.POS_SHORT, 970 RegisterType.CHAR, 971 RegisterType.INTEGER, 972 RegisterType.FLOAT); 973 974 private static final BitSet WideLowCategories = BitSetUtils.bitSetOfIndexes( 975 RegisterType.LONG_LO, 976 RegisterType.DOUBLE_LO); 977 978 private static final BitSet WideHighCategories = BitSetUtils.bitSetOfIndexes( 979 RegisterType.LONG_HI, 980 RegisterType.DOUBLE_HI); 981 982 private static final BitSet ReferenceOrUninitCategories = BitSetUtils.bitSetOfIndexes( 983 RegisterType.NULL, 984 RegisterType.UNINIT_REF, 985 RegisterType.UNINIT_THIS, 986 RegisterType.REFERENCE); 987 988 private static final BitSet BooleanCategories = BitSetUtils.bitSetOfIndexes( 989 RegisterType.NULL, 990 RegisterType.ONE, 991 RegisterType.BOOLEAN); 992 993 private void analyzeMove(@Nonnull AnalyzedInstruction analyzedInstruction) { 994 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 995 996 RegisterType sourceRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 997 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, sourceRegisterType); 998 } 999 1000 private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) { 1001 AnalyzedInstruction previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex-1); 1002 if (!previousInstruction.instruction.getOpcode().setsResult()) { 1003 throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + 1004 "invoke-*/fill-new-array instruction"); 1005 } 1006 1007 RegisterType resultRegisterType; 1008 ReferenceInstruction invokeInstruction = (ReferenceInstruction)previousInstruction.instruction; 1009 Reference reference = invokeInstruction.getReference(); 1010 1011 if (reference instanceof MethodReference) { 1012 resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference)reference).getReturnType()); 1013 } else { 1014 resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference)reference); 1015 } 1016 1017 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType); 1018 } 1019 1020 private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { 1021 int instructionAddress = getInstructionAddress(analyzedInstruction); 1022 1023 RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; 1024 1025 for (TryBlock tryBlock: methodImpl.getTryBlocks()) { 1026 for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { 1027 1028 if (handler.getHandlerCodeAddress() == instructionAddress) { 1029 String type = handler.getExceptionType(); 1030 if (type == null) { 1031 exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, 1032 classPath.getClass("Ljava/lang/Throwable;")); 1033 } else { 1034 exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) 1035 .merge(exceptionType); 1036 } 1037 } 1038 } 1039 } 1040 1041 if (exceptionType.category == RegisterType.UNKNOWN) { 1042 throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); 1043 } 1044 1045 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); 1046 } 1047 1048 private void analyzeReturnVoidBarrier(AnalyzedInstruction analyzedInstruction) { 1049 analyzeReturnVoidBarrier(analyzedInstruction, true); 1050 } 1051 1052 private void analyzeReturnVoidBarrier(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1053 Instruction10x deodexedInstruction = new ImmutableInstruction10x(Opcode.RETURN_VOID); 1054 1055 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1056 1057 if (analyzeResult) { 1058 analyzeInstruction(analyzedInstruction); 1059 } 1060 } 1061 1062 private void analyzeConst(@Nonnull AnalyzedInstruction analyzedInstruction) { 1063 NarrowLiteralInstruction instruction = (NarrowLiteralInstruction)analyzedInstruction.instruction; 1064 1065 //we assume that the literal value is a valid value for the given instruction type, because it's impossible 1066 //to store an invalid literal with the instruction. so we don't need to check the type of the literal 1067 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1068 RegisterType.getRegisterTypeForLiteral(instruction.getNarrowLiteral())); 1069 } 1070 1071 private void analyzeWideConst(@Nonnull AnalyzedInstruction analyzedInstruction) { 1072 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1073 } 1074 1075 private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { 1076 TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); 1077 RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); 1078 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); 1079 } 1080 1081 private void analyzeConstClass(@Nonnull AnalyzedInstruction analyzedInstruction) { 1082 TypeProto classClass = classPath.getClass("Ljava/lang/Class;"); 1083 RegisterType classType = RegisterType.getRegisterType(RegisterType.REFERENCE, classClass); 1084 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, classType); 1085 } 1086 1087 private void analyzeCheckCast(@Nonnull AnalyzedInstruction analyzedInstruction) { 1088 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1089 TypeReference reference = (TypeReference)instruction.getReference(); 1090 RegisterType castRegisterType = RegisterType.getRegisterType(classPath, reference); 1091 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType); 1092 } 1093 1094 private void analyzeInstanceOf(@Nonnull AnalyzedInstruction analyzedInstruction) { 1095 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BOOLEAN_TYPE); 1096 } 1097 1098 private void analyzeArrayLength(@Nonnull AnalyzedInstruction analyzedInstruction) { 1099 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.INTEGER_TYPE); 1100 } 1101 1102 private void analyzeNewInstance(@Nonnull AnalyzedInstruction analyzedInstruction) { 1103 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1104 1105 int register = ((OneRegisterInstruction)analyzedInstruction.instruction).getRegisterA(); 1106 RegisterType destRegisterType = analyzedInstruction.getPostInstructionRegisterType(register); 1107 if (destRegisterType.category != RegisterType.UNKNOWN) { 1108 //the post-instruction destination register will only be set if we have already analyzed this instruction 1109 //at least once. If this is the case, then the uninit reference has already been propagated to all 1110 //successors and nothing else needs to be done. 1111 assert destRegisterType.category == RegisterType.UNINIT_REF; 1112 return; 1113 } 1114 1115 TypeReference typeReference = (TypeReference)instruction.getReference(); 1116 1117 RegisterType classType = RegisterType.getRegisterType(classPath, typeReference); 1118 1119 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1120 RegisterType.getRegisterType(RegisterType.UNINIT_REF, classType.type)); 1121 } 1122 1123 private void analyzeNewArray(@Nonnull AnalyzedInstruction analyzedInstruction) { 1124 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1125 1126 TypeReference type = (TypeReference)instruction.getReference(); 1127 if (type.getType().charAt(0) != '[') { 1128 throw new AnalysisException("new-array used with non-array type"); 1129 } 1130 1131 RegisterType arrayType = RegisterType.getRegisterType(classPath, type); 1132 1133 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, arrayType); 1134 } 1135 1136 private void analyzeFloatWideCmp(@Nonnull AnalyzedInstruction analyzedInstruction) { 1137 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.BYTE_TYPE); 1138 } 1139 1140 private void analyze32BitPrimitiveAget(@Nonnull AnalyzedInstruction analyzedInstruction, 1141 @Nonnull RegisterType registerType) { 1142 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); 1143 } 1144 1145 private void analyzeAgetWide(@Nonnull AnalyzedInstruction analyzedInstruction) { 1146 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1147 1148 RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1149 if (arrayRegisterType.category != RegisterType.NULL) { 1150 if (arrayRegisterType.category != RegisterType.REFERENCE || 1151 !(arrayRegisterType.type instanceof ArrayProto)) { 1152 throw new AnalysisException("aget-wide used with non-array register: %s", arrayRegisterType.toString()); 1153 } 1154 ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; 1155 1156 if (arrayProto.dimensions != 1) { 1157 throw new AnalysisException("aget-wide used with multi-dimensional array: %s", 1158 arrayRegisterType.toString()); 1159 } 1160 1161 char arrayBaseType = arrayProto.getElementType().charAt(0); 1162 if (arrayBaseType == 'J') { 1163 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1164 } else if (arrayBaseType == 'D') { 1165 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); 1166 } else { 1167 throw new AnalysisException("aget-wide used with narrow array: %s", arrayRegisterType); 1168 } 1169 } else { 1170 // If the array register is null, we can assume that the destination register was meant to be a wide type. 1171 // This is the same behavior as dalvik's verifier 1172 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); 1173 } 1174 } 1175 1176 private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { 1177 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1178 1179 RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1180 if (arrayRegisterType.category != RegisterType.NULL) { 1181 if (arrayRegisterType.category != RegisterType.REFERENCE || 1182 !(arrayRegisterType.type instanceof ArrayProto)) { 1183 throw new AnalysisException("aget-object used with non-array register: %s", 1184 arrayRegisterType.toString()); 1185 } 1186 1187 ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; 1188 1189 String elementType = arrayProto.getImmediateElementType(); 1190 1191 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, 1192 RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); 1193 } else { 1194 // If the array register is null, we can assume that the destination register was meant to be a reference 1195 // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier 1196 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); 1197 } 1198 } 1199 1200 private void analyze32BitPrimitiveIgetSget(@Nonnull AnalyzedInstruction analyzedInstruction, 1201 @Nonnull RegisterType registerType) { 1202 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, registerType); 1203 } 1204 1205 private void analyzeIgetSgetWideObject(@Nonnull AnalyzedInstruction analyzedInstruction) { 1206 ReferenceInstruction referenceInstruction = (ReferenceInstruction)analyzedInstruction.instruction; 1207 1208 FieldReference fieldReference = (FieldReference)referenceInstruction.getReference(); 1209 1210 RegisterType fieldType = RegisterType.getRegisterType(classPath, fieldReference.getType()); 1211 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, fieldType); 1212 } 1213 1214 private void analyzeInvokeDirect(@Nonnull AnalyzedInstruction analyzedInstruction) { 1215 FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction; 1216 analyzeInvokeDirectCommon(analyzedInstruction, instruction.getRegisterC()); 1217 } 1218 1219 private void analyzeInvokeDirectRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1220 RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction; 1221 analyzeInvokeDirectCommon(analyzedInstruction, instruction.getStartRegister()); 1222 } 1223 1224 private void analyzeInvokeDirectCommon(@Nonnull AnalyzedInstruction analyzedInstruction, int objectRegister) { 1225 //the only time that an invoke instruction changes a register type is when using invoke-direct on a 1226 //constructor (<init>) method, which changes the uninitialized reference (and any register that the same 1227 //uninit reference has been copied to) to an initialized reference 1228 1229 ReferenceInstruction instruction = (ReferenceInstruction)analyzedInstruction.instruction; 1230 1231 MethodReference methodReference = (MethodReference)instruction.getReference(); 1232 1233 if (!methodReference.getName().equals("<init>")) { 1234 return; 1235 } 1236 1237 RegisterType objectRegisterType = analyzedInstruction.getPreInstructionRegisterType(objectRegister); 1238 1239 if (objectRegisterType.category != RegisterType.UNINIT_REF && 1240 objectRegisterType.category != RegisterType.UNINIT_THIS) { 1241 return; 1242 } 1243 1244 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, objectRegister, 1245 RegisterType.getRegisterType(RegisterType.REFERENCE, objectRegisterType.type)); 1246 1247 for (int i=0; i<analyzedInstruction.postRegisterMap.length; i++) { 1248 RegisterType postInstructionRegisterType = analyzedInstruction.postRegisterMap[i]; 1249 if (postInstructionRegisterType.category == RegisterType.UNKNOWN) { 1250 RegisterType preInstructionRegisterType = 1251 analyzedInstruction.getPreInstructionRegisterType(i); 1252 1253 if (preInstructionRegisterType.category == RegisterType.UNINIT_REF || 1254 preInstructionRegisterType.category == RegisterType.UNINIT_THIS) { 1255 RegisterType registerType; 1256 if (preInstructionRegisterType == objectRegisterType) { 1257 registerType = analyzedInstruction.postRegisterMap[objectRegister]; 1258 } else { 1259 registerType = preInstructionRegisterType; 1260 } 1261 1262 setPostRegisterTypeAndPropagateChanges(analyzedInstruction, i, registerType); 1263 } 1264 } 1265 } 1266 } 1267 1268 private void analyzeUnaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1269 @Nonnull RegisterType destRegisterType) { 1270 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1271 } 1272 1273 private void analyzeBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1274 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1275 if (checkForBoolean) { 1276 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 1277 1278 RegisterType source1RegisterType = 1279 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1280 RegisterType source2RegisterType = 1281 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterC()); 1282 1283 if (BooleanCategories.get(source1RegisterType.category) && 1284 BooleanCategories.get(source2RegisterType.category)) { 1285 destRegisterType = RegisterType.BOOLEAN_TYPE; 1286 } 1287 } 1288 1289 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1290 } 1291 1292 private void analyzeBinary2AddrOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1293 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1294 if (checkForBoolean) { 1295 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1296 1297 RegisterType source1RegisterType = 1298 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterA()); 1299 RegisterType source2RegisterType = 1300 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1301 1302 if (BooleanCategories.get(source1RegisterType.category) && 1303 BooleanCategories.get(source2RegisterType.category)) { 1304 destRegisterType = RegisterType.BOOLEAN_TYPE; 1305 } 1306 } 1307 1308 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1309 } 1310 1311 private void analyzeLiteralBinaryOp(@Nonnull AnalyzedInstruction analyzedInstruction, 1312 @Nonnull RegisterType destRegisterType, boolean checkForBoolean) { 1313 if (checkForBoolean) { 1314 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1315 1316 RegisterType sourceRegisterType = 1317 analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); 1318 1319 if (BooleanCategories.get(sourceRegisterType.category)) { 1320 int literal = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); 1321 if (literal == 0 || literal == 1) { 1322 destRegisterType = RegisterType.BOOLEAN_TYPE; 1323 } 1324 } 1325 } 1326 1327 setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, destRegisterType); 1328 } 1329 1330 private RegisterType getDestTypeForLiteralShiftRight(@Nonnull AnalyzedInstruction analyzedInstruction, boolean signedShift) { 1331 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1332 1333 RegisterType sourceRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), 1334 Primitive32BitCategories); 1335 long literalShift = ((NarrowLiteralInstruction)analyzedInstruction.instruction).getNarrowLiteral(); 1336 1337 if (literalShift == 0) { 1338 return sourceRegisterType; 1339 } 1340 1341 RegisterType destRegisterType; 1342 if (!signedShift) { 1343 destRegisterType = RegisterType.INTEGER_TYPE; 1344 } else { 1345 destRegisterType = sourceRegisterType; 1346 } 1347 1348 literalShift = literalShift & 0x1f; 1349 1350 switch (sourceRegisterType.category) { 1351 case RegisterType.INTEGER: 1352 case RegisterType.FLOAT: 1353 if (!signedShift) { 1354 if (literalShift > 24) { 1355 return RegisterType.POS_BYTE_TYPE; 1356 } 1357 if (literalShift >= 16) { 1358 return RegisterType.CHAR_TYPE; 1359 } 1360 } else { 1361 if (literalShift >= 24) { 1362 return RegisterType.BYTE_TYPE; 1363 } 1364 if (literalShift >= 16) { 1365 return RegisterType.SHORT_TYPE; 1366 } 1367 } 1368 break; 1369 case RegisterType.SHORT: 1370 if (signedShift && literalShift >= 8) { 1371 return RegisterType.BYTE_TYPE; 1372 } 1373 break; 1374 case RegisterType.POS_SHORT: 1375 if (literalShift >= 8) { 1376 return RegisterType.POS_BYTE_TYPE; 1377 } 1378 break; 1379 case RegisterType.CHAR: 1380 if (literalShift > 8) { 1381 return RegisterType.POS_BYTE_TYPE; 1382 } 1383 break; 1384 case RegisterType.BYTE: 1385 break; 1386 case RegisterType.POS_BYTE: 1387 return RegisterType.POS_BYTE_TYPE; 1388 case RegisterType.NULL: 1389 case RegisterType.ONE: 1390 case RegisterType.BOOLEAN: 1391 return RegisterType.NULL_TYPE; 1392 default: 1393 assert false; 1394 } 1395 1396 return destRegisterType; 1397 } 1398 1399 1400 private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { 1401 if (inlineResolver == null) { 1402 throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); 1403 } 1404 1405 Instruction35mi instruction = (Instruction35mi)analyzedInstruction.instruction; 1406 Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); 1407 1408 Opcode deodexedOpcode; 1409 switch (resolvedMethod.getAccessFlags()) { 1410 case InlineMethodResolver.DIRECT: 1411 deodexedOpcode = Opcode.INVOKE_DIRECT; 1412 break; 1413 case InlineMethodResolver.STATIC: 1414 deodexedOpcode = Opcode.INVOKE_STATIC; 1415 break; 1416 case InlineMethodResolver.VIRTUAL: 1417 deodexedOpcode = Opcode.INVOKE_VIRTUAL; 1418 break; 1419 default: 1420 throw new ExceptionWithContext("Unexpected access flags on resolved inline method: %d, %s", 1421 resolvedMethod.getAccessFlags(), ReferenceUtil.getReferenceString(resolvedMethod)); 1422 } 1423 1424 Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(), 1425 instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), 1426 instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); 1427 1428 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1429 analyzeInstruction(analyzedInstruction); 1430 } 1431 1432 private void analyzeExecuteInlineRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1433 if (inlineResolver == null) { 1434 throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing"); 1435 } 1436 1437 Instruction3rmi instruction = (Instruction3rmi)analyzedInstruction.instruction; 1438 Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction); 1439 1440 Opcode deodexedOpcode = null; 1441 switch (resolvedMethod.getAccessFlags()) { 1442 case InlineMethodResolver.DIRECT: 1443 deodexedOpcode = Opcode.INVOKE_DIRECT_RANGE; 1444 break; 1445 case InlineMethodResolver.STATIC: 1446 deodexedOpcode = Opcode.INVOKE_STATIC_RANGE; 1447 break; 1448 case InlineMethodResolver.VIRTUAL: 1449 deodexedOpcode = Opcode.INVOKE_VIRTUAL_RANGE; 1450 break; 1451 default: 1452 assert false; 1453 } 1454 1455 Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(deodexedOpcode, instruction.getRegisterCount(), 1456 instruction.getStartRegister(), resolvedMethod); 1457 1458 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1459 analyzeInstruction(analyzedInstruction); 1460 } 1461 1462 private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction) { 1463 analyzeInvokeDirectEmpty(analyzedInstruction, true); 1464 } 1465 1466 private void analyzeInvokeDirectEmpty(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1467 Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction; 1468 1469 Instruction35c deodexedInstruction = new ImmutableInstruction35c(Opcode.INVOKE_DIRECT, 1470 instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), 1471 instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), 1472 instruction.getReference()); 1473 1474 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1475 1476 if (analyzeResult) { 1477 analyzeInstruction(analyzedInstruction); 1478 } 1479 } 1480 1481 private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction) { 1482 analyzeInvokeObjectInitRange(analyzedInstruction, true); 1483 } 1484 1485 private void analyzeInvokeObjectInitRange(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1486 Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction; 1487 1488 Instruction3rc deodexedInstruction = new ImmutableInstruction3rc(Opcode.INVOKE_DIRECT_RANGE, 1489 instruction.getRegisterCount(), instruction.getStartRegister(), instruction.getReference()); 1490 1491 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1492 1493 if (analyzeResult) { 1494 analyzeInstruction(analyzedInstruction); 1495 } 1496 } 1497 1498 private boolean analyzeIputIgetQuick(@Nonnull AnalyzedInstruction analyzedInstruction) { 1499 Instruction22cs instruction = (Instruction22cs)analyzedInstruction.instruction; 1500 1501 int fieldOffset = instruction.getFieldOffset(); 1502 RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, instruction.getRegisterB(), 1503 ReferenceOrUninitCategories); 1504 1505 if (objectRegisterType.category == RegisterType.NULL) { 1506 return false; 1507 } 1508 1509 TypeProto registerTypeProto = objectRegisterType.type; 1510 assert registerTypeProto != null; 1511 1512 TypeProto classTypeProto = classPath.getClass(registerTypeProto.getType()); 1513 FieldReference field = classTypeProto.getFieldByOffset(fieldOffset); 1514 1515 if (field == null) { 1516 throw new AnalysisException("Could not resolve the field in class %s at offset %d", 1517 objectRegisterType.type.getType(), fieldOffset); 1518 } 1519 1520 String fieldType = field.getType(); 1521 1522 Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, 1523 instruction.getOpcode()); 1524 1525 Instruction22c deodexedInstruction = new ImmutableInstruction22c(opcode, (byte)instruction.getRegisterA(), 1526 (byte)instruction.getRegisterB(), field); 1527 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1528 1529 analyzeInstruction(analyzedInstruction); 1530 1531 return true; 1532 } 1533 1534 private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper, 1535 boolean isRange) { 1536 int methodIndex; 1537 int objectRegister; 1538 1539 if (isRange) { 1540 Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; 1541 methodIndex = instruction.getVtableIndex(); 1542 objectRegister = instruction.getStartRegister(); 1543 } else { 1544 Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; 1545 methodIndex = instruction.getVtableIndex(); 1546 objectRegister = instruction.getRegisterD(); 1547 } 1548 1549 RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister, 1550 ReferenceOrUninitCategories); 1551 TypeProto objectRegisterTypeProto = objectRegisterType.type; 1552 assert objectRegisterTypeProto != null; 1553 1554 if (objectRegisterType.category == RegisterType.NULL) { 1555 return false; 1556 } 1557 1558 MethodReference resolvedMethod; 1559 if (isSuper) { 1560 // invoke-super is only used for the same class that we're currently in 1561 TypeProto typeProto = classPath.getClass(method.getDefiningClass()); 1562 TypeProto superType; 1563 1564 String superclassType = typeProto.getSuperclass(); 1565 if (superclassType != null) { 1566 superType = classPath.getClass(superclassType); 1567 } else { 1568 // This is either java.lang.Object, or an UnknownClassProto 1569 superType = typeProto; 1570 } 1571 1572 resolvedMethod = superType.getMethodByVtableIndex(methodIndex); 1573 } else{ 1574 resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex); 1575 } 1576 1577 if (resolvedMethod == null) { 1578 throw new AnalysisException("Could not resolve the method in class %s at index %d", 1579 objectRegisterType.type.getType(), methodIndex); 1580 } 1581 1582 Instruction deodexedInstruction; 1583 if (isRange) { 1584 Instruction3rms instruction = (Instruction3rms)analyzedInstruction.instruction; 1585 Opcode opcode; 1586 if (isSuper) { 1587 opcode = Opcode.INVOKE_SUPER_RANGE; 1588 } else { 1589 opcode = Opcode.INVOKE_VIRTUAL_RANGE; 1590 } 1591 1592 deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getRegisterCount(), 1593 instruction.getStartRegister(), resolvedMethod); 1594 } else { 1595 Instruction35ms instruction = (Instruction35ms)analyzedInstruction.instruction; 1596 Opcode opcode; 1597 if (isSuper) { 1598 opcode = Opcode.INVOKE_SUPER; 1599 } else { 1600 opcode = Opcode.INVOKE_VIRTUAL; 1601 } 1602 1603 deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(), 1604 instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), 1605 instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod); 1606 } 1607 1608 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1609 analyzeInstruction(analyzedInstruction); 1610 1611 return true; 1612 } 1613 1614 private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) { 1615 return analyzePutGetVolatile(analyzedInstruction, true); 1616 } 1617 1618 private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction, boolean analyzeResult) { 1619 FieldReference field = (FieldReference)((ReferenceInstruction)analyzedInstruction.instruction).getReference(); 1620 String fieldType = field.getType(); 1621 1622 Opcode originalOpcode = analyzedInstruction.instruction.getOpcode(); 1623 1624 Opcode opcode = OdexedFieldInstructionMapper.getAndCheckDeodexedOpcodeForOdexedOpcode(fieldType, 1625 originalOpcode); 1626 1627 Instruction deodexedInstruction; 1628 1629 if (originalOpcode.isOdexedStaticVolatile()) { 1630 OneRegisterInstruction instruction = (OneRegisterInstruction)analyzedInstruction.instruction; 1631 deodexedInstruction = new ImmutableInstruction21c(opcode, instruction.getRegisterA(), field); 1632 } else { 1633 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 1634 1635 deodexedInstruction = new ImmutableInstruction22c(opcode, instruction.getRegisterA(), 1636 instruction.getRegisterB(), field); 1637 } 1638 1639 analyzedInstruction.setDeodexedInstruction(deodexedInstruction); 1640 1641 if (analyzeResult) { 1642 analyzeInstruction(analyzedInstruction); 1643 } 1644 return true; 1645 } 1646 1647 @Nonnull 1648 private static RegisterType getAndCheckSourceRegister(@Nonnull AnalyzedInstruction analyzedInstruction, 1649 int registerNumber, BitSet validCategories) { 1650 assert registerNumber >= 0 && registerNumber < analyzedInstruction.postRegisterMap.length; 1651 1652 RegisterType registerType = analyzedInstruction.getPreInstructionRegisterType(registerNumber); 1653 1654 checkRegister(registerType, registerNumber, validCategories); 1655 1656 if (validCategories == WideLowCategories) { 1657 checkRegister(registerType, registerNumber, WideLowCategories); 1658 checkWidePair(registerNumber, analyzedInstruction); 1659 1660 RegisterType secondRegisterType = analyzedInstruction.getPreInstructionRegisterType(registerNumber + 1); 1661 checkRegister(secondRegisterType, registerNumber+1, WideHighCategories); 1662 } 1663 1664 return registerType; 1665 } 1666 1667 private static void checkRegister(RegisterType registerType, int registerNumber, BitSet validCategories) { 1668 if (!validCategories.get(registerType.category)) { 1669 throw new AnalysisException(String.format("Invalid register type %s for register v%d.", 1670 registerType.toString(), registerNumber)); 1671 } 1672 } 1673 1674 private static void checkWidePair(int registerNumber, AnalyzedInstruction analyzedInstruction) { 1675 if (registerNumber + 1 >= analyzedInstruction.postRegisterMap.length) { 1676 throw new AnalysisException(String.format("v%d cannot be used as the first register in a wide register" + 1677 "pair because it is the last register.", registerNumber)); 1678 } 1679 } 1680}