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.
201 lines
6.1 KiB
201 lines
6.1 KiB
/* 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.modules;
|
|
import jode.bytecode.Handler;
|
|
import jode.bytecode.Opcodes;
|
|
import jode.bytecode.ClassInfo;
|
|
import jode.bytecode.BytecodeInfo;
|
|
import jode.bytecode.Instruction;
|
|
import jode.bytecode.Reference;
|
|
import jode.bytecode.TypeSignature;
|
|
import jode.obfuscator.Identifier;
|
|
import jode.obfuscator.*;
|
|
import jode.GlobalOptions;
|
|
|
|
import @COLLECTIONS@.Iterator;
|
|
import @COLLECTIONS@.ListIterator;
|
|
|
|
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
|
|
|
|
private ClassInfo canonizeIfaceRef(ClassInfo clazz, Reference ref) {
|
|
while (clazz != null) {
|
|
if (clazz.findMethod(ref.getName(), ref.getType()) != null)
|
|
return clazz;
|
|
ClassInfo[] ifaces = clazz.getInterfaces();
|
|
for (int i = 0; i < ifaces.length; i++) {
|
|
ClassInfo realClass = canonizeIfaceRef(ifaces[i], ref);
|
|
if (realClass != null)
|
|
return realClass;
|
|
}
|
|
clazz = clazz.getSuperclass();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Identifier canonizeReference(Instruction instr) {
|
|
Reference ref = instr.getReference();
|
|
Identifier ident = Main.getClassBundle().getIdentifier(ref);
|
|
String clName = ref.getClazz();
|
|
String realClazzName;
|
|
if (ident != null) {
|
|
ClassIdentifier clazz = (ClassIdentifier)ident.getParent();
|
|
realClazzName = "L" + (clazz.getFullName()
|
|
.replace('.', '/')) + ";";
|
|
} else {
|
|
/* We have to look at the ClassInfo's instead, to
|
|
* point to the right method.
|
|
*/
|
|
ClassInfo clazz;
|
|
if (clName.charAt(0) == '[') {
|
|
/* Arrays don't define new methods (well clone(),
|
|
* but that can be ignored).
|
|
*/
|
|
clazz = ClassInfo.javaLangObject;
|
|
} else {
|
|
clazz = ClassInfo.forName
|
|
(clName.substring(1, clName.length()-1)
|
|
.replace('/','.'));
|
|
}
|
|
if (instr.getOpcode() == opc_invokeinterface) {
|
|
clazz = canonizeIfaceRef(clazz, ref);
|
|
} else if (instr.getOpcode() >= opc_invokevirtual) {
|
|
while (clazz != null
|
|
&& clazz.findMethod(ref.getName(),
|
|
ref.getType()) == null)
|
|
clazz = clazz.getSuperclass();
|
|
} else {
|
|
while (clazz != null
|
|
&& clazz.findField(ref.getName(),
|
|
ref.getType()) == null)
|
|
clazz = clazz.getSuperclass();
|
|
}
|
|
|
|
if (clazz == null) {
|
|
GlobalOptions.err.println("WARNING: Can't find reference: "
|
|
+ref);
|
|
realClazzName = clName;
|
|
} else
|
|
realClazzName = "L" + clazz.getName().replace('.', '/') + ";";
|
|
}
|
|
if (!realClazzName.equals(ref.getClazz())) {
|
|
ref = Reference.getReference(realClazzName,
|
|
ref.getName(), ref.getType());
|
|
instr.setReference(ref);
|
|
}
|
|
return ident;
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads the opcodes out of the code info and determine its
|
|
* references
|
|
* @return an enumeration of the references.
|
|
*/
|
|
public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) {
|
|
for (Iterator iter = bytecode.getInstructions().iterator();
|
|
iter.hasNext(); ) {
|
|
Instruction instr = (Instruction) iter.next();
|
|
switch (instr.getOpcode()) {
|
|
case opc_checkcast:
|
|
case opc_instanceof:
|
|
case opc_multianewarray: {
|
|
String clName = instr.getClazzType();
|
|
int i = 0;
|
|
while (i < clName.length() && clName.charAt(i) == '[')
|
|
i++;
|
|
if (i < clName.length() && clName.charAt(i) == 'L') {
|
|
clName = clName.substring(i+1, clName.length()-1)
|
|
.replace('/','.');
|
|
Main.getClassBundle().reachableClass(clName);
|
|
}
|
|
break;
|
|
}
|
|
case opc_invokespecial:
|
|
case opc_invokestatic:
|
|
case opc_invokeinterface:
|
|
case opc_invokevirtual:
|
|
case opc_putstatic:
|
|
case opc_putfield:
|
|
m.setGlobalSideEffects();
|
|
/* fall through */
|
|
case opc_getstatic:
|
|
case opc_getfield: {
|
|
Identifier ident = canonizeReference(instr);
|
|
if (ident != null) {
|
|
if (instr.getOpcode() == opc_putstatic
|
|
|| instr.getOpcode() == opc_putfield) {
|
|
FieldIdentifier fi = (FieldIdentifier) ident;
|
|
if (fi != null && !fi.isNotConstant())
|
|
fi.setNotConstant();
|
|
} else if (instr.getOpcode() == opc_invokevirtual
|
|
|| instr.getOpcode() == opc_invokeinterface) {
|
|
((ClassIdentifier) ident.getParent())
|
|
.reachableReference(instr.getReference(), true);
|
|
} else {
|
|
ident.setReachable();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Handler[] handlers = bytecode.getExceptionHandlers();
|
|
for (int i=0; i< handlers.length; i++) {
|
|
if (handlers[i].type != null)
|
|
Main.getClassBundle()
|
|
.reachableClass(handlers[i].type);
|
|
}
|
|
}
|
|
|
|
public void transformCode(BytecodeInfo bytecode) {
|
|
for (ListIterator iter = bytecode.getInstructions().listIterator();
|
|
iter.hasNext(); ) {
|
|
Instruction instr = (Instruction) iter.next();
|
|
if (instr.getOpcode() == opc_putstatic
|
|
|| instr.getOpcode() == opc_putfield) {
|
|
Reference ref = instr.getReference();
|
|
FieldIdentifier fi = (FieldIdentifier)
|
|
Main.getClassBundle().getIdentifier(ref);
|
|
if (fi != null
|
|
&& (Main.stripping & Main.STRIP_UNREACH) != 0
|
|
&& !fi.isReachable()) {
|
|
/* Replace instruction with pop opcodes. */
|
|
int stacksize =
|
|
(instr.getOpcode()
|
|
== Instruction.opc_putstatic) ? 0 : 1;
|
|
stacksize += TypeSignature.getTypeSize(ref.getType());
|
|
switch (stacksize) {
|
|
case 1:
|
|
iter.set(new Instruction(Instruction.opc_pop));
|
|
break;
|
|
case 2:
|
|
iter.set(new Instruction(Instruction.opc_pop2));
|
|
break;
|
|
case 3:
|
|
iter.set(new Instruction(Instruction.opc_pop2));
|
|
iter.add(new Instruction(Instruction.opc_pop));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|