use of org.jf.dexlib2.analysis.AnalysisException in project smali by JesusFreke.
the class MethodAnalyzer method analyzeExecuteInline.
private void analyzeExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) {
if (inlineResolver == null) {
throw new AnalysisException("Cannot analyze an odexed instruction unless we are deodexing");
}
Instruction35mi instruction = (Instruction35mi) analyzedInstruction.instruction;
Method resolvedMethod = inlineResolver.resolveExecuteInline(analyzedInstruction);
Opcode deodexedOpcode;
int acccessFlags = resolvedMethod.getAccessFlags();
if (AccessFlags.STATIC.isSet(acccessFlags)) {
deodexedOpcode = Opcode.INVOKE_STATIC;
} else if (AccessFlags.PRIVATE.isSet(acccessFlags)) {
deodexedOpcode = Opcode.INVOKE_DIRECT;
} else {
deodexedOpcode = Opcode.INVOKE_VIRTUAL;
}
Instruction35c deodexedInstruction = new ImmutableInstruction35c(deodexedOpcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
analyzeInstruction(analyzedInstruction);
}
use of org.jf.dexlib2.analysis.AnalysisException in project smali by JesusFreke.
the class MethodAnalyzer method analyzeMoveResult.
private void analyzeMoveResult(@Nonnull AnalyzedInstruction analyzedInstruction) {
AnalyzedInstruction previousInstruction = null;
if (analyzedInstruction.instructionIndex > 0) {
previousInstruction = analyzedInstructions.valueAt(analyzedInstruction.instructionIndex - 1);
}
if (previousInstruction == null || !previousInstruction.instruction.getOpcode().setsResult()) {
throw new AnalysisException(analyzedInstruction.instruction.getOpcode().name + " must occur after an " + "invoke-*/fill-new-array instruction");
}
RegisterType resultRegisterType;
ReferenceInstruction invokeInstruction = (ReferenceInstruction) previousInstruction.instruction;
Reference reference = invokeInstruction.getReference();
if (reference instanceof MethodReference) {
resultRegisterType = RegisterType.getRegisterType(classPath, ((MethodReference) reference).getReturnType());
} else {
resultRegisterType = RegisterType.getRegisterType(classPath, (TypeReference) reference);
}
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, resultRegisterType);
}
use of org.jf.dexlib2.analysis.AnalysisException in project smali by JesusFreke.
the class MethodAnalyzer method analyzeInvokeVirtualQuick.
private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper, boolean isRange) {
int methodIndex;
int objectRegister;
if (isRange) {
Instruction3rms instruction = (Instruction3rms) analyzedInstruction.instruction;
methodIndex = instruction.getVtableIndex();
objectRegister = instruction.getStartRegister();
} else {
Instruction35ms instruction = (Instruction35ms) analyzedInstruction.instruction;
methodIndex = instruction.getVtableIndex();
objectRegister = instruction.getRegisterC();
}
RegisterType objectRegisterType = getAndCheckSourceRegister(analyzedInstruction, objectRegister, ReferenceOrUninitCategories);
TypeProto objectRegisterTypeProto = objectRegisterType.type;
if (objectRegisterType.category == RegisterType.NULL) {
return false;
}
assert objectRegisterTypeProto != null;
MethodReference resolvedMethod;
if (isSuper) {
// invoke-super is only used for the same class that we're currently in
TypeProto typeProto = classPath.getClass(method.getDefiningClass());
TypeProto superType;
String superclassType = typeProto.getSuperclass();
if (superclassType != null) {
superType = classPath.getClass(superclassType);
} else {
// This is either java.lang.Object, or an UnknownClassProto
superType = typeProto;
}
resolvedMethod = superType.getMethodByVtableIndex(methodIndex);
} else {
resolvedMethod = objectRegisterTypeProto.getMethodByVtableIndex(methodIndex);
}
if (resolvedMethod == null) {
throw new AnalysisException("Could not resolve the method in class %s at index %d", objectRegisterType.type.getType(), methodIndex);
}
// no need to check class access for invoke-super. A class can obviously access its superclass.
ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
if (classPath.getClass(resolvedMethod.getDefiningClass()).isInterface()) {
resolvedMethod = new ReparentedMethodReference(resolvedMethod, objectRegisterTypeProto.getType());
} else if (!isSuper && !TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
// the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
// than resolvedMethod.getDefiningClass()), and walk up the class hierarchy.
ClassDef methodClass = classPath.getClassDef(objectRegisterTypeProto.getType());
while (!TypeUtils.canAccessClass(thisClass.getType(), methodClass)) {
String superclass = methodClass.getSuperclass();
if (superclass == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", ReferenceUtil.getMethodDescriptor(resolvedMethod, true));
}
methodClass = classPath.getClassDef(superclass);
}
// methodClass is now the first accessible class found. Now. we need to make sure that the method is
// actually valid for this class
MethodReference newResolvedMethod = classPath.getClass(methodClass.getType()).getMethodByVtableIndex(methodIndex);
if (newResolvedMethod == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s", ReferenceUtil.getMethodDescriptor(resolvedMethod, true));
}
resolvedMethod = newResolvedMethod;
resolvedMethod = new ImmutableMethodReference(methodClass.getType(), resolvedMethod.getName(), resolvedMethod.getParameterTypes(), resolvedMethod.getReturnType());
}
if (normalizeVirtualMethods) {
MethodReference replacementMethod = normalizeMethodReference(resolvedMethod);
if (replacementMethod != null) {
resolvedMethod = replacementMethod;
}
}
Instruction deodexedInstruction;
if (isRange) {
Instruction3rms instruction = (Instruction3rms) analyzedInstruction.instruction;
Opcode opcode;
if (isSuper) {
opcode = Opcode.INVOKE_SUPER_RANGE;
} else {
opcode = Opcode.INVOKE_VIRTUAL_RANGE;
}
deodexedInstruction = new ImmutableInstruction3rc(opcode, instruction.getStartRegister(), instruction.getRegisterCount(), resolvedMethod);
} else {
Instruction35ms instruction = (Instruction35ms) analyzedInstruction.instruction;
Opcode opcode;
if (isSuper) {
opcode = Opcode.INVOKE_SUPER;
} else {
opcode = Opcode.INVOKE_VIRTUAL;
}
deodexedInstruction = new ImmutableInstruction35c(opcode, instruction.getRegisterCount(), instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(), instruction.getRegisterF(), instruction.getRegisterG(), resolvedMethod);
}
analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
analyzeInstruction(analyzedInstruction);
return true;
}
use of org.jf.dexlib2.analysis.AnalysisException in project smali by JesusFreke.
the class MethodAnalyzer method buildInstructionList.
private void buildInstructionList() {
int registerCount = methodImpl.getRegisterCount();
ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions());
analyzedInstructions.ensureCapacity(instructions.size());
//first, create all the instructions and populate the instructionAddresses array
int currentCodeAddress = 0;
for (int i = 0; i < instructions.size(); i++) {
Instruction instruction = instructions.get(i);
analyzedInstructions.append(currentCodeAddress, new AnalyzedInstruction(this, instruction, i, registerCount));
assert analyzedInstructions.indexOfKey(currentCodeAddress) == i;
currentCodeAddress += instruction.getCodeUnits();
}
//next, populate the exceptionHandlers array. The array item for each instruction that can throw an exception
//and is covered by a try block should be set to a list of the first instructions of each exception handler
//for the try block covering the instruction
List<? extends TryBlock<? extends ExceptionHandler>> tries = methodImpl.getTryBlocks();
tries = TryListBuilder.massageTryBlocks(tries);
int triesIndex = 0;
TryBlock currentTry = null;
AnalyzedInstruction[] currentExceptionHandlers = null;
AnalyzedInstruction[][] exceptionHandlers = new AnalyzedInstruction[instructions.size()][];
if (tries != null) {
for (int i = 0; i < analyzedInstructions.size(); i++) {
AnalyzedInstruction instruction = analyzedInstructions.valueAt(i);
Opcode instructionOpcode = instruction.instruction.getOpcode();
currentCodeAddress = getInstructionAddress(instruction);
//check if we have gone past the end of the current try
if (currentTry != null) {
if (currentTry.getStartCodeAddress() + currentTry.getCodeUnitCount() <= currentCodeAddress) {
currentTry = null;
triesIndex++;
}
}
//check if the next try is applicable yet
if (currentTry == null && triesIndex < tries.size()) {
TryBlock<? extends ExceptionHandler> tryBlock = tries.get(triesIndex);
if (tryBlock.getStartCodeAddress() <= currentCodeAddress) {
assert (tryBlock.getStartCodeAddress() + tryBlock.getCodeUnitCount() > currentCodeAddress);
currentTry = tryBlock;
currentExceptionHandlers = buildExceptionHandlerArray(tryBlock);
}
}
//for the current instruction
if (currentTry != null && instructionOpcode.canThrow()) {
exceptionHandlers[i] = currentExceptionHandlers;
}
}
}
//and no reachable code will have an unreachable predessor or successor
assert analyzedInstructions.size() > 0;
BitSet instructionsToProcess = new BitSet(instructions.size());
addPredecessorSuccessor(startOfMethod, analyzedInstructions.valueAt(0), exceptionHandlers, instructionsToProcess);
while (!instructionsToProcess.isEmpty()) {
int currentInstructionIndex = instructionsToProcess.nextSetBit(0);
instructionsToProcess.clear(currentInstructionIndex);
AnalyzedInstruction instruction = analyzedInstructions.valueAt(currentInstructionIndex);
Opcode instructionOpcode = instruction.instruction.getOpcode();
int instructionCodeAddress = getInstructionAddress(instruction);
if (instruction.instruction.getOpcode().canContinue()) {
if (currentInstructionIndex == analyzedInstructions.size() - 1) {
throw new AnalysisException("Execution can continue past the last instruction");
}
AnalyzedInstruction nextInstruction = analyzedInstructions.valueAt(currentInstructionIndex + 1);
addPredecessorSuccessor(instruction, nextInstruction, exceptionHandlers, instructionsToProcess);
}
if (instruction.instruction instanceof OffsetInstruction) {
OffsetInstruction offsetInstruction = (OffsetInstruction) instruction.instruction;
if (instructionOpcode == Opcode.PACKED_SWITCH || instructionOpcode == Opcode.SPARSE_SWITCH) {
AnalyzedInstruction analyzedSwitchPayload = analyzedInstructions.get(instructionCodeAddress + offsetInstruction.getCodeOffset());
if (analyzedSwitchPayload == null) {
throw new AnalysisException("Invalid switch payload offset");
}
SwitchPayload switchPayload = (SwitchPayload) analyzedSwitchPayload.instruction;
for (SwitchElement switchElement : switchPayload.getSwitchElements()) {
AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + switchElement.getOffset());
if (targetInstruction == null) {
throw new AnalysisException("Invalid switch target offset");
}
addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
}
} else if (instructionOpcode != Opcode.FILL_ARRAY_DATA) {
int targetAddressOffset = offsetInstruction.getCodeOffset();
AnalyzedInstruction targetInstruction = analyzedInstructions.get(instructionCodeAddress + targetAddressOffset);
addPredecessorSuccessor(instruction, targetInstruction, exceptionHandlers, instructionsToProcess);
}
}
}
}
Aggregations