@Nonnull public RegisterType merge(@Nonnull RegisterType other) { if (other.equals(this)) { return this; return RegisterType.getRegisterType(mergedCategory, mergedType);
return new RegisterType(category, typeProto);
private void analyzeConst(@Nonnull AnalyzedInstruction analyzedInstruction) { NarrowLiteralInstruction instruction = (NarrowLiteralInstruction)analyzedInstruction.instruction; //we assume that the literal value is a valid value for the given instruction type, because it's impossible //to store an invalid literal with the instruction. so we don't need to check the type of the literal setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterTypeForLiteral(instruction.getNarrowLiteral())); }
private void propagateParameterTypes(int parameterStartRegister) { int i=0; for (MethodParameter parameter: method.getParameters()) { if (TypeUtils.isWideType(parameter)) { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, true)); setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, false)); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getRegisterType(classPath, parameter)); } } }
private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { int instructionAddress = getInstructionAddress(analyzedInstruction); RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) { for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { if (handler.getHandlerCodeAddress() == instructionAddress) { String type = handler.getExceptionType(); if (type == null) { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass("Ljava/lang/Throwable;")); } else { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) .merge(exceptionType); } } } } if (exceptionType.category == RegisterType.UNKNOWN) { throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); }
protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = postRegisterMap[registerNumber]; if (oldRegisterType.equals(registerType)) { return false; } postRegisterMap[registerNumber] = registerType; return true; }
@Nonnull public static RegisterType getWideRegisterType(@Nonnull CharSequence type, boolean firstRegister) { switch (type.charAt(0)) { case 'J': if (firstRegister) { return getRegisterType(LONG_LO, null); } else { return getRegisterType(LONG_HI, null); } case 'D': if (firstRegister) { return getRegisterType(DOUBLE_LO, null); } else { return getRegisterType(DOUBLE_HI, null); } default: throw new ExceptionWithContext("Cannot use this method for narrow register type: %s", type); } }
protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = preRegisterMap[registerNumber]; RegisterType mergedRegisterType = oldRegisterType.merge(registerType); if (mergedRegisterType.equals(oldRegisterType)) { return false; } preRegisterMap[registerNumber] = mergedRegisterType; verifiedInstructions.clear(instructionIndex); if (!setsRegister(registerNumber)) { postRegisterMap[registerNumber] = mergedRegisterType; return true; } return false; }
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException { int registerNum = registers.nextSetBit(0); if (registerNum < 0) { return false; } writer.write('#'); for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) { RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum); registerFormatter.writeTo(writer, registerNum); writer.write('='); registerType.writeTo(writer); writer.write(';'); } return true; } }
private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-object used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; String elementType = arrayProto.getImmediateElementType(); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); } else { // If the array register is null, we can assume that the destination register was meant to be a reference // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); } }
private static void checkRegister(RegisterType registerType, int registerNumber, BitSet validCategories) { if (!validCategories.get(registerType.category)) { throw new AnalysisException(String.format("Invalid register type %s for register v%d.", registerType.toString(), registerNumber)); } }
/** * Iterates over the predecessors of this instruction, and merges all the post-instruction register types for the * given register. Any dead, unreachable, or odexed predecessor is ignored * @param registerNumber the register number * @return The register type resulting from merging the post-instruction register types from all predecessors */ protected RegisterType mergePreRegisterTypeFromPredecessors(int registerNumber) { RegisterType mergedRegisterType = null; for (AnalyzedInstruction predecessor: predecessors) { RegisterType predecessorRegisterType = predecessor.postRegisterMap[registerNumber]; assert predecessorRegisterType != null; mergedRegisterType = predecessorRegisterType.merge(mergedRegisterType); } return mergedRegisterType; }
/** * Sets the "post-instruction" register type as indicated. * @param registerNumber Which register to set * @param registerType The "post-instruction" register type * @return true if the given register type is different than the existing post-instruction register type */ protected boolean setPostRegisterType(int registerNumber, RegisterType registerType) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = postRegisterMap[registerNumber]; if (oldRegisterType.equals(registerType)) { return false; } postRegisterMap[registerNumber] = registerType; return true; }
private void analyzeConstString(@Nonnull AnalyzedInstruction analyzedInstruction) { TypeProto stringClass = classPath.getClass("Ljava/lang/String;"); RegisterType stringType = RegisterType.getRegisterType(RegisterType.REFERENCE, stringClass); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, stringType); }
protected boolean mergeRegister(int registerNumber, RegisterType registerType, BitSet verifiedInstructions, boolean override) { assert registerNumber >= 0 && registerNumber < postRegisterMap.length; assert registerType != null; RegisterType oldRegisterType = preRegisterMap[registerNumber]; RegisterType mergedRegisterType; if (override) { mergedRegisterType = getMergedPreRegisterTypeFromPredecessors(registerNumber); } else { mergedRegisterType = oldRegisterType.merge(registerType); } if (mergedRegisterType.equals(oldRegisterType)) { return false; } preRegisterMap[registerNumber] = mergedRegisterType; verifiedInstructions.clear(instructionIndex); if (!setsRegister(registerNumber)) { postRegisterMap[registerNumber] = mergedRegisterType; return true; } return false; }
private boolean writeRegisterInfo(IndentingWriter writer, BitSet registers) throws IOException { int registerNum = registers.nextSetBit(0); if (registerNum < 0) { return false; } writer.write('#'); for (; registerNum >= 0; registerNum = registers.nextSetBit(registerNum + 1)) { RegisterType registerType = analyzedInstruction.getPostInstructionRegisterType(registerNum); registerFormatter.writeTo(writer, registerNum); writer.write('='); registerType.writeTo(writer); writer.write(';'); } return true; } }
private void propagateParameterTypes(int parameterStartRegister) { int i=0; for (MethodParameter parameter: method.getParameters()) { if (TypeUtils.isWideType(parameter)) { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, true)); setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getWideRegisterType(parameter, false)); } else { setPostRegisterTypeAndPropagateChanges(startOfMethod, parameterStartRegister + i++, RegisterType.getRegisterType(classPath, parameter)); } } }
private void analyzeAgetObject(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-object used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; String elementType = arrayProto.getImmediateElementType(); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(elementType))); } else { // If the array register is null, we can assume that the destination register was meant to be a reference // type, so we set the destination to NULL. This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.NULL_TYPE); } }
private void analyzeMoveException(@Nonnull AnalyzedInstruction analyzedInstruction) { int instructionAddress = getInstructionAddress(analyzedInstruction); RegisterType exceptionType = RegisterType.UNKNOWN_TYPE; for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) { for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) { if (handler.getHandlerCodeAddress() == instructionAddress) { String type = handler.getExceptionType(); if (type == null) { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass("Ljava/lang/Throwable;")); } else { exceptionType = RegisterType.getRegisterType(RegisterType.REFERENCE, classPath.getClass(type)) .merge(exceptionType); } } } } if (exceptionType.category == RegisterType.UNKNOWN) { throw new AnalysisException("move-exception must be the first instruction in an exception handler block"); } setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, exceptionType); }
private void analyzeAgetWide(@Nonnull AnalyzedInstruction analyzedInstruction) { ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); if (arrayRegisterType.category != RegisterType.NULL) { if (arrayRegisterType.category != RegisterType.REFERENCE || !(arrayRegisterType.type instanceof ArrayProto)) { throw new AnalysisException("aget-wide used with non-array register: %s", arrayRegisterType.toString()); } ArrayProto arrayProto = (ArrayProto)arrayRegisterType.type; if (arrayProto.dimensions != 1) { throw new AnalysisException("aget-wide used with multi-dimensional array: %s", arrayRegisterType.toString()); } char arrayBaseType = arrayProto.getElementType().charAt(0); if (arrayBaseType == 'J') { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); } else if (arrayBaseType == 'D') { setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.DOUBLE_LO_TYPE); } else { throw new AnalysisException("aget-wide used with narrow array: %s", arrayRegisterType); } } else { // If the array register is null, we can assume that the destination register was meant to be a wide type. // This is the same behavior as dalvik's verifier setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, RegisterType.LONG_LO_TYPE); } }