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