Initial revision

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@500 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent c0c72ebfec
commit 20091fa56d
  1. 89
      jode/jode/bytecode/Reference.java
  2. 26
      jode/jode/obfuscator/CodeAnalyzer.java
  3. 1267
      jode/jode/obfuscator/ConstantAnalyzer.java
  4. 35
      jode/jode/obfuscator/FieldListener.java
  5. 47
      jode/jode/obfuscator/IdentifierEvent.java
  6. 34
      jode/jode/obfuscator/IdentifierListener.java
  7. 224
      jode/jode/obfuscator/LogicalDeadCodeOptimizer.java
  8. 424
      jode/jode/obfuscator/RemovePopAnalyzer.java
  9. 125
      jode/jode/obfuscator/SimpleAnalyzer.java
  10. 43
      jode/jode/obfuscator/WildCard.java

@ -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…
Cancel
Save