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