diff --git a/jode/.cvsignore b/jode/.cvsignore new file mode 100644 index 0000000..92379e3 --- /dev/null +++ b/jode/.cvsignore @@ -0,0 +1,9 @@ +Makefile +Makefile.in +configure +config.log +config.cache +config.status +stamp-h +libtool +aclocal.m4 diff --git a/jode/AUTHORS b/jode/AUTHORS new file mode 100644 index 0000000..fc38b9f --- /dev/null +++ b/jode/AUTHORS @@ -0,0 +1 @@ +Jochen Hoenicke \ No newline at end of file diff --git a/jode/ChangeLog b/jode/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/jode/INSTALL b/jode/INSTALL new file mode 100644 index 0000000..2aafeea --- /dev/null +++ b/jode/INSTALL @@ -0,0 +1,33 @@ +Before installing, make sure you have a java compiler (e.g javac or +jikes) and the java 1.1 runtime class library installed. If you want +to run this program you need at least a 1.1 compatible java virtual +machine. There are some bugs in javac included in the SUN JDK 1.1, it +won't work. + +This package was designed to use the GNU standard for configuration +and makefiles. To build and install do the following: + +0). Make sure that you have all libraries that are needed in you +classpath. You need gnu.getopt, and if you have JDK 1.1 you also need +the collection classes and swing for 1.1. + +1). Run "aclocal && autoconf && automake --add-missing". + +2). Run the "configure" script to configure the package. There are +various options you might want to pass to configure to control how the +package is built. "configure --help" will give a complete list. + +If you have jikes, you should specify it with --with-jikes. You can +give a path to the directory where it resides, otherwise it is +searched in the path. + +3). Type "make" to build the package. If you don't have jikes, you +should make clean first, since the dependency problem is not yet +resolved. + +4). Type "make install" to install everything. This doesn't work yet. + +The created jar file is stored in the share directory. + + Jochen + diff --git a/jode/Makefile.am b/jode/Makefile.am new file mode 100644 index 0000000..b0ee681 --- /dev/null +++ b/jode/Makefile.am @@ -0,0 +1,5 @@ +## Input file for automake to generate the Makefile.in used by configure + +SUBDIRS = jode bin doc test + +EXTRA_DIST = TODO diff --git a/jode/NEWS b/jode/NEWS new file mode 100644 index 0000000..de761b2 --- /dev/null +++ b/jode/NEWS @@ -0,0 +1,10 @@ +1.0.90 is a prerelease.. +* First version using configure. Jode can now be almost automatically + build, see INSTALL for instructions. +* The decompiler can handler inner and anoymous classes. +* You now need the gnu getopt package. +* You need JDK 1.2 or alternatively the swing and collection packages + for 1.1 + + + diff --git a/jode/README b/jode/README new file mode 100644 index 0000000..c3f70f8 --- /dev/null +++ b/jode/README @@ -0,0 +1,106 @@ +takes class-files as input and produces something similar to the +original java-File. Of course this can't be perfect: There is no way +to produce the comments or the names of local variables (except when +compiled with -g) and there are often more ways to write +the same thing. But it does its job quite well.

+ +

Quick Test

+I have now an applet interface to the decompiler. +Check it out. + +

How to get it

+

You can donwload the files in zip form. +The sources contain only the +java files, the classes +contain only the class files.

+ +

I also have a tar.gz file containing only +the RCS directories. This is the form I maintain the +project, but you probably need unix and a few tools to use them.

+ +

There are also some snapshots that have new +features like inner and anonymous classes.

+ +

Click here to browse the files online. +

+ + + +

How to use it

+ +

I have some simple step by step pages. There are three +possibilities: +

+ +

Known bugs

+ +

There may be situations, where the code doesn't understand complex +expressions. In this many ugly temporary variables are used, but the +code should still be compileable. This does especially happen when +you compile with `-O' flag and javac has inlined some methods.

+ +

Sometimes this program may exit with an Exception or +produce incorrect code. Most time the code can't be compiled, so that +it can be easily spotted. If you have one of these problems (except +those that occur on some of the jode.test files, I would +be very interested in a bug report (including the class +file, if possible).

+ +

Sometimes it generates some GOTO expression and +labels. This can't be compiled, but shouldn't happen any more with +javac or jikes.

+ +

It doesn't handle inner and anonymous classes, yet. You can +decompile them separately, though (use `+$' switch under +jikes), but there is a bug in javac, so that a final variable is twice +initialized. If you encounter this problem just remove the doubled +line by hand.

+ +

New! The latest snapshot can handle +inner and anonymous classes.

+ + +

Why did I wrote it?

+ +

Someday I found guavad, a disassembler for java byte +code (it does similar things like javap -c). I used +it on a class file, and found that it was possible to reconstruct the +original java code. First I did it by hand on some small routines, +but I soon realized that it was a rather stupid task, and that I could +write a perl script +that does the same. At the end of the next day I had a working +decompiler.

+ +

Now while it was working, it was not easy to use. You had to +decompile the code first with a disassembler, cut the method, you +wanted to decompile and then run the perl script on it. So I decided +to get some information of the class files and do this all +automatically. I decided to write it in java now, +because it suited best.

+ +

Just for the records: the java code is now more than 50 times +bigger than the original perl script and is still growing.

+ +

License

+ +

This code is under GNU GPL. That basically means, that you can copy +or modify this code, as long as you put all your modification under +the GPL again. Look +here for the complete license.

+ +
+ +

+http://www.informatik.uni-oldenburg.de/~delwi/jode/jode.html, last +updated on 17-Jun-1999.

+ + + diff --git a/jode/acinclude.m4 b/jode/acinclude.m4 new file mode 100644 index 0000000..8434847 --- /dev/null +++ b/jode/acinclude.m4 @@ -0,0 +1,44 @@ +dnl +dnl Add macros +dnl JODE_CHECK_JAVA +dnl + +dnl JODE_CHECK_JAVA(path) +AC_DEFUN(JODE_CHECK_JAVA, +[ + AC_PATH_PROG(JAVA, java, "", $1/bin:$1/jre/bin:$PATH) + AC_PATH_PROG(JAVAC, javac, "", $1/bin:$PATH) + AC_PATH_PROG(JAR, jar, "", $1/bin:$PATH) + for path in $1/lib $1/jre/lib $1/shared; do + for classlib in classes.zip rt.jar; do + AC_CHECK_FILES($path/$classlib, + [ CLASSLIB=$path/$classlib + break 3 + ], [ true ]) + done + done + AC_SUBST(CLASSPATH) + AC_SUBST(CLASSLIB) +]) + +AC_DEFUN(JODE_CHECK_CLASS, +[ + if (IFS=":" + clazz=`echo $1 | sed -e 's/\./\//g' -e 's/\(.*\)/\1.class/'` + jode_found=0 + for path in $2; do + if test -d $path; then + if test -e $path/$clazz; then + exit 0 + fi + elif $UNZIP -v -C $path $clazz &>/dev/null ; then + exit 0 + fi + done; + exit 1) + then + $3 + else + $4 + fi +]) diff --git a/jode/bin/.cvsignore b/jode/bin/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/bin/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/bin/Makefile.am b/jode/bin/Makefile.am new file mode 100644 index 0000000..da0c744 --- /dev/null +++ b/jode/bin/Makefile.am @@ -0,0 +1,4 @@ +## Input file for automake to generate the Makefile.in used by configure + +bin_SCRIPTS = jode + diff --git a/jode/bin/jode.in b/jode/bin/jode.in new file mode 100644 index 0000000..75bad3b --- /dev/null +++ b/jode/bin/jode.in @@ -0,0 +1,14 @@ +#!@SHELL@ +prefix=@prefix@ + +case $1 in + [Ss]wi*) CLAZZ=jode.swingui.Main; shift ;; + [Dd]ec*) CLAZZ=jode.Decompiler; shift ;; + [Oo]bf*) CLAZZ=jode.obfuscator.Main; shift ;; + *) CLAZZ=jode.Decompiler ;; +esac + + +CP=`echo $CLASSPATH | sed s/:/,/` +CLASSPATH=@datadir@/jode-@VERSION@.jar:@CLASSPATH@ \ +@JAVA@ $CLAZZ --classpath $CP $* diff --git a/jode/configure.in b/jode/configure.in new file mode 100644 index 0000000..75fb50e --- /dev/null +++ b/jode/configure.in @@ -0,0 +1,139 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT() + +AM_INIT_AUTOMAKE(jode, 1.0.90) + +dnl Checks for programs. +dnl AC_PROG_CXX +dnl AC_PROG_AWK +dnl AC_PROG_CC +dnl AC_PROG_CPP +dnl AC_PROG_INSTALL +dnl AC_PROG_LN_S +AC_PROG_MAKE_SET +dnl AC_PROG_RANLIB +dnl AC_PATH_PROG(ZIP, zip) +AC_PATH_PROG(UNZIP, unzip) + +dnl Checks for libraries. + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. + +dnl Checks for library functions. + +dnl hack to quote Makefile lines +QUOTE="" +AC_SUBST(QUOTE) + +AC_SUBST(SHELL) + +AC_ARG_WITH(java, + [ --with-java specify path to a java-like program ], + [ + if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then + # set javac to user input value + JODE_CHECK_JAVA(${withval}) + else + JODE_CHECK_JAVA(/usr/lib/java) + fi + ], + [ + JODE_CHECK_JAVA(/usr/lib/java) + ]) + +dnl jikes can also handle dependancies. +AC_ARG_WITH(jikes, +[ --with-jikes specify location of jikes ], +[ + USER_SPECIFIED_JIKES=true + if test "${withval}" = "yes" || test "${withval}" = ""; then + AC_PATH_PROG(JIKES, jikes, "", $PATH) + else + echo "searching jikes in ${withval}:$PATH" + AC_PATH_PROG(JIKES, jikes, "", ${withval}:$PATH) + fi + if test -n "$JIKES"; then + JAVAC=$JIKES + fi +], +[ + USER_SPECIFIED_JIKES= + AC_PATH_PROG(JIKES, jikes, "", $PATH) +]) +AM_CONDITIONAL(HAVE_JIKES, test x"$JIKES" != x) + +AC_ARG_WITH(javac, + [ --with-javac specify location of javac ], + [ + if test x$USER_SPECIFIED_JIKES == xtrue; then + AC_MSG_ERROR(You must only give one option --with-javac or --with-jikes) + fi + if test ${withval} != "" || test ${withval} != "yes" || test ${withval} != "no"; then + AC_CHECK_FILES(${withval}, + [ JAVAC=${withval} ], + [ AC_MSG_ERROR(${withval} does not exists) ]) + fi +], [ true ]) + +JODE_CHECK_CLASS(java.lang.Object, $CLASSLIB, + [ true ], + [ AC_MSG_ERROR(Please specify location of java class library for jikes) ]) + +AC_MSG_CHECKING(for collection classes) +JODE_CHECK_CLASS(java.util.Set, $CLASSPATH:$CLASSLIB, + [ COLLECTIONS="java.util" ], + [ JODE_CHECK_CLASS(com.sun.java.util.collections.Set, $CLASSPATH:$CLASSLIB, + [ COLLECTIONS="com.sun.java.util.collections" ], + [ AC_MSG_RESULT(no) + AC_MSG_ERROR(You need the Java 1.2 collection classes in your classpath) + ]) + ] ) +AC_MSG_RESULT($COLLECTIONS) +AC_SUBST(COLLECTIONS) + +AC_MSG_CHECKING(for gnu.getopt) +JODE_CHECK_CLASS(gnu.getopt.Getopt, $CLASSPATH:$CLASSLIB, + [ AC_MSG_RESULT(yes) ], + [ AC_MSG_RESULT(no) + AC_MSG_ERROR(You need gnu getopt for java.) ]) + +AC_MSG_CHECKING(for swing) +JODE_CHECK_CLASS(javax.swing.JFrame, $CLASSPATH:$CLASSLIB, + [ JAVAX_SWING="javax.swing" ], + [ JODE_CHECK_CLASS(com.sun.swing.JFrame, $CLASSPATH:$CLASSLIB, + [ JAVAX_SWING="com.sun.java.swing" ], + [ JAVAX_SWING="no" ]) ] ) +AC_MSG_RESULT($JAVAX_SWING) +AC_SUBST(JAVAX_SWING) +if test x"$JAVAX_SWING" != x; then + SWINGUI="swingui" +else + AC_MSG_WARN(Swing is not in classpath ... skipping swingui) + SWINGUI="" +fi +AC_SUBST(SWINGUI) + +AC_SUBST(CLASSPATH) +AC_SUBST(JAVAC) + +AC_OUTPUT(Makefile +jode/Makefile +jode/bytecode/Makefile +jode/decompiler/Makefile +jode/expr/Makefile +jode/flow/Makefile +jode/jvm/Makefile +jode/obfuscator/Makefile +jode/swingui/Makefile +jode/type/Makefile +jode/util/Makefile +jode/GlobalOptions.java +jode/swingui/Main.java +jode/swingui/PackagesTreeModel.java +bin/Makefile +bin/jode +doc/Makefile +test/Makefile) + diff --git a/jode/doc/.cvsignore b/jode/doc/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/doc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/doc/Makefile.am b/jode/doc/Makefile.am new file mode 100644 index 0000000..cc2d74b --- /dev/null +++ b/jode/doc/Makefile.am @@ -0,0 +1,5 @@ +## Input file for automake to generate the Makefile.in used by configure + +EXTRA_DIST = \ + jode.html jode-applet.html jode-obfuscator.html jode-unix.html \ + jode-useapplet.html jode-win.html diff --git a/jode/jode-applet.html b/jode/doc/jode-applet.html similarity index 88% rename from jode/jode-applet.html rename to jode/doc/jode-applet.html index 278effc..c71c73f 100644 --- a/jode/jode-applet.html +++ b/jode/doc/jode-applet.html @@ -5,11 +5,11 @@ -Home Up +Up

Test Applet

- + diff --git a/jode/jode-obfuscator.html b/jode/doc/jode-obfuscator.html similarity index 90% rename from jode/jode-obfuscator.html rename to jode/doc/jode-obfuscator.html index 0a9b43c..995c085 100644 --- a/jode/jode-obfuscator.html +++ b/jode/doc/jode-obfuscator.html @@ -4,6 +4,7 @@ Using the obfuscator +Up The obfuscator currently takes a lot of options (I plan to use an extra file containing the options). You should therefore create a diff --git a/jode/jode-unix.html b/jode/doc/jode-unix.html similarity index 98% rename from jode/jode-unix.html rename to jode/doc/jode-unix.html index ad4acf4..6371c53 100644 --- a/jode/jode-unix.html +++ b/jode/doc/jode-unix.html @@ -4,7 +4,8 @@ Using the decompiler under Unix -Home Up
+Up +

Step by Step

diff --git a/jode/jode-useapplet.html b/jode/doc/jode-useapplet.html similarity index 96% rename from jode/jode-useapplet.html rename to jode/doc/jode-useapplet.html index 5cf2c5f..24bcc3a 100644 --- a/jode/jode-useapplet.html +++ b/jode/doc/jode-useapplet.html @@ -4,7 +4,7 @@ Using the decompiler as applet (locally) -Home Up
+Up

Step by Step

diff --git a/jode/jode-win.html b/jode/doc/jode-win.html similarity index 97% rename from jode/jode-win.html rename to jode/doc/jode-win.html index c5f9aa6..99d9927 100644 --- a/jode/jode-win.html +++ b/jode/doc/jode-win.html @@ -4,7 +4,7 @@ Using the decompiler under Windows -Home Up
+Up

Step by Step

diff --git a/jode/jode.html b/jode/doc/jode.html similarity index 97% rename from jode/jode.html rename to jode/doc/jode.html index 435e923..38175bd 100644 --- a/jode/jode.html +++ b/jode/doc/jode.html @@ -12,7 +12,9 @@ java-decompiler, reverse engineering, free, GPL"> -Home + +An uptodate version of this page is located here.

+

What is it?

This is a decompiler for java I have written in my spare time. It @@ -43,7 +45,6 @@ features like inner and anonymous classes.

-

How to use it

I have some simple step by step pages. There are three diff --git a/jode/jode/.cvsignore b/jode/jode/.cvsignore new file mode 100644 index 0000000..9f5ef71 --- /dev/null +++ b/jode/jode/.cvsignore @@ -0,0 +1,4 @@ +Makefile +Makefile.in +.java.deps +jode.jar diff --git a/jode/jode/Decompiler.java b/jode/jode/Decompiler.java index 2ccccad..f0deed2 100644 --- a/jode/jode/Decompiler.java +++ b/jode/jode/Decompiler.java @@ -155,6 +155,8 @@ public class Decompiler { } else if (params[i].equals("--import")) { importPackageLimit = Integer.parseInt(params[++i]); importClassLimit = Integer.parseInt(params[++i]); + } else if (params[i].equals("--classpath")) { + classPath = params[++i]; } else if (params[i].equals("--cp")) { classPath = params[++i]; } else if (params[i].equals("--")) { diff --git a/jode/jode/GlobalOptions.java b/jode/jode/GlobalOptions.java.in similarity index 79% rename from jode/jode/GlobalOptions.java rename to jode/jode/GlobalOptions.java.in index 727271a..0d79e80 100644 --- a/jode/jode/GlobalOptions.java +++ b/jode/jode/GlobalOptions.java.in @@ -22,7 +22,7 @@ import java.io.PrintWriter; import java.util.StringTokenizer; public class GlobalOptions { - public final static String version = "1.0 snapshot 19990629"; + public final static String version = "@VERSION@"; public final static String email = "jochen@gnu.org"; public final static String copyright = "Jode (c) 1998,1999 Jochen Hoenicke <"+email+">"; @@ -54,34 +54,40 @@ public class GlobalOptions { public static void usageDebugging() { err.println("Debugging option: --debug=flag1,flag2,..."); err.println("possible flags:"); - err.println("\tbytecode " + + err.println(" bytecode " + "show bytecode, as it is read from class file."); - err.println("\tverifier " + + err.println(" verifier " + "show result of bytecode verification."); - err.println("\ttypes " + + err.println(" types " + "show type intersections"); - err.println("\tflow " + + err.println(" flow " + "show flow block merging."); - err.println("\tanalyze " + - "show analyzation order of flow blocks."); - err.println("\tinout " + - "show T1/T2 in/out set analysis."); - err.println("\tlvt " + + err.println(" analyze " + + "show T1/T2 analyzation of flow blocks."); + err.println(" inout " + + "show in/out set analysis."); + err.println(" lvt " + "dump LocalVariableTable."); - err.println("\tcheck " + + err.println(" check " + "do time consuming sanity checks."); - err.println("\tlocals " + + err.println(" locals " + "dump local merging information."); - err.println("\tconstructors " + + err.println(" constructors " + "dump constructor simplification."); - err.println("\tinterpreter " + + err.println(" interpreter " + "debug execution of interpreter."); System.exit(0); } - - public static void setDebugging(String debuggingString) { - if (debuggingString.length() == 0 || debuggingString.equals("help")) + + /** + * Parse the argument given to the debugging flag. + * @return true, if the argument parsed without problems. + */ + public static boolean setDebugging(String debuggingString) { + if (debuggingString.length() == 0 || debuggingString.equals("help")) { usageDebugging(); + return false; + } StringTokenizer st = new StringTokenizer(debuggingString, ","); next_token: @@ -94,7 +100,8 @@ public class GlobalOptions { } } err.println("Illegal debugging flag: "+token); - usageDebugging(); + return false; } + return true; } } diff --git a/jode/jode/Makefile.am b/jode/jode/Makefile.am new file mode 100644 index 0000000..d39cc04 --- /dev/null +++ b/jode/jode/Makefile.am @@ -0,0 +1,54 @@ +## Input file for automake to generate the Makefile.in used by configure + +SUBDIRS = bytecode type util jvm expr flow decompiler obfuscator @SWINGUI@ + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):.:$(CLASSPATH):$(CLASSLIB) +VPATH=$(srcdir):$(top_srcdir):$(top_builddir) + +MY_JAVA_FILES = \ + AssertError.java \ + Decompiler.java \ + GlobalOptions.java \ + JodeApplet.java \ + JodeWindow.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + + +JARFILE = jode-@VERSION@.jar +data_DATA = $(JARFILE) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class + @rm -f $(JARFILE) .java.deps + +$(JARFILE): $(noinst_DATA) + CLASSPATH=$(top_builddir):$(CLASSPATH) $(JAVA) -mx80m \ + jode.obfuscator.Main --dest $(JARFILE) \ + --revtable rename.table \ + --rename=none --breakserial --strip=unreach -v -v \ + --preserve 'jode.Decompiler.main.*' \ + --preserve 'jode.JodeApplet..*' \ + --preserve 'jode.JodeWindow.main.*' \ + --preserve 'jode.obfuscator.Main.main.*' \ + --preserve 'jode.swingui.Main.main.*' jode diff --git a/jode/jode/bytecode/.cvsignore b/jode/jode/bytecode/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/bytecode/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/bytecode/ClassInfo.java b/jode/jode/bytecode/ClassInfo.java index c8742ed..e0482cb 100644 --- a/jode/jode/bytecode/ClassInfo.java +++ b/jode/jode/bytecode/ClassInfo.java @@ -231,6 +231,11 @@ public class ClassInfo extends BinaryInfo { } public void read(DataInputStream input, int howMuch) throws IOException { + /* Since we have to read the whole class anyway, we load all + * info, that we may need later and that does not take much memory. + */ + howMuch |= FIELDS | METHODS | HIERARCHY | INNERCLASSES | OUTERCLASSES; + howMuch &= ~status; /* header */ if (input.readInt() != 0xcafebabe) throw new ClassFormatException("Wrong magic"); @@ -261,11 +266,13 @@ public class ClassInfo extends BinaryInfo { } /* fields */ - if ((howMuch & FIELDS) != 0) { + if ((howMuch & (FIELDS | ALL_ATTRIBUTES)) != 0) { int count = input.readUnsignedShort(); - fields = new FieldInfo[count]; + if ((howMuch & FIELDS) != 0) + fields = new FieldInfo[count]; for (int i=0; i< count; i++) { - fields[i] = new FieldInfo(this); + if ((howMuch & FIELDS) != 0) + fields[i] = new FieldInfo(this); fields[i].read(cpool, input, howMuch); } } else { @@ -278,11 +285,13 @@ public class ClassInfo extends BinaryInfo { } /* methods */ - if ((howMuch & METHODS) != 0) { + if ((howMuch & (METHODS | ALL_ATTRIBUTES)) != 0) { int count = input.readUnsignedShort(); - methods = new MethodInfo[count]; + if ((howMuch & METHODS) != 0) + methods = new MethodInfo[count]; for (int i=0; i< count; i++) { - methods[i] = new MethodInfo(this); + if ((howMuch & METHODS) != 0) + methods[i] = new MethodInfo(this); methods[i].read(cpool, input, howMuch); } } else { @@ -296,6 +305,7 @@ public class ClassInfo extends BinaryInfo { /* attributes */ readAttributes(cpool, input, howMuch); + status |= howMuch; } public void reserveSmallConstants(GrowableConstantPool gcp) { @@ -546,7 +556,6 @@ public class ClassInfo extends BinaryInfo { new DataInputStream(classpath.getFile(name.replace('.', '/') + ".class")); read(input, howMuch); - status |= howMuch; } catch (IOException ex) { String message = ex.getMessage(); @@ -645,7 +654,7 @@ public class ClassInfo extends BinaryInfo { public FieldInfo findField(String name, String typeSig) { if ((status & FIELDS) == 0) loadInfo(FIELDS); - for (int i=0; i< methods.length; i++) + for (int i=0; i< fields.length; i++) if (fields[i].getName().equals(name) && fields[i].getType().equals(typeSig)) return fields[i]; diff --git a/jode/jode/bytecode/FieldInfo.java b/jode/jode/bytecode/FieldInfo.java index 4facd8f..d67f409 100644 --- a/jode/jode/bytecode/FieldInfo.java +++ b/jode/jode/bytecode/FieldInfo.java @@ -159,6 +159,7 @@ public class FieldInfo extends BinaryInfo { } public Object getConstant() { + clazzInfo.loadInfo(ALL_ATTRIBUTES); return constant; } diff --git a/jode/jode/bytecode/Makefile.am b/jode/jode/bytecode/Makefile.am new file mode 100644 index 0000000..322a226 --- /dev/null +++ b/jode/jode/bytecode/Makefile.am @@ -0,0 +1,46 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + BinaryInfo.java \ + BytecodeInfo.java \ + ClassFormatException.java \ + ClassInfo.java \ + ConstantPool.java \ + FieldInfo.java \ + GrowableConstantPool.java \ + Handler.java \ + InnerClassInfo.java \ + Instruction.java \ + LineNumber.java \ + LocalVariableInfo.java \ + MethodInfo.java \ + Opcodes.java \ + Reference.java \ + SearchPath.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/bytecode/MethodInfo.java b/jode/jode/bytecode/MethodInfo.java index 8e41301..37d2dfe 100644 --- a/jode/jode/bytecode/MethodInfo.java +++ b/jode/jode/bytecode/MethodInfo.java @@ -211,10 +211,12 @@ public class MethodInfo extends BinaryInfo { } public void setBytecode(BytecodeInfo newBytecode) { + clazzInfo.loadInfo(ALL_ATTRIBUTES); bytecode = newBytecode; } public void setExceptions(String[] newExceptions) { + clazzInfo.loadInfo(ALL_ATTRIBUTES); exceptions = newExceptions; } diff --git a/jode/jode/decompiler/.cvsignore b/jode/jode/decompiler/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/decompiler/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/decompiler/Makefile.am b/jode/jode/decompiler/Makefile.am new file mode 100644 index 0000000..d20893b --- /dev/null +++ b/jode/jode/decompiler/Makefile.am @@ -0,0 +1,46 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + Analyzer.java \ + ClassAnalyzer.java \ + ClassDeclarer.java \ + DeadCodeAnalysis.java \ + Declarable.java \ + FieldAnalyzer.java \ + ImportHandler.java \ + LocalInfo.java \ + LocalVarEntry.java \ + LocalVariableRangeList.java \ + LocalVariableTable.java \ + MethodAnalyzer.java \ + Opcodes.java \ + OuterValueListener.java \ + Scope.java \ + TabbedPrintWriter.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/expr/.cvsignore b/jode/jode/expr/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/expr/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/expr/Makefile.am b/jode/jode/expr/Makefile.am new file mode 100644 index 0000000..2dd7352 --- /dev/null +++ b/jode/jode/expr/Makefile.am @@ -0,0 +1,73 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + ArrayLengthOperator.java \ + ArrayLoadOperator.java \ + ArrayStoreOperator.java \ + BinaryOperator.java \ + CheckCastOperator.java \ + CheckNullOperator.java \ + ClassFieldOperator.java \ + CombineableOperator.java \ + CompareBinaryOperator.java \ + CompareToIntOperator.java \ + CompareUnaryOperator.java \ + ConstOperator.java \ + ConstantArrayOperator.java \ + ConstructorOperator.java \ + ConvertOperator.java \ + Expression.java \ + GetFieldOperator.java \ + IIncOperator.java \ + IfThenElseOperator.java \ + InstanceOfOperator.java \ + InvokeOperator.java \ + LValueExpression.java \ + LocalLoadOperator.java \ + LocalStoreOperator.java \ + LocalVarOperator.java \ + MatchableOperator.java \ + MonitorEnterOperator.java \ + MonitorExitOperator.java \ + NewArrayOperator.java \ + NewOperator.java \ + NoArgOperator.java \ + NopOperator.java \ + Operator.java \ + OuterLocalOperator.java \ + PopOperator.java \ + PrePostFixOperator.java \ + PutFieldOperator.java \ + ShiftOperator.java \ + SimpleOperator.java \ + StoreInstruction.java \ + StringAddOperator.java \ + ThisOperator.java \ + UnaryOperator.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/flow/.cvsignore b/jode/jode/flow/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/flow/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index e30c6ab..2b16504 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -1522,6 +1522,8 @@ public class FlowBlock { public void simplify() { block.simplify(); + if (nextByAddr != null) + nextByAddr.simplify(); } /** diff --git a/jode/jode/flow/Makefile.am b/jode/jode/flow/Makefile.am new file mode 100644 index 0000000..eed8d21 --- /dev/null +++ b/jode/jode/flow/Makefile.am @@ -0,0 +1,70 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + BreakBlock.java \ + BreakableBlock.java \ + CaseBlock.java \ + CatchBlock.java \ + CombineIfGotoExpressions.java \ + CompleteSynchronized.java \ + ConditionalBlock.java \ + ContinueBlock.java \ + CreateAssignExpression.java \ + CreateCheckNull.java \ + CreateClassField.java \ + CreateConstantArray.java \ + CreateExpression.java \ + CreateForInitializer.java \ + CreateIfThenElseOperator.java \ + CreateNewConstructor.java \ + CreatePrePostIncExpression.java \ + DescriptionBlock.java \ + EmptyBlock.java \ + FinallyBlock.java \ + FlowBlock.java \ + IfThenElseBlock.java \ + InstructionBlock.java \ + InstructionContainer.java \ + JsrBlock.java \ + Jump.java \ + LoopBlock.java \ + RetBlock.java \ + ReturnBlock.java \ + SequentialBlock.java \ + SpecialBlock.java \ + StructuredBlock.java \ + SwitchBlock.java \ + SynchronizedBlock.java \ + ThrowBlock.java \ + TransformConstructors.java \ + TransformExceptionHandlers.java \ + TryBlock.java \ + VariableSet.java \ + VariableStack.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/flow/TransformExceptionHandlers.java b/jode/jode/flow/TransformExceptionHandlers.java index 94319f1..8cf167f 100644 --- a/jode/jode/flow/TransformExceptionHandlers.java +++ b/jode/jode/flow/TransformExceptionHandlers.java @@ -77,6 +77,12 @@ public class TransformExceptionHandlers { /* ...Last sort by typecode signature. Shouldn't happen to often. */ + if (type == second.type) + return 0; + if (type == null) + return -1; + if (second.type == null) + return 1; return type.getTypeSignature() .compareTo(second.type.getTypeSignature()); } @@ -364,13 +370,16 @@ public class TransformExceptionHandlers { } public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, + int startOutExit, int endOutExit, int startMonExit, int endMonExit) { FlowBlock subRoutine = null; + FlowBlock exitBlock = null; Iterator succs = tryFlow.successors.values().iterator(); dest_loop: while (succs.hasNext()) { + boolean isFirstJump = true; for (Jump jumps = (Jump) succs.next(); - jumps != null; jumps = jumps.next) { + jumps != null; jumps = jumps.next, isFirstJump = false) { StructuredBlock prev = jumps.prev; @@ -431,28 +440,59 @@ public class TransformExceptionHandlers { continue; } - /* The block is a jsr that is not preceeded by another jsr. - * This must be the monitorexit subroutine. - */ - if (prev instanceof JsrBlock && subRoutine == null) { - - subRoutine = jumps.destination; - subRoutine.analyze(startMonExit, endMonExit); - transformSubRoutine(subRoutine.block); - - if (subRoutine.block instanceof InstructionBlock) { - Expression instr = - ((InstructionBlock)subRoutine.block) - .getInstruction(); - if (isMonitorExit(instr, local)) { - tryFlow.mergeAddr(subRoutine); - continue dest_loop; - } - } - } + if (isFirstJump) { + /* This is the first jump to that destination. + * Check if the destination does the monitorExit + */ - /* Now we have a jump that is not preceded by a monitorexit. - * Complain! + /* The block is a jsr that is not preceeded by + * another jsr. This must be the monitorexit + * subroutine. + */ + if (prev instanceof JsrBlock && subRoutine == null) { + + subRoutine = jumps.destination; + subRoutine.analyze(startMonExit, endMonExit); + transformSubRoutine(subRoutine.block); + + if (subRoutine.block instanceof InstructionBlock) { + Expression instr = + ((InstructionBlock)subRoutine.block) + .getInstruction(); + if (isMonitorExit(instr, local)) { + tryFlow.mergeAddr(subRoutine); + continue dest_loop; + } + } + } + + /* Now we have a jump that is not preceded by a + * monitorexit. There's a last chance: the jump + * jumps directly to the correct monitorexit + * instruction, which lies outside the try/catch + * block. + */ + if (exitBlock == null + && jumps.destination.getAddr() >= startOutExit + && jumps.destination.getNextAddr() <= endOutExit) { + jumps.destination.analyze(startOutExit, endOutExit); + + StructuredBlock sb = jumps.destination.block; + if (sb instanceof SequentialBlock) + sb = sb.getSubBlocks()[0]; + if (sb instanceof InstructionBlock) { + Expression instr = ((InstructionBlock)sb) + .getInstruction(); + if (isMonitorExit(instr, local)) { + sb.removeBlock(); + exitBlock = jumps.destination; + continue dest_loop; + } + } + } + } + + /* Complain! */ DescriptionBlock msg = new DescriptionBlock("ERROR: NO MONITOREXIT"); @@ -517,11 +557,13 @@ public class TransformExceptionHandlers { LocalInfo local = ((LocalLoadOperator)monexit.getSubExpressions()[0]) .getLocalInfo(); - tryFlow.mergeAddr(catchFlow); checkAndRemoveMonitorExit - (tryFlow, local, catchFlow.getNextAddr(), endHandler); - + (tryFlow, local, + tryFlow.getNextAddr(), catchFlow.getAddr(), + catchFlow.getNextAddr(), endHandler); + + tryFlow.mergeAddr(catchFlow); SynchronizedBlock syncBlock = new SynchronizedBlock(local); TryBlock tryBlock = (TryBlock) tryFlow.block; syncBlock.replace(tryBlock); @@ -677,12 +719,13 @@ public class TransformExceptionHandlers { TryBlock tryBlock = (TryBlock)tryFlow.block; if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { - /* remove the nested tryBlock */ + /* remove the surrounding tryBlock */ TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; innerTry.gen = tryBlock.gen; innerTry.replace(tryBlock); tryBlock = innerTry; - tryFlow.lastModified = innerTry; + tryFlow.lastModified = tryBlock; + tryFlow.block = tryBlock; } FinallyBlock newBlock = new FinallyBlock(); newBlock.setCatchBlock(finallyBlock); @@ -826,26 +869,27 @@ public class TransformExceptionHandlers { FlowBlock tryFlow = exc.start; tryFlow.checkConsistent(); - if ((GlobalOptions.debuggingFlags - & GlobalOptions.DEBUG_ANALYZE) != 0) - GlobalOptions.err.println - ("analyzeTry(" - + exc.start.addr + ", " + exc.endAddr+")"); - while (tryFlow.analyze(tryFlow.addr, exc.endAddr)); - if (last == null + if (last == null || exc.type == null || last.start.addr != exc.start.addr || last.endAddr != exc.endAddr) { /* The last handler does catch another range. * Create a new try block. */ + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_ANALYZE) != 0) + GlobalOptions.err.println + ("analyzeTry(" + + exc.start.addr + ", " + exc.endAddr+")"); + while (tryFlow.analyze(tryFlow.addr, exc.endAddr)); + TryBlock tryBlock = new TryBlock(tryFlow); - } else if (! (tryFlow.block instanceof TryBlock)) - throw new AssertError("no TryBlock"); + } else if (!(tryFlow.block instanceof TryBlock)) + throw new AssertError("no TryBlock"); FlowBlock catchFlow = exc.handler; boolean isMultiUsed = catchFlow.predecessors.size() != 0; - if (!isMultiUsed) { + if (!isMultiUsed && next != null) { for (Iterator j = handlers.tailSet(next).iterator(); j.hasNext();) { Handler h = (Handler) j.next(); @@ -865,8 +909,8 @@ public class TransformExceptionHandlers { FlowBlock newFlow = new FlowBlock(catchFlow.method, catchFlow.addr, 0); newFlow.setBlock(jump); - catchFlow.prevByAddr.setNextByAddr(newFlow); - newFlow.setNextByAddr(catchFlow); + catchFlow.prevByAddr.nextByAddr = newFlow; + newFlow.nextByAddr = catchFlow; catchFlow = newFlow; } else { if ((GlobalOptions.debuggingFlags diff --git a/jode/jode/jvm/.cvsignore b/jode/jode/jvm/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/jvm/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/jvm/Makefile.am b/jode/jode/jvm/Makefile.am new file mode 100644 index 0000000..42c17f1 --- /dev/null +++ b/jode/jode/jvm/Makefile.am @@ -0,0 +1,39 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + CodeVerifier.java \ + Interpreter.java \ + InterpreterException.java \ + NewObject.java \ + RuntimeEnvironment.java \ + SimpleRuntimeEnvironment.java \ + SyntheticAnalyzer.java \ + Value.java \ + VerifyException.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/obfuscator/.cvsignore b/jode/jode/obfuscator/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/obfuscator/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/obfuscator/ClassBundle.java b/jode/jode/obfuscator/ClassBundle.java index 20c087a..013d19b 100644 --- a/jode/jode/obfuscator/ClassBundle.java +++ b/jode/jode/obfuscator/ClassBundle.java @@ -139,8 +139,10 @@ public class ClassBundle { analyze(); } - public void analyzeIdentifier(Identifier i) { - toAnalyze.add(i); + public void analyzeIdentifier(Identifier ident) { + if (ident == null) + throw new NullPointerException(); + toAnalyze.add(ident); } public void analyze() { diff --git a/jode/jode/obfuscator/ClassIdentifier.java b/jode/jode/obfuscator/ClassIdentifier.java index 0885c80..86f659b 100644 --- a/jode/jode/obfuscator/ClassIdentifier.java +++ b/jode/jode/obfuscator/ClassIdentifier.java @@ -40,6 +40,7 @@ import jode.util.Iterator; import jode.util.List; import jode.util.LinkedList; import jode.util.Map; +import jode.util.UnsupportedOperationException; ///#endif import java.lang.reflect.Modifier; @@ -57,7 +58,6 @@ public class ClassIdentifier extends Identifier { String superName; String[] ifaceNames; - List identifiers; List fieldIdents, methodIdents; List knownSubClasses = new LinkedList(); List virtualReachables = new LinkedList(); @@ -82,6 +82,7 @@ public class ClassIdentifier extends Identifier { String fullName = getFullName() + "."; for (Iterator i = getChilds(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); + System.err.println("checking "+ident); if (wildcard.matches(fullName + ident.getName()) || wildcard.matches(fullName + ident.getName() + "." +ident.getType())) { @@ -94,8 +95,24 @@ public class ClassIdentifier extends Identifier { } } - public void preserveIdentifier(String name, String typeSig) { - preserveMatchingIdentifier(new WildCard(name+"."+typeSig)); + private FieldIdentifier findField(String name, String typeSig) { + for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) { + FieldIdentifier ident = (FieldIdentifier) i.next(); + if (ident.getName().equals(name) + && ident.getType().equals(typeSig)) + return ident; + } + return null; + } + + private MethodIdentifier findMethod(String name, String typeSig) { + for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { + MethodIdentifier ident = (MethodIdentifier) i.next(); + if (ident.getName().equals(name) + && ident.getType().equals(typeSig)) + return ident; + } + return null; } public void reachableIdentifier(String name, String typeSig, @@ -109,6 +126,20 @@ public class ClassIdentifier extends Identifier { found = true; } } + if (!found) { + // This means that the method is inherited from parent and + // must be marked as reachable there, (but not virtual). + // Consider following: + // A method in Collection and AbstractCollection is not reachable + // but it is reachable in Set and not implemented in AbstractSet + // In that case the method must be marked reachable in + // AbstractCollection. + ClassIdentifier superIdent = Main.getClassBundle() + .getClassIdentifier(info.getSuperclass().getName()); + if (superIdent != null) + superIdent.reachableIdentifier(name, typeSig, false); + } + if (isVirtual) { for (Iterator i = knownSubClasses.iterator(); i.hasNext(); ) ((ClassIdentifier)i.next()) @@ -117,13 +148,13 @@ public class ClassIdentifier extends Identifier { } } - public void chainIdentifier(Identifier chainIdent) { + public void chainMethodIdentifier(Identifier chainIdent) { String name = chainIdent.getName(); String typeSig = chainIdent.getType(); - for (Iterator i = getChilds(); i.hasNext(); ) { + for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); - if (ident.getName().equals(ident.getName()) - && (ident.getType().equals(typeSig))) + if (ident.getName().equals(name) + && ident.getType().equals(typeSig)) chainIdent.addShadow(ident); } } @@ -246,33 +277,28 @@ public class ClassIdentifier extends Identifier { * a compatible class. */ public void preserveSerializable() { - preserveIdentifier("writeObject", "(Ljava.io.ObjectOutputStream)V"); - preserveIdentifier("readObject", "(Ljava.io.ObjectOutputStream)V"); + Identifier method + = findMethod("writeObject", "(Ljava.io.ObjectOutputStream)V"); + if (method != null) + method.setPreserved(); + method = findMethod("readObject", "(Ljava.io.ObjectInputStream)V"); + if (method != null) + method.setPreserved(); if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) { setPreserved(); - boolean hasSerialUID = false; - for (Iterator i = getFieldIdents().iterator(); i.hasNext(); ) { - Identifier ident = (Identifier) i.next(); - if ("serialVersionUID".equals(ident.getName()) - && "J".equals(ident.getType())) { - ident.setReachable(); - ident.setPreserved(); - hasSerialUID = true; - break; - } - } - if (!hasSerialUID) { + Identifier UIDident = findField("serialVersionUID", "J"); + if (UIDident == null) { /* add a field serializableVersionUID if not existent */ long serialVersion = calcSerialVersionUID(); FieldInfo UIDField = new FieldInfo (info, "serialVersionUID", "J", Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL); UIDField.setConstant(new Long(serialVersion)); - FieldIdentifier fident = new FieldIdentifier(this, UIDField); - fident.setPreserved(); - fident.setReachable(); - fieldIdents.add(fident); + UIDident = new FieldIdentifier(this, UIDField); + fieldIdents.add(UIDident); } + UIDident.setReachable(); + UIDident.setPreserved(); for (Iterator i=getFieldIdents().iterator(); i.hasNext(); ) { FieldIdentifier ident = (FieldIdentifier) i.next(); if ((ident.info.getModifiers() @@ -358,7 +384,7 @@ public class ClassIdentifier extends Identifier { | Modifier.FINAL) & modif) == 0 && !(mid.getName().equals(""))) { // chain the preserved/same name lists. - chainIdentifier(mid); + chainMethodIdentifier(mid); } } } else { @@ -371,8 +397,10 @@ public class ClassIdentifier extends Identifier { if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL) & modif) == 0 && !topmethods[i].getName().equals("")) { - preserveIdentifier + Identifier method = findMethod (topmethods[i].getName(), topmethods[i].getType()); + if (method != null) + method.setPreserved(); } } } @@ -393,10 +421,8 @@ public class ClassIdentifier extends Identifier { Collections.shuffle(Arrays.asList(finfos), rand); Collections.shuffle(Arrays.asList(minfos), rand); } - identifiers = new ArrayList(finfos.length + minfos.length); - fieldIdents = identifiers.subList(0, 0); - methodIdents = identifiers.subList(0, 0); - identifiers = Collections.unmodifiableList(identifiers); + fieldIdents = new ArrayList(finfos.length); + methodIdents = new ArrayList(minfos.length); for (int i=0; i< finfos.length; i++) fieldIdents.add(new FieldIdentifier(this, finfos[i])); @@ -665,36 +691,30 @@ public class ClassIdentifier extends Identifier { transformSuperIfaces(); transformInnerClasses(); - int newFieldCount = 0, newMethodCount = 0; - if ((Main.stripping & Main.STRIP_UNREACH) != 0) { - for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) { - Identifier ident = (Identifier) i.next(); - if (!ident.isReachable()) - i.remove(); - } - for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { - Identifier ident = (Identifier) i.next(); - if (!ident.isReachable()) - i.remove(); - } - } - FieldInfo[] newFields = new FieldInfo[fieldIdents.size()]; - MethodInfo[] newMethods = new MethodInfo[methodIdents.size()]; - newFieldCount = newMethodCount = 0; + Collection newFields = new ArrayList(fieldIdents.size()); + Collection newMethods = new ArrayList(methodIdents.size()); for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) { FieldIdentifier ident = (FieldIdentifier)i.next(); - ident.doTransformations(); - newFields[newFieldCount++] = ident.info; + if ((Main.stripping & Main.STRIP_UNREACH) == 0 + || ident.isReachable()) { + ident.doTransformations(); + newFields.add(ident.info); + } } for (Iterator i = methodIdents.iterator(); i.hasNext(); ) { MethodIdentifier ident = (MethodIdentifier)i.next(); - ident.doTransformations(); - newMethods[newMethodCount++] = ident.info; + if ((Main.stripping & Main.STRIP_UNREACH) == 0 + || ident.isReachable()) { + ident.doTransformations(); + newMethods.add(ident.info); + } } - info.setFields(newFields); - info.setMethods(newMethods); + info.setFields((FieldInfo[]) newFields.toArray + (new FieldInfo[newFields.size()])); + info.setMethods((MethodInfo[]) newMethods.toArray + (new MethodInfo[newMethods.size()])); } public void storeClass(DataOutputStream out) throws IOException { @@ -702,7 +722,7 @@ public class ClassIdentifier extends Identifier { GlobalOptions.err.println("Writing "+this); info.write(out); info = null; - identifiers = null; + fieldIdents = methodIdents = null; } public Identifier getParent() { @@ -746,7 +766,28 @@ public class ClassIdentifier extends Identifier { } public Iterator getChilds() { - return identifiers.iterator(); + final Iterator fieldIter = fieldIdents.iterator(); + final Iterator methodIter = methodIdents.iterator(); + + return new Iterator() { + boolean fieldsNext = fieldIter.hasNext(); + public boolean hasNext() { + return fieldsNext ? true : methodIter.hasNext(); + } + + public Object next() { + if (fieldsNext) { + Object result = fieldIter.next(); + fieldsNext = fieldIter.hasNext(); + return result; + } + return methodIter.next(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; } public String toString() { @@ -754,24 +795,13 @@ public class ClassIdentifier extends Identifier { } public Identifier getIdentifier(String fieldName, String typeSig) { - for (Iterator i = identifiers.iterator(); i.hasNext(); ) { + for (Iterator i = getChilds(); i.hasNext(); ) { Identifier ident = (Identifier) i.next(); if (ident.getName().equals(fieldName) && ident.getType().startsWith(typeSig)) return ident; } - for (int i=0; i < ifaceNames.length; i++) { - ClassIdentifier ifaceident = Main.getClassBundle() - .getClassIdentifier(ifaceNames[i]); - if (ifaceident != null) { - Identifier ident - = ifaceident.getIdentifier(fieldName, typeSig); - if (ident != null) - return ident; - } - } - if (superName != null) { ClassIdentifier superident = Main.getClassBundle() .getClassIdentifier(superName); diff --git a/jode/jode/obfuscator/ConstantAnalyzer.java b/jode/jode/obfuscator/ConstantAnalyzer.java index 27d5619..9889ed5 100644 --- a/jode/jode/obfuscator/ConstantAnalyzer.java +++ b/jode/jode/obfuscator/ConstantAnalyzer.java @@ -448,10 +448,17 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { (clName.substring(1, clName.length()-1) .replace('/','.')); } - while (clazz != null - && clazz.findMethod(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); + 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: " @@ -1371,6 +1378,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { } public void analyzeCode(MethodIdentifier listener, BytecodeInfo bytecode) { + this.listener = listener; this.bytecode = bytecode; working = true; if (constInfos == null) diff --git a/jode/jode/obfuscator/FieldIdentifier.java b/jode/jode/obfuscator/FieldIdentifier.java index dd881ae..cae8bfc 100644 --- a/jode/jode/obfuscator/FieldIdentifier.java +++ b/jode/jode/obfuscator/FieldIdentifier.java @@ -111,6 +111,8 @@ public class FieldIdentifier extends Identifier{ } public void addFieldListener(Identifier ident) { + if (ident == null) + throw new NullPointerException(); if (!fieldListeners.contains(ident)) fieldListeners.add(ident); } diff --git a/jode/jode/obfuscator/Identifier.java b/jode/jode/obfuscator/Identifier.java index c92a6ea..95e58a3 100644 --- a/jode/jode/obfuscator/Identifier.java +++ b/jode/jode/obfuscator/Identifier.java @@ -179,14 +179,13 @@ public abstract class Identifier { if (GlobalOptions.verboseLevel > 4) GlobalOptions.err.println(toString() + " is preserved"); } else { - Identifier rep = getRepresentative(); if (rep.wasAliased) return; rep.wasAliased = true; // set alias to empty string, so it won't conflict! - alias = ""; + rep.alias = ""; String newAlias = null; next_alias: for (;;) { @@ -198,7 +197,7 @@ public abstract class Identifier { ptr = ptr.right; } setAlias(newAlias.toString()); - return; + break; } } for (Iterator i = getChilds(); i.hasNext(); ) diff --git a/jode/jode/obfuscator/Main.java b/jode/jode/obfuscator/Main.java index 861c19f..a9b88d4 100644 --- a/jode/jode/obfuscator/Main.java +++ b/jode/jode/obfuscator/Main.java @@ -184,7 +184,7 @@ public class Main { } public static CodeAnalyzer createCodeAnalyzer() { - return new ConstantAnalyzer() /*XXX*/; + return new SimpleAnalyzer() /*XXX*/; } static CodeTransformer[] codeTransformers = { diff --git a/jode/jode/obfuscator/Makefile.am b/jode/jode/obfuscator/Makefile.am new file mode 100644 index 0000000..2cf76b8 --- /dev/null +++ b/jode/jode/obfuscator/Makefile.am @@ -0,0 +1,53 @@ +## Input file for automake to generate the Makefile.in used by configure + +JAR = @JAR@ +JAVAC = @JAVAC@ +JIKES = @JIKES@ +CLASSPATH = @CLASSPATH@ +CLASSLIB = @CLASSLIB@ +BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB) + +MY_JAVA_FILES = \ + ClassBundle.java \ + ClassIdentifier.java \ + CodeAnalyzer.java \ + CodeTransformer.java \ + ConstantAnalyzer.java \ + ConstantRuntimeEnvironment.java \ + FieldIdentifier.java \ + Identifier.java \ + IdentifierMatcher.java \ + LocalIdentifier.java \ + LocalOptimizer.java \ + Main.java \ + MethodIdentifier.java \ + ModifierMatcher.java \ + NameSwapper.java \ + PackageIdentifier.java \ + RemovePopAnalyzer.java \ + Renamer.java \ + SimpleAnalyzer.java \ + StrongRenamer.java \ + TranslationTable.java \ + WildCard.java +# LocalizeFieldTransformer.java + +noinst_DATA = $(MY_JAVA_FILES:.java=.class) +EXTRA_DIST = $(MY_JAVA_FILES) + +if HAVE_JIKES + +@QUOTE@-include $(top_builddir)/jode/.java.deps + +%.class: %.java + $(JIKES) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) +M=$(top_builddir)/jode/.java.deps -d $(top_builddir) $< + +else + +%.class: %.java + $(JAVAC) -classpath $(BUILD_CLASSPATH):$(CLASSLIB) -depend -d $(top_builddir) $< + +endif + +clean-local: + @rm -f *.class diff --git a/jode/jode/obfuscator/ModifierMatcher.java b/jode/jode/obfuscator/ModifierMatcher.java index 1119c09..806b863 100644 --- a/jode/jode/obfuscator/ModifierMatcher.java +++ b/jode/jode/obfuscator/ModifierMatcher.java @@ -107,7 +107,7 @@ public class ModifierMatcher implements IdentifierMatcher, Cloneable { if (implies(and, xor, andMasks[i], xorMasks[i])) continue next_i; - for (int j=0; j= 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 @@ -54,52 +113,21 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { /* fall through */ case opc_getstatic: case opc_getfield: { - Reference ref = (Reference) instr.objData; - Identifier ident = Main.getClassBundle().getIdentifier(ref); - String clName = ref.getClazz(); - String realClazzName; + Identifier ident = canonizeReference(instr); if (ident != null) { - ClassIdentifier clazz = (ClassIdentifier)ident.getParent(); - realClazzName = "L" + (clazz.getFullName() - .replace('.', '/')) + ";"; 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 { - clazz.reachableIdentifier - (ref.getName(), ref.getType(), - instr.opcode == opc_invokevirtual - || instr.opcode == opc_invokeinterface); + ident.setReachable(); } - } 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('/','.')); - } - while (clazz != null - && clazz.findMethod(ref.getName(), - ref.getType()) == null) - clazz = clazz.getSuperclass(); - - realClazzName = (clazz != null) ? clName - : "L" + clazz.getName().replace('.', '/') + ";"; - } - if (!realClazzName.equals(ref.getClazz())) { - ref = Reference.getReference(realClazzName, - ref.getName(), ref.getType()); - instr.objData = ref; } break; } diff --git a/jode/jode/swingui/.cvsignore b/jode/jode/swingui/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/jode/jode/swingui/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/jode/jode/swingui/Main.java b/jode/jode/swingui/Main.java.in similarity index 96% rename from jode/jode/swingui/Main.java rename to jode/jode/swingui/Main.java.in index ba871e1..077a4f4 100644 --- a/jode/jode/swingui/Main.java +++ b/jode/jode/swingui/Main.java.in @@ -22,15 +22,11 @@ import jode.GlobalOptions; import jode.decompiler.*; import jode.bytecode.ClassInfo; import jode.bytecode.SearchPath; -///#ifndef OLDSWING -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.tree.*; -///#else -///import com.sun.java.swing.*; -///import com.sun.java.swing.event.*; -///import com.sun.java.swing.tree.*; -///#endif + +import @JAVAX_SWING@.*; +import @JAVAX_SWING@.event.*; +import @JAVAX_SWING@.tree.*; + import java.awt.*; import java.awt.event.*; import java.io.*; @@ -270,7 +266,7 @@ public class Main String cp = System.getProperty("java.class.path", ""); cp = cp.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar); for (int i=0; i