Analyze synthetic methods

now by bytecode instead of decompiled code


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@751 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 2818b261aa
commit 2e3d00bd3f
  1. 307
      jode/jode/jvm/SyntheticAnalyzer.java

@ -17,82 +17,287 @@
* $Id$
*/
package jode.decompiler;
package jode.jvm;
import jode.GlobalOptions;
import jode.flow.*;
import jode.expr.*;
import jode.type.Type;
import jode.type.MethodType;
import java.lang.reflect.Modifier;
import jode.bytecode.*;
public class SyntheticAnalyzer {
public class SyntheticAnalyzer implements jode.bytecode.Opcodes {
public final static int UNKNOWN = 0;
public final static int GETCLASS = 1;
public final static int GETFIELD = 2;
public final static int PUTFIELD = 3;
public final static int ACCESSGETFIELD = 2;
public final static int ACCESSPUTFIELD = 3;
public final static int ACCESSMETHOD = 4;
public final static int ACCESSGETSTATIC = 5;
public final static int ACCESSPUTSTATIC = 6;
public final static int ACCESSSTATICMETHOD = 7;
int type = UNKNOWN;
MethodAnalyzer method;
int kind = UNKNOWN;
Reference reference;
MethodInfo method;
public SyntheticAnalyzer(MethodAnalyzer method) {
public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
this.method = method;
if (method.getName().equals("class$"))
if (!checkGetClass() && GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("class$ seems to be wrong");
if (method.getBytecode() == null)
return;
if (!checkName || method.getName().equals("class$"))
if (checkGetClass())
return;
if (!checkName || method.getName().startsWith("access$"))
if (checkAccess())
return;
}
public int getKind() {
return kind;
}
public Reference getReference() {
return reference;
}
private static final int[] getClassOpcodes = {
opc_aload, opc_invokestatic, opc_areturn,
opc_astore, opc_new, opc_dup, opc_aload,
opc_invokevirtual, opc_invokespecial, opc_athrow
};
private static final Object[] getClassRefs = {
null, Reference.getReference("Ljava/lang/Class;", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;"),
null, null, "Ljava/lang/NoClassDefFoundError;", null, null,
Reference.getReference("Ljava/lang/Throwable;", "getMessage",
"()Ljava/lang/String;"),
Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>",
"(Ljava/lang/String;)V"), null
};
boolean checkGetClass() {
MethodType type = method.getType();
if (!method.isStatic()
|| !type.getReturnType().isOfType(Type.tJavaLangClass)
|| type.getParameterTypes().length != 1
|| !type.getParameterTypes()[0].isOfType(Type.tString))
|| !(method.getType()
.equals("(Ljava/lang/String;)Ljava/lang/Class;")))
return false;
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers.length != 1)
return false;
FlowBlock flow = method.getMethodHeader();
if (!flow.hasNoJumps())
Instruction instr = bytecode.getFirstInstr();
if (excHandlers[0].start != instr)
return false;
StructuredBlock tryblock = flow.getBlock();
if (!(tryblock instanceof TryBlock))
for (int i=0; i< getClassOpcodes.length; i++) {
if (instr.opcode != getClassOpcodes[i])
return false;
StructuredBlock[] subBlocks = tryblock.getSubBlocks();
if (subBlocks.length != 2
|| !(subBlocks[0] instanceof ReturnBlock)
|| !(subBlocks[1] instanceof CatchBlock))
if (i==0 && instr.localSlot != 0)
return false;
if ((i == 3 || i == 6) && instr.localSlot != 1)
return false;
if (i == 2 && excHandlers[0].end != instr)
return false;
if (i == 3 && excHandlers[0].catcher != instr)
return false;
if (getClassRefs[i] != null
&& !getClassRefs[i].equals(instr.objData))
return false;
instr = instr.nextByAddr;
}
if (instr != null)
return false;
this.kind = GETCLASS;
return true;
}
private final int modifierMask = (Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.PUBLIC | Modifier.STATIC);
// Now check the return Block, it should be
// return Class.forName(local_0);
ReturnBlock ret = (ReturnBlock) subBlocks[0];
Expression retExpr = ret.getInstruction();
if (!(retExpr instanceof ComplexExpression)
|| !(retExpr.getOperator() instanceof InvokeOperator))
public boolean checkStaticAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Instruction instr = bytecode.getFirstInstr();
if (instr.opcode == opc_getstatic) {
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = instr.nextByAddr;
if (instr.opcode < opc_ireturn || instr.opcode > opc_areturn)
return false;
if (instr.nextByAddr != null)
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETSTATIC;
return true;
}
int params = 0, slot = 0;
while (instr.opcode >= opc_iload && instr.opcode <= opc_aload
&& instr.localSlot == slot) {
params++;
slot += (instr.opcode == opc_lload
|| instr.opcode == opc_dload) ? 2 : 1;
instr = instr.nextByAddr;
}
if (instr.opcode == opc_putstatic) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = instr.nextByAddr;
if (instr.opcode != opc_return)
return false;
if (instr.nextByAddr != null)
return false;
reference = ref;
kind = ACCESSPUTSTATIC;
return true;
}
if (instr.opcode == opc_invokestatic) {
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC)
|| refType.getParameterTypes().length != params)
return false;
instr = instr.nextByAddr;
if (refType.getReturnType() == Type.tVoid) {
if (instr.opcode != opc_return)
return false;
InvokeOperator invoke = (InvokeOperator) retExpr.getOperator();
if (!invoke.isStatic()
|| !invoke.getClassType().equals(Type.tJavaLangClass)
|| !(invoke.getMethodType().getReturnType()
.equals(Type.tJavaLangClass))
|| invoke.getMethodType().getParameterTypes().length != 1
|| !(invoke.getMethodType().getParameterTypes()[0]
.equals(Type.tString))
|| !invoke.getMethodName().equals("forName"))
} else {
if (instr.opcode < opc_ireturn || instr.opcode > opc_areturn)
return false;
}
if (instr.nextByAddr != null)
return false;
Expression[] subExpr =
((ComplexExpression) retExpr).getSubExpressions();
if (!(subExpr[0] instanceof LocalLoadOperator)
|| ((LocalLoadOperator) subExpr[0]).getLocalInfo().getSlot() != 0)
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSSTATICMETHOD;
return true;
}
return false;
}
// Now check the CatchBlock it should contain (we don't check all):
// throw new NoClassDefFoundError(exception.getMessage());
CatchBlock catchBlock = (CatchBlock) subBlocks[1];
StructuredBlock subBlock = catchBlock.getSubBlocks()[0];
if (!(subBlock instanceof ThrowBlock)
|| !(catchBlock.getExceptionType().equals
(Type.tClass("java.lang.ClassNotFoundException"))))
public boolean checkAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0)
return false;
if (method.isStatic()) {
if (checkStaticAccess())
return true;
}
Instruction instr = bytecode.getFirstInstr();
if (instr.opcode != opc_aload || instr.localSlot != 0)
return false;
instr = instr.nextByAddr;
if (instr.opcode == opc_getfield) {
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = instr.nextByAddr;
if (instr.opcode < opc_ireturn || instr.opcode > opc_areturn)
return false;
if (instr.nextByAddr != null)
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETFIELD;
return true;
}
int params = 0, slot = 1;
while (instr.opcode >= opc_iload && instr.opcode <= opc_aload
&& instr.localSlot == slot) {
params++;
slot += (instr.opcode == opc_lload
|| instr.opcode == opc_dload) ? 2 : 1;
instr = instr.nextByAddr;
}
if (instr.opcode == opc_putfield) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = instr.nextByAddr;
if (instr.opcode != opc_return)
return false;
this.type = GETCLASS;
if (instr.nextByAddr != null)
return false;
reference = ref;
kind = ACCESSPUTFIELD;
return true;
}
if (instr.opcode == opc_invokespecial) {
Reference ref = (Reference) instr.objData;
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| refType.getParameterTypes().length != params)
return false;
instr = instr.nextByAddr;
if (refType.getReturnType() == Type.tVoid) {
if (instr.opcode != opc_return)
return false;
} else {
if (instr.opcode < opc_ireturn || instr.opcode > opc_areturn)
return false;
}
if (instr.nextByAddr != null)
return false;
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSMETHOD;
return true;
}
return false;
}
}

Loading…
Cancel
Save