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/obfuscator/SimpleAnalyzer.java

176 lines
5.4 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;
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.GlobalOptions;
import jode.type.Type;
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
public Identifier canonizeReference(Instruction instr) {
Reference ref = (Reference) instr.objData;
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.opcode >= 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.objData = 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 (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
switch (instr.opcode) {
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray: {
String clName = (String) instr.objData;
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);
Main.getClassBundle().reachableIdentifier(clName, false);
}
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.opcode == opc_putstatic
|| instr.opcode == opc_putfield) {
FieldIdentifier fi = (FieldIdentifier) ident;
if (fi != null && !fi.isNotConstant())
fi.setNotConstant();
} else if (instr.opcode == opc_invokevirtual
|| instr.opcode == opc_invokeinterface) {
((ClassIdentifier) ident.getParent())
.reachableIdentifier(ident.getName(),
ident.getType(), true);
} else {
ident.setReachable();
}
}
break;
}
}
}
Handler[] handlers = bytecode.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].type != null)
Main.getClassBundle()
.reachableIdentifier(handlers[i].type, false);
}
}
public void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
if (instr.opcode == opc_putstatic
|| instr.opcode == opc_putfield) {
Reference ref = (Reference) instr.objData;
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.opcode
== Instruction.opc_putstatic) ? 0 : 1;
stacksize += Type.tType(ref.getType()).stackSize();
if (stacksize == 3) {
/* Add a pop instruction after this opcode. */
Instruction second = instr.appendInstruction();
second.length = 1;
second.opcode = Instruction.opc_pop;
stacksize--;
}
instr.objData = null;
instr.intData = 0;
instr.opcode = Instruction.opc_pop - 1 + stacksize;
instr.length = 1;
}
}
}
}
}