00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
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
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
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
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
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
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
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
00388
00389
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
00449
00450
00451
00452 if (flags & jACC_NATIVE) result += sprintf(result, "native ");
00453
00454 if (flags & jACC_ABSTRACT) result += sprintf(result, "abstract ");
00455
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
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
00562 return ht_snprintf(buf, maxlen, "<%s>", data);
00563 }
00564