git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@500 379699f6-c40d-0410-875b-85095c16579estable
parent
c0c72ebfec
commit
20091fa56d
@ -0,0 +1,89 @@ |
|||||||
|
/* Reference Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.bytecode; |
||||||
|
import java.util.Vector; |
||||||
|
import java.util.Enumeration; |
||||||
|
import jode.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class represents a field or method reference |
||||||
|
* |
||||||
|
* For simplicity currently most fields are public. You shouldn't change |
||||||
|
* many of them, though. |
||||||
|
*/ |
||||||
|
public class Reference { |
||||||
|
/** |
||||||
|
* The class info. |
||||||
|
*/ |
||||||
|
String className; |
||||||
|
/** |
||||||
|
* The member name. Don't make this a MethodInfo, since the clazz |
||||||
|
* may not be readable. |
||||||
|
*/ |
||||||
|
String memberName; |
||||||
|
/** |
||||||
|
* The member type. |
||||||
|
*/ |
||||||
|
String memberType; |
||||||
|
|
||||||
|
public Reference(String className, String name, String type) { |
||||||
|
this.className = className; |
||||||
|
this.memberName = name; |
||||||
|
this.memberType = type; |
||||||
|
} |
||||||
|
|
||||||
|
public String getClazz() { |
||||||
|
return className; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return memberName; |
||||||
|
} |
||||||
|
|
||||||
|
public String getType() { |
||||||
|
return memberType; |
||||||
|
} |
||||||
|
|
||||||
|
public void setClazz(String name) { |
||||||
|
className = name; |
||||||
|
} |
||||||
|
|
||||||
|
public void setName(String name) { |
||||||
|
memberName = name; |
||||||
|
} |
||||||
|
|
||||||
|
public void setType(String type) { |
||||||
|
memberType = type; |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return className + "." + memberName + "." + memberType; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o instanceof Reference) { |
||||||
|
Reference other = (Reference) o; |
||||||
|
return other.className.equals(className) |
||||||
|
&& other.memberName.equals(memberName) |
||||||
|
&& other.memberType.equals(memberType); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* CodeAnalyzer Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
import jode.bytecode.BytecodeInfo; |
||||||
|
|
||||||
|
public interface CodeAnalyzer { |
||||||
|
public void analyzeCode(); |
||||||
|
public BytecodeInfo stripCode(); |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@ |
|||||||
|
/* FieldListener Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
|
||||||
|
/** |
||||||
|
* This is the interface for field listeners, to get information when |
||||||
|
* something interesting happens to a field. |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
|
||||||
|
public interface FieldListener extends java.util.EventListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* This method gets called, when a field can no longer be constant. |
||||||
|
*/ |
||||||
|
public void fieldNotConstant(IdentifierEvent ev); |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
/* IdentifierEvent Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
public class IdentifierEvent extends java.util.EventObject { |
||||||
|
/* 0 - 9: general events */ |
||||||
|
public final static int REACHABLE = 0; |
||||||
|
public final static int PRESERVED = 1; |
||||||
|
|
||||||
|
/* 10 - 19: field events */ |
||||||
|
public final static int CONSTANT = 10; |
||||||
|
/* 20 - 29: method events */ |
||||||
|
/* 30 - 39: class events */ |
||||||
|
/* 40 - 49: package events */ |
||||||
|
|
||||||
|
public final int id; |
||||||
|
|
||||||
|
public IdentifierEvent(Identifier source, int id) { |
||||||
|
super(source); |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public final int getID() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* IdentifierListener Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
|
||||||
|
/** |
||||||
|
* This is the interface for identifier listeners, to get information when |
||||||
|
* something interesting happens to a identifier. |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
|
||||||
|
public interface IdentifierListener extends java.util.EventListener { |
||||||
|
/** |
||||||
|
* This method gets called, when a identifier is reachable. |
||||||
|
*/ |
||||||
|
public void identifierReachable(IdentifierEvent ev); |
||||||
|
} |
@ -0,0 +1,224 @@ |
|||||||
|
/* LogicalDeadCodeOptimizer Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class analyzes the method to detect and remove logical dead |
||||||
|
* code. If a field, local or stack entry, is tested to have a |
||||||
|
* certain value, that is remembered and if a similar test occurs |
||||||
|
* again, we may know, that it always evaluates to true |
||||||
|
* resp. false.<br> |
||||||
|
* |
||||||
|
* Each field/local/stack entry has a Constraint, that tells e.g. if |
||||||
|
* that value is always a constant, always not zero, always zero, or |
||||||
|
* always equal to another stack entry etc. These constraints can be |
||||||
|
* propagated, and if the condition of a opc_if is always the same, |
||||||
|
* that opc_if can be removed resp. replaces by a opc_goto. <br> |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
public class LogicalDeadCodeOptimizer { |
||||||
|
class Constraint { |
||||||
|
/* The constant are aligned so that the operation ^1 negates the |
||||||
|
* comparison and like the VM opcodes. |
||||||
|
*/ |
||||||
|
public int EQ = 0; |
||||||
|
public int NE = 1; |
||||||
|
public int LT = 2; |
||||||
|
public int GE = 3; |
||||||
|
public int GT = 4; |
||||||
|
public int LE = 5; |
||||||
|
|
||||||
|
/** |
||||||
|
* This gives the compareOps for this constraint (one of |
||||||
|
* EQ/NE/GE/GT/LE/LT). */ |
||||||
|
int compareOp; |
||||||
|
/** |
||||||
|
* The reference value to which is compared (this is the |
||||||
|
* second argument of the compare). |
||||||
|
*/ |
||||||
|
ConstrainedValue reference; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class ConstrainedValue { |
||||||
|
boolean isConstant; |
||||||
|
Object constant; |
||||||
|
|
||||||
|
/** |
||||||
|
* If this is not constant, this are all constraints. |
||||||
|
*/ |
||||||
|
Constraint[] constraints; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public boolean implies(Constraint constraint) { |
||||||
|
if (isConstant) { |
||||||
|
// check if always
|
||||||
|
// value.constant compareOp reference
|
||||||
|
return constraint.reference.compareToConstant |
||||||
|
(value.constant, compareOp) == 1; |
||||||
|
} else { |
||||||
|
//
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Compares this object with other. |
||||||
|
* @param compareOp one of Constraint.EQ/NE/LT/LE/GT/GE. |
||||||
|
* @param other a constant, null, a String or a Number. |
||||||
|
* @return 1, if (other compareOp this) always true, <br> |
||||||
|
* 0, if (other compareOp this) always false, <br> |
||||||
|
* -1, otherwise |
||||||
|
*/ |
||||||
|
public int compareToConstant(Object other, int compareOp) { |
||||||
|
if (isConstant) { |
||||||
|
switch (compareOp) { |
||||||
|
case EQ: |
||||||
|
return other.equals(constant) ? 1 : 0; |
||||||
|
case NE: |
||||||
|
return other.equals(constant) ? 0 : 1; |
||||||
|
case LE: |
||||||
|
case LT: |
||||||
|
case GE: |
||||||
|
case GT: { |
||||||
|
/* This must be a number */ |
||||||
|
int cmp = ((Number)other).compareTo((Number)constant); |
||||||
|
if (compareOp == LE && cmp <= 0 |
||||||
|
|| compareOp == LT && cmp < 0 |
||||||
|
|| compareOp == GE && cmp >= 0 |
||||||
|
|| compareOp == GT && cmp > 0) |
||||||
|
return 1; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
/* Not a constant, try the constraints. */ |
||||||
|
|
||||||
|
/* First we find all equal references */ |
||||||
|
Vector equalRefs = new Vector(); |
||||||
|
equalRefs.add(this); |
||||||
|
for (int i=0; i < equalRefs.size(); i++) { |
||||||
|
Constraint[] cs = ((ConstrainedValue) |
||||||
|
equalRefs.elementAt(i)).constraints; |
||||||
|
for (int j=0; j < cs.count; j++) { |
||||||
|
if (cs[j].compareOp == EQ |
||||||
|
&& !equalRefs.contains(cs[j].reference)) |
||||||
|
equalRefs.addElement(cs[j].reference); |
||||||
|
} |
||||||
|
} |
||||||
|
/* If we wanted to only check for EQ or NE we can do this now. |
||||||
|
*/ |
||||||
|
if (compareOp == EQ || compareOp == NE) { |
||||||
|
for (int i=0; i < equalRefs.size(); i++) { |
||||||
|
Constraint[] cs = ((ConstrainedValue) |
||||||
|
equalRefs.elementAt(i)).constraints; |
||||||
|
for (int j=0; j < cs.count; j++) { |
||||||
|
if ((1 << cs[j].compareOp |
||||||
|
& (1<<NE | 1<<LT | 1<<GT)) != 0 |
||||||
|
&& cs[j].reference.isConstant |
||||||
|
&& cs[j].reference.constant.equals(other)) { |
||||||
|
/* Yeah, we are not equal to that constant. */ |
||||||
|
return (compareOp == NE) ? 1 : 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
/* No helpful constraints found */ |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Check if we are greater / greater or equal */ |
||||||
|
|
||||||
|
if (cs[j]) |
||||||
|
/* This is a constant, check if constraint |
||||||
|
* is okay and compare. |
||||||
|
*/ |
||||||
|
if (cmpOp == cs[j].compareOp |
||||||
|
&& cs[j].compareOp == cmpOp |
||||||
|
|| cs[j].compareOp ^ 7 == cmpOp) |
||||||
|
/* We are lucky, this is a constant |
||||||
|
* (can this happen?) |
||||||
|
*/ |
||||||
|
return cs[j].reference.compareToConstant |
||||||
|
(other, compareOp); |
||||||
|
|
||||||
|
/* Now try to prove that always greater */ |
||||||
|
|
||||||
|
|
||||||
|
Stack stack = new Stack(); |
||||||
|
Stack cmpopStack = new Stack(); |
||||||
|
stack.push(this); |
||||||
|
cmpopStack.push(new Integer(compareOp)); |
||||||
|
while (!stack.isEmpty()) { |
||||||
|
ConstrainedValue cv = (ConstrainedValue) stack.pop(); |
||||||
|
Constraint[] cs = cv.constraints; |
||||||
|
int cmpop = ((Integer) cmpopStack.pop()).intValue(); |
||||||
|
for (int i=0; i < cs.count; i++) { |
||||||
|
if (/* always consider equals. */ |
||||||
|
cs.compareOp == EQ |
||||||
|
/* never consider nonequals */ |
||||||
|
|| (cs.compareOp >= NE |
||||||
|
/* consider same compares */ |
||||||
|
&& cs.compareOp == cmpop |
||||||
|
/* and consider same compares except equal */ |
||||||
|
&& cs.compareOp ^ 7 == cmpop)) { |
||||||
|
|
||||||
|
/* if cs.compareOp is greater or lower |
||||||
|
* (not equal), we can allow equal in cmpop */ |
||||||
|
if (cs.compareOp != EQ |
||||||
|
&& (cs.compareOp & 1) == 0 |
||||||
|
&& (cmpop & 1) == 0) |
||||||
|
cmpop ^= 7; |
||||||
|
if (cs.reference.isConstant()) { |
||||||
|
if (other.compareToConstant |
||||||
|
(cmpop, cs.reference.isConstant()) == 1) |
||||||
|
return 1; |
||||||
|
} else if (!stack.contains(cs.reference)) { |
||||||
|
stack.push(cs.reference); |
||||||
|
cmpopStack.push(new Integer(cmpop)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* OPEN QUESTIONS: |
||||||
|
* we have a variable whose value is > 0. |
||||||
|
* is after an increase the value still >0? |
||||||
|
* (not necessarily, e.g. value == Integer.MAX_VALUE) |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Every local/stack has a list of Constraint. |
||||||
|
* Operations: |
||||||
|
* -when two control flows flow together, we need to intersect |
||||||
|
* Constraints: All constraints are considered, a constraint |
||||||
|
* is taken, if it is implied by a constraint in the other list. |
||||||
|
* |
||||||
|
* -load operations copy local Constraint to stack Constraint. |
||||||
|
* -store operations copy stack Constraint to local Constraint. |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,424 @@ |
|||||||
|
/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
import jode.bytecode.*; |
||||||
|
import jode.AssertError; |
||||||
|
import jode.MethodType; |
||||||
|
import jode.Type; |
||||||
|
|
||||||
|
public class RemovePopAnalyzer implements CodeAnalyzer, Opcodes { |
||||||
|
MethodIdentifier m; |
||||||
|
BytecodeInfo bytecode; |
||||||
|
|
||||||
|
public RemovePopAnalyzer(BytecodeInfo bytecode, MethodIdentifier m) { |
||||||
|
this.m = m; |
||||||
|
this.bytecode = bytecode; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads the opcodes out of the code info and determine its |
||||||
|
* references |
||||||
|
* @return an enumeration of the references. |
||||||
|
*/ |
||||||
|
public void analyzeCode() { |
||||||
|
} |
||||||
|
|
||||||
|
class PopInfo { |
||||||
|
int firstPop = 0; |
||||||
|
int[] pops; |
||||||
|
Instruction nextInstr; |
||||||
|
} |
||||||
|
|
||||||
|
Instruction findMatchingPush(Instruction instr) { |
||||||
|
int count = 0; |
||||||
|
while (true) { |
||||||
|
if (instr.preds.size() != 1) |
||||||
|
return null; |
||||||
|
instr = instr.prevByAddr; |
||||||
|
switch (instr.opcode) { |
||||||
|
case opc_ldc2_w: |
||||||
|
case opc_lload: case opc_dload: |
||||||
|
if (count < 2) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count -= 2; |
||||||
|
break; |
||||||
|
case opc_ldc: |
||||||
|
case opc_iload: case opc_fload: case opc_aload: |
||||||
|
case opc_new: |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
count --; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_iaload: case opc_faload: case opc_aaload: |
||||||
|
case opc_baload: case opc_caload: case opc_saload: |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
count++; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_dup: case opc_dup_x1: case opc_dup_x2: { |
||||||
|
/* XXX This is a very special case, if we pop a value |
||||||
|
* that is dupped we can omit the dup; it doesn't matter |
||||||
|
* if we pop the dupped value or the original value. |
||||||
|
*/ |
||||||
|
int depth = (instr.opcode - opc_dup); |
||||||
|
if (count < 2 + depth) |
||||||
|
return (count == 0 || count == depth+1) ? instr : null; |
||||||
|
count --; |
||||||
|
break; |
||||||
|
} |
||||||
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: { |
||||||
|
int depth = (instr.opcode - opc_dup2); |
||||||
|
if (count < 4 + depth) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count -= 2; |
||||||
|
break; |
||||||
|
} |
||||||
|
case opc_swap: |
||||||
|
case opc_lneg: case opc_dneg: |
||||||
|
case opc_l2d: case opc_d2l: |
||||||
|
case opc_laload: case opc_daload: |
||||||
|
if (count < 2) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
break; |
||||||
|
case opc_ineg: case opc_fneg: |
||||||
|
case opc_i2f: case opc_f2i: |
||||||
|
case opc_i2b: case opc_i2c: case opc_i2s: |
||||||
|
case opc_newarray: case opc_anewarray: |
||||||
|
case opc_arraylength: |
||||||
|
case opc_checkcast: |
||||||
|
case opc_instanceof: |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
break; |
||||||
|
case opc_iadd: case opc_fadd: |
||||||
|
case opc_isub: case opc_fsub: |
||||||
|
case opc_imul: case opc_fmul: |
||||||
|
case opc_idiv: case opc_fdiv: |
||||||
|
case opc_irem: case opc_frem: |
||||||
|
case opc_iand: case opc_ior : case opc_ixor: |
||||||
|
case opc_ishl: case opc_ishr: case opc_iushr: |
||||||
|
case opc_fcmpl: case opc_fcmpg: |
||||||
|
case opc_l2i: case opc_l2f: |
||||||
|
case opc_d2i: case opc_d2f: |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
count++; |
||||||
|
break; |
||||||
|
case opc_ladd: case opc_dadd: |
||||||
|
case opc_lsub: case opc_dsub: |
||||||
|
case opc_lmul: case opc_dmul: |
||||||
|
case opc_ldiv: case opc_ddiv: |
||||||
|
case opc_lrem: case opc_drem: |
||||||
|
case opc_land: case opc_lor : case opc_lxor: |
||||||
|
if (count < 2) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count += 2; |
||||||
|
break; |
||||||
|
case opc_lshl: case opc_lshr: case opc_lushr: |
||||||
|
if (count < 2) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count++; |
||||||
|
break; |
||||||
|
case opc_i2l: case opc_i2d: |
||||||
|
case opc_f2l: case opc_f2d: |
||||||
|
if (count < 2) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count--; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_lcmp: |
||||||
|
case opc_dcmpl: case opc_dcmpg: |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
count += 3; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_invokevirtual: |
||||||
|
case opc_invokespecial: |
||||||
|
case opc_invokestatic: |
||||||
|
case opc_invokeinterface: { |
||||||
|
Reference ref = (Reference) instr.objData; |
||||||
|
MethodType mt = (MethodType) Type.tType(ref.getType()); |
||||||
|
if (count < mt.getReturnType().stackSize()) |
||||||
|
return (count == 0) ? instr : null; |
||||||
|
count -= mt.getReturnType().stackSize(); |
||||||
|
if (instr.opcode != opc_invokestatic) |
||||||
|
count++; |
||||||
|
for (int i = mt.getParameterTypes().length-1; i >= 0; i--) |
||||||
|
count += mt.getParameterTypes()[i].stackSize(); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
case opc_getstatic: |
||||||
|
case opc_getfield: { |
||||||
|
Reference ref = (Reference) instr.objData; |
||||||
|
int size = Type.tType(ref.getType()).stackSize(); |
||||||
|
if (count < size) |
||||||
|
return count == 0 ? instr : null; |
||||||
|
count -= size; |
||||||
|
if (instr.opcode == opc_getfield) |
||||||
|
count++; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
case opc_multianewarray: { |
||||||
|
if (count == 0) |
||||||
|
return instr; |
||||||
|
int dims = instr.prevByAddr.intData; |
||||||
|
count += dims - 1; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
case opc_nop: |
||||||
|
case opc_iinc: |
||||||
|
break; |
||||||
|
case opc_putfield: |
||||||
|
count++; |
||||||
|
/* fall through */ |
||||||
|
case opc_putstatic: |
||||||
|
count += instr.objData instanceof Long |
||||||
|
|| instr.objData instanceof Double ? 2 : 1; |
||||||
|
break; |
||||||
|
case opc_monitorenter: |
||||||
|
case opc_monitorexit: |
||||||
|
case opc_istore: |
||||||
|
case opc_fstore: case opc_astore: |
||||||
|
case opc_pop: |
||||||
|
count ++; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_lstore: case opc_dstore: |
||||||
|
case opc_pop2: |
||||||
|
count += 2; |
||||||
|
break; |
||||||
|
|
||||||
|
case opc_iastore: |
||||||
|
case opc_fastore: case opc_aastore: |
||||||
|
case opc_bastore: case opc_castore: case opc_sastore: |
||||||
|
count += 3; |
||||||
|
break; |
||||||
|
case opc_lastore: case opc_dastore: |
||||||
|
count += 4; |
||||||
|
break; |
||||||
|
default: |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static Instruction shrinkPop(Instruction popInstr, int amount) { |
||||||
|
int newPop = popInstr.opcode - (opc_pop-1) - amount; |
||||||
|
if (newPop < 0) |
||||||
|
throw new jode.AssertError("pop1 on long or double"); |
||||||
|
if (newPop == 0) { |
||||||
|
Instruction nextInstr = popInstr.nextByAddr; |
||||||
|
popInstr.removeInstruction(); |
||||||
|
return nextInstr; |
||||||
|
} |
||||||
|
popInstr.opcode = opc_pop - 1 + newPop; |
||||||
|
return popInstr; |
||||||
|
} |
||||||
|
|
||||||
|
public BytecodeInfo stripCode() { |
||||||
|
Instruction instr = bytecode.getFirstInstr(); |
||||||
|
while (instr != null) { |
||||||
|
switch (instr.opcode) { |
||||||
|
case opc_nop: { |
||||||
|
Instruction nextInstr = instr.nextByAddr; |
||||||
|
instr.removeInstruction(); |
||||||
|
instr = nextInstr; |
||||||
|
continue; |
||||||
|
} |
||||||
|
case opc_pop: |
||||||
|
case opc_pop2: { |
||||||
|
Instruction prevInstr = findMatchingPush(instr); |
||||||
|
int opcode = prevInstr == null ? -1 : prevInstr.opcode; |
||||||
|
switch (opcode) { |
||||||
|
case opc_ldc2_w: |
||||||
|
case opc_lload: case opc_dload: |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
instr = shrinkPop(instr, 2); |
||||||
|
continue; |
||||||
|
case opc_ldc: |
||||||
|
case opc_iload: case opc_fload: case opc_aload: |
||||||
|
case opc_dup: |
||||||
|
case opc_new: |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
instr = shrinkPop(instr, 1); |
||||||
|
continue; |
||||||
|
case opc_iaload: case opc_faload: case opc_aaload: |
||||||
|
case opc_baload: case opc_caload: case opc_saload: |
||||||
|
/* We have to pop one entry more. */ |
||||||
|
prevInstr.opcode = opc_pop; |
||||||
|
instr = prevInstr; |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_dup_x1: |
||||||
|
prevInstr.opcode = opc_swap; |
||||||
|
instr = shrinkPop(instr, 1); |
||||||
|
continue; |
||||||
|
case opc_dup2: |
||||||
|
if (instr.opcode == opc_pop2) { |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
} else |
||||||
|
prevInstr.opcode = opc_dup; |
||||||
|
instr = instr.nextByAddr; |
||||||
|
instr.prevByAddr.removeInstruction(); |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_lneg: case opc_dneg: |
||||||
|
case opc_l2d: case opc_d2l: |
||||||
|
case opc_laload: case opc_daload: |
||||||
|
if (instr.opcode != opc_pop2) |
||||||
|
break; |
||||||
|
/* fall through */ |
||||||
|
case opc_ineg: case opc_fneg: |
||||||
|
case opc_i2f: case opc_f2i: |
||||||
|
case opc_i2b: case opc_i2c: case opc_i2s: |
||||||
|
case opc_newarray: case opc_anewarray: |
||||||
|
case opc_arraylength: |
||||||
|
case opc_instanceof: |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_iadd: case opc_fadd: |
||||||
|
case opc_isub: case opc_fsub: |
||||||
|
case opc_imul: case opc_fmul: |
||||||
|
case opc_idiv: case opc_fdiv: |
||||||
|
case opc_irem: case opc_frem: |
||||||
|
case opc_iand: case opc_ior : case opc_ixor: |
||||||
|
case opc_ishl: case opc_ishr: case opc_iushr: |
||||||
|
case opc_fcmpl: case opc_fcmpg: |
||||||
|
case opc_l2i: case opc_l2f: |
||||||
|
case opc_d2i: case opc_d2f: |
||||||
|
prevInstr.opcode = opc_pop2; |
||||||
|
shrinkPop(instr, 1); |
||||||
|
instr = prevInstr; |
||||||
|
continue; |
||||||
|
case opc_ladd: case opc_dadd: |
||||||
|
case opc_lsub: case opc_dsub: |
||||||
|
case opc_lmul: case opc_dmul: |
||||||
|
case opc_ldiv: case opc_ddiv: |
||||||
|
case opc_lrem: case opc_drem: |
||||||
|
case opc_land: case opc_lor : case opc_lxor: |
||||||
|
if (instr.opcode != opc_pop2) |
||||||
|
break; |
||||||
|
prevInstr.opcode = opc_pop2; |
||||||
|
instr = prevInstr; |
||||||
|
continue; |
||||||
|
case opc_lshl: case opc_lshr: case opc_lushr: |
||||||
|
if (instr.opcode != opc_pop2) |
||||||
|
break; |
||||||
|
prevInstr.opcode = opc_pop; |
||||||
|
instr = prevInstr; |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_i2l: case opc_i2d: |
||||||
|
case opc_f2l: case opc_f2d: |
||||||
|
if (instr.opcode != opc_pop2) |
||||||
|
break; |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
instr.opcode = opc_pop; |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_lcmp: |
||||||
|
case opc_dcmpl: case opc_dcmpg: |
||||||
|
prevInstr.opcode = opc_pop2; |
||||||
|
if (instr.opcode == opc_pop) |
||||||
|
instr.opcode = opc_pop2; |
||||||
|
else { |
||||||
|
Instruction thirdPop = instr.appendInstruction(false); |
||||||
|
thirdPop.length = 1; |
||||||
|
thirdPop.opcode = opc_pop; |
||||||
|
} |
||||||
|
instr = prevInstr; |
||||||
|
continue; |
||||||
|
|
||||||
|
case opc_getstatic: |
||||||
|
case opc_getfield: { |
||||||
|
Reference ref = (Reference) prevInstr.objData; |
||||||
|
int count = Type.tType(ref.getType()).stackSize(); |
||||||
|
if (prevInstr.opcode == opc_getfield) |
||||||
|
count--; |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
if (count > 0) |
||||||
|
instr = shrinkPop(instr, count); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
case opc_multianewarray: { |
||||||
|
int dims = prevInstr.intData; |
||||||
|
prevInstr.removeInstruction(); |
||||||
|
if (dims == 0) |
||||||
|
instr = shrinkPop(instr, 1); |
||||||
|
else { |
||||||
|
dims--; |
||||||
|
while (dims > 0) { |
||||||
|
Instruction aPop = instr.insertInstruction(); |
||||||
|
aPop.length = 1; |
||||||
|
aPop.opcode = opc_pop; |
||||||
|
dims--; |
||||||
|
instr = aPop; |
||||||
|
} |
||||||
|
} |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
case opc_invokevirtual: |
||||||
|
case opc_invokespecial: |
||||||
|
case opc_invokestatic: |
||||||
|
case opc_invokeinterface: |
||||||
|
if (((MethodType) |
||||||
|
Type.tType(((Reference) prevInstr.objData).getType())) |
||||||
|
.getReturnType().stackSize() != 1) |
||||||
|
break; |
||||||
|
/* fall through */ |
||||||
|
case opc_checkcast: |
||||||
|
case -1: |
||||||
|
if (instr.opcode == opc_pop2) { |
||||||
|
/* This is/may be a double pop on a single value |
||||||
|
* split it and continue with second half |
||||||
|
*/ |
||||||
|
instr.opcode = opc_pop; |
||||||
|
instr = instr.appendInstruction(false); |
||||||
|
instr.opcode = opc_pop; |
||||||
|
instr.length = 1; |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
if (instr.opcode == opc_pop |
||||||
|
&& instr.prevByAddr.opcode == opc_pop) { |
||||||
|
/* merge two single pops together. */ |
||||||
|
instr.prevByAddr.removeInstruction(); |
||||||
|
instr.opcode = opc_pop2; |
||||||
|
} |
||||||
|
/* Cant do anything with this pop */ |
||||||
|
} |
||||||
|
/* fall through */ |
||||||
|
default: |
||||||
|
instr = instr.nextByAddr; |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
return bytecode; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,125 @@ |
|||||||
|
/* SimpleAnalyzer Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
import jode.bytecode.*; |
||||||
|
import jode.Type; |
||||||
|
|
||||||
|
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { |
||||||
|
MethodIdentifier m; |
||||||
|
BytecodeInfo bytecode; |
||||||
|
|
||||||
|
public SimpleAnalyzer(BytecodeInfo bytecode,MethodIdentifier m) { |
||||||
|
this.m = m; |
||||||
|
this.bytecode = bytecode; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads the opcodes out of the code info and determine its |
||||||
|
* references |
||||||
|
* @return an enumeration of the references. |
||||||
|
*/ |
||||||
|
public void analyzeCode() { |
||||||
|
for (Instruction instr = bytecode.getFirstInstr(); |
||||||
|
instr != null; instr = instr.nextByAddr) { |
||||||
|
switch (instr.opcode) { |
||||||
|
case opc_new: |
||||||
|
case opc_anewarray: |
||||||
|
case opc_checkcast: |
||||||
|
case opc_instanceof: |
||||||
|
case opc_multianewarray: { |
||||||
|
String clName = (String) instr.objData; |
||||||
|
if (clName.charAt(0) == '[') { |
||||||
|
int i; |
||||||
|
for (i=0; i< clName.length(); i++) |
||||||
|
if (clName.charAt(i) != '[') |
||||||
|
break; |
||||||
|
if (i >= clName.length() || clName.charAt(i) != 'L') |
||||||
|
break; |
||||||
|
int index = clName.indexOf(';', i); |
||||||
|
if (index != clName.length()-1) |
||||||
|
break; |
||||||
|
clName = clName.substring(i+1, index); |
||||||
|
} |
||||||
|
m.clazz.bundle.reachableIdentifier(clName, false); |
||||||
|
break; |
||||||
|
} |
||||||
|
case opc_getstatic: |
||||||
|
case opc_getfield: |
||||||
|
case opc_invokespecial: |
||||||
|
case opc_invokestatic: |
||||||
|
case opc_invokeinterface: |
||||||
|
case opc_invokevirtual: { |
||||||
|
Reference ref = (Reference) instr.objData; |
||||||
|
m.clazz.bundle.reachableIdentifier |
||||||
|
(ref.getClazz()+"."+ref.getName()+"."+ref.getType(), |
||||||
|
instr.opcode == opc_invokevirtual |
||||||
|
|| instr.opcode == opc_invokeinterface); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Handler[] handlers = bytecode.getExceptionHandlers(); |
||||||
|
for (int i=0; i< handlers.length; i++) { |
||||||
|
if (handlers[i].type != null) |
||||||
|
m.clazz.bundle.reachableIdentifier(handlers[i].type, false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public BytecodeInfo stripCode() { |
||||||
|
for (Instruction instr = bytecode.getFirstInstr(); |
||||||
|
instr != null; instr = instr.nextByAddr) { |
||||||
|
if (instr.opcode == opc_putstatic |
||||||
|
|| instr.opcode == opc_putfield) { |
||||||
|
Reference ref = (Reference) instr.objData; |
||||||
|
ClassIdentifier ci = (ClassIdentifier) |
||||||
|
m.clazz.bundle.getIdentifier(ref.getClazz()); |
||||||
|
if (ci != null) { |
||||||
|
FieldIdentifier fi = (FieldIdentifier) |
||||||
|
ci.getIdentifier(ref.getName(), ref.getType()); |
||||||
|
if (jode.Obfuscator.shouldStrip && !fi.isReachable()) { |
||||||
|
/* Replace instruction with pop opcodes. */ |
||||||
|
int stacksize = |
||||||
|
(instr.opcode |
||||||
|
== Instruction.opc_putstatic) ? 0 : 1; |
||||||
|
stacksize += Type.tType(ref.getType()).stackSize(); |
||||||
|
if (stacksize == 3) { |
||||||
|
/* Add a pop instruction after this opcode. */ |
||||||
|
Instruction second = new Instruction(bytecode); |
||||||
|
second.addr = instr.addr+1; |
||||||
|
second.length = 1; |
||||||
|
second.opcode = Instruction.opc_pop; |
||||||
|
second.nextByAddr = instr.nextByAddr; |
||||||
|
instr.nextByAddr = second; |
||||||
|
second.nextByAddr.preds.removeElement(instr); |
||||||
|
second.nextByAddr.preds.addElement(second); |
||||||
|
stacksize--; |
||||||
|
} |
||||||
|
instr.objData = null; |
||||||
|
instr.intData = 0; |
||||||
|
instr.opcode = Instruction.opc_pop - 1 + stacksize; |
||||||
|
instr.length = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return bytecode; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/* WildCard Copyright (C) 1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation; either version 2, or (at your option) |
||||||
|
* any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.obfuscator; |
||||||
|
|
||||||
|
public class WildCard { |
||||||
|
|
||||||
|
public static boolean matches(String wildcard, String test) { |
||||||
|
int indexWild = wildcard.indexOf('*'); |
||||||
|
if (indexWild == -1) |
||||||
|
return wildcard.equals(test); |
||||||
|
if (!test.startsWith(wildcard.substring(0, indexWild))) |
||||||
|
return false; |
||||||
|
|
||||||
|
test = test.substring(indexWild); |
||||||
|
int nextWild; |
||||||
|
while ((nextWild = wildcard.indexOf('*', indexWild + 1)) != -1) { |
||||||
|
String pattern = wildcard.substring(indexWild+1, nextWild); |
||||||
|
while (!test.startsWith(pattern)) |
||||||
|
test = test.substring(1); |
||||||
|
test = test.substring(nextWild - indexWild); |
||||||
|
indexWild = nextWild; |
||||||
|
} |
||||||
|
|
||||||
|
return test.endsWith(wildcard.substring(indexWild+1)); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue