Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/decompiler/CodeAnalyzer.java

656 lines
22 KiB

package jode;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
import java.util.*;
import java.io.*;
public class CodeAnalyzer implements Analyzer, Constants {
BinaryCode bincode;
MethodInstructionHeader methodHeader;
int[] references;
Hashtable tryAddrs = new Hashtable();
Hashtable catchAddrs = new Hashtable();
Hashtable labels = new Hashtable();
MethodAnalyzer method;
public JodeEnvironment env;
/**
* Get the method.
* @return The method to which this code belongs.
*/
public MethodAnalyzer getMethod() {return method;}
void readCode(byte[] code)
throws ClassFormatError
{
InstructionHeader[] instr = new InstructionHeader[code.length];
int returnCount;
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
for (int addr = 0; addr < code.length; ) {
instr[addr] = Opcodes.readOpcode(addr, stream, this);
addr = instr[addr].getNextAddr();
}
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
methodHeader = new MethodInstructionHeader(instr);
}
void setExceptionHandler(BinaryExceptionHandler handler) {
/*
tryAddrs.put(new Integer(handler.startPC), handler);
references[handler.startPC]++;
catchAddrs.put(new Integer(handler.handlerPC), handler);
references[handler.handlerPC]++;
*/
}
/*
Instruction getInstruction(int addr) {
return instr[addr];
}
void setInstruction(int addr, Instruction i) {
instr[addr] = i;
}
void removeInstruction(int addr) {
instr[addr] = null;
}
*/
static int WRONG = -3;
static int SPECIAL = -2;
static int FIRST = -1;
int getPreviousAddr(int addr) {
/*
int i;
for (i = addr-1; i >= 0 && instr[i] == null; i--) {}
return i;
*/
return addr;
}
int getNextAddr(int addr) {
/*
return addr + instr[addr].getLength();
*/
return addr;
}
int getPredecessor(int addr) {
/*
if (references[addr] != 1)
return WRONG;
if (addr == 0)
return FIRST;
if (catchAddrs.get(new Integer(addr)) != null)
return SPECIAL;
int i = getPreviousAddr(addr);
if (instr[i].getLength() != addr-i)
throw new RuntimeException("length mismatch");
int[] successors = instr[i].getSuccessors();
for (int j=0; j< successors.length; j++) {
if (successors[j] == addr)
return i;
}
*/
return WRONG;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
InstructionHeader ih;
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = ih.getNextInstruction()) {
ih.dumpSource(writer);
}
}
public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e)
throws ClassFormatError
{
method = ma;
env = e;
bincode = bc;
readCode(bincode.getCode());
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int i=0; i<handlers.length; i++) {
setExceptionHandler(handlers[i]);
}
}
// public InstructionHeader convertIInc(InstructionHeader ih) {
// Expression[] expr = {
// new Expression
// (new ConstOperator(ALL_INT_TYPE,
// Integer.toString(value)),
// new Expression[0])
// };
// return new InstructionHeader
// (addr, 6, new Expression
// (new LocalStoreOperator
// (ALL_INT_TYPE, local,
// Operator.OPASSIGN_OP+operation),
// expr));
// }
public InstructionHeader removeNop(InstructionHeader ih) {
Instruction pred;
try {
NopOperator op = (NopOperator) ih.getInstruction();
ih = ih.getUniquePredecessor();
pred = ih.getInstruction();
if (pred == null)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(2, pred);
return ih;
}
public InstructionHeader createConstantArray(InstructionHeader ih) {
Expression[] consts;
int count;
Type type;
try {
if (ih.getInstruction() instanceof DupOperator)
/* this is not the end of the array assign */
return null;
ih = ih.getUniquePredecessor();
ArrayStoreOperator store =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getUniquePredecessor();
Expression lastconst = (Expression) ih.getInstruction();
ih = ih.getUniquePredecessor();
Expression lastindexexpr = (Expression) ih.getInstruction();
ConstOperator lastindexop =
(ConstOperator) lastindexexpr.getOperator();
if (!MyType.isOfType(lastindexop.getType(), MyType.tUInt))
return null;
int lastindex = Integer.parseInt(lastindexop.getValue());
ih = ih.getUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
consts = new Expression[lastindex+1];
consts[lastindex] = lastconst;
count = 1;
while (lastindex-- > 0) {
ih = ih.getUniquePredecessor();
ArrayStoreOperator store2 =
(ArrayStoreOperator) ih.getInstruction();
ih = ih.getUniquePredecessor();
lastconst = (Expression) ih.getInstruction();
ih = ih.getUniquePredecessor();
Expression indexexpr = (Expression) ih.getInstruction();
ConstOperator indexop =
(ConstOperator) indexexpr.getOperator();
if (!MyType.isOfType(indexop.getType(), MyType.tUInt))
return null;
int index = Integer.parseInt(indexop.getValue());
if (index > lastindex)
return null;
while (index < lastindex) {
consts[lastindex] = new Expression
(new ConstOperator(MyType.tUnknown, ""),
new Expression[0]);
lastindex--;
}
consts[lastindex] = lastconst;
ih = ih.getUniquePredecessor();
dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize())
return null;
count++;
}
ih = ih.getUniquePredecessor();
Expression newArrayExpr = (Expression) ih.getInstruction();
NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator();
type = newArrayOp.getType();
if (newArrayOp.getOperandCount() != 1)
return null;
Expression countexpr =
(Expression) newArrayExpr.getSubExpressions()[0];
ConstOperator countop =
(ConstOperator) countexpr.getOperator();
if (!MyType.isOfType(countop.getType(), MyType.tUInt))
return null;
if (Integer.parseInt(countop.getValue()) != consts.length)
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator op = new ConstantArrayOperator(type, consts.length);
ih.combine(4*count+1, new Expression(op, consts));
return ih;
}
public InstructionHeader createExpression(InstructionHeader ih) {
Operator op;
Expression exprs[];
int count;
try {
op = (Operator) ih.getInstruction();
int params = op.getOperandCount();
exprs = new Expression[params];
count = 1;
for (int i = params-1; i>=0; i--) {
count++;
ih = ih.getUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid()) {
if (i == params-1)
return null;
Expression e = exprs[i+1].tryToCombine(exprs[i]);
if (e == null)
return null;
i++;
exprs[i] = e;
}
}
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(count, new Expression(op, exprs));
return ih;
}
// public int combineExpressions(int addr) {
// int count = 0;
// int start = addr;
// if (!(instr[addr] instanceof Expression) ||
// !((Expression)instr[addr]).isVoid())
// return -1;
// do {
// addr = getNextAddr(addr);
// count++;
// } while (addr < instr.length &&
// references[addr] == 1 &&
// instr[addr] instanceof Expression &&
// ((Expression)instr[addr]).isVoid());
// Expression[] expr = new Expression[count];
// addr = start;
// for (int i=0; i < count; i++) {
// expr[i] = (Expression)instr[addr];
// int next = getNextAddr(addr);
// instr[addr] = null;
// addr = next;
// }
// instr[start] = new Block(start, addr-start, expr);
// return start;
// }
public InstructionHeader createAssignExpression(InstructionHeader ih) {
StoreInstruction store;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != store.getLValueOperandCount() &&
dup.getCount() != store.getLValueType().stackSize())
return null;
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store));
return ih;
}
public InstructionHeader createLocalPostIncExpression(InstructionHeader ih)
{
IIncOperator iinc;
int op;
Type type;
try {
Expression iincExpr = (Expression) ih.getInstruction();
iinc = (IIncOperator) iincExpr.getOperator();
if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP)
op = Operator.INC_OP;
else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP)
op = Operator.DEC_OP;
else
return null;
if (!iinc.getValue().equals("1") &&
!iinc.getValue().equals("-1"))
return null;
if (iinc.getValue().equals("-1"))
op ^= 1;
ih = ih.getUniquePredecessor();
Expression loadExpr = (Expression) ih.getInstruction();
LocalLoadOperator load =
(LocalLoadOperator)loadExpr.getOperator();
if (!iinc.matches(load))
return null;
type = MyType.intersection(load.getType(), MyType.tUInt);
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new LocalPostFixOperator(type, op, iinc);
ih.combine(2, postop);
return ih;
}
public InstructionHeader createPostIncExpression(InstructionHeader ih) {
StoreInstruction store;
int op;
Type type;
try {
store = (StoreInstruction) ih.getInstruction();
if (store.getLValueOperandCount() == 0)
return null;
ih = ih.getUniquePredecessor();
BinaryOperator binOp = (BinaryOperator) ih.getInstruction();
if (binOp.getOperator() == store.ADD_OP)
op = Operator.INC_OP;
else if (store.getOperator() == store.NEG_OP)
op = Operator.DEC_OP;
else
return null;
ih = ih.getUniquePredecessor();
Expression expr = (Expression) ih.getInstruction();
ConstOperator constOp = (ConstOperator) expr.getOperator();
if (!constOp.getValue().equals("1") &&
!constOp.getValue().equals("-1"))
return null;
if (constOp.getValue().equals("-1"))
op ^= 1;
ih = ih.getUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != store.getLValueType().stackSize() ||
dup.getDepth() != store.getLValueOperandCount())
return null;
ih = ih.getUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getUniquePredecessor();
DupOperator dup2 = (DupOperator) ih.getInstruction();
if (dup2.getCount() != store.getLValueOperandCount() ||
dup2.getDepth() != 0)
return null;
type = MyType.intersection(load.getType(), store.getLValueType());
} catch (NullPointerException ex) {
return null;
} catch (ClassCastException ex) {
return null;
}
Operator postop = new PostFixOperator(type, op, store);
ih.combine(6, postop);
return ih;
}
public InstructionHeader createAssignOp(InstructionHeader ih) {
Expression rightHandSide;
StoreInstruction store;
BinaryOperator binop;
try {
store = (StoreInstruction) ih.getInstruction();
ih = ih.getUniquePredecessor();
binop = (BinaryOperator) ih.getInstruction();
if (binop.getOperator() < binop.ADD_OP ||
binop.getOperator() >= binop.ASSIGN_OP)
return null;
ih = ih.getUniquePredecessor();
rightHandSide = (Expression) ih.getInstruction();
if (rightHandSide.isVoid())
return null; /* XXX */
ih = ih.getUniquePredecessor();
Operator load = (Operator) ih.getInstruction();
if (!store.matches(load))
return null;
ih = ih.getUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 &&
dup.getCount() != store.getLValueOperandCount())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ih.combine(3, rightHandSide);
InstructionHeader storeIH = ih.getNextInstruction();
store.setOperator(store.OPASSIGN_OP+binop.getOperator());
store.setLValueType(MyType.intersection(binop.getType(),
store.getLValueType()));
storeIH.combine(2, store);
return ih;
}
public InstructionHeader combineNewConstructor(InstructionHeader ih) {
InvokeOperator constrCall;
Expression exprs[];
try {
constrCall = (InvokeOperator) ih.getInstruction();
if (!constrCall.isConstructor())
return null;
int params = constrCall.getOperandCount();
exprs = new Expression[params];
for (int i = params-1; i>0; i--) {
ih = ih.getUniquePredecessor();
exprs[i] = (Expression) ih.getInstruction();
if (exprs[i].isVoid())
return null; /* XXX */
}
ih = ih.getUniquePredecessor();
DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getCount() != 1 && dup.getDepth() != 0)
return null;
ih = ih.getUniquePredecessor();
exprs[0] = (Expression) ih.getInstruction();
if (exprs[0].isVoid())
return null;
NewOperator op = (NewOperator) exprs[0].getOperator();
if (constrCall.getClassType() != op.getType())
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
ConstructorOperator conOp =
new ConstructorOperator(constrCall.getClassType(),
constrCall.getField());
ih.combine(exprs.length+2, new Expression(conOp, exprs));
return ih;
}
public InstructionHeader combineIfGotoExpressions(InstructionHeader ih2) {
InstructionHeader ih1;
Expression[] e;
int operator;
try {
if (ih2.switchType != MyType.tBoolean)
return null;
InstructionHeader[] dests2 = ih2.getSuccessors();
/* if ih2.getUniquePredecessor.getOperator().isVoid() XXX */
Vector predec = ih2.getPredecessors();
if (predec.size() != 1)
return null;
ih1 = (InstructionHeader) predec.elementAt(0);
if (ih1.switchType != MyType.tBoolean)
return null;
InstructionHeader[] dests1 = ih1.getSuccessors();
if (dests1[0] != ih2)
return null;
if (dests1[1] == dests2[0]) {
e = new Expression[2];
operator = Operator.LOG_AND_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = ((Expression)ih2.getInstruction()).negate();
} else if (dests1[1] == dests2[1]) {
e = new Expression[2];
operator = Operator.LOG_OR_OP;
e[1] = (Expression)ih2.getInstruction();
e[0] = (Expression)ih2.getInstruction();
} else
return null;
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
Expression cond =
new Expression(new BinaryOperator(Type.tBoolean, operator), e);
ih1.combineConditional(cond);
return ih1;
}
public InstructionHeader createIfThenElseOperator(InstructionHeader ih) {
InstructionHeader ifHeader;
Expression e[] = new Expression[3];
InstructionHeader[] succs;
try {
Vector predec = ih.getPredecessors();
if (predec.size() != 1)
return null;
ifHeader = (InstructionHeader) predec.elementAt(0);
if (ifHeader.switchType != Type.tBoolean)
return null;
succs = ifHeader.getSuccessors();
if (succs[1] != ih ||
succs[0].getNextInstruction() != succs[1] ||
succs[0].getSuccessors().length != 1 ||
succs[1].getSuccessors().length != 1 ||
succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0])
return null;
e[0] = (Expression) ifHeader.getInstruction();
e[1] = (Expression) succs[0].getInstruction();
e[2] = (Expression) succs[1].getInstruction();
} catch (ClassCastException ex) {
return null;
} catch (NullPointerException ex) {
return null;
}
IfThenElseOperator iteo = new IfThenElseOperator
(MyType.intersection(e[1].getType(),e[2].getType()));
ifHeader.instr = new Expression(iteo, e);
ifHeader.nextInstruction = ih.nextInstruction;
ifHeader.successors = ih.successors;
ifHeader.switchType = Type.tVoid;
ifHeader.nextInstruction.predecessors.removeElement(succs[0]);
ifHeader.nextInstruction.predecessors.removeElement(succs[1]);
ifHeader.nextInstruction.predecessors.addElement(ifHeader);
return ifHeader;
}
public void analyze()
{
InstructionHeader ih, next;
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = next) {
if (env.isVerbose)
System.err.print(".");
if ((next = removeNop(ih)) != null) continue;
if ((next = createExpression(ih)) != null) continue;
if ((next = createPostIncExpression(ih)) != null) continue;
if ((next = createLocalPostIncExpression(ih)) != null) continue;
if ((next = createAssignOp(ih)) != null) continue;
if ((next = combineNewConstructor(ih)) != null) continue;
if ((next = combineIfGotoExpressions(ih)) != null) continue;
if ((next = createIfThenElseOperator(ih)) != null) continue;
if ((next = createAssignExpression(ih)) != null) continue;
if ((next = createConstantArray(ih)) != null) continue;
next = ih.getNextInstruction();
}
for (ih = methodHeader.getNextInstruction(); ih != null;
ih = ih.getNextInstruction()) {
ih.instr = ih.getInstruction().simplify();
}
// for (int addr = 0; addr < instr.length; ) {
// int nextAddr;
// nextAddr = createExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createAssignExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createArrayOpAssign(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = createPostIncExpression(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// // nextAddr = createIfGotoStatement(addr);
// // if (nextAddr >= 0) {
// // addr = nextAddr;
// // continue;
// // }
// nextAddr = combineIfGotoExpressions(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// nextAddr = combineConditionalExpr(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// addr += instr[addr].getLength();
// }
// for (int addr = 0; addr < instr.length; ) {
// int nextAddr;
// nextAddr = combineExpressions(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
// addr += instr[addr].getLength();
// }
}
public String getTypeString(Type type) {
return type.toString();
}
public ClassDefinition getClassDefinition() {
return env.getClassDefinition();
}
}