Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

classread.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      classread.cc
00004  *
00005  *      Copyright (C) 2001 Stanley Gambarin <stanleyg76@yahoo.com>
00006  *      Copyright (C) 2002 Sebastian Biallas (sb@biallas.net)
00007  *
00008  *      This program is free software; you can redistribute it and/or modify
00009  *      it under the terms of the GNU General Public License version 2 as
00010  *      published by the Free Software Foundation.
00011  *
00012  *      This program is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU General Public License
00018  *      along with this program; if not, write to the Free Software
00019  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020  */
00021 
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include "analy.h"
00026 #include "class.h"
00027 #include "htstring.h"
00028 #include "snprintf.h"
00029 #include "stream.h"
00030 
00031 
00032 static u1 inp[4];
00033 static u4 offset;
00034 #define cls_read(a, b, c, d) (((b) != ((d)->read((a), (b)*(c)))) \
00035                                 ? (0) : (offset+=(b), (b)))
00036 #define READ1() \
00037   (((inp[0]=inp[1]=inp[2]=inp[3]=0),  \
00038    (1 == cls_read (inp, 1, 1, htio))) \
00039    ? (u1)(inp[0]) : 0)
00040 #define READ2() \
00041   (((inp[0]=inp[1]=inp[2]=inp[3]=0),  \
00042    (2 == cls_read (inp, 2, 1, htio))) \
00043    ? ((((u2)inp[0])<<8)|inp[1]) : 0)
00044 #define READ4() \
00045   (((inp[0]=inp[1]=inp[2]=inp[3]=0),  \
00046    (4 == cls_read (inp, 4, 1, htio))) \
00047    ? (((((((u4)inp[0]<<8)|inp[1])<<8)|inp[2])<<8)|inp[3]) : 0)
00048 #define READN(inb, n) cls_read (inb, n, 1, htio)
00049 #define SKIPN(n) {u1 b; for (u4 i=0; i<n; i++) {cls_read(&b, 1, 1, htio);}}
00050 
00051 ClassMethod::ClassMethod(char *n, char *d, ClassAddress s, UINT l, int f)
00052 {
00053         name = ht_strdup(n);
00054         start = s;
00055         type = d;
00056         length = l;
00057         flags = f;
00058 }
00059 
00060 ClassMethod::~ClassMethod()
00061 {
00062         free(name);
00063 }
00064 
00065 int ClassMethod::compareTo(const Object *obj) const
00066 {
00067         ClassMethod *cm = (ClassMethod*)obj;
00068         if ((start + length - 1) < cm->start) return -1;
00069         if (start > (cm->start + cm->length - 1)) return 1;
00070         return 0;
00071 }
00072 
00073 
00074 /* extract name from a utf8 constant pool entry */
00075 static char *get_string(ht_stream *htio, classfile *clazz, UINT index)
00076 {
00077         return (index < clazz->cpool_count) ? clazz->cpool[index]->value.string : (char*)"?";
00078 }
00079 
00080 /* extract name from a utf8 constant pool class entry */
00081 static char *get_class_name(ht_stream *htio, classfile *clazz, UINT index)
00082 {
00083         return (index < clazz->cpool_count) ? get_string(htio, clazz, clazz->cpool[index]->value.llval[0]): (char*)"?";
00084 }
00085 
00086 /* extract name from a utf8 constant pool class entry */
00087 static void get_name_and_type(ht_stream *htio, classfile *clazz, UINT index, char *name, char *type)
00088 {
00089         strcpy(name, (index < clazz->cpool_count) ? get_string(htio, clazz, clazz->cpool[index]->value.llval[0]) : "?");
00090         strcpy(type, (index < clazz->cpool_count) ? get_string(htio, clazz, clazz->cpool[index]->value.llval[1]) : "?");
00091 }
00092 
00093 /* read and return constant pool entry */
00094 static cp_info *read_cpool_entry (ht_stream *htio, classfile *clazz)
00095 {
00096         cp_info *cp;
00097         u2 idx;
00098 
00099         cp         = (cp_info *)malloc (sizeof (*cp));
00100         cp->offset = offset;
00101         cp->tag    = READ1();
00102         switch (cp->tag) {
00103                 case CONSTANT_Utf8:
00104                         idx = READ2();
00105                         cp->value.string = (char *)malloc (idx+1);
00106                         cls_read (cp->value.string, idx, 1, htio);
00107                         cp->value.string[idx] = 0;
00108                         break;
00109                 case CONSTANT_Integer:
00110                 case CONSTANT_Float:
00111                         cp->value.fval = READ4();
00112                         break;
00113                 case CONSTANT_Long:
00114                 case CONSTANT_Double:
00115                         cp->value.llval[0] = READ4();
00116                         cp->value.llval[1] = READ4();
00117                         break;
00118                 case CONSTANT_Class:
00119                 case CONSTANT_String:
00120                         cp->value.llval[0] = READ2();
00121                         break;
00122                 case CONSTANT_Fieldref:
00123                 case CONSTANT_Methodref:
00124                 case CONSTANT_InterfaceMethodref:
00125                 case CONSTANT_NameAndType:
00126                         cp->value.llval[0] = READ2();
00127                         cp->value.llval[1] = READ2();
00128                         break;
00129                 default:
00130                         return NULL;
00131         }
00132         return (cp);
00133 }
00134 
00135 /* read and return an attribute read */
00136 attrib_info *attribute_read(ht_stream *htio, classfile *clazz)
00137 {
00138         attrib_info *a;
00139         u4 len;
00140         char *aname;
00141 
00142         a = (attrib_info *)malloc(sizeof (*a));
00143         if (!a) {
00144                 return NULL;
00145         }
00146         a->offset    = offset;
00147         a->name      = READ2();
00148         a->len = len = READ4();
00149 
00150         aname = get_string(htio, clazz, a->name);
00151         if (!strcmp (aname, "ConstantValue")) {
00152                 a->tag = ATTRIB_ConstantValue;
00153         } else if (!strcmp(aname, "Code")) {
00154                 a->tag = ATTRIB_Code;
00155                 a->code.max_stack = READ2();
00156                 a->code.max_locals = READ2();
00157                 a->code.len = READ4();
00158                 a->code.start = offset;
00159                 len -= 2+2+4;
00160         } else if (!strcmp(aname, "Exceptions")) {
00161                 a->tag = ATTRIB_Exceptions;
00162         } else if (!strcmp(aname, "InnerClasses")) {
00163                 a->tag = ATTRIB_InnerClasses;
00164         } else if (!strcmp(aname, "Synthetic")) {
00165                 a->tag = ATTRIB_Synthetic;
00166         } else if (!strcmp(aname, "SourceFile")) {
00167                 a->tag = ATTRIB_SourceFile;
00168         } else if (!strcmp(aname, "LineNumberTable")) {
00169                 a->tag = ATTRIB_LineNumberTable;
00170         } else if (!strcmp(aname, "LocalVariableTable")) {
00171                 a->tag = ATTRIB_LocalVariableTable;
00172         } else if (!strcmp(aname, "Deprecated")) {
00173                 a->tag = ATTRIB_Deprecated;
00174         }
00175         SKIPN(len);
00176         return (a);
00177 }
00178 
00179 /* read and return method info */
00180 static mf_info *read_fieldmethod (ht_stream *htio, ht_class_shared_data *shared)
00181 {
00182         mf_info *m;
00183         u2 idx;
00184         classfile *clazz = shared->file;
00185 
00186         m = (mf_info *)calloc(1, sizeof (*m));
00187         if (!m) {
00188                 return NULL;
00189         }
00190         m->offset = offset;
00191         m->flags = READ2();
00192         m->name = get_string(htio, clazz, READ2());
00193         m->desc = get_string(htio, clazz, READ2());
00194         m->attribs_count = idx = READ2();
00195         if (idx) {
00196                 m->attribs = (attrib_info **)malloc(idx * sizeof (*(m->attribs)));
00197                 if (!m->attribs) {
00198                         return NULL;
00199                 }
00200                 for (int i=0; i<(int)idx; i++) {
00201                         m->attribs[i] = attribute_read(htio, clazz);
00202                 }
00203         }
00204         return m;
00205 }
00206 
00207 /* read and return classfile */
00208 ht_class_shared_data *class_read(ht_streamfile *htio)
00209 {
00210         ht_class_shared_data *shared;
00211         classfile *clazz;
00212         u2 count;
00213         u2 cpcount, index;
00214 
00215         clazz = (classfile *)malloc(sizeof (*clazz));
00216         if (!clazz) {
00217                 return NULL;
00218         }
00219         shared = (ht_class_shared_data *)malloc(sizeof (ht_class_shared_data));
00220         shared->file = clazz;
00221         shared->methods = new ht_stree();
00222         shared->methods->init(compare_keys_ht_data);
00223         shared->valid = new Area();
00224         shared->valid->init();
00225         shared->initialized = new Area();
00226         shared->initialized->init();
00227         clazz->offset = offset = 0;
00228         clazz->magic  = READ4();
00229         if (clazz->magic != 0xCAFEBABE) {
00230                 return NULL;
00231         }
00232         clazz->minor_version = READ2();
00233         clazz->major_version = READ2();
00234         count = clazz->cpool_count = READ2();
00235         clazz->cpool = (cp_info **)malloc((count+1) * sizeof (*(clazz->cpool)));
00236         if (!clazz->cpool) {
00237                 return NULL;
00238         }
00239         cpcount = clazz->cpool_count;
00240         for (int i=1; i<(int)count; i++) {
00241                 clazz->cpool[i] = read_cpool_entry(htio, clazz);
00242                 if ((clazz->cpool[i]->tag == CONSTANT_Long) ||
00243                         (clazz->cpool[i]->tag == CONSTANT_Double)) {
00244                         i++;
00245                 }
00246         }
00247         clazz->coffset = offset;
00248         clazz->access_flags = READ2();
00249         shared->flags = clazz->access_flags;
00250         index = READ2();
00251         clazz->this_class = index;
00252         index = READ2();
00253         clazz->super_class = index;
00254         count = clazz->interfaces_count = READ2();
00255         shared->classinfo.interfaces = NULL;
00256         shared->classinfo.thisclass = get_class_name(htio, clazz, clazz->this_class);
00257         if (strcmp(shared->classinfo.thisclass, "?") == 0) return NULL;
00258         shared->classinfo.superclass = get_class_name(htio, clazz, clazz->super_class);
00259         if (strcmp(shared->classinfo.superclass, "?") == 0) return NULL;
00260         if (count) {
00261                 clazz->interfaces = (u2 *)malloc(count * sizeof (*(clazz->interfaces)));
00262                 if (!clazz->interfaces) {
00263                         return NULL;
00264                 }
00265                 shared->classinfo.interfaces = new ht_clist();
00266                 ((ht_clist*)shared->classinfo.interfaces)->init();
00267                 for (int i=0; i<(int)count; i++) {
00268                         index = READ2();
00269                         clazz->interfaces[i] = index;
00270                         shared->classinfo.interfaces->append(new ht_data_string(get_class_name(htio, clazz, index)));
00271                 }
00272         } else {
00273                 clazz->interfaces = 0;
00274         }
00275         clazz->foffset = offset;
00276         count = clazz->fields_count = READ2();
00277         if (count) {
00278                 clazz->fields = (mf_info **)malloc(count * sizeof (*(clazz->fields)));
00279                 if (!clazz->fields) {
00280                         return NULL;
00281                 }
00282                 for (int i=0; i<(int)count; i++) {
00283                         clazz->fields[i] = read_fieldmethod(htio, shared);
00284                 }
00285         } else {
00286                 clazz->fields = 0;
00287         }
00288         clazz->moffset = offset;
00289         count = clazz->methods_count = READ2();
00290         if (count) {
00291                 clazz->methods = (mf_info **)malloc(count * sizeof (*(clazz->methods)));
00292                 if (!clazz->methods) {
00293                         return NULL;
00294                 }
00295                 for (int i=0; i<(int)count; i++) {
00296                         clazz->methods[i] = read_fieldmethod(htio, shared);
00297                         int acount = clazz->methods[i]->attribs_count;
00298                         bool ok = false;
00299                         for (int j=0; j < acount; j++) {
00300                                 attrib_info *ai = clazz->methods[i]->attribs[j];
00301                                 if (ai->tag == ATTRIB_Code) {
00302                                         ClassMethod *cm = new ClassMethod(clazz->methods[i]->name, clazz->methods[i]->desc, ai->code.start, ai->code.len, clazz->methods[i]->flags);
00303                                         shared->methods->insert(cm, NULL);
00304                                         Address *a1 = new AddressFlat32(ai->code.start);
00305                                         Address *a2 = new AddressFlat32(ai->code.start+ai->code.len);
00306                                         shared->initialized->add(a1, a2);
00307                                         shared->valid->add(a1, a2);
00308                                         delete a1;
00309                                         delete a2;
00310                                         ok = true;
00311                                 }
00312                         }
00313                         if (!ok) {
00314                                 // fake abstract method
00315                                 ClassMethod *cm = new ClassMethod(clazz->methods[i]->name, clazz->methods[i]->desc, offset, 1, clazz->methods[i]->flags);
00316                                 shared->methods->insert(cm, NULL);
00317                                 Address *a1 = new AddressFlat32(offset);
00318                                 Address *a2 = new AddressFlat32(offset+1);
00319                                 shared->valid->add(a1, a2);
00320                                 delete a1;
00321                                 delete a2;
00322                         }
00323                 }
00324         } else {
00325                 clazz->methods = 0;
00326         }
00327         clazz->aoffset = offset;
00328         count = clazz->attribs_count = READ2();
00329         if (count) {
00330                 clazz->attribs = (attrib_info **)malloc (count*sizeof (*(clazz->attribs)));
00331                 if (!clazz->attribs) {
00332                         return NULL;
00333                 }
00334                 for (int i=0; i<(int)count; i++) {
00335                         clazz->attribs[i] = attribute_read (htio, clazz);
00336                         if (!clazz->attribs[i]) {
00337                                 return NULL;
00338                         }
00339                 }
00340         } else {
00341                 clazz->attribs = 0;
00342         }
00343         return shared;
00344 }
00345 
00346 void class_unread(ht_class_shared_data *shared)
00347 {
00348         u1 tag;
00349         classfile *clazz = shared->file;
00350 
00351         if (!clazz) return;
00352         for (UINT i=1; i<clazz->cpool_count; i++) {
00353                 tag = clazz->cpool[i]->tag;
00354                 free (clazz->cpool[i]);
00355                 if ((tag == CONSTANT_Long) || (tag == CONSTANT_Double)) {
00356                         i++;
00357                 }
00358         }
00359         if (clazz->cpool_count) free(clazz->cpool);
00360         if (clazz->interfaces) free(clazz->interfaces);
00361         for (UINT i=0; i<clazz->fields_count; i++) {
00362                 for (UINT j=0; j<clazz->fields[i]->attribs_count; j++) {
00363                         free(clazz->fields[i]->attribs[j]);
00364                 }
00365                 if (clazz->fields[i]->attribs_count) free(clazz->fields[i]->attribs);
00366                 free(clazz->fields[i]);
00367         }
00368         if (clazz->fields_count) free(clazz->fields);
00369         for (UINT i=0; i<clazz->methods_count; i++) {
00370                 for (UINT j=0; j<clazz->methods[i]->attribs_count; j++) {
00371                         free (clazz->methods[i]->attribs[j]);
00372                 }
00373                 if (clazz->methods[i]->attribs_count) free(clazz->methods[i]->attribs);
00374                 free(clazz->methods[i]);
00375         }
00376         if (clazz->methods_count) free(clazz->methods);
00377         for (UINT i=0; i<clazz->attribs_count; i++) {
00378                 free(clazz->attribs[i]);
00379         }
00380         if (clazz->attribs_count) {
00381                 free(clazz->attribs);
00382         }
00383         if (shared->valid) {
00384                 shared->valid->done();
00385                 delete shared->valid;
00386         }
00387 /*     if (shared->initialized) {
00388                 shared->initialized->done();
00389                 delete shared->initialized;
00390         }*/
00391         free(shared);
00392 }
00393 
00394 #define STRIP_PATH
00395 
00396 int java_demangle_type(char *result, char **type)
00397 {
00398         switch (*((*type)++)) {
00399                 case '[': {
00400                         char temp[200];
00401                         java_demangle_type(temp, type);
00402                         return sprintf(result, "%s[]", temp);
00403                 }
00404                 case 'B':
00405                         return sprintf(result, "byte");
00406                 case 'C':
00407                         return sprintf(result, "char");
00408                 case 'D':
00409                         return sprintf(result, "double");
00410                 case 'F':
00411                         return sprintf(result, "float");
00412                 case 'I':
00413                         return sprintf(result, "int");
00414                 case 'J':
00415                         return sprintf(result, "long");
00416                 case 'L': {
00417                         char *oldresult = result;
00418                         while (**type != ';') {
00419                                 *result = **type;
00420 #ifdef STRIP_PATH
00421                                 if (*result == '/') result = oldresult; else
00422 #endif
00423                                 result++;
00424                                 (*type)++;
00425                         }
00426                         (*type)++;
00427                         *result = 0;
00428                         return result-oldresult;
00429                 }
00430                 case 'S':
00431                         return sprintf(result, "short");
00432                 case 'V':
00433                         return sprintf(result, "void");
00434                 case 'Z':
00435                         return sprintf(result, "boolean");
00436                 default:
00437                         return sprintf(result, "%c", *(*type-1));
00438         }
00439 }
00440 
00441 char *java_demangle_flags(char *result, int flags)
00442 {
00443         if (flags & jACC_PUBLIC) result += sprintf(result, "public ");
00444         if (flags & jACC_PRIVATE) result += sprintf(result, "private ");
00445         if (flags & jACC_PROTECTED) result += sprintf(result, "protected ");
00446         if (flags & jACC_STATIC) result += sprintf(result, "static ");
00447         if (flags & jACC_FINAL) result += sprintf(result, "final ");
00448 //     if (flags & jACC_SUPER)
00449 //     if (flags & jACC_SYNCHRONIZED)
00450 //     if (flags & jACC_VOLATILE)
00451 //     if (flags & jACC_TRANSIENT)
00452         if (flags & jACC_NATIVE) result += sprintf(result, "native ");
00453 //     if (flags & jACC_INTERFACE)
00454         if (flags & jACC_ABSTRACT) result += sprintf(result, "abstract ");
00455 //     if (flags & jACC_STRICT)
00456         return result;
00457 }
00458 
00459 static char *java_strip_path(char *name)
00460 {
00461 #ifdef STRIP_PATH
00462         char *nname = strrchr(name, '/');
00463         return nname?(nname+1):name;
00464 #else
00465         return name;
00466 #endif
00467 }
00468 
00469 void java_demangle(char *result, char *classname, char *name, char *type, int flags)
00470 {
00471         result = java_demangle_flags(result, flags);
00472         name = java_strip_path(name);
00473         classname = java_strip_path(classname);
00474         strcpy(result, name);
00475         if (*type != '(') return;
00476         char *ret = strchr(type, ')');
00477         if (!ret) return;
00478         ret++;
00479         result += java_demangle_type(result, &ret);
00480         if (strcmp(name, "<init>")==0) {
00481                 name = classname;
00482         }
00483         result += sprintf(result, " %s::%s(", classname, name);
00484         type++;
00485         while (*type != ')') {
00486                 result += java_demangle_type(result, &type);
00487                 if (*type != ')') {
00488                         result += sprintf(result, ", ");
00489                 }
00490         }
00491         result += sprintf(result, ")");
00492 }
00493 
00494 int token_translate(char *buf, int maxlen, dword token, ht_class_shared_data *shared)
00495 {
00496         classfile *clazz = shared->file;
00497         char tag[20];
00498         char data[1024];
00499         char classname[1024];
00500         char name[1024];
00501         char type[1024];
00502         strcpy(tag, "?");
00503         strcpy(data, "?");
00504         strcpy(classname, "?");
00505         strcpy(name, "?");
00506         strcpy(type, "?");
00507         if (token < clazz->cpool_count)
00508         switch (clazz->cpool[token]->tag) {
00509                 case CONSTANT_Class:
00510                         strcpy(tag, "Class");
00511                         strcpy(data, java_strip_path(get_class_name(NULL, clazz, token)));
00512                         break;
00513                 case CONSTANT_Double:
00514                         strcpy(tag, "Double");
00515                         sprintf(data, "double");
00516                         break;
00517                 case CONSTANT_Float:
00518                         strcpy(tag, "Float");
00519                         sprintf(data, "%f", (float)clazz->cpool[token]->value.llval[0]);
00520                         break;
00521                 case CONSTANT_Integer:
00522                         strcpy(tag, "Int");
00523                         sprintf(data, "0x%lx", clazz->cpool[token]->value.llval[0]);
00524                         break;
00525                 case CONSTANT_Long:
00526                         strcpy(tag, "Long");
00527                         sprintf(data, "long");
00528                         break;
00529                 case CONSTANT_String: {
00530                         strcpy(tag, "String");
00531                         char *d = data;
00532                         *(d++) = '\"';
00533                         // FIXME: add "..." on too long strings
00534                         d += escape_special_str(d, 256, get_string(NULL, clazz, clazz->cpool[token]->value.llval[0]), "\"", false);
00535                         *(d++) = '\"';
00536                         *d = 0;
00537                         break;
00538                 }
00539                 case CONSTANT_Fieldref: {
00540                         strcpy(tag, "Field");
00541                         get_name_and_type(NULL, clazz, clazz->cpool[token]->value.llval[1], name, type);
00542                         char dtype[1024];
00543                         char *ttype=type;
00544                         java_demangle_type(dtype, &ttype);
00545                         ht_snprintf(data, sizeof data, "%s %s", dtype, name);
00546                         break;
00547                 }
00548                 case CONSTANT_Methodref:
00549                         strcpy(tag, "Method");
00550                         strcpy(classname, get_class_name(NULL, clazz, clazz->cpool[token]->value.llval[0]));
00551                         get_name_and_type(NULL, clazz, clazz->cpool[token]->value.llval[1], name, type);
00552                         java_demangle(data, classname, name, type, 0);
00553                         break;
00554                 case CONSTANT_InterfaceMethodref:
00555                         strcpy(tag, "InterfaceMethod");
00556                         strcpy(classname, get_class_name(NULL, clazz, clazz->cpool[token]->value.llval[0]));
00557                         get_name_and_type(NULL, clazz, clazz->cpool[token]->value.llval[1], name, type);
00558                         java_demangle(data, classname, name, type, 0);
00559                         break;
00560         }
00561 //     return ht_snprintf(buf, maxlen, "<%s %s>", tag, data);
00562         return ht_snprintf(buf, maxlen, "<%s>", data);
00563 }
00564 

Generated on Fri May 7 21:15:29 2004 by doxygen 1.3.5