/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver (JesusFreke)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib.Code.Analysis;
import org.jf.dexlib.*;
import org.jf.dexlib.Code.*;
import org.jf.dexlib.Code.Format.*;
import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.ExceptionWithContext;
import org.jf.dexlib.Util.SparseArray;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.List;
/**
* The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types
* for each register, it can deodex odexed instructions, and it can verify the bytecode. The analysis and verification
* are done in two separate passes, because the analysis has to process instructions multiple times in some cases, and
* there's no need to perform the verification multiple times, so we wait until the method is fully analyzed and then
* verify it.
*
* Before calling the analyze() method, you must have initialized the ClassPath by calling
* ClassPath.InitializeClassPath
*/
public class MethodAnalyzer {
private final ClassDataItem.EncodedMethod encodedMethod;
private final DeodexUtil deodexUtil;
private SparseArray<AnalyzedInstruction> instructions;
private static final int NOT_ANALYZED = 0;
private static final int ANALYZED = 1;
private static final int VERIFIED = 2;
private int analyzerState = NOT_ANALYZED;
private BitSet analyzedInstructions;
private ValidationException validationException = null;
//This is a dummy instruction that occurs immediately before the first real instruction. We can initialize the
//register types for this instruction to the parameter types, in order to have them propagate to all of its
//successors, e.g. the first real instruction, the first instructions in any exception handlers covering the first
//instruction, etc.
private AnalyzedInstruction startOfMethod;
public MethodAnalyzer(ClassDataItem.EncodedMethod encodedMethod, boolean deodex,
InlineMethodResolver inlineResolver) {
if (encodedMethod == null) {
throw new IllegalArgumentException("encodedMethod cannot be null");
}
if (encodedMethod.codeItem == null || encodedMethod.codeItem.getInstructions().length == 0) {
throw new IllegalArgumentException("The method has no code");
}
this.encodedMethod = encodedMethod;
if (deodex) {
if (inlineResolver != null) {
this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile(), inlineResolver);
} else {
this.deodexUtil = new DeodexUtil(encodedMethod.method.getDexFile());
}
} else {
this.deodexUtil = null;
}
//override AnalyzedInstruction and provide custom implementations of some of the methods, so that we don't
//have to handle the case this special case of instruction being null, in the main class
startOfMethod = new AnalyzedInstruction(null, -1, encodedMethod.codeItem.getRegisterCount()) {
public boolean setsRegister() {
return false;
}
@Override
public boolean setsWideRegister() {
return false;
}
@Override
public boolean setsRegister(int registerNumber) {
return false;
}
@Override
public int getDestinationRegister() {
assert false;
return -1;
};
};
buildInstructionList();
analyzedInstructions = new BitSet(instructions.size());
}
public boolean isAnalyzed() {
return analyzerState >= ANALYZED;
}
public boolean isVerified() {
return analyzerState == VERIFIED;
}
public void analyze() {
assert encodedMethod != null;
assert encodedMethod.codeItem != null;
if (analyzerState >= ANALYZED) {
//the instructions have already been analyzed, so there is nothing to do
return;
}
CodeItem codeItem = encodedMethod.codeItem;
MethodIdItem methodIdItem = encodedMethod.method;
int totalRegisters = codeItem.getRegisterCount();
int parameterRegisters = methodIdItem.getPrototype().getParameterRegisterCount();
int nonParameterRegisters = totalRegisters - parameterRegisters;
for (AnalyzedInstruction instruction: instructions.getValues()) {
instruction.dead = true;
}
//if this isn't a static method, determine which register is the "this" register and set the type to the
//current class
if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
nonParameterRegisters--;
int thisRegister = totalRegisters - parameterRegisters - 1;
//if this is a constructor, then set the "this" register to an uninitialized reference of the current class
if ((encodedMethod.accessFlags & AccessFlags.CONSTRUCTOR.getValue()) != 0) {
setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
RegisterType.getRegisterType(RegisterType.Category.UninitThis,
ClassPath.getClassDef(methodIdItem.getContainingClass())));
} else {
setPostRegisterTypeAndPropagateChanges(startOfMethod, thisRegister,
RegisterType.getRegisterType(RegisterType.Category.Reference,
ClassPath.getClassDef(methodIdItem.getContainingClass())));
}
}
TypeListItem parameters = methodIdItem.getPrototype().getParameters();
if (parameters != null) {
RegisterType[] parameterTypes = getParameterTypes(parameters, parameterRegisters);
for (int i=0; i<parameterTypes.length; i++) {
RegisterType registerType = parameterTypes[i];
int registerNum = (totalRegisters - parameterRegisters) + i;
setPostRegisterTypeAndPropagateChanges(startOfMethod, registerNum, registerType);
}
}
RegisterType uninit = RegisterType.getRegisterType(RegisterType.Category.Uninit, null);
for (int i=0; i<nonParameterRegisters; i++) {
setPostRegisterTypeAndPropagat
评论0