diff options
author | John Criswell <criswell@uiuc.edu> | 2004-02-27 18:06:50 +0000 |
---|---|---|
committer | John Criswell <criswell@uiuc.edu> | 2004-02-27 18:06:50 +0000 |
commit | 4929390840d09806b575f1239e0ed61c592ea13d (patch) | |
tree | 3844ae57a83b06ff10faa19eeb777368bbbeb633 | |
parent | 20354b6d9a8307a0a6c82f35933641f36d02697f (diff) |
Initial commit of hbd.
git-svn-id: https://llvm.org/svn/llvm-project/test-suite/trunk@11918 91177308-0d34-0410-b5e6-96231b3b80d8
43 files changed, 3749 insertions, 0 deletions
diff --git a/MultiSource/Applications/hbd/Makefile b/MultiSource/Applications/hbd/Makefile new file mode 100644 index 00000000..b796bb34 --- /dev/null +++ b/MultiSource/Applications/hbd/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../../../.. +PROG = hbd +CPPFLAGS += -DHAVE_CONFIG_H +LDFLAGS += -lstdc++ +LIBS += -lstdc++ +RUN_OPTIONS = Sort.class +REQUIRES_EH_SUPPORT := 1 +include ../../Makefile.multisrc diff --git a/MultiSource/Applications/hbd/access.cpp b/MultiSource/Applications/hbd/access.cpp new file mode 100644 index 00000000..cdb1ee4e --- /dev/null +++ b/MultiSource/Applications/hbd/access.cpp @@ -0,0 +1,48 @@ +/* access.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <string.h> +#include "general.h" +#include "access.h" + +char *flag2str[] = { + "public ", "private ", "protected ", "static ", + "final ", "synchronized ", "threadsafe ", "transient ", + "native ", "interface ", "abstract " +}; + +int flag2strlen[] = { + 7, 8, 10, 7, 6, 13, 11, 10, 7, 10, 9 +}; + +char *AccessFlags::toString(char *buffer) +{ + u16 f, i; + + *buffer = '\0'; + + for (f = flags, i = 0; f; f>>=1, i++) { + if (f & 1) { + strcat(buffer, flag2str[i]); + } + } + return buffer; +} + +u16 AccessFlags::strlen() +{ + u16 buffsize = 0, f, i; + + for (f = flags, i = 0; f; f>>=1, i++) { + if (f & 1) { + buffsize += flag2strlen[i]; + } + } + + return buffsize; +} diff --git a/MultiSource/Applications/hbd/access.h b/MultiSource/Applications/hbd/access.h new file mode 100644 index 00000000..6ab46276 --- /dev/null +++ b/MultiSource/Applications/hbd/access.h @@ -0,0 +1,66 @@ +/* access.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef ACCESS_H +#define ACCESS_H + +#include "general.h" + +/* The various types of Access flags Java uses */ +enum Access { + ACC_PUBLIC = 0x0001, /* visible to everyone */ + ACC_PRIVATE = 0x0002, /* visible only to defining class */ + ACC_PROTECTED = 0x0004, /* visible to subclasses */ + ACC_STATIC = 0x0008, /* instance variable is static */ + ACC_FINAL = 0x0010, /* no further subclassing, overriding */ + ACC_SYNCHRONIZED = 0x0020, /* wrap method call */ + /* in monitor lock */ + ACC_THREADSAFE = 0x0040, /* can cache in registers */ + ACC_TRANSIENT = 0x0080, /* not persistant */ + ACC_NATIVE = 0x0100, /* implemented in C */ + ACC_INTERFACE = 0x0200, /* class is an interface */ + ACC_ABSTRACT = 0x0400 /* no definition provided */ +}; + +/* + A class representing a set of access flags with + various useful methods. +*/ + +struct AccessFlags { + u16 flags; + + AccessFlags() { + flags = 0; + } + + AccessFlags(u16 inflags) { + flags = inflags; + } + + void operator =(u16 inflags) { + flags = inflags; + } + + void operator +=(Access a) { + flags |= (u16)a; + } + + void operator -=(Access a) { + flags &= ~(u16)a; + } + + int operator &(u16 intflags) { + return flags & intflags; + } + + char *toString(char *buffer); + u16 strlen(); +}; + +#endif diff --git a/MultiSource/Applications/hbd/class.cpp b/MultiSource/Applications/hbd/class.cpp new file mode 100644 index 00000000..d25a50af --- /dev/null +++ b/MultiSource/Applications/hbd/class.cpp @@ -0,0 +1,418 @@ +/* class.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <string.h> +#include <ctype.h> +#include "general.h" +#include "options.h" +#include "cp.h" +#include "access.h" +#include "field.h" +#include "exp.h" +#include "method.h" +#include "version.h" +#include "class.h" +#include "file.h" +#include "err.h" +#include "consts.h" + +#define JAVA_CLASSFILE_MAGIC 0xCafeBabeL + +char *progname; + +Classfile::Classfile(int argc, char **argv) { + functoinsert = 0; + outfile = stdout; infile = stdin; + progname = *argv++; + if (strcmp(progname + strlen(progname) - 3, "hbt") == 0) { + for (; (--argc) && (**argv == '-'); argv++) { + options = (CL_Options)0; + switch (toupper((*argv)[1])) { + case 'D': *(int *)&options |= (int)OPT_DEBUG; break; + case 'I': functoinsert = &((*argv)[2]); break; + default: + fprintf(stderr, "Unknown flag: %s\n", argv[1]); + fatalerror(COMMAND_LINE_ERR_HBT, progname); + } + } + char *tmpstr; + switch (argc) { + case 1: + tmpstr = new char[strlen(argv[0])+5]; + strcpy(tmpstr, argv[0]); + strcat(tmpstr, ".bak"); + rename(argv[0], tmpstr); + if ((infile = fopen(tmpstr, "rb"))==NULL) { + fprintf(stderr, "Could not open file %s\n", argv[0]); + goto defaultcase_hbt; + } + if ((outfile = fopen(argv[0], "wb"))==NULL) { + fprintf(stderr, "Could not open file %s\n", argv[1]); + goto defaultcase_hbt; + } + delete tmpstr; + break; + default: defaultcase_hbt: + fatalerror(COMMAND_LINE_ERR_HBT, progname); + } + if (functoinsert == 0) + fatalerror(COMMAND_LINE_ERR_HBT, progname); + outfile_pos = 0; + } else { + for (; (--argc) && (**argv == '-'); argv++) { + options = (CL_Options)0; + switch (toupper((*argv)[1])) { + case 'O': *(int *)&options |= (int)OPT_DECOMPILE_OFF; break; + case 'D': *(int *)&options |= (int)OPT_DEBUG; break; + default: + fprintf(stderr, "Unknown flag: %s\n", argv[1]); + fatalerror(COMMAND_LINE_ERR_HBD, progname); + } + } + switch (argc) { + case 2: + if ((outfile = fopen(argv[1], "wb"))==NULL) { + fprintf(stderr, "Could not open file %s\n", argv[1]); + goto defaultcase_hbd; + } + case 1: + if ((infile = fopen(argv[0], "rb"))==NULL) { + fprintf(stderr, "Could not open file %s\n", argv[0]); + goto defaultcase_hbd; + } + break; + default: defaultcase_hbd: + fatalerror(COMMAND_LINE_ERR_HBD, progname); + } + } + infile_pos = 0; +} + +void Classfile::read() { + u16 numimports; + + if (get32(infile, &infile_pos) != JAVA_CLASSFILE_MAGIC) fatalerror(NOT_A_CLASS_ERR); + + version.read(this); + fprintf(stderr, "Classfile version %d.%d\n", version.major_version, version.minor_version); + + imports_count = 0; + cp.read(this, &imports_count); + access_flags = get16(infile, &infile_pos); + + this_class = get16(infile, &infile_pos); + super_class = get16(infile, &infile_pos); + if (((interfaces = new u16[interfaces_count = get16(infile, &infile_pos)]) == 0) && interfaces_count) memerr(); + u16 i,j; + for (j = 0, i = interfaces_count; i--;) { + interfaces[j++] = get16(infile, &infile_pos); + } + if (((fields = new field_info_ptr[fields_count = get16(infile, &infile_pos)]) == 0) && fields_count) memerr(); + for (j = 0, i = fields_count; i--;) { + field_info *fip = fields[j++] = new field_info; + if (!fip) memerr(); + field_info &fi = *fip; + fi.isconstant = 0; + fi.access_flags = get16(infile, &infile_pos); + fi.name = cp[get16(infile, &infile_pos)]->chp; + fi.sig = cp[get16(infile, &infile_pos)]->chp; + for (int l = get16(infile, &infile_pos); l--;) { + u16 attribute_name_index = get16(infile, &infile_pos); + u32 attribute_size = get32(infile, &infile_pos); + char *attribute_name = cp[attribute_name_index]->chp; + if (!strcmp(attribute_name,"ConstantValue")) { + if (attribute_size != 2) { + fprintf(stderr, "Bad size on ConstantValue Attribute - should be 2!\n"); + exit(1); + } else { + fi.isconstant = 1; + fi.constval_index = get16(infile, &infile_pos); + } + } else { + fprintf(stderr, "Skipping Unknown Field Attribute: %s (size %ld)\n", attribute_name, attribute_size); + for (u32 m = attribute_size; m--;) get8(infile, &infile_pos); + } + } + } + if (((methods = new method_info_ptr[methods_count = get16(infile, &infile_pos)]) == 0) && methods_count) memerr(); + imports_count += methods_count; + numimports = 0; + if ((imports = new char_ptr[imports_count]) == 0) memerr(); + char *tmpstr1, *tmpstr2, *tmpstr; + int package_name_length; + tmpstr = cp(this_class)->chp; + if ((tmpstr1 = strchr(tmpstr,'/')) != 0) { + int l; + while (tmpstr1) { + l = tmpstr1 - tmpstr; + tmpstr1 = strchr(tmpstr1 + 1, '/'); + } + if ((package_name = new char[l+1]) == 0) memerr(); + strncpy(package_name, tmpstr, l); + package_name[l] = '\0'; + if ((this_class_name = new char[strlen(tmpstr + l + 1) + 1]) == 0) memerr(); + strcpy(this_class_name, cp(this_class)->chp = tmpstr + l + 1); + tmpstr = package_name; + package_name_length = strlen(tmpstr); + while ((tmpstr = strchr(tmpstr,'/')) != 0) *tmpstr++ = '.'; + } else { + package_name = 0; + package_name_length = 0; + if ((this_class_name = new char[strlen(tmpstr) + 1]) == 0) memerr(); + strcpy(this_class_name, tmpstr); + } + for (i16 l = cp.count(); --l >= 0;) { + cp_info tmpcpi = *(cp[l]); + if (tmpcpi.tag == CONSTANT_Class) { + char **chap = &(cp(l)->chp); + tmpstr = *chap; + if (!strncmp(tmpstr, "java/lang/", 10)) *chap = tmpstr + 10; + else while ((tmpstr = strchr(tmpstr,'/')) != 0) *tmpstr++ = '.'; + tmpstr = *chap; + if (package_name && !strncmp(tmpstr, package_name, package_name_length)) *chap = tmpstr += package_name_length + 1; + if ((numimports!=imports_count)&&(tmpstr2 = strrchr(tmpstr,'.')) != 0) { + imports[numimports++] = tmpstr; + for (int tint = numimports - 2; tint>=0; tint--) { + if (!strcmp(imports[tint], tmpstr)) { + --numimports; + break; + } + } + *chap = tmpstr2 + 1; + } + } else if(tmpcpi.tag == CONSTANT_NameAndType) { + // int tmpindex; + tmpstr = cp[/*tmpindex = */((NameAndType*)tmpcpi.p)->signature_index]->chp; + char *copytmpstr = tmpstr2 = strdup(tmpstr); if (!copytmpstr) memerr(); + char *srcstr = tmpstr2, *deststr = tmpstr, *tmpstr3, *tmpstr4; + while ((*deststr++ = *srcstr++) != '\0') { + if (*(srcstr-1) == 'L') { + tmpstr3 = strchr(srcstr, ';'); if (!tmpstr3) fatalerror(UNKNOWN_ERR); + if (!strncmp(srcstr, "java/lang/", 10)) srcstr += 10; + else { + tmpstr2 = srcstr; + while (((tmpstr2 = strchr(tmpstr2,'/')) != 0)&&(tmpstr2 < tmpstr3)) *tmpstr2++ = '.'; + } + if (package_name && !strncmp(srcstr, package_name, package_name_length)) srcstr += package_name_length + 1; + if (numimports!=imports_count && (tmpstr4 = strchr(srcstr, '.')) != 0 && tmpstr4 < tmpstr3) { + while (tmpstr4 != 0 && tmpstr4 < tmpstr3) { tmpstr2 = tmpstr4+1; tmpstr4 = strchr(tmpstr2,'.'); } + int tint = tmpstr3 - srcstr; + char *tstr = imports[numimports++] = new char[tint+1]; + if (!tstr) memerr(); + tstr = strncpy(tstr, srcstr, tint); + tstr[tint] = '\0'; + for (tint = numimports - 2; tint>=0; tint--) { + if (!strcmp(imports[tint], tstr)) { + --numimports; + delete tstr; + break; + } + } + srcstr = tmpstr2; + } + while ((*deststr++ = *srcstr++) != ';') ; + } + } + } + } + for (j = 0, i = methods_count; i--;) { + method_info *mip = methods[j++] = new method_info; + if (!mip) memerr(); + method_info &mi = *mip; + mi.access_flags = get16(infile, &infile_pos); + char *tmpstr; + mi.name = cp[get16(infile, &infile_pos)]->chp; + mi.sig = cp[get16(infile, &infile_pos)]->chp; + + // int tmpindex; + tmpstr = mi.sig; + char *copytmpstr = tmpstr2 = strdup(tmpstr); if (!copytmpstr) memerr(); + char *srcstr = tmpstr2, *deststr = tmpstr, *tmpstr3, *tmpstr4; + while ((*deststr++ = *srcstr++) != '\0') { + if (*(srcstr-1) == 'L') { + tmpstr3 = strchr(srcstr, ';'); if (!tmpstr3) fatalerror(UNKNOWN_ERR); + if (!strncmp(srcstr, "java/lang/", 10)) srcstr += 10; + else { + tmpstr2 = srcstr; + while (((tmpstr2 = strchr(tmpstr2,'/')) != 0)&&(tmpstr2 < tmpstr3)) *tmpstr2++ = '.'; + } + if (package_name && !strncmp(srcstr, package_name, package_name_length)) srcstr += package_name_length + 1; + if (numimports!=imports_count && (tmpstr4 = strchr(srcstr, '.')) != 0 && tmpstr4 < tmpstr3) { + while (tmpstr4 != 0 && tmpstr4 < tmpstr3) { tmpstr2 = tmpstr4+1; tmpstr4 = strchr(tmpstr2,'.'); } + int tint = tmpstr3 - srcstr; + char *tstr = imports[numimports++] = new char[tint+1]; + if (!tstr) memerr(); + tstr = strncpy(tstr, srcstr, tint); + tstr[tint] = '\0'; + for (tint = numimports - 2; tint>=0; tint--) { + if (!strcmp(imports[tint], tstr)) { + --numimports; + delete tstr; + break; + } + } + srcstr = tmpstr2; + } + } + } + mi.num_throws = 0; + mi.local_variable_table_length = 0; + mi.line_number_table_length = 0; + for (int l = get16(infile, &infile_pos); l--;) { + u16 attribute_name_index = get16(infile, &infile_pos); + u32 attribute_size = get32(infile, &infile_pos); + char *attribute_name = cp[attribute_name_index]->chp; + if (!strcmp(attribute_name,"Code")) { + mi.max_stack = (u8)get16(infile, &infile_pos); + mi.max_locals = (u8)get16(infile, &infile_pos); + if ((mi.code = new u8[mi.code_length = get32(infile, &infile_pos)]) == 0) memerr(); + getstr(mi.code, mi.code_length, infile); + if (((mi.exception_table = new ExceptionTableEntry[mi.exception_table_length = get16(infile, &infile_pos)]) == 0) && mi.exception_table_length) memerr(); + for (u16 n = 0, m = mi.exception_table_length; m--;) { + mi.exception_table[n].tag = TRY; + mi.exception_table[n].start_pc = get16(infile, &infile_pos); + mi.exception_table[n].end_pc = get16(infile, &infile_pos); + mi.exception_table[n].handler_pc = get16(infile, &infile_pos); + mi.exception_table[n++].catch_type = get16(infile, &infile_pos); + } + // getstr(mi.exception_table, mi.exception_table_length << 3, infile); + for (int l2 = get16(infile, &infile_pos); l2--;) { + u16 attribute_name_index2 = get16(infile, &infile_pos); + u32 attribute_size2 = get32(infile, &infile_pos); + char *attribute_name2 = cp[attribute_name_index2]->chp; + if (!strcmp(attribute_name2,"LineNumberTable")) { + if ((mi.line_number_table = new LineNumberTableEntry[mi.line_number_table_length = get16(infile, &infile_pos)]) == 0) memerr(); + getstr(mi.line_number_table, mi.line_number_table_length << 2, infile); + } else if (!strcmp(attribute_name2,"LocalVariableTable")) { + if ((mi.local_variable_table = new LocalVariableTableEntry[mi.local_variable_table_length = get16(infile, &infile_pos)]) == 0) memerr(); + getstr(mi.local_variable_table, mi.local_variable_table_length * 10, infile); + if ((mi.local_names = new char*[2*mi.local_variable_table_length]) == 0) memerr(); + int o; + for (o = mi.local_variable_table_length; o--;) { + char *tmpstr = cp[mi.local_variable_table[o].name_index]->chp; + if ((mi.local_names[mi.local_variable_table[o].slot] = new char[strlen(tmpstr) + 1]) == 0) memerr(); + strcpy(mi.local_names[mi.local_variable_table[o].slot], tmpstr); + } + if ((mi.local_sigs = new char*[2*mi.local_variable_table_length]) == 0) memerr(); + for (o = mi.local_variable_table_length; o--;) { + char *tmpstr = cp[mi.local_variable_table[o].signature_index]->chp; + if ((mi.local_sigs[mi.local_variable_table[o].slot] = new char[strlen(tmpstr) + 1]) == 0) memerr(); + strcpy(mi.local_sigs[mi.local_variable_table[o].slot], tmpstr); + } + } else { + fprintf(stderr, "Skipping Unknown Code Attribute: %s (size %ld)\n", attribute_name2, attribute_size2); + for (int m = attribute_size2; m--;) get8(infile, &infile_pos); + } + } + } else if (!strcmp(attribute_name,"Exceptions")) { + int *tmpintptr; + if ((tmpintptr = mi.throws = new int[mi.num_throws = get16(infile, &infile_pos)]) == 0) memerr(); + for (int m = mi.num_throws;m--;) *tmpintptr++ = get16(infile, &infile_pos); //*tmpstr++ = constant_pool[constant_pool[get16(infile)].i].cp; + } else { + fprintf(stderr, "Skipping Unknown Method Attribute: %s (size %ld)\n", attribute_name, attribute_size); + // char *ti = new int[attribute_size], *tip = ti; + for (unsigned int m = 0; m++!=attribute_size;) printf("%02x%c", /**tip++ =*/ get8(infile, &infile_pos), (m%8)?' ':(m%16?'\n':'\t')); + printf("\n"); + // int tc = ti[0]<<8+ti[1] + } + } + } + imports_count = numimports; + for (j = 0, i = get16(infile, &infile_pos); i--;) { + u16 attribute_name_index = get16(infile, &infile_pos); + u32 attribute_size = get32(infile, &infile_pos); + char *attribute_name = cp[attribute_name_index]->chp; + if (!strcmp(attribute_name,"SourceFile")) { + if (attribute_size != 2) { + fprintf(stderr, "Bad size on SourceFile Attribute - should be 2!\n"); + exit(1); + } else { + char *tmpstr = cp[get16(infile, &infile_pos)]->chp; + if ((source_name = new char[strlen(tmpstr) + 1]) == 0) memerr(); + strcpy(source_name, tmpstr); + } + } else { + fprintf(stderr, "Skipping Unknown Attribute: %s (size %ld)\n", attribute_name, attribute_size); + for (u32 k = attribute_size; k--;) get8(infile, &infile_pos); + } + } +} + +void Classfile::print() { + int i,j; + fprintf(stderr, "Compiled from %s\n", source_name); + fprintf(outfile, "/*\n** Compiled from %s - COPYRIGHT UNKNOWN.\n**\n" + "** Decompiled using the HomeBrew Decompiler\n" + "** Copyright (c) 1994-2003 Widget (aka Pete Ryland).\n" + "** Available under GPL from http://pdr.cx/hbd/\n*/\n\n", source_name); + if (package_name) fprintf(outfile, "package %s;\n\n", package_name); + char **strptr = imports; + for (i = imports_count; i--;) { + fprintf(outfile, "import %s;\n", *strptr++); + } + fprintf(outfile, "\n"); + char *tmpstr = new char[access_flags.strlen() + 1]; + fprintf(outfile, "%sclass %s ", access_flags.toString(tmpstr), this_class_name); + delete tmpstr; + if (super_class) { + if (!strcmp(tmpstr = cp(super_class)->chp, "Object")) { + super_class_name = "Object"; + } else { + if ((super_class_name = new char[strlen(tmpstr) + 1]) == 0) memerr(); + strcpy(super_class_name, tmpstr); + fprintf(outfile, "extends %s ", super_class_name); + } + } + if (interfaces_count) { + fprintf(outfile, "implements "); + for (j = 0, i = interfaces_count - 1; i--;) { + fprintf(outfile, "%s, ", cp(interfaces[j])->chp); + } + fprintf(outfile, "%s ", cp(interfaces[j])->chp); + } + fprintf(outfile, "{"); + for (j = 0, i = fields_count; i--;) { + field_info &fi = *(fields[j++]); + tmpstr = new char[fi.access_flags.strlen() + 1]; + fprintf(outfile, "\n %s", fi.access_flags.toString(tmpstr)); + delete tmpstr; + tmpstr = fi.sig; + printsigname(this, outfile, tmpstr, fi.name, 0); + if (fi.isconstant) { + fprintf(outfile, " = "); + char *chptr = fi.sig; + switch(*chptr++) { + case SIGNATURE_INT: + fprintf(outfile, "0x%lX", cp[fi.constval_index]->i); + break; + case SIGNATURE_LONG: + if(cp[fi.constval_index]->i) { + fprintf(outfile, "0x%lX%08lXL", cp[fi.constval_index]->i, + cp[(u16)((i16)fi.constval_index + 1)]->i); + } else { + fprintf(outfile, "0x%lXL", cp[(u16)((i16)fi.constval_index + 1)]->i); + } + break; + case SIGNATURE_FLOAT: + fprintf(outfile, "%#.100Gf", cp[fi.constval_index]->f); + break; + case SIGNATURE_DOUBLE: + fprintf(outfile, "%#.100Gd",(float)*(double*)(cp[fi.constval_index]->i)); + break; + default: + fprintf(stderr, "Bad type for constant\n"); + } + } + fprintf(outfile, ";"); + } + for (j = 0, i = methods_count; i--;) { + if (decompileblock(this, methods[j++])) fprintf(outfile, "/* Decompilation Error. Continuing... */"); + } + fprintf(outfile, "\n}"); + return; +} diff --git a/MultiSource/Applications/hbd/class.h b/MultiSource/Applications/hbd/class.h new file mode 100644 index 00000000..c14583e4 --- /dev/null +++ b/MultiSource/Applications/hbd/class.h @@ -0,0 +1,105 @@ +/* class.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef CLASS_H +#define CLASS_H + +#include <stdio.h> +#include "options.h" +#include "version.h" +#include "cp.h" +#include "access.h" +#include "general.h" +#include "field.h" +#include "method.h" + +/* The master classfile structure. */ +struct Classfile { + /* The input and output files */ + FILE *infile, *outfile; + + /* These keeps a tab on where in the files we are */ + int infile_pos, outfile_pos; + + /* The command-line options we are using */ + CL_Options options; + + /* The basic class file format starts from here */ + + /* The class version - should always be 45.3 */ + ClassVersion version; + + /* The Constant Pool */ + ConstPool cp; + + /* The access modifiers for this class */ + AccessFlags access_flags; + + /* An index into the constant pool of the name + of this class. */ + u16 this_class; + + /* This contains the name of the package for this class, + resolved from the above constant-pool reference */ + char *package_name; + + /* This contains the name of the actual class, + resolved from the above constant-pool reference */ + char *this_class_name; + + /* This is an index into the constant pool for the name + of the parent class */ + u16 super_class; + + /* The resolved string */ + char *super_class_name; + + /* This table contains indexes into the constant pool + for the interfaces that this class implements */ + u16 interfaces_count; + u16 *interfaces; + + /* This table contains the fields in this class */ + u16 fields_count; + field_info_ptr *fields; + + /* This table contains the methods in this class */ + u16 methods_count; + method_info_ptr *methods; + + /* The name of the source file from which this + class was compiled. This is determined from + the SourceFile attribute. */ + char *source_name; + + /* This table holds the import statements that this + class would have needed to enable it to refer to + all the classes it uses without referring to + their package name. It is determined from clues + the parser finds along the way. */ + u16 imports_count; + char **imports; + + /* The function that the translator will be inserting + the code for */ + char *functoinsert; + + /* The constructor, which will parse the command-line + arguments */ + Classfile(int argc, char **argv); + + /* The read() and print() methods are only used by the + decompiler */ + /* The read() method parses the input file */ + void read(); + /* print() decompiles and prints the decompilation + of the class */ + void print(); +}; + +#endif diff --git a/MultiSource/Applications/hbd/config.h b/MultiSource/Applications/hbd/config.h new file mode 100644 index 00000000..8ac4f283 --- /dev/null +++ b/MultiSource/Applications/hbd/config.h @@ -0,0 +1,53 @@ +/* src/config.h. Generated by configure. */ +/* src/config-h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "hbd" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.2.3" diff --git a/MultiSource/Applications/hbd/consts.h b/MultiSource/Applications/hbd/consts.h new file mode 100644 index 00000000..c388f713 --- /dev/null +++ b/MultiSource/Applications/hbd/consts.h @@ -0,0 +1,28 @@ +/* consts.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef CONSTS_H +#define CONSTS_H + +/* These are the tags that the constant pool uses. */ +enum { + CONSTANT_Utf8 = 1, + CONSTANT_Unicode, /* unused */ + CONSTANT_Integer, + CONSTANT_Float, + CONSTANT_Long, + CONSTANT_Double, + CONSTANT_Class, + CONSTANT_String, + CONSTANT_Fieldref, + CONSTANT_Methodref, + CONSTANT_InterfaceMethodref, + CONSTANT_NameAndType +}; + +#endif diff --git a/MultiSource/Applications/hbd/cp.cpp b/MultiSource/Applications/hbd/cp.cpp new file mode 100644 index 00000000..6d2730c8 --- /dev/null +++ b/MultiSource/Applications/hbd/cp.cpp @@ -0,0 +1,83 @@ +/* cp.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "general.h" +#include "cp.h" +#include "file.h" +#include "err.h" +#include "class.h" +#include "consts.h" + +void ConstPool::read(Classfile *c, u16 *imports_count) { + if ((constant_pool = new cp_info[(constant_pool_count = get16(c->infile, &c->infile_pos))]) == 0) memerr(); + for (int j = 1, i = constant_pool_count - 1; i--;) { + cp_info *cpi = &constant_pool[j++]; + cpi->tag = (unsigned char)get8(c->infile, &c->infile_pos); + unsigned short size; + D(fprintf(c->outfile, "\npos: 0x%05X\tindex: %4d\t",c->infile_pos,j-1)) + switch(cpi->tag) { + case CONSTANT_Utf8: + if ((cpi->chp = new char[(size = get16(c->infile, &c->infile_pos)) + 1]) == 0) memerr(); + getstr(cpi->chp, size, c->infile); + cpi->chp[size] = '\0'; + D(fprintf(c->outfile, "UTF8: %s\t", cpi->chp)) + break; + case CONSTANT_Unicode: D(fprintf(c->outfile, "Unicode\t")) /* unused */ + break; + case CONSTANT_Integer: + cpi->i = get32(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "32-bit int: 0x%8lX\t", cpi->i)) + break; + case CONSTANT_Float: + cpi->i = get32(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "32-bit float: %.25G\t", cpi->f)) + break; + case CONSTANT_Long: + cpi->i = get32(c->infile, &c->infile_pos); + cpi = &constant_pool[j++]; + cpi->tag = 0; + cpi->i = get32(c->infile, &c->infile_pos); + D(((cpi - 1)->i) ? fprintf(c->outfile, "64-bit int: 0x%lX%08lX", (cpi - 1)->i, cpi->i) : fprintf(c->outfile, "64-bit int: 0x%lX", cpi->i)) + if (i--) continue; + break; + case CONSTANT_Double: + *(((unsigned long *)&cpi->i) + 1) = get32(c->infile, &c->infile_pos); + cpi->i = get32(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "64-bit float: %.25G\t",(float)*(double*)(&cpi->i))) constant_pool[j++].tag = 0; + if (i--) continue; + break; + case CONSTANT_Class: + imports_count++; + cpi->i = get16(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "Class: name = index %d\t", (int)cpi->i)) + break; + case CONSTANT_String: + cpi->i = get16(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "String: index %d\t", (int)cpi->i)) + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + if ((cpi->p = new Ref) == 0) memerr(); + ((Ref*)cpi->p)->class_index = get16(c->infile, &c->infile_pos); + ((Ref*)cpi->p)->name_and_type = get16(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "Ref: class_index %d, n&t_index %d\t", ((Ref*)cpi->p)->class_index, ((Ref*)cpi->p)->name_and_type)) + break; + case CONSTANT_NameAndType: + imports_count++; + if ((cpi->p = new NameAndType) == 0) memerr(); + ((NameAndType*)cpi->p)->name_index = get16(c->infile, &c->infile_pos); + ((NameAndType*)cpi->p)->signature_index = get16(c->infile, &c->infile_pos); + D(fprintf(c->outfile, "Name&Type: name_index %d, sig_index %d\t", ((NameAndType*)cpi->p)->name_index, ((NameAndType*)cpi->p)->signature_index)) + break; + default: + fprintf(stderr, "Error reading constant pool entry %d of %d at file pos 0x%08x!\n", j, constant_pool_count, c->infile_pos); + fatalerror(CP_ERR); + } + } +} diff --git a/MultiSource/Applications/hbd/cp.h b/MultiSource/Applications/hbd/cp.h new file mode 100644 index 00000000..548ea3d2 --- /dev/null +++ b/MultiSource/Applications/hbd/cp.h @@ -0,0 +1,68 @@ +/* cp.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef CP_H +#define CP_H + +#include "general.h" + +/* These are structures that the constant pool's table + can contain. */ + +typedef struct { + u16 class_index; + u16 name_and_type; +} Ref; + +typedef struct { + u16 name_index; + u16 signature_index; +} NameAndType; + +/* The generic structure of constants that will appear + in the table of constants in the constant pool */ +struct cp_info { + unsigned char tag; + union { + long i; + void *p; + double d; + float f; + char *chp; + }; +}; + +/* Forward declaration of the Classfile struct */ +struct Classfile; + +/* The ConstPool struct, which contains the Constant + Pool. */ +struct ConstPool { + /* The number of entries in this Constant Pool */ + u16 constant_pool_count; + + /* The table of constants */ + cp_info *constant_pool; + + /* This will parse the input file for a constant pool */ + void read(Classfile *c, u16 *imports_count); + + /* These methods provide easy access to commonly + used parts of constant pool entries */ + cp_info *operator [](u16 i) { + return &(constant_pool[i]); + } + cp_info *operator ()(u16 i) { + return &(constant_pool[constant_pool[i].i]); + } + u16 count() { + return constant_pool_count; + } +}; + +#endif diff --git a/MultiSource/Applications/hbd/d1-pushc.cpp b/MultiSource/Applications/hbd/d1-pushc.cpp new file mode 100644 index 00000000..5f217e07 --- /dev/null +++ b/MultiSource/Applications/hbd/d1-pushc.cpp @@ -0,0 +1,80 @@ +/* d1-pushc.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" +#include "consts.h" + +int pushimm(Classfile *c) /* push immediate value e.g. bipush 34 */ +{ + int pcval = currpc - 1; + int val = JDNEXT8S(); + if (ch == 0x11) { val<<=8; val+=JDNEXT8U(); } + char *temp_str = new char[32]; + sprintf(temp_str, "%i", val); + *stkptr++ = new Exp(pcval, temp_str, INT, IM); /* id->linfo = val */ + return 0; +} + +int pushconst(Classfile *c) /* push value from cp e.g. ldc1 #3 */ +{ + int pcval = currpc - 1; + int val = JDNEXT8U(); + if (ch != 0x12) { val<<=8; val+=JDNEXT8U(); } + Type idtype; + char tmpstr[1024]; + cp_info *cpi = c->cp[val]; + switch (cpi->tag) { + case CONSTANT_Integer: + sprintf(tmpstr, "0x%lX", cpi->i); + idtype = INT; +// id->linfo = cpi->i; + break; + case CONSTANT_Long: + if (cpi->i) + sprintf(tmpstr, "0x%lX%08lXL", cpi->i, (cpi + 1)->i); + else + sprintf(tmpstr, "0x%lXL", (cpi + 1)->i); + idtype = LONG; +// id->linfo = (cpi + 1)->i; +// id->llinfo[2] = cpi->i; + break; + case CONSTANT_Float: + sprintf(tmpstr, "%.25Gf", cpi->f); + idtype = FLOAT; +// id->dinfo = cpi->f; + break; + case CONSTANT_Double: + sprintf(tmpstr, "%.25Gd", *(double *)&cpi->i); + idtype = DOUBLE; +// id->dinfo = *(double*)&cpi->i; + break; + case CONSTANT_String: + sprintf(tmpstr, "\"%s\"", c->cp[cpi->i]->chp); + idtype = OBJECT; /* java.lang.String */ +// id->dinfo = (int)c->cp[cpi->i]->chp; + break; + default: + fprintf(stderr, "Unkown tag %d on constant\n", cpi->tag); + return -1; + } + char *idname = new char[strlen(tmpstr) + 1]; + strcpy(idname, tmpstr); + *stkptr++ = new Exp(pcval, idname, idtype, CP, val); + return 0; +} + +int pushimp(Classfile *c) /* push implied immediate value e.g. iconst_m1 */ +{ + *stkptr++ = new Exp(currpc - 1, ch - 1); + return 0; +} + diff --git a/MultiSource/Applications/hbd/d2-pushl.cpp b/MultiSource/Applications/hbd/d2-pushl.cpp new file mode 100644 index 00000000..1e717454 --- /dev/null +++ b/MultiSource/Applications/hbd/d2-pushl.cpp @@ -0,0 +1,60 @@ +/* d2-pushl.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "general.h" +#include "exp.h" +#include "decomp.h" +#include "method.h" + +int pushlocal(Classfile *c) /* push value from local (or params) */ +{ + int pcval = currpc - 1; + int val; + Type idtype = VOID; + if (ch < 0x1A) { + val = JDNEXT8S(); + switch (ch) { + case 0x15: idtype = INT; break; + case 0x16: idtype = LONG; break; + case 0x17: idtype = FLOAT; break; + case 0x18: idtype = DOUBLE; break; + case 0x19: idtype = OBJECT; break; + } + } else if (ch < 0x1E) { + val = ch - 0x1A; + idtype = INT; + } else if (ch < 0x22) { + val = ch - 0x1E; + idtype = LONG; + } else if (ch < 0x26) { + val = ch - 0x22; + idtype = FLOAT; + } else if (ch < 0x2A) { + val = ch - 0x26; + idtype = DOUBLE; + } else /* if (ch < 0x2E) */ { + val = ch - 0x2A; + idtype = OBJECT; + } + char *tmpstr = miptr->local_names[val], *idname; + if (tmpstr) { + idname = new char[strlen(tmpstr) + 1]; + strcpy(idname, tmpstr); + } else { + fprintf(stderr, "Error in code: local used before defined.\n"); + return 1; + } + Exp *e = new Exp(pcval, idname, idtype, LO, val); +// if((lastaction == 16)&&(!strcmp((*(donestkptr-1))->exp1->e->id->name,id->name))) { +// *stkptr++ = *(--donestkptr); + *stkptr++ = e; +// } else { +// *stkptr++ = e; +// } + return 0; +} diff --git a/MultiSource/Applications/hbd/d3-popl.cpp b/MultiSource/Applications/hbd/d3-popl.cpp new file mode 100644 index 00000000..7febaf58 --- /dev/null +++ b/MultiSource/Applications/hbd/d3-popl.cpp @@ -0,0 +1,116 @@ +/* d3-popl.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdlib.h> +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int storelocal(Classfile *c) /* pop value to local (including params) */ +{ + unsigned pcval = currpc - 1; + int val; + Type idtype = VOID; + if (ch < 0x3B) { + switch (ch) { + case 0x36: idtype = INT; break; + case 0x37: idtype = LONG; break; + case 0x38: idtype = FLOAT; break; + case 0x39: idtype = DOUBLE; break; + case 0x3A: idtype = OBJECT; break; + } + val = JDNEXT8S(); + } else if (ch < 0x3F) { + val = ch - 0x3B; + idtype = INT; + } else if (ch < 0x43) { + val = ch - 0x3F; + idtype = LONG; + } else if (ch < 0x47) { + val = ch - 0x43; + idtype = FLOAT; + } else if (ch < 0x4B) { + val = ch - 0x47; + idtype = DOUBLE; + } else { + val = ch - 0x4B; + idtype = OBJECT; + } +// if (val) { + char *tmpstr = miptr->local_names[val], *idname; + if (tmpstr) { + idname = new char[strlen(tmpstr) + 1]; + strcpy(idname, tmpstr); + idtype = miptr->local_types[val]; + } else { + idname = miptr->local_names[val] = new char[7]; + sprintf(idname, "var%d", val); + if ((miptr->local_types[val] == VOID)||(miptr->local_types[val] == UNKNOWN)) { + if (idtype != INT) + miptr->local_types[val] = idtype; + else + miptr->local_types[val] = UNKNOWN; + } + } + Exp *e1 = new Exp(pcval, idname, idtype, LO, val); + Exp *e2 = *(--stkptr); + Exp *e = new Exp(pcval, min(pcval, e2->minpc), BINARY, idtype, ASSIGN, e1, e2); + if (!tmpstr) miptr->local_firstuses[val] = e->minpc; + if ((e2->e->type == INT) && (e1->e->type == BOOLEAN)) + if ((e2->e == std_exps + 2)||(e2->e == std_exps + 3)) /* 0 or 1 */ + e2->e += 13; /* false or true */ + else + /* CMPEQ */; + *donestkptr++ = e; + return 0; +} + +int iinclocal(Classfile *c) /* increment local by value */ +{ + int pcval = currpc - 1; + int val; + val = JDNEXT8S(); + char *id1name; + char *tmpstr = miptr->local_names[val]; + if (tmpstr) { +// id1name = new char[strlen(tmpstr) + 1]; +// strcpy(id1name, tmpstr); + id1name = tmpstr; + } else { + printf("Local int used before defined.\n"); + return 1; + } + if (miptr->local_types[val] == UNKNOWN) miptr->local_types[val] = INT; +// if (miptr->local_types[val] == UNKNOWN) miptr->local_types[val] = INT; +// if (miptr->local_types[val] == VOID) miptr->local_types[val] = INT; + if ((miptr->local_types[val] != INT)&&(miptr->local_types[val] != SHORT)) { + printf("Incrementation of local var%d of type %d i.e. %s.\n", val, miptr->local_types[val], type2str[miptr->local_types[val]]); + return 1; + } + int incnum = JDNEXT8S(); +// id2->linfo = incnum; + Exp *e; + if ((incnum!=1)&&(incnum!=-1)) { + Exp *e1 = new Exp(pcval, id1name, INT, LO, val); + char *id2name = new char[5]; sprintf(id2name, "%ld", labs(incnum)); + Exp *e2 = new Exp(pcval, id2name, INT, IM); + e = new Exp(pcval, BINARY, INT, (incnum<0)?SUBASSIGN:ADDASSIGN, e1, e2); + } else { + Exp *e1 = new Exp(pcval, id1name, INT, LO, val); + e = new Exp(pcval, PREUNARY, INT, (incnum<0)?DEC:INC, e1); + } + + if ((lastaction == 4)&&(!strcmp((*(stkptr-1))->e->id->name,id1name))) { + e->e->et = POSTUNARY; e->minpc = min(e->minpc, (*(stkptr-1))->minpc); + *(stkptr-1) = e; + } else { + *donestkptr++ = e; + } + return 0; +} diff --git a/MultiSource/Applications/hbd/d4-array.cpp b/MultiSource/Applications/hbd/d4-array.cpp new file mode 100644 index 00000000..931f8754 --- /dev/null +++ b/MultiSource/Applications/hbd/d4-array.cpp @@ -0,0 +1,68 @@ +/* d4-array.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int anewarray(Classfile *c) +{ + unsigned pcval = currpc - 1; + int val = JDNEXT16U(); + char *class_name = c->cp(val)->chp; + Exp *e1 = new Exp(pcval, class_name, VOID, NO); + Exp *e2 = new Exp(pcval, ARRAYACCESS, VOID, ID, e1, *(stkptr-1)); + *(stkptr-1) = new Exp(pcval, min(pcval, e2->exp2->minpc), PREUNARY, ARRAY, NEW, e2); + return 0; +} + +int multianewarray(Classfile *c) +{ + printf("Multi"); + unsigned pcval = currpc - 1; + /*int val = */JDNEXT16U(); +// char *class_name; // = c->constant_pool[c->constant_pool[val].i].cp; +// for (val = JDNEXT8U(); val--;) { +// --stkptr; +// } stkptr++; + Exp *e1 = *(stkptr-1); + *(stkptr-1) = new Exp(pcval, min(pcval, e1->minpc), PREUNARY, ARRAY, NEW, e1); + return 0; +} + +int doarraylength(Classfile *c) /* 190 == 0xBE */ +{ + unsigned pcval = currpc - 1; + Exp *e1 = *(stkptr-1); + Exp *e2 = new Exp(pcval, "length", VOID, NO); + *(stkptr-1) = new Exp(pcval, min(pcval, e1->minpc), BINARY, INT, DOT, e1, e2); + return 0; +} + +int doarrayget(Classfile *c) +{ + unsigned pcval = currpc - 1; + Exp *e2 = *(--stkptr); + Exp *e1 = *(stkptr-1); + *(stkptr-1) = new Exp(pcval, min(min(pcval, e1->minpc), e2->minpc), ARRAYACCESS, + (Type)(ch - (0x2E - INT)), ID, e1, e2); + return 0; +} + +int doarrayput(Classfile *c) +{ + unsigned pcval = currpc - 1; + Exp *e4 = *(--stkptr); + Exp *e3 = *(--stkptr); + Exp *e2 = *(--stkptr); + unsigned minpcval = min(min(pcval, e2->minpc), e3->minpc); + Exp *e1 = new Exp(pcval, minpcval, ARRAYACCESS, OBJECT, ID, e2, e3); + *donestkptr++ = new Exp(pcval, minpcval, BINARY, OBJECT, ASSIGN, e1, e4); + return 0; +} diff --git a/MultiSource/Applications/hbd/d5-stack.cpp b/MultiSource/Applications/hbd/d5-stack.cpp new file mode 100644 index 00000000..c38df102 --- /dev/null +++ b/MultiSource/Applications/hbd/d5-stack.cpp @@ -0,0 +1,39 @@ +/* d5-stack.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int dopop(Classfile *c) +{ + if (stkptr != stack) *donestkptr++ = *(--stkptr); + return 0; +} + + +int dodup(Classfile *c) +{ + if ((*(stkptr-1))->e->op != NEW) { + *stkptr = *(stkptr-1); + (*stkptr)->numrefs++; + stkptr++; + } + return 0; +} + +int dodup_x1(Classfile *c) +{ + *stkptr = *(stkptr-1); + *(stkptr-1) = *(stkptr-2); + *(stkptr-2) = *stkptr; + (*stkptr)->numrefs++; + stkptr++; + return 0; +} diff --git a/MultiSource/Applications/hbd/d6-arith.cpp b/MultiSource/Applications/hbd/d6-arith.cpp new file mode 100644 index 00000000..217d17a4 --- /dev/null +++ b/MultiSource/Applications/hbd/d6-arith.cpp @@ -0,0 +1,99 @@ +/* d6-arith.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +extern int cond_pcend; +extern Exp *cond_e; +extern Exp *cond_e2; +extern Exp **cond_donestkptr; +extern Exp **cond_stkptr; + +int pushbinop(Classfile *c) /* push binary operation, popping operands e.g. lxor */ +{ + unsigned pcval = currpc - 1; + Exp *e2 = *(--stkptr); + Exp *e1 = *(stkptr-1); + *(stkptr-1) = new Exp(pcval, min(min(e1->minpc, e2->minpc), pcval), BINARY, + e1->e->type, + (Op)((ch < 0x74)? + ((ch - 0x60) >> 2) : (0x07 + ((ch - 0x78) >> 1))), + e1, e2); + return 0; +} + +int pushunop(Classfile *c) /* push unary operation, popping operand e.g. lneg */ +{ + unsigned pcval = currpc - 1, branch_pc; + char *tmpstr, *buff; + Exp *e1 = *(stkptr-1); + Op eop = CAST; + Type etype = VOID; + int val; + switch (ch) { + case 0x74: case 0x75: case 0x76: case 0x77: eop = NEG; etype = e1->e->type; break; + case 0x88: case 0x8B: case 0x8E: etype = INT; break; + case 0x85: case 0x8C: case 0x8F: etype = LONG; break; + case 0x86: case 0x89: case 0x90: etype = FLOAT; break; + case 0x87: case 0x8A: case 0x8D: etype = DOUBLE; break; + case 0x91: etype = BYTE; break; + case 0x92: etype = CHAR; break; + case 0x93: etype = SHORT; break; + case 0xBF: + --stkptr; + *donestkptr++ = new Exp(pcval, min(e1->minpc, pcval), PREUNARY, VOID, THROW, e1); + return 0; + case 0xBB: + val = JDNEXT16U(); + tmpstr = c->cp(val)->chp; + buff = new char[strlen(tmpstr) + 1]; strcpy(buff, tmpstr); + e1 = new Exp(pcval, buff, VOID, CP, val); + *(stkptr++) = new Exp(pcval, min(e1->minpc, pcval), PREUNARY, OBJECT, NEW, e1); +// if ((ch = JDNEXT8()) == 0x59) +// return actiontable[actions[ch = JDNEXT8()]](); +// else +// return actiontable[actions[ch]](); + case 0xBA: eop = NEW; break; + case 0xA7: /* GOTO really shouldn't be here! */ + if (stkptr!=stack) { +// if (stkptr!=(stack+1)) { fprintf(stderr, "Error in conditional operator!\n"); return 1; } + if (cond_pcend != -1) { fprintf(stderr, "Can't handle recursive conditional operators!\n"); return 1; } + cond_pcend = pcval + JDNEXT16S(); + cond_stkptr = stkptr; + cond_e2 = *(--stkptr); + --donestkptr; + if ((*donestkptr)->e->et == BRANCH) { + if ((*donestkptr)->branch_pc != currpc) { + fprintf(stderr, "Error in conditional operator!\n"); return 1; + } + cond_e = *donestkptr; + } else { + fprintf(stderr, "Use of comma operator in conditionals not yet supported.\n"); + return 1; + } + cond_donestkptr = donestkptr; + return 0; + } + branch_pc = pcval + JDNEXT16S(); + tmpstr = new char[100]; + sprintf(tmpstr,"label%i", branch_pc); + buff = new char[strlen(tmpstr) + 1]; strcpy(buff, tmpstr); + delete tmpstr; + e1 = new Exp(pcval, buff, VOID/*label*/, IM); + *donestkptr++ = new Exp(pcval, PREUNARY, VOID, GOTO, e1, branch_pc); + return 0; + default: + fprintf(stderr, "Error in pushing unary operation\n"); + exit(-1); + } + *(stkptr-1) = new Exp(pcval, min(e1->minpc, pcval), PREUNARY, etype, eop, e1); + return 0; +} diff --git a/MultiSource/Applications/hbd/d7-cntrl.cpp b/MultiSource/Applications/hbd/d7-cntrl.cpp new file mode 100644 index 00000000..12b55705 --- /dev/null +++ b/MultiSource/Applications/hbd/d7-cntrl.cpp @@ -0,0 +1,84 @@ +/* d7-cntrl.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int cond_pcend; +Exp *cond_e; +Exp *cond_e2; +Exp **cond_donestkptr; +Exp **cond_stkptr; + +int doif1(Classfile *c) +{ + unsigned pcval = currpc - 1; + Exp *e = *(--stkptr), *e1, *e2; + switch (e->e->type) { + case CMPTYPE: + if (e->e->op != CMP) { fprintf(stderr, "doif1 error\n"); return 1; } + e->e->op = (Op)(EQUAL + ch - 0x99); e->e->type = BOOLEAN; + break; + case BOOLEAN: + if (ch == 0x99) // ifeq (ie if false) + if (notexp(&e)) { fprintf(stderr, "doif1 error\n"); return 1; } + break; + case INT: + e1 = *stkptr; e2 = new Exp(pcval, I0EXP); + e = new Exp(pcval, e1->minpc, BINARY, BOOLEAN, (Op)(EQUAL + ch - 0x99), e1, e2); + break; + case OBJECT: + e1 = *stkptr; e2 = new Exp(pcval, NULLEXP); + e = new Exp(pcval, e1->minpc, BINARY, BOOLEAN, (Op)(EQUAL + ch - 0xC6), e1, e2); + break; + default: + break; + } + *donestkptr++ = new Exp(pcval, e->minpc, IFEXP, e, pcval + JDNEXT16S()); + return 0; +} + +int doif2(Classfile *c) +{ + unsigned pcval = currpc - 1; + Exp *e2 = *(--stkptr); + Exp *e1 = *(--stkptr); + Exp *e = new Exp(pcval, min(e1->minpc, e2->minpc), BINARY, BOOLEAN, + (Op)(EQUAL + ((ch - 0x9F) % 6)), e1, e2); + *donestkptr++ = new Exp(pcval, e->minpc, /*std_exp*/IFEXP, e, + /*branch_pc*/pcval + JDNEXT16S()); + return 0; +} + +int docmp(Classfile *c) +{ + unsigned pcval = currpc - 1; + Exp *e2 = *(--stkptr); + Exp *e1 = *(stkptr-1); + *(stkptr-1) = new Exp(pcval, min(e1->minpc, e2->minpc), BINARY, CMPTYPE, CMP, e1, e2); + return 0; +} + +int finishconditional(Classfile *c) { + if ((stkptr != cond_stkptr) || (donestkptr != cond_donestkptr)) + { fprintf(stderr, "Error cond\n"); return 1; } + cond_e->e++; + if ((cond_e->exp1->e->op > LESSOREQUAL) || (cond_e->exp1->e->op < EQUAL)) { + if (cond_e->exp1->e->type != BOOLEAN) { fprintf(stderr, "Can't not a non-boolean\n"); return 1; } + Exp *e1 = cond_e->exp1; + cond_e->exp1 = new Exp(currpc, e1->minpc, PREUNARY, BOOLEAN, NOT_BOOL, e1); + } else { + *((int*)(&cond_e->exp1->e->op)) ^= 1; + } + cond_e->exp2 = cond_e2; cond_e->exp3 = *(stkptr-1); + *(stkptr-1) = cond_e; + cond_pcend = -1; + return 0; +} diff --git a/MultiSource/Applications/hbd/d8-ret.cpp b/MultiSource/Applications/hbd/d8-ret.cpp new file mode 100644 index 00000000..17b4615e --- /dev/null +++ b/MultiSource/Applications/hbd/d8-ret.cpp @@ -0,0 +1,35 @@ +/* d8-ret.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int doreturn(Classfile *c) /* push return op, popping operand e.g. ireturn LO3 */ +{ + unsigned pcval = currpc - 1; + if (ch == 0xB1) { + if (bufflength > 0) { + Exp *e1 = new Exp(pcval, "/* void */", VOID, IM); + *donestkptr++ = new Exp(pcval, PREUNARY, VOID, RETURN, e1); + } + } else { + Exp *e1 = *(stkptr-1); + if ((e1->e->type == INT) && (miptr->ret_type == BOOLEAN)) { + if ((e1->e == std_exps + 2)||(e1->e == std_exps + 3)) + e1->e += 13; /* convert 0 or 1 to false or true */ + else + /* CMPEQ */; + } + --stkptr; + *donestkptr++ = new Exp(pcval, min(pcval, e1->minpc), PREUNARY, VOID, RETURN, e1); + } + return 0; +} + diff --git a/MultiSource/Applications/hbd/d9-swtch.cpp b/MultiSource/Applications/hbd/d9-swtch.cpp new file mode 100644 index 00000000..36fac620 --- /dev/null +++ b/MultiSource/Applications/hbd/d9-swtch.cpp @@ -0,0 +1,43 @@ +/* d9-swtch.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int dotableswitch(Classfile *c) +{ + unsigned pcval = currpc - 1; + while(currpc%4) JDNEXT8U(); + Exp *e1 = *(--stkptr); + unsigned defaultpc = JDNEXT32S(); + unsigned low = JDNEXT32S(), high = JDNEXT32S(), numcases = high - low + 1; + Case *tcase = new Case[numcases]; + *donestkptr++ = new Exp(pcval, e1->minpc, SWITCH, VOID, ID, e1, defaultpc, numcases, tcase); + for (unsigned m = low; m <= high;) { + tcase->caseval = m++; + (tcase++)->branch_pc = JDNEXT32S(); + } + return 0; +} + +int doluswitch(Classfile *c) +{ + unsigned pcval = currpc - 1; + while(currpc%4) JDNEXT8U(); + Exp *e1 = *(--stkptr); + unsigned defaultpc = JDNEXT32U(), numcases = JDNEXT32U(); + Case *tcase = new Case[numcases]; + *donestkptr++ = new Exp(pcval, e1->minpc, SWITCH, VOID, ID, e1, defaultpc, numcases, tcase); + for (unsigned m = numcases; m--;) { + tcase->caseval = JDNEXT32U(); + (tcase++)->branch_pc = JDNEXT32U(); + } + return 0; +} diff --git a/MultiSource/Applications/hbd/da-field.cpp b/MultiSource/Applications/hbd/da-field.cpp new file mode 100644 index 00000000..2279a472 --- /dev/null +++ b/MultiSource/Applications/hbd/da-field.cpp @@ -0,0 +1,112 @@ +/* da-field.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" +#include "field.h" + +int doget(Classfile *c) +{ + unsigned pcval = currpc - 1; + int val = JDNEXT16S(); + Ref *mr = (Ref*)c->cp[val]->p; + NameAndType *nt = (NameAndType*)c->cp[mr->name_and_type]->p; + char *tmpstr = c->cp[nt->name_index]->chp; + Exp *e = new Exp(pcval, tmpstr, sig2type(c->cp[nt->signature_index]->chp), CP, val); + if (ch == 0xB2) { /* getstatic */ + Exp *e1; + tmpstr = c->cp(mr->class_index)->chp; +// int tmpint = strlen(c->package_name); + if (strcmp(tmpstr, c->this_class_name)) { + Exp *e2 = new Exp(pcval, tmpstr, VOID, NO); + e1 = new Exp(pcval, BINARY, e->e->type, DOT, e2, e); + e->e->type = VOID; + } else { + e1 = e; + } + *stkptr++ = e1; + return 0; + } else { /* getfield */ + if (((*(stkptr-1))->e->et == IDENT) && !strcmp((*(stkptr-1))->e->id->name,"this")) { + /* this.bar == bar */ + e->minpc = min(pcval, (*(stkptr-1))->minpc); + *(stkptr-1) = e; return 0; + } else { + /* foo.bar */ + *(stkptr-1) = new Exp(pcval, min(pcval, (*(stkptr-1))->minpc), BINARY, + e->e->type, DOT, *(stkptr-1), e); + e->e->type = VOID; + return 0; + } + } +} + +int doput(Classfile *c) +{ + unsigned pcval = currpc - 1; + int val = JDNEXT16S(); + Ref *mr = (Ref*)c->cp[val]->p; + NameAndType *nt = (NameAndType*)c->cp[mr->name_and_type]->p; + char *tmpstr = c->cp[nt->name_index]->chp; + Exp *e = new Exp(pcval, tmpstr, sig2type(c->cp[nt->signature_index]->chp), NO); + if (ch == 0xB3) { /* putstatic */ + Exp *e1; + tmpstr = c->cp(mr->class_index)->chp; + if (strcmp(tmpstr, c->this_class_name)) { + Exp *e2 = new Exp(pcval, tmpstr, VOID, NO); + e1 = new Exp(pcval, BINARY, e->e->type, DOT, e2, e); + e->e->type = VOID; + } else { + e1 = e; + } + Exp *e3 = *(--stkptr); + if ((e3->e->type == INT) && (e1->e->type == BOOLEAN)) { + if ((e3->e == std_exps + 2)||(e3->e == std_exps + 3)) + e3->e += 13; + else + /* CMPEQ */; + } + *donestkptr++ = new Exp(pcval, min(pcval, e3->minpc), BINARY, + e1->e->type, ASSIGN, e1, e3); + return 0; + } else { /* putfield */ + Exp *e3 = *(stkptr-2); + if ((e3->e->et == IDENT) && !strcmp(e3->e->id->name,"this")) { + /* this.bar == bar */ + e3 = *(--stkptr); + if ((e3->e->type == INT) && (e->e->type == BOOLEAN)) { + if ((e3->e == std_exps + 2)||(e3->e == std_exps + 3)) + e3->e += 13; + else + /* CMPEQ */; + } + stkptr--; + *donestkptr++ = new Exp(pcval, min(min(pcval, (*stkptr)->minpc), + (*stkptr)->minpc), + BINARY, e->e->type, ASSIGN, e, e3); + return 0; + } else { + /* foo.bar */ + Exp *e1 = new Exp(pcval, min((*(stkptr-1))->minpc, pcval), BINARY, + e->e->type, DOT, e3, e); + e->e->type = VOID; + e3 = *(--stkptr); + if ((e3->e->type == INT) && (e1->e->type == BOOLEAN)) { + if ((e3->e == std_exps + 2)||(e3->e == std_exps + 3)) + e3->e += 13; + else + /* CMPEQ */; + } + *donestkptr++ = new Exp(pcval, min(e3->minpc, e1->minpc), BINARY, + e1->e->type, ASSIGN, e1, e3); + return 0; + } + } +} diff --git a/MultiSource/Applications/hbd/db-meth.cpp b/MultiSource/Applications/hbd/db-meth.cpp new file mode 100644 index 00000000..494d8aa4 --- /dev/null +++ b/MultiSource/Applications/hbd/db-meth.cpp @@ -0,0 +1,117 @@ +/* db-meth.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int invokefunc(Classfile *c) +{ + unsigned pcval = currpc - 1; + unsigned minpcval = pcval; + int i; + Type exptypes[256]; + int val = JDNEXT16S(); + Ref *mr = (Ref*)c->cp[val]->p; + NameAndType *nt = (NameAndType*)c->cp[mr->name_and_type]->p; + char *classname = c->cp(mr->class_index)->chp; + char *tmpstr = c->cp[nt->signature_index]->chp; + char *name = c->cp[nt->name_index]->chp; + Exp **el = new Exp*[strlen(tmpstr)-2]; + Exp *e1 = new Exp(pcval, name, VOID, NO); + unsigned numexps = 0; + while (*(++tmpstr) != ')') { + exptypes[numexps++] = sig2type(tmpstr); + if (*tmpstr == '[') tmpstr++; + if (*tmpstr == 'L') while (*(++tmpstr) != ';') /* do nothing */; + } + Type etype = sig2type(tmpstr + 1); + Exp **elp = el; + for (i = numexps; i--;) { + if (((*(--stkptr))->e->type == INT) && (exptypes[i] == BOOLEAN)) { + if (((*stkptr)->e == std_exps + 2)||((*stkptr)->e == std_exps + 3)) + (*stkptr)->e += 13; + else + /* CMPEQ */; + } + *elp++ = *stkptr; + minpcval = min(minpcval, (*stkptr)->minpc); + } + if (ch == 0xB9) { /* invokeinterface */ + if (numexps != (unsigned)(JDNEXT8U() - 1)) { + fprintf(stderr,"Error in interface method invocation - nargs doesn't match.\n"); + return 1; + } + JDNEXT8U(); /* reserved byte */ + } + if (ch != 0xB8) { /* invokevirtual OR invokenonvirtual OR invokeinterface */ + if (((*(stkptr-1))->e->et == IDENT) && !strcmp((*(stkptr-1))->e->id->name,"this")) { + /* this.bar(...) == bar(...) */ + if (strcmp(classname,c->this_class_name)) { /* super.bar(...) */ + if (!strcmp(name,"<init>")) { /* super() */ + e1->e->id->name = "super"; + minpcval = min(minpcval, (*(stkptr-1))->minpc); + Exp *e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e1, numexps, el); + if (etype == VOID) { + --stkptr; *donestkptr++ = e; + } else *(stkptr-1) = e; + return 0; + } + minpcval = min(minpcval, (*(stkptr-1))->minpc); + Exp *e2 = new Exp(pcval, "super", VOID, NO); + Exp *e3 = new Exp(pcval, minpcval, BINARY, FUNC, DOT, e2, e1); + Exp *e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e3, numexps, el); + if (etype == VOID) { + --stkptr; *donestkptr++ = e; + } else *(stkptr-1) = e; + return 0; + } else { + if (!strcmp(name,"<init>")) { + minpcval = min(minpcval, (*(stkptr-1))->minpc); + e1->e->id->name = "this"; + } + Exp *e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e1, numexps, el); + if (e->e->type == VOID) { + --stkptr; *donestkptr++ = e; + } else *(stkptr-1) = e; + return 0; + } + } else { + /* foo.bar(...) */ + Exp *e; + if (!strcmp(name,"<init>")) { + /* killexp(e1)? */ + minpcval = min(minpcval, (*(stkptr-1))->minpc); + e = new Exp(pcval, minpcval, FUNCTIONCALL, OBJECT, ID, *(stkptr-1), numexps, el); + } else { + minpcval = min(minpcval, (*(stkptr-1))->minpc); + Exp *e3 = new Exp(pcval, minpcval, BINARY, FUNC, DOT, *(stkptr-1), e1); + e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e3, numexps, el); + } + if ((e->exp1->e->op != NEW) && (etype == VOID)) { + --stkptr; *donestkptr++ = e; + } else *(stkptr-1) = e; + return 0; + } + } else { /* invokestatic */ + Exp *e; + tmpstr = c->cp(mr->class_index)->chp; + if (strcmp(tmpstr, c->this_class_name)) { + Exp *e2 = new Exp(pcval, tmpstr, VOID, NO); + Exp *e3 = new Exp(pcval, minpcval, BINARY, FUNC, DOT, e2, e1); + e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e3, numexps, el); + } else + e = new Exp(pcval, minpcval, FUNCTIONCALL, etype, ID, e1, numexps, el); + if (etype == VOID) + *donestkptr++ = e; + else + *stkptr++ = e; + return 0; + } +} diff --git a/MultiSource/Applications/hbd/dc-misc.cpp b/MultiSource/Applications/hbd/dc-misc.cpp new file mode 100644 index 00000000..d3ec176e --- /dev/null +++ b/MultiSource/Applications/hbd/dc-misc.cpp @@ -0,0 +1,32 @@ +/* dc-misc.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "exp.h" +#include "class.h" +#include "decomp.h" +#include "cp.h" + +int docheckcast(Classfile *c) +{ + unsigned pcval = currpc - 1; + unsigned val = JDNEXT16U(); + Exp *e1 = *(stkptr-1); + Exp *e2 = new Exp(pcval, c->cp(val)->chp, OBJECT, CP, val); + *(stkptr-1) = new Exp(pcval, min(e1->minpc, pcval), PREUNARY, OBJECT, CAST, e1, e2); + return 0; +} + +int doinstanceof(Classfile *c) +{ + unsigned pcval = currpc - 1; + unsigned val = JDNEXT16U(); + Exp *e1 = *(stkptr-1); + Exp *e2 = new Exp(pcval, c->cp(val)->chp, OBJECT, CP, val); + *(stkptr-1) = new Exp(pcval, e1->minpc, BINARY, BOOLEAN, INSTANCEOF, e1, e2); + return 0; +} diff --git a/MultiSource/Applications/hbd/decomp.cpp b/MultiSource/Applications/hbd/decomp.cpp new file mode 100644 index 00000000..faa4d00f --- /dev/null +++ b/MultiSource/Applications/hbd/decomp.cpp @@ -0,0 +1,340 @@ +/* decomp.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "general.h" +#include "options.h" +#include "version.h" +#include "cp.h" +#include "access.h" +#include "field.h" +#include "exp.h" +#include "method.h" +#include "consts.h" +#include "class.h" +#include "file.h" +#include "sig.h" +#include "decomp.h" + +void printintlist(intlist *t) { + fprintf(stderr, "["); + intnode *n = t->head; + while (n) { + fprintf(stderr, "%d", n->node); + n = n->next; + if (!n) + break; + fprintf(stderr, ", "); + } + fprintf(stderr, "]\n"); +} + +int ch; +unsigned char *inbuff; +int bufflength; +unsigned currpc; +int lastaction; +method_info *miptr; + +Exp *stack[8]; +Exp **stkptr; +Exp *donestack[256]; +Exp **donestkptr; + +//Block *blocks[16]; +//int numblocks; +//int currblock; + +int indentlevel; + +/* +char pass1size[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 2, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +*/// 1,1,1,1,/*C*/1,1,1,1,1,/*.*/-1,-1,-1,-1,-1,-1,-1, // cmps +// -1,-1,-1,-1,-1,-1,-1,-2,-3,-4,-5,-6,/*R*/1,1,1,1, // returns +// 1,1/*.*/,3,3,3,3, 3, 3, 5, 3, 3, 3, 0, 3, 1, 1, +/* 3, 0, 0, 0, 0, 3,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +int addifblock(void) +{ + unsigned pcval = currpc - 1; + Block *b = blocks[currblock++] = new Block; + b->tag = IF; + b->start_pc = pcval + 3; + b->end_pc = pcval + (signed)(((unsigned)JDNEXT8() << 8) + (unsigned)JDNEXT8()); + b->else_pc = 0; + b->exp = 0; + fprintf(stderr, "if(?) goto %d else %d\n", b->end_pc, b->start_pc); + return 0; +} + +int addgotoblock(void) +{ + unsigned pcval = currpc - 1; + Block *b = blocks[currblock++] = new Block; + b->tag = GOTOLABEL; + b->start_pc = pcval + 3; + b->end_pc = pcval + (signed)(((unsigned)JDNEXT8() << 8) + (unsigned)JDNEXT8()); + b->else_pc = 0; + b->exp = 0; + fprintf(stderr, "goto %d instead of %d\n", b->end_pc, b->start_pc); + return 0; +} + +int (*pass1actions[])(void) = { + 0, addifblock, addgotoblock, 0, 0, 0, 0, 0, + 0, 0, 0 +}; +*/ +char actions[] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,15, 0, + 0, 0,15, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, + 0, 0, 0,18, 0, 0, 0,21, 0,13,25, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, + + 6, 6, 6, 6,16, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 0,22,22,22,22, 22,12,12,12,12,12,12,23, + 23,23,23,23,23,23,23, 7, 0, 0,27,24,10,10,10,10, + 10,10, 8, 9, 8, 9,11,11, 11,11, 7, 7, 0,19,14, 7, + 17,26, 0, 0, 0,20/*?(multianewarray)*/,12,12, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +int (*actiontable[])(Classfile *c) = { + 0, pushimp, pushimm, pushconst, pushlocal, storelocal, pushbinop, pushunop, + doget, doput, doreturn, invokefunc, doif1, dodup, doarraylength, doarrayget, + iinclocal, docheckcast, doarrayput, anewarray, multianewarray, dopop, docmp, doif2, + doluswitch, dodup_x1, doinstanceof, dotableswitch +}; + +int decompileblock(Classfile *c, method_info_ptr mi) { + char *str; +// int i; + miptr = mi; + cond_pcend = -1; + char *strptr; + int dodecompile = ((int)(c->options)) ^ 2; + + if (mi->name == "<init>") { + } + + strptr = new char[mi->access_flags.strlen() + 1]; + fprintf(c->outfile, "\n %s", mi->access_flags.toString(strptr)); + delete strptr; + char *tmp = mi->sig; + if (printsigname(c, c->outfile, tmp, mi->name, mi)) return 1; + for (int m = 0; m != mi->num_throws;) { + fprintf(c->outfile, " throws %s", c->cp(mi->throws[m++])->chp); + } + if ((mi->access_flags & (ACC_NATIVE | ACC_ABSTRACT))) dodecompile = 0; + if (dodecompile) { + +/**********************************************************************/ +/** PASS1 - input stage, analyse opcodes, create stack of statements **/ +/**********************************************************************/ + int action = 0; + inbuff = mi->code; + bufflength = mi->code_length; + currpc = 0; + stkptr = stack; + donestkptr = donestack; + + indentlevel = 0; +// indents_end = indents_begin = (intlist *)0; + + while (bufflength > 0) { + if (((int)currpc == cond_pcend)) if (finishconditional(c)) return 1; + ch = JDNEXT8U(); + lastaction = action; + action = actions[ch]; + if (action) { + if(actiontable[action](c)) return 1; + } else { + fprintf(c->outfile, "// unknown opcode 0x%02X\n", ch); + } + } + + fprintf(c->outfile, " {\n"); + +/**********************************************************************/ +/** PASS2 - lazy conditionals (&& and ||), note backward jump refs **/ +/**********************************************************************/ + looplist *branchbacklist = new looplist(); + Exp **p = donestack; + for (;p < (donestkptr-1);p++) { + Exp *pptr = *p, *pptr1 = *(p+1), *pptr2 = *(p+2); + if (pptr->e->op == GOTO) + goto here; + if (pptr->e->et == BRANCH) { + if (pptr1->e->et == BRANCH || pptr1->e->op == COND) { + unsigned minpc = min(pptr->minpc, pptr1->minpc); + Exp *e; + if (pptr->branch_pc == pptr1->branch_pc) { + e = new Exp(minpc, BINARY, BOOLEAN, OR_BOOL, + pptr->exp1, pptr1->exp1); + } else { + if (pptr->branch_pc == pptr2->minpc) { + e = new Exp(minpc, BINARY, BOOLEAN, AND_BOOL, + pptr->exp1, pptr1->exp1); + if (notexp(&(e->exp1))) return 1; + } else { + goto here; + } + } + killexp(pptr); + pptr1->exp1 = e; + pptr1->minpc = minpc; + *p = pptr1; *(++p) = 0; + pptr = pptr1; pptr1 = pptr2; + } +here: + if (pptr->minpc >= pptr->branch_pc) { + branchbacklist->add(new Loop(pptr->minpc, pptr->branch_pc, + pptr1->minpc, pptr->exp1, LOOP_DOWHILE)); + } + } + } + +/**********************************************************************/ +/** PASS3 - analyse control flow, recursively print statement stack **/ +/**********************************************************************/ + intlist *iflist = new intlist(); + intlist *elselist = new intlist(); + looplist *branchbacklist2 = new looplist(); + + p = donestack; + while (p != donestkptr) { + Exp *pptr = *p++; + if (pptr) { + if (!branchbacklist->isempty()) { + Loop *l = branchbacklist->top(); + if (l->jumpto_pc == pptr->minpc) { + l->type = LOOP_DOWHILE; + fprintf(c->outfile, " do {\n", str); + indentlevel++; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + branchbacklist2->push(branchbacklist->pop()); + } + } + if (!branchbacklist->isempty()) { + Loop *l = branchbacklist->top(); + if (pptr->e->op == GOTO && pptr->branch_pc == l->jumpfrom_pc) { + l->type = LOOP_WHILE; + str = l->condition->toString(0); + fprintf(c->outfile, " while (%s) {\n", str); + delete str; + indentlevel++; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + branchbacklist2->push(branchbacklist->pop()); + continue; + } + } + if (!iflist->isempty() && iflist->top() == pptr->minpc) { + iflist->pop(); + fprintf(c->outfile, " }\n"); + indentlevel--; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + } + if (pptr->e->op == GOTO || pptr->e->et == BRANCH) { + if (!branchbacklist2->isempty()) { + Loop *l = branchbacklist2->top(); + if (l->jumpfrom_pc == pptr->minpc) { + if (l->type == LOOP_DOWHILE) { + if (pptr->e->op == GOTO) { + fprintf(c->outfile, " } while(true);\t/*%d*/\n", pptr->minpc); + } else { + char *str = l->condition->toString(0); + fprintf(c->outfile, " } while(%s);\t/*%d*/\n", str, + pptr->minpc); + delete str; + } + } else { + fprintf(c->outfile, " }\t/*%d*/\n", pptr->minpc); + } + branchbacklist2->pop(); + indentlevel--; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + continue; + } + if (branchbacklist2->containsPast(pptr->branch_pc)) { + fprintf(c->outfile, " break;\t/*%d*/\n", (*(p-1))->minpc); + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + continue; + } + } + if (!iflist->isempty() && iflist->top() == ((*p)?(*p)->minpc:0)) { + elselist->push(pptr->branch_pc); + iflist->pop(); + fprintf(c->outfile, " } else {\t/*%d*/\n", (*(p-1))->minpc); + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + continue; + } + if (pptr->e->et == BRANCH && pptr->branch_pc > pptr->minpc) { + iflist->push(pptr->branch_pc); + indentlevel++; + } + } else { + if (pptr->e->op == RETURN && !iflist->isempty() + && iflist->top() == ((*p)?(*p)->minpc:0)) { + iflist->pop(); + str = pptr->toString(0); + if (str) { + fprintf(c->outfile, " %s;\t/*%d*/\n", str, (*(p-1))->minpc); + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + } + delete str; + fprintf(c->outfile, " }\n"); + indentlevel--; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + continue; + } else { + if (!elselist->isempty() && elselist->top() == pptr->minpc) { + elselist->pop(); + fprintf(c->outfile, " }\n"); + indentlevel--; + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + } + } + } + str = pptr->toString(0); + if (str) { + fprintf(c->outfile, strrchr(str,'{')?" %s":" %s;", str); + fprintf(c->outfile, "\t/*%d*/",(*(p-1))->minpc); + fprintf(c->outfile, "\n"); + for (int i=indentlevel; i--;) fprintf(c->outfile, " "); + } + delete str; + } + } + fprintf(c->outfile, " }"); + } else { + fprintf(c->outfile, ";"); + } + return 0; +} diff --git a/MultiSource/Applications/hbd/decomp.h b/MultiSource/Applications/hbd/decomp.h new file mode 100644 index 00000000..aa5c01c9 --- /dev/null +++ b/MultiSource/Applications/hbd/decomp.h @@ -0,0 +1,85 @@ +/* decomp.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef DECOMP_H +#define DECOMP_H + +#include "general.h" + +/* These all need to be global for various reasons */ +extern int ch; +extern char actions[]; +extern int (*actiontable[])(Classfile *c); +extern unsigned char *inbuff; +extern int bufflength; +extern unsigned currpc; + +/* Various macros to read the bytecodes and keep track of + where we are in the code */ +#define JDNEXT8S() (i8)(currpc++,bufflength--,*inbuff++) +#define JDNEXT8U() (u8)(currpc++,bufflength--,*inbuff++) +#define JDNEXT16S() (i16)(currpc+=2,bufflength-=2,inbuff+=2, \ + (((u16)*(inbuff-2))<<8)+((u16)*(inbuff-1))) +#define JDNEXT16U() (u16)(currpc+=2,bufflength-=2,inbuff+=2, \ + (((u16)*(inbuff-2))<<8)+((u16)*(inbuff-1))) +#define JDNEXT32S() (i32)(currpc+=4,bufflength-=4,inbuff+=4, \ + (((u32)*(inbuff-4))<<24)+(((u32)*(inbuff-3))<<16) \ + +(((u32)*(inbuff-2))<<8)+((u32)*(inbuff-1))) +#define JDNEXT32U() (u32)(currpc+=4,bufflength-=4,inbuff+=4, \ + (((u32)*(inbuff-4))<<24)+(((u32)*(inbuff-3))<<16) \ + +(((u32)*(inbuff-2))<<8)+((u32)*(inbuff-1))) +//#define JDLAST(num) (*(inbuff-(num)-1)) +#define JDLAST8S() (i8)(*(inbuff-1)) +#define JDLAST8U() (u8)(*(inbuff-1)) +#define JDPEEK8S() (i8)(*inbuff) +#define JDPEEK8U() (u8)(*inbuff) + +/* These are all the prototypes for the actions that are used + by the decompiler */ +int pushimp(Classfile *c); +int pushimm(Classfile *c); +int pushconst(Classfile *c); +int pushlocal(Classfile *c); +int storelocal(Classfile *c); +int pushbinop(Classfile *c); +int pushunop(Classfile *c); +int finishconditional(Classfile *c); +int doget(Classfile *c); +int doput(Classfile *c); +int doreturn(Classfile *c); +int invokefunc(Classfile *c); +int doif1(Classfile *c); +int dodup(Classfile *c); +int doarraylength(Classfile *c); +int doarrayget(Classfile *c); +int iinclocal(Classfile *c); +int docheckcast(Classfile *c); +int doarrayput(Classfile *c); +int anewarray(Classfile *c); +int multianewarray(Classfile *c); +int dopop(Classfile *c); +int docmp(Classfile *c); +int doif2(Classfile *c); +int doluswitch(Classfile *c); +int dodup_x1(Classfile *c); +int doinstanceof(Classfile *c); +int dotableswitch(Classfile *c); + +/* These are the globals which contain the + various stacks used by the decompiler. */ +extern Exp *stack[]; +extern Exp **stkptr; +extern Exp *donestack[]; +extern Exp **donestkptr; +extern int lastaction; +extern int cond_pcend; +extern Exp *cond_e1; +extern Exp *cond_e1; +extern Exp **cond_donestkptr; + +#endif diff --git a/MultiSource/Applications/hbd/err.cpp b/MultiSource/Applications/hbd/err.cpp new file mode 100644 index 00000000..0c920824 --- /dev/null +++ b/MultiSource/Applications/hbd/err.cpp @@ -0,0 +1,32 @@ +/* err.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include <stdarg.h> +#include "general.h" +#include "options.h" + +char *errmsgs[] = { + "Unknown error.", + "Out of memory error.", + DEBUG_ON? "Usage: %s [-O] [-D] InFile.class [OutFile.java]\n" + :"Usage: %s [-O] InFile.class [OutFile.java]\n", + DEBUG_ON? "Usage: %s [-D] -Ifuncname InFile.class\n" + :"Usage: %s -Ifuncname InFile.class\n", + "Not a class.", + "Unsupported Class Version.", + "3" +}; +void fatalerror(int msgid,...) +{ + va_list ap; + va_start(ap, msgid); + vfprintf(stderr, errmsgs[msgid], ap); + va_end(ap); + exit(msgid); +} diff --git a/MultiSource/Applications/hbd/err.h b/MultiSource/Applications/hbd/err.h new file mode 100644 index 00000000..f86f2557 --- /dev/null +++ b/MultiSource/Applications/hbd/err.h @@ -0,0 +1,29 @@ +/* errhandl.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef ERRHANDL_H +#define ERRHANDL_H + +/* The various errors that can occur in the programs. + These are passed to the fatalerror() function + below. */ +enum errorids { + UNKNOWN_ERR, OUT_OF_MEM_ERR, + COMMAND_LINE_ERR_HBD, COMMAND_LINE_ERR_HBT, + NOT_A_CLASS_ERR, BAD_VERSION_ERR, CP_ERR +}; + +/* This function will exit the program giving + an appropriate error. The msgid should be + from the enum above */ +void fatalerror(int msgid,...); + +/* Since this is commonly used, we have a macro for it */ +#define memerr() fatalerror(OUT_OF_MEM_ERR) + +#endif diff --git a/MultiSource/Applications/hbd/exp.cpp b/MultiSource/Applications/hbd/exp.cpp new file mode 100644 index 00000000..e4d88a1e --- /dev/null +++ b/MultiSource/Applications/hbd/exp.cpp @@ -0,0 +1,217 @@ +/* exp.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "exp.h" + +Exp_ std_exps[] = { + Exp_(&idnull), Exp_(&idneg1), Exp_(&id0i), Exp_(&id1i), Exp_(&id2i), Exp_(&id3i), + Exp_(&id4i), Exp_(&id5i), Exp_(&id0L), Exp_(&id1L), Exp_(&id0f), Exp_(&id1f), + Exp_(&id2f), Exp_(&id0d), Exp_(&id1d), Exp_(&idfalse), Exp_(&idtrue), + Exp_(1, BRANCH, VOID, ID, 0), Exp_(1, TERNARY, BOOLEAN, COND, 0) +}; + +void killexp(Exp *e) { + if (!(--e->numrefs)) { + if (!e->e->isstd) { + if (e->e->et == IDENT) { +// delete e->e->id->name; +// delete e->e->id; + } +// delete e->e; + } +// delete e; + } +} + +int notexp(Exp **e_ptr) { + Exp *e = *e_ptr; + switch (e->e->op) { + case NOT_BOOL: + *e_ptr = e->exp1; + killexp(e); + break; + case OR_BOOL: + e->e->op = AND_BOOL; + notexp(&(e->exp1)); + notexp(&(e->exp2)); + break; + case AND_BOOL: + e->e->op = OR_BOOL; + notexp(&(e->exp1)); + notexp(&(e->exp2)); + break; + case OR: case AND: + notexp(&(e->exp1)); + notexp(&(e->exp2)); + case EQUAL: case NOTEQUAL: case LESS: case GREATEROREQUAL: + case GREATER: case LESSOREQUAL: + *((int*)(&e->e->op)) ^= 1; + break; + default: + if (e->e->type != BOOLEAN) { + fprintf(stderr, "Can't not a non-boolean\n"); + return 1; + } + *e_ptr = new Exp(e->pc, e->minpc, PREUNARY, BOOLEAN, NOT_BOOL, e); + } + return 0; +} + +/* +Exp::Exp(int pcval, char *idname, Type idtype) { + numrefs = 1; + minpc = pc = pcval; + e = new Exp_; + e->isstd = 0; + e->et = IDENT; + e->op = ID; + e->type = idtype; + e->id = new Id; + e->id->name = idname; +} +*/ + +char *Exp::toString(unsigned nextpc) { + char *e1, *e2, *e3, *o, *o2, *s, *t1; + int sizestr, i; + switch (e->et) { + case IDENT: + s = new char[strlen(e->id->name) + 1]; + strcpy(s, e->id->name); + return s; + case PREUNARY: + exp1->numrefs += numrefs-1; + e1 = exp1->toString(0); + if (e->op == CAST) { + if (e->type == OBJECT) { + exp2->numrefs += numrefs-1; + e2 = exp2->toString(0); + killexp(exp2); + o = new char[strlen(e2) + 3]; + sprintf(o, "(%s)", e2); + delete e2; + } else { + o = new char[strlen(type2str[e->type]) + 3]; + sprintf(o, "(%s)", type2str[e->type]); + } + } else { + o = strdup(op2str[e->op]); + } + s = new char[5 + strlen(o) + strlen(e1)]; + if (op_prec[exp1->e->op] < (op_prec[e->op] + 0)) + sprintf(s, "%s(%s)", o, e1); + else + sprintf(s, "%s%s", o, e1); + killexp(exp1); delete e1; delete o; + return s; + case POSTUNARY: + exp1->numrefs += numrefs-1; + e1 = exp1->toString(0); o = op2str[e->op]; + s = new char[5 + strlen(o) + strlen(e1)]; + sprintf(s, (op_prec[exp1->e->op] < (op_prec[e->op] + 0))?"(%s)%s":"%s%s", e1, o); + killexp(exp1); delete e1; + return s; + case BINARY: + exp1->numrefs += numrefs-1; + exp2->numrefs += numrefs-1; + e1 = exp1->toString(0); e2 = exp2->toString(0); + o = op2str[e->op]; + t1 = new char[9 + strlen(o)]; + sprintf(t1, "%s%s%s", + (op_prec[exp1->e->op] < (op_prec[e->op] + 0))?"(%s)":"%s", + o, (op_prec[exp2->e->op] < (op_prec[e->op] + 0))?"(%s)":"%s"); + s = new char[strlen(t1) + strlen(e1) + strlen(e2) - 3]; + sprintf(s, t1, e1, e2); delete t1; + killexp(exp1); killexp(exp2); delete e1; delete e2; + return s; + case TERNARY: + exp1->numrefs += numrefs-1; exp2->numrefs += numrefs-1; exp3->numrefs += numrefs-1; + e1 = exp1->toString(0); e2 = exp2->toString(0); e3 = exp3->toString(0); + o = op2str[e->op]; o2 = op2str[e->op + 1]; + t1 = new char[19]; + sprintf(t1, "%s%s%s%s%s", + (op_prec[exp1->e->op] < (op_prec[e->op] + 0))?"(%s)":"%s", + o, (op_prec[exp2->e->op] < (op_prec[e->op] + 0))?"(%s)":"%s", + o2, (op_prec[exp3->e->op] < (op_prec[e->op] + 0))?"(%s)":"%s"); + s = new char[strlen(t1) + strlen(e1) + strlen(e2) + strlen(e3) - 5]; + sprintf(s, t1, e1, e2, e3); delete t1; + killexp(exp1); killexp(exp2); killexp(exp3); + delete e1; delete e2; delete e3; + return s; + case FUNCTIONCALL: + t1 = new char[256]; + exp1->numrefs += numrefs-1; + e1 = exp1->toString(0); sizestr = strlen(e1) + 3; + sprintf(t1, "%s(", e1); + killexp(exp1); delete e1; + i = numexps; + if (i) { + while (--i) { + explist[i]->numrefs += numrefs-1; + e1 = explist[i]->toString(0); strcat(t1, e1); sizestr += strlen(e1) + 2; + killexp(explist[i]); delete e1; strcat(t1, ", "); + } + explist[0]->numrefs += numrefs-1; + e1 = explist[0]->toString(0); strcat(t1, e1); sizestr += strlen(e1); + killexp(explist[0]); delete e1; + } + strcat(t1,")"); + s = new char[sizestr]; + strcpy(s, t1); + delete t1; + return s; + case ARRAYACCESS: + exp1->numrefs += numrefs-1; exp2->numrefs += numrefs-1; + e1 = exp1->toString(0); e2 = exp2->toString(0); + s = new char[strlen(e1) + strlen(e2) + 3]; + sprintf(s, "%s[%s]", e1, e2); + killexp(exp1); killexp(exp2); delete e1; delete e2; + return s; + case BRANCH: +// if ((unsigned)e->op > minpc) { +// { +// intlist *i = indents_end, *j; +// if ((!i) || (i->node >= branch_pc)) { +// indents_end = new intlist; +// indents_end->node = branch_pc; +// indents_end->next = i; +// } else { +// while ((i->next) && (i->next->node < branch_pc)) i = i->next; +// j = i->next; i = i->next = new intlist; i->next = j; +// i->node = branch_pc; +// } +// indentlevel++; + notexp(&exp1); + exp1->numrefs += numrefs-1; + e1 = exp1->toString(0); + s = new char[strlen(e1) + 8]; + sprintf(s, "if (%s) {", e1); +// } else { +// exp1->numrefs += numrefs-1; +// e1 = exp1->toString(0); +// s = new char[strlen(e1) + 21]; +// sprintf(s, "if (%s) goto label%d", e1, branch_pc); +// } + killexp(exp1); delete e1; + return s; + case SWITCH: + exp1->numrefs += numrefs-1; + e1 = exp1->toString(0); + s = new char[strlen(e1) + 29]; + sprintf(s, "switch (%s) default: label%d", e1, default_pc); + killexp(exp1); delete e1; + return s; + default: + fprintf(stderr, "Error converting expressions to strings. %d\n", e->et); + exit(-1); + return 0; + } +} diff --git a/MultiSource/Applications/hbd/exp.h b/MultiSource/Applications/hbd/exp.h new file mode 100644 index 00000000..0802bf14 --- /dev/null +++ b/MultiSource/Applications/hbd/exp.h @@ -0,0 +1,333 @@ +/* exp.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef EXP_H +#define EXP_H + +#include "id.h" +#include "op.h" + +/* The various types of expressions */ +enum Exptype { + NOEXP, IDENT, PREUNARY, POSTUNARY, + BINARY, TERNARY, FUNCTIONCALL, ARRAYACCESS, + BRANCH, SWITCH +}; + +/* + This structure is a secondary structure to + the actual Exp struct. It is used to allow + us to have a set of "standard" Expressions + for things like an integer constant "1" which + is often used. This saves both time and memory. +*/ +struct Exp_ { + int isstd; /* 1 if this is one of the standard Exp_'s */ + Exptype et; /* The tpye of expression this is */ + Type type; /* The Java type of the result of this Exp_ */ + Op op; /* The operation performed in this Exp_ */ + Id *id; /* A reference to an Id if this Exp_ + is simply an identifier */ + + /* This constructor creates an expression for the + given identifier */ + Exp_(Id *idptr) { + isstd = 1; et = IDENT; type = idptr->type; + op = ID; id = idptr; + } + + /* These constructors will create more general Exp_'s */ + Exp_(Exptype _et, Type _type, Op _op) { + isstd = 0; et = _et; type = _type; op = _op; + } + Exp_(Exptype _et, Type _type, Op _op, Id *_id) { + isstd = 0; et = _et; type = _type; op = _op; id = _id; + } + Exp_(int _isstd, Exptype _et, Type _type, Op _op, Id *_id) { + isstd = _isstd; et = _et; type = _type; op = _op; id = _id; + } +}; + +/* This is the table of commonly-used Exp_'s */ +extern Exp_ std_exps[]; + +struct Case { long caseval; long branch_pc; }; + +/* The main Exp struct */ +struct Exp { + /* The secondary Exp_ structure for this Exp */ + Exp_ *e; + + /* A reference count */ + unsigned numrefs; + + unsigned pc; + unsigned minpc; + Exp *exp1, *exp2; + + union { + Exp *exp3; + unsigned default_pc; + }; + union { + unsigned numexps; + unsigned branch_pc; + unsigned numcases; + }; + union { + Exp **explist; + Case *cases; + }; + + /* Constructors for "standard" Exp_'s */ + Exp(unsigned pcval, unsigned stdexpnum) { + numrefs = 1; pc = minpc = pcval; e = std_exps + stdexpnum; + } + Exp(unsigned pcval, unsigned minpcval, + unsigned stdexpnum, Exp *_exp1, unsigned branchpcval) { + numrefs = 1; pc = pcval; minpc = minpcval; + e = std_exps + stdexpnum; + exp1 = _exp1; branch_pc = branchpcval; + } + + /* A constructor for Identifiers */ + Exp(unsigned pcval, Exptype et, Type type, Op op, Id *id) { + numrefs = 1; pc = minpc = pcval; + e = new Exp_(et, type, op, id); + } + + /* A fairly general constructor */ + Exp(unsigned pcval, Exptype et, + Type type, Op op, Exp *_exp1 = 0, Exp *_exp2 = 0) { + numrefs = 1; pc = minpc = pcval; + e = new Exp_(et, type, op); + exp1 = _exp1; exp2 = _exp2; + } + + /* A constructor for case "expressions" */ + Exp(unsigned pcval, unsigned minpcval, Exptype et, + Type type, Op op, Exp *_exp1, unsigned defaultpcval, + unsigned _numcases, Case *_cases) { + numrefs = 1; pc = pcval; minpc = minpcval; + e = new Exp_(et, type, op); + exp1 = _exp1; default_pc = defaultpcval; + numcases = _numcases; cases = _cases; + } + + /* A constructor for method calls */ + Exp(unsigned pcval, unsigned minpcval, Exptype et, + Type type, Op op, Exp *_exp1, + unsigned _numexps, Exp** _explist) { + numrefs = 1; pc = pcval; minpc = minpcval; + e = new Exp_(et, type, op); + exp1 = _exp1; numexps = _numexps; + explist = _explist; + } + + /* A constructor for conditionals */ + Exp(unsigned pcval, Exptype et, Type type, + Op op, Exp *_exp1, unsigned branchpcval) { + numrefs = 1; pc = minpc = pcval; + e = new Exp_(et, type, op); + exp1 = _exp1; branch_pc = branchpcval; + } + + /* Another general constructor */ + Exp(unsigned pcval, int minpcval, Exptype et, + Type type, Op op, Exp *_exp1, Exp *_exp2 = 0) { + numrefs = 1; pc = pcval; minpc = minpcval; + e = new Exp_(et, type, op); + exp1 = _exp1; exp2 = _exp2; + } + + /* Another constructor for identifiers */ + Exp(unsigned pcval, char *idname, + Type idtype, Loc idloc, int idlocinfo = 0) { + Id *id = new Id; id->name = idname; id->type = idtype; + id->loc = idloc; id->locinfo = idlocinfo; + numrefs = 1; pc = minpc = pcval; + e = new Exp_(IDENT, idtype, ID, id); + } + + /* Provides a string representation of this Expression */ + char *toString(unsigned nextpc); +}; + +/* This enum provides an easier way to look up the table of + "standard" Exp_'s */ +enum stdexp_vals { + NULLEXP, INEG1EXP, I0EXP, I1EXP, I2EXP, I3EXP, I4EXP, I5EXP, + L0EXP, L1EXP, F0EXP, F1EXP, F2EXP, D0EXP, D1EXP, FALSEEXP, + TRUEEXP, IFEXP +}; + +/* This recursively deletes an expression and it's children */ +void killexp(Exp *e); + +/* This will negate a boolean expression. It will cause an + error if called on a non-boolean expression */ +int notexp(Exp **e); + +/* These handle the indent level during the print phase */ + +struct intnode { + unsigned node; + intnode *next; + + intnode(unsigned i) { + node = i; + next = 0; + } + + intnode(unsigned i, intnode *n) { + node = i; + next = n; + } +}; + +struct intlist { + intnode *head; + intnode *tail; + + intlist() { + head = 0; + tail = 0; + } + + void push(unsigned i) { + intnode *n = new intnode(i, head); + head = n; + if (tail == 0) + tail = head; + } + + void add(unsigned i) { + intnode *n = new intnode(i); + if (tail == 0) { + head = tail = n; + } else { + tail->next = n; + tail = n; + } + } + + unsigned top() { + return head?head->node:0; + } + + int isempty() { + return head==0; + } + + unsigned pop() { + intnode *n = head; + unsigned i = n->node; + head = n->next; + delete n; + if (head == 0) + tail = 0; + return i; + } + + int contains(unsigned i) { + intnode *n = head; + while (n) { + if (n->node == i) + return 1; + n = n->next; + } + return 0; + } +}; + +typedef enum { LOOP_WHILE, LOOP_DOWHILE, LOOP_FOR } LoopType; + +struct Loop { + unsigned jumpfrom_pc, jumpto_pc, jumppast_pc; + Exp *condition; + LoopType type; + + Loop(unsigned from, unsigned to, unsigned past, Exp *cond, LoopType lt) { + jumpfrom_pc = from; jumpto_pc = to; jumppast_pc = past; + condition = cond; type = lt; + } +}; + +struct loopnode { + Loop *node; + loopnode *next; + + loopnode(Loop *e) { + node = e; + next = 0; + } + + loopnode(Loop *e, loopnode *n) { + node = e; + next = n; + } +}; + +struct looplist { + loopnode *head; + loopnode *tail; + + looplist() { + head = 0; + tail = 0; + } + + void push(Loop *e) { + loopnode *n = new loopnode(e, head); + head = n; + if (tail == 0) + tail = head; + } + + void add(Loop *e) { + loopnode *n = new loopnode(e); + if (tail == 0) { + head = tail = n; + } else { + tail->next = n; + tail = n; + } + } + + Loop *top() { + return head?head->node:0; + } + + int isempty() { + return head==0; + } + + Loop *pop() { + loopnode *n = head; + Loop *e = n->node; + head = n->next; + delete n; + if (head == 0) + tail = 0; + return e; + } + + int containsPast(unsigned i) { + loopnode *n = head; + while (n) { + if (n->node->jumppast_pc == i) + return 1; + n = n->next; + } + return 0; + } +}; + +extern int indentlevel; + +#endif diff --git a/MultiSource/Applications/hbd/field.h b/MultiSource/Applications/hbd/field.h new file mode 100644 index 00000000..f9840c1b --- /dev/null +++ b/MultiSource/Applications/hbd/field.h @@ -0,0 +1,34 @@ +/* field.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef FIELD_H +#define FIELD_H + +#include "access.h" + +/* This struct contains the info for one field */ +typedef struct { + /* The access flags for this field */ + AccessFlags access_flags; + + /* The name of this field. + Resolved from the constant pool */ + char *name; + + /* The signature of this field. + Also, resolved from the constant pool */ + char *sig; + + /* 1 if this is a constant */ + int isconstant; + + /* If it is a constant, its index to the constant pool */ + u16 constval_index; +} field_info, *field_info_ptr; + +#endif diff --git a/MultiSource/Applications/hbd/file.h b/MultiSource/Applications/hbd/file.h new file mode 100644 index 00000000..fd8cf97d --- /dev/null +++ b/MultiSource/Applications/hbd/file.h @@ -0,0 +1,51 @@ +/* file.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef FILE_H +#define FILE_H + +/* Various macros to read and copy from the files, + and maintain tabs on where in the files we are at. */ + +inline u8 get8(FILE *f, int *f_pos) { + *f_pos++; + return getc(f); +} + +inline u16 get16(FILE *f, int *f_pos) { + u16 t1 = get8(f, f_pos); u16 t2 = get8(f, f_pos); + return (u16)((t1 << 8) | t2); +} + +inline u32 get32(FILE *f, int *f_pos) { + u32 t1 = get16(f, f_pos); u32 t2 = get16(f, f_pos); + return (u32)((t1 << 16) | t2); +} + +#define getstr(str, size, f) ((f##_pos+=size), \ + fread(str,size,1,f)) + +#define put8(f, v) ((f##_pos++),(putc((v), f))) +#define put16(f, v) (put8(f, (v) >> 8), put8(f, (v))) +#define putstr(outf, size, str) ((outf##_pos+=size), \ + fwrite(str,size,1,outf)) + +#define copy8(inf, outf) ((outf##_pos++),(inf##_pos++), \ + putc(getc(inf), outf)) +#define copy16(inf, outf) (u16)( \ + (((u16)copy8(inf,outf)) << 8) \ + | (u16)copy8(inf,outf)) +#define copy32(inf, outf) (u32)( \ + (((u32)copy16(inf,outf)) << 16) \ + | (u32)copy16(inf,outf)) +#define copystr(str, size, inf, outf) ((outf##_pos+=size), \ + (inf##_pos+=size), \ + fread(str,size,1,inf), \ + fwrite(str,size,1,outf)) + +#endif diff --git a/MultiSource/Applications/hbd/general.h b/MultiSource/Applications/hbd/general.h new file mode 100644 index 00000000..5abb4877 --- /dev/null +++ b/MultiSource/Applications/hbd/general.h @@ -0,0 +1,45 @@ +/* general.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef _GENERAL_H_ +#define _GENERAL_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* These allow us to set debugging mode on at + compile-time or make it an option at run-time. */ +//#define debug +#define debug_optional + +/* The D macro */ +#if defined(debug) +# define D(x) x +#elif defined(debug_optional) +extern int debugon; +# define D(x) if(debugon){ x; } else {} +#else +# define D(x) +#endif /* debug */ + +/* The min macro */ +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +/* Miscellaneous typedefs for specific-sized quantities. + These should be in a machine-dependant file. */ +typedef unsigned char u8; +typedef signed char i8; +typedef unsigned short u16; +typedef signed short i16; +typedef unsigned long u32; +typedef signed long i32; + +typedef char *char_ptr; + +#endif diff --git a/MultiSource/Applications/hbd/hbd.1 b/MultiSource/Applications/hbd/hbd.1 new file mode 100644 index 00000000..07ae0c56 --- /dev/null +++ b/MultiSource/Applications/hbd/hbd.1 @@ -0,0 +1,83 @@ +.\" This -*- nroff -*- file has been generated from +.\" DocBook SGML with docbook-to-man on Debian GNU/Linux. +...\" +...\" transcript compatibility for postscript use. +...\" +...\" synopsis: .P! <file.ps> +...\" +.de P! +\\&. +.fl \" force out current output buffer +\\!%PB +\\!/showpage{}def +...\" the following is from Ken Flowers -- it prevents dictionary overflows +\\!/tempdict 200 dict def tempdict begin +.fl \" prolog +.sy cat \\$1\" bring in postscript file +...\" the following line matches the tempdict above +\\!end % tempdict % +\\!PE +\\!. +.sp \\$2u \" move below the image +.. +.de pF +.ie \\*(f1 .ds f1 \\n(.f +.el .ie \\*(f2 .ds f2 \\n(.f +.el .ie \\*(f3 .ds f3 \\n(.f +.el .ie \\*(f4 .ds f4 \\n(.f +.el .tm ? font overflow +.ft \\$1 +.. +.de fP +.ie !\\*(f4 \{\ +. ft \\*(f4 +. ds f4\" +' br \} +.el .ie !\\*(f3 \{\ +. ft \\*(f3 +. ds f3\" +' br \} +.el .ie !\\*(f2 \{\ +. ft \\*(f2 +. ds f2\" +' br \} +.el .ie !\\*(f1 \{\ +. ft \\*(f1 +. ds f1\" +' br \} +.el .tm ? font underflow +.. +.ds f1\" +.ds f2\" +.ds f3\" +.ds f4\" +'\" t +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n +.TH "HBD" "1" +.SH "NAME" +hbd \(em Decompiles Java .class files. +.SH "SYNOPSIS" +.PP +\fBhbd\fP [\fB-O \fIdon't decompile\fP\fP] [\fB-D \fIdebug mode\fP\fP] [Inputfile.class] +.SH "DESCRIPTION" +.PP +The HomeBrew Decompiler, \fBhbd\fP, can +be used to decompile Java .class files. +.PP +The class file to be decompiled is passed on the command +line and the resulting decompilation goes to stdout. Any +errors can be seen on stderr. +.SH "OPTIONS" +.IP "\fB-D\fP " 10 +Debug mode. +.IP "\fB-O\fP " 10 +Do not decompile. +.SH "AUTHOR" +.PP +This manual page was written by Pete Ryland pdr@pdr.cx. +Permission is granted to copy, distribute and/or modify this +document under the terms of the GNU Free Documentation +License, Version 1.1 or any later version published by the Free +Software Foundation; with no Invariant Sections, no Front-Cover +Texts and no Back-Cover Texts. +...\" created by instant / docbook-to-man, Sat 15 Feb 2003, 20:06 diff --git a/MultiSource/Applications/hbd/hbd.cpp b/MultiSource/Applications/hbd/hbd.cpp new file mode 100644 index 00000000..074cc68d --- /dev/null +++ b/MultiSource/Applications/hbd/hbd.cpp @@ -0,0 +1,21 @@ +/* hbd.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include "class.h" + +int debugon = 0; + +int main(int argc, char **argv) +{ + fprintf(stderr, "HomeBrew Decompiler. Copyright (c) 1994-2003 Pete Ryland.\n"); + Classfile c(argc, argv); + c.read(); + c.print(); + return 0; +} diff --git a/MultiSource/Applications/hbd/hbd.sgml b/MultiSource/Applications/hbd/hbd.sgml new file mode 100644 index 00000000..70180b96 --- /dev/null +++ b/MultiSource/Applications/hbd/hbd.sgml @@ -0,0 +1,130 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man manpage.sgml > manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + + + The docbook-to-man binary is found in the docbook-to-man package. + Please remember that if you create the nroff version in one of the + debian/rules file targets (such as build), you will need to include + docbook-to-man in your Build-Depends control field. + + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Pete</firstname>"> + <!ENTITY dhsurname "<surname>Ryland</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>February 15, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>pdr@pdr.cx</email>"> + <!ENTITY dhusername "Pete Ryland"> + <!ENTITY dhucpackage "<refentrytitle>HBD</refentrytitle>"> + <!ENTITY dhpackage "hbd"> + + <!ENTITY debian "<productname>Debian</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> + <!ENTITY gpl "&gnu; <acronym>GPL</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>1994-2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>Decompiles Java .class files.</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg><option>-O <replaceable>don't decompile</replaceable></option></arg> + <arg><option>-D <replaceable>debug mode</replaceable></option></arg> + <arg>Inputfile.class</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para>The HomeBrew Decompiler, <command>&dhpackage;</command>, can + be used to decompile Java .class files.</para> + + <para>The class file to be decompiled is passed on the command + line and the resulting decompilation goes to stdout. Any + errors can be seen on stderr.</para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>-D</option> + </term> + <listitem> + <para>Debug mode.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>-O</option> + </term> + <listitem> + <para>Do not decompile.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>AUTHOR</title> + + <para>This manual page was written by &dhusername; &dhemail;. + Permission is granted to copy, distribute and/or modify this + document under the terms of the &gnu; Free Documentation + License, Version 1.1 or any later version published by the Free + Software Foundation; with no Invariant Sections, no Front-Cover + Texts and no Back-Cover Texts.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> + + diff --git a/MultiSource/Applications/hbd/id.cpp b/MultiSource/Applications/hbd/id.cpp new file mode 100644 index 00000000..4420dac4 --- /dev/null +++ b/MultiSource/Applications/hbd/id.cpp @@ -0,0 +1,27 @@ +/* id.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include "id.h" + +Id idnull = {"null", OBJECT, IM, 0}, + idneg1 = {"-1", INT, IM, 0}, + id0i = {"0", INT, IM, 0}, + id1i = {"1", INT, IM, 0}, + id2i = {"2", INT, IM, 0}, + id3i = {"3", INT, IM, 0}, + id4i = {"4", INT, IM, 0}, + id5i = {"5", INT, IM, 0}, + id0L = {"0L", LONG, IM, 0}, + id1L = {"1L", LONG, IM, 0}, + id0f = {"0.0f", FLOAT, IM, 0}, + id1f = {"1.0f", FLOAT, IM, 0}, + id2f = {"2.0f", FLOAT, IM, 0}, + id0d = {"0.0d", DOUBLE, IM, 0}, + id1d = {"1.0d", DOUBLE, IM, 0}, + idfalse = {"false", BOOLEAN, IM, 0}, + idtrue = {"true", BOOLEAN, IM, 0}; diff --git a/MultiSource/Applications/hbd/id.h b/MultiSource/Applications/hbd/id.h new file mode 100644 index 00000000..a4ba4e83 --- /dev/null +++ b/MultiSource/Applications/hbd/id.h @@ -0,0 +1,50 @@ +/* id.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef ID_H +#define ID_H + +#include "sig.h" + +/* The location of an identifier */ +enum Loc { + NO /* Not Applicable */, IM /* Immediate */, + CP /* Const Pool */, LO /* Local */ +}; /* Id location */ + +/* The Id structure, which contains information + about one identifier. */ +struct Id { + /* Its name */ + char *name; + + /* Its Java type */ + Type type; + + /* Where this ident is located */ + Loc loc; + + /* An index into the "loc" of where this ident is */ + int locinfo; + + union { + long linfo; + double dinfo; + long llinfo[2]; + }; +}; + +/* "Standard" identifiers used by the standard Exp_'s */ +extern Id idnull, idneg1, + id0i, id1i, id2i, id3i, id4i, id5i, + id0L, id1L, + id0f, id1f, id2f, + id0d, id1d, + idfalse, idtrue; + +#endif diff --git a/MultiSource/Applications/hbd/method.h b/MultiSource/Applications/hbd/method.h new file mode 100644 index 00000000..4329661e --- /dev/null +++ b/MultiSource/Applications/hbd/method.h @@ -0,0 +1,148 @@ +/* method.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef METHOD_H +#define METHOD_H + +#include "access.h" +#include "exp.h" + +/* These are used by our table of blocks */ +typedef enum { TRY, IF, DOWHILE, WHILE, GOTOLABEL } Blocktype; + +typedef struct { + /* The type of block this is */ + Blocktype tag; + + /* Its starting and ending code offsets */ + unsigned short start_pc; + unsigned short end_pc; + + /* Other offset, depending on the block type */ + union { + unsigned else_pc; + unsigned short handler_pc; + }; + + /* An index into the constant pool + of the class we're catching */ + unsigned short catch_type; + + /* The list of expressions within this block */ + Exp *exp; +} Block, ExceptionTableEntry; + +/* The line number table has these as entries. + They are currently parsed from the input file, + but not used */ +typedef struct { + unsigned short start_pc; + unsigned short line_number; +} LineNumberTableEntry; + +/* This table stores the local table information. + This is parsed from the input file in the + optional LocalVariableTable attribute */ +typedef struct { + /* The first code offset where this var is used */ + unsigned short start_pc; + + /* The length of the scope of this local */ + unsigned short length; + + /* The constant pool index to its name */ + unsigned short name_index; + + /* The constant pool index to its type signature */ + unsigned short signature_index; + + /* Which local we are talking about */ + unsigned short slot; +} LocalVariableTableEntry; + +/* The main method structure */ +typedef struct { + /* The access flags for this method */ + AccessFlags access_flags; + + /* The name of the method */ + char *name; + + /* Its type signature */ + char *sig; + + /* The maximum stack size the JVM code can use */ + unsigned char max_stack; + + /* The maximium number of locals in scope at any one time */ + unsigned char max_locals; + + /* The length of the code in bytes */ + unsigned code_length; + + /* The code */ + unsigned char *code; + + /* The exception table */ + unsigned short exception_table_length; + ExceptionTableEntry *exception_table; + + /* The line number table */ + unsigned short line_number_table_length; + LineNumberTableEntry *line_number_table; + + /* The local variable table */ + unsigned short local_variable_table_length; + LocalVariableTableEntry *local_variable_table; + + /* A table of the names of the locals. + These are potentially created + as each local is encountered. */ + char **local_names; + + /* The type signatures of the locals. + These need to be guessed if there is no + LocalVariableTable attribute in the method. */ + char **local_sigs; + + /* The first code offset where each local is used. + Again, these need to be guessed if there is no + LocalVariableTable attribute in the method. */ + unsigned *local_firstuses; + + /* The types of the locals, + corresponding to the local_sigs above */ + Type *local_types; + + /* The type signature of the + return value of the method */ + char *ret_sig; + + /* The type of the return value + corresponding to the signature above */ + Type ret_type; + + /* The number of different exceptions that + this method is able to throw and not catch */ + int num_throws; + + /* A table of constant-pool entries to the classes + that this method throws */ + int *throws; +} method_info, *method_info_ptr; + +/* This global contains the method + we are currently working on */ +extern method_info *miptr; + +/* Forward declaration */ +typedef struct Classfile Classfile; +/* Decompiles the given method's code */ +int decompileblock(Classfile *c, method_info_ptr mi); + +#endif diff --git a/MultiSource/Applications/hbd/op.cpp b/MultiSource/Applications/hbd/op.cpp new file mode 100644 index 00000000..6bb24f76 --- /dev/null +++ b/MultiSource/Applications/hbd/op.cpp @@ -0,0 +1,30 @@ +/* op.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +char *op2str[] = { + " + ", " - ", " * ", " / ", " %% ", ".", " = ", " << ", + " >> ", " >>> ", " & ", " | ", " ^ ", "~", "-", "(cast)", + "return ", "throw ", "new ", "goto ", " += ", " -= ", "++", "--", + " ? ", " : ", " error ", " cmp ", " == ", " != ", " < ", " >= ", + " > ", " <= ", "!", " && ", " || ", " instanceof ", ", ", + "" +}; +int op_prec[] = { + 27, 27, 29, 29, 29, 39, 2, 26, + 26, 26, 19, 17, 18, 32, 32, 39, + 38, 38, 38, 38, 2, 2, 32, 32, + 14, 14, 39, 20, 20, 20, 22, 22, + 22, 22, 32, 16, 15, 32, 1, + 39 +}; +int op_assoc[] = { + 0,0,0,0,0,0,1,0, 0,0,0,0,0,0,0,0, + 0,0,1,1,0,0,0,0, 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0, + 0 +}; diff --git a/MultiSource/Applications/hbd/op.h b/MultiSource/Applications/hbd/op.h new file mode 100644 index 00000000..78317c3e --- /dev/null +++ b/MultiSource/Applications/hbd/op.h @@ -0,0 +1,36 @@ +/* op.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef _OP_H_ +#define _OP_H_ + +/* The operations that can go in + the op field of the Exp struct */ +enum Op { + ADD, SUB, MUL, DIV, + MOD, DOT, ASSIGN, SHL, + SHR, USHR, AND, OR, + XOR, NOT, NEG, CAST, + RETURN, THROW, NEW, GOTO, + ADDASSIGN, SUBASSIGN, INC, DEC, + COND, COND_, CMP, DUMMY, + EQUAL, NOTEQUAL, LESS, GREATEROREQUAL, + GREATER, LESSOREQUAL, NOT_BOOL, AND_BOOL, + OR_BOOL, INSTANCEOF, COMMA, ID +}; + +/* The Java string representation of the operations */ +extern char *op2str[]; + +/* The precedence of the ops */ +extern int op_prec[]; + +/* The accociativity of the ops */ +extern int op_assoc[]; + +#endif diff --git a/MultiSource/Applications/hbd/options.h b/MultiSource/Applications/hbd/options.h new file mode 100644 index 00000000..c6a2656d --- /dev/null +++ b/MultiSource/Applications/hbd/options.h @@ -0,0 +1,27 @@ +/* options.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +#ifdef debug_optional +#define DEBUG_ON 1 +#else +#define DEBUG_ON 0 +#endif + +/* The command-line options */ +enum CL_Options { + OPT_DEBUG = DEBUG_ON, + OPT_DECOMPILE_OFF = 2 +}; + +//void parse_cmdline(FILE **infile_ptr, FILE **outfile_ptr, +// CL_Options *options, int argc, char **argv); + +#endif diff --git a/MultiSource/Applications/hbd/sig.cpp b/MultiSource/Applications/hbd/sig.cpp new file mode 100644 index 00000000..d1c69b51 --- /dev/null +++ b/MultiSource/Applications/hbd/sig.cpp @@ -0,0 +1,145 @@ +/* sig.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include <string.h> +#include "general.h" +#include "class.h" +#include "method.h" +#include "sig.h" +#include "err.h" + +char *type2str[] = { + "void", "byte", "char", "short", "int", "long", "float", "double", "object" +}; + +Type sig2type(char* sig) +{ + switch (*sig) { + case SIGNATURE_BYTE: return BYTE; + case SIGNATURE_CHAR: return CHAR; + case SIGNATURE_DOUBLE: return DOUBLE; + case SIGNATURE_FLOAT: return FLOAT; + case SIGNATURE_INT: return INT; + case SIGNATURE_LONG: return LONG; + case SIGNATURE_CLASS: return OBJECT; + case SIGNATURE_SHORT: return SHORT; + case SIGNATURE_BOOLEAN: return BOOLEAN; + case SIGNATURE_ARRAY: return OBJECT; + case SIGNATURE_FUNC: return FUNC; + case SIGNATURE_VOID: return VOID; + default: + fprintf(stderr, "Error converting signature to a type.\n"); + exit(1); + } + return VOID; +} + +int printsigname(Classfile *c, FILE* outfile, char *&sig, char *name, void *mip) +{ + method_info_ptr mi = (method_info_ptr)mip; + int i; + char *t, *t2; + switch(*sig++) { + case SIGNATURE_BYTE: fprintf(outfile, "byte %s", name); return 0; + case SIGNATURE_CHAR: fprintf(outfile, "char %s", name); return 0; + case SIGNATURE_DOUBLE: fprintf(outfile, "double %s", name); return 0; + case SIGNATURE_FLOAT: fprintf(outfile, "float %s", name); return 0; + case SIGNATURE_INT: fprintf(outfile, "int %s", name); return 0; + case SIGNATURE_LONG: fprintf(outfile, "long %s", name); return 0; + case SIGNATURE_CLASS: + t = sig; + while (*sig++ != ';') ; + if ((t2 = new char[sig - t]) == 0) memerr(); + strncpy(t2, t, sig - t - 1); + t2[sig - t - 1] = '\0'; + t = t2; + if (!strncmp(t, "java/lang/", 10)) t += 10; + else while ((t2 = strchr(t2, '/')) != 0) *t2 = '.'; + i = c->package_name?strlen(c->package_name):0; + if (c->package_name && !strncmp(t, c->package_name, i)) t += i + 1; + fprintf(outfile, "%s %s", t, name); + return 0; + case SIGNATURE_SHORT: fprintf(outfile, "short %s", name); return 0; + case SIGNATURE_BOOLEAN: fprintf(outfile, "boolean %s", name); return 0; + case SIGNATURE_ARRAY: + i = 0; + while ((*sig >= '0') && (*sig <= '9')) i = (i * 10) + *sig++ - '0'; + printsigname(c, outfile, sig, name, mi); + if (i) fprintf(outfile, "[%d]", i); else fprintf(outfile, "[]"); + return 0; + case SIGNATURE_FUNC: + if (!mi) { + fprintf(stderr, "Non-function with function sig!\n"); + return 0; + } + t = sig; + while (*sig++ != SIGNATURE_ENDFUNC) /* skip for now */; + if (!strcmp(name, "<clinit>")) { +// fprintf(outfile, "\b"); + return 0; + } + if ((mi->ret_sig = new char[strlen(sig) + 1]) == 0) memerr(); + strcpy(mi->ret_sig, sig); + mi->ret_type = sig2type(mi->ret_sig); + if (strcmp(name, "<init>")) + printsigname(c, outfile, sig, name, mi); /* return type and name */ + else + fprintf(outfile, "%s", c->this_class_name); + fprintf(outfile, "("); + mi->max_locals++; + if (!mi->local_variable_table_length) { + if (((mi->local_names = new char_ptr[mi->max_locals]) == 0) || + ((mi->local_sigs = new char_ptr[mi->max_locals]) == 0) || + ((mi->local_types = new Type[mi->max_locals]) == 0) || + ((mi->local_firstuses = new unsigned[mi->max_locals]) == 0)) memerr(); + for (int it = mi->max_locals; it--; ) { + mi->local_firstuses[it] = 0; + mi->local_names[it] = mi->local_sigs[it] = 0; + mi->local_types[it] = VOID; + } + if ((mi->access_flags & ACC_STATIC) == 0) { + mi->local_names[0] = "this"; + mi->local_sigs[0] = "L"; + mi->local_types[0] = OBJECT; + mi->local_firstuses[0] = 0; + } + } + i = ((mi->access_flags & ACC_STATIC) == 0) ? 1 : 0; + while (*t != SIGNATURE_ENDFUNC) { + if (mi->local_variable_table_length) { + if (strcmp(t,mi->local_sigs[i])) { + fprintf(stderr, "Function Parameter type mismatch\n"); + return 1; + } + printsigname(c, outfile, t,mi->local_names[i],mi); + } else { + if ((mi->local_names[i] = new char[6]) == 0) memerr(); + sprintf(mi->local_names[i], "var%d", i); + char *t2 = t; + printsigname(c, outfile, t,mi->local_names[i],mi); + if ((mi->local_sigs[i] = new char[t - t2 + 1]) == 0) memerr(); + strncpy(mi->local_sigs[i], t2, t-t2); + mi->local_sigs[i][t-t2] = '\0'; + mi->local_types[i] = sig2type(mi->local_sigs[i]); + mi->local_firstuses[i] = 0; + } + if ((*(t-1) == 'D') || (*(t-1) == 'J')) i++; + i++; + if (*t != SIGNATURE_ENDFUNC) fprintf(outfile, ", "); + } + fprintf(outfile, ")"); + return 0; + case SIGNATURE_VOID: fprintf(outfile, "void %s", name); return 0; +// case 0: fprintf(outfile, "%s", name); return 0; + default: + fprintf(stderr, "Error reading type signature!\n"); + return 1; + } +} + diff --git a/MultiSource/Applications/hbd/sig.h b/MultiSource/Applications/hbd/sig.h new file mode 100644 index 00000000..d479fa4d --- /dev/null +++ b/MultiSource/Applications/hbd/sig.h @@ -0,0 +1,73 @@ +/* sig.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef SIG_H +#define SIG_H + +#include <stdio.h> + +/* The Java types */ +typedef enum { + VOID, BYTE, CHAR, SHORT, + INT, LONG, FLOAT, DOUBLE, + OBJECT, ARRAY, BOOLEAN, FUNC, + CMPTYPE, /* -1, 0, or 1 */ + UNKNOWN, UNKNOWN_1, UNKNOWN_4, + UNKNOWN_8 +} Type; + +/* This converts a signature string to a type */ +Type sig2type(char* sig); + +/* This contains string representations of the types */ +extern char *type2str[]; + +/* These defines are used for converting sigs */ +#define SIGNATURE_ANY 'A' +#define SIGNATURE_ARRAY '[' +#define SIGNATURE_BYTE 'B' +#define SIGNATURE_CHAR 'C' +#define SIGNATURE_CLASS 'L' +#define SIGNATURE_ENDCLASS ';' +#define SIGNATURE_ENUM 'E' +#define SIGNATURE_FLOAT 'F' +#define SIGNATURE_DOUBLE 'D' +#define SIGNATURE_FUNC '(' +#define SIGNATURE_ENDFUNC ')' +#define SIGNATURE_INT 'I' +#define SIGNATURE_LONG 'J' +#define SIGNATURE_SHORT 'S' +#define SIGNATURE_VOID 'V' +#define SIGNATURE_BOOLEAN 'Z' + +#define SIGNATURE_ANY_STRING "A" +#define SIGNATURE_ARRAY_STRING "[" +#define SIGNATURE_BYTE_STRING "B" +#define SIGNATURE_CHAR_STRING "C" +#define SIGNATURE_CLASS_STRING "L" +#define SIGNATURE_ENDCLASS_STRING ";" +#define SIGNATURE_ENUM_STRING "E" +#define SIGNATURE_FLOAT_STRING "F" +#define SIGNATURE_DOUBLE_STRING "D" +#define SIGNATURE_FUNC_STRING "(" +#define SIGNATURE_ENDFUNC_STRING ")" +#define SIGNATURE_INT_STRING "I" +#define SIGNATURE_LONG_STRING "J" +#define SIGNATURE_SHORT_STRING "S" +#define SIGNATURE_VOID_STRING "V" +#define SIGNATURE_BOOLEAN_STRING "Z" + +/* Forward declaration */ +struct Classfile; + +/* This prints the method name with return type + and parameters in the format used in Java source files */ +int printsigname(Classfile *c, FILE *outfile, + char *&sig, char *name, void *mi); + +#endif diff --git a/MultiSource/Applications/hbd/version.cpp b/MultiSource/Applications/hbd/version.cpp new file mode 100644 index 00000000..c8e16acf --- /dev/null +++ b/MultiSource/Applications/hbd/version.cpp @@ -0,0 +1,23 @@ +/* version.cpp */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#include <stdio.h> +#include "general.h" +#include "version.h" +#include "file.h" +#include "err.h" +#include "class.h" + +void ClassVersion::read(Classfile *c) { + minor_version = get16(c->infile, &c->infile_pos); + if ((major_version = get16(c->infile, &c->infile_pos)) != 45) + fatalerror(BAD_VERSION_ERR); + else if (minor_version != 3) { + fprintf(stderr, "Warning: Class Version 45.%d. (Program designed for ver 45.3)\n", minor_version); + } +} diff --git a/MultiSource/Applications/hbd/version.h b/MultiSource/Applications/hbd/version.h new file mode 100644 index 00000000..63db3200 --- /dev/null +++ b/MultiSource/Applications/hbd/version.h @@ -0,0 +1,28 @@ +/* version.h */ +/* + Java Decompiler + Copyright (c) 1994-2003, Pete Ryland. + Distributed under the GNU GPL Version 2. + This package is available from http://pdr.cx/hbd/ +*/ + +#ifndef VERSION_H +#define VERSION_H + +#include "general.h" + +/* Forward declaration */ +struct Classfile; + +/* This struct is for the class file version */ +struct ClassVersion { + u16 minor_version; + u16 major_version; + + /* read() is used by the decompiler to read + the version of the input class file and + make sure it is a version that we support */ + void read(Classfile *c); +}; + +#endif |