00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #include "config.h"
00050 #include "system.h"
00051
00052 #include "jcf.h"
00053 #include "tree.h"
00054 #include "java-tree.h"
00055
00056 #include "version.h"
00057
00058 #include <getopt.h>
00059
00060
00061 FILE *out;
00062
00063 char *output_file = NULL;
00064
00065 int verbose = 0;
00066
00067 int flag_disassemble_methods = 0;
00068 int flag_print_class_info = 1;
00069 int flag_print_constant_pool = 1;
00070 int flag_print_fields = 1;
00071 int flag_print_methods = 1;
00072 int flag_print_attributes = 1;
00073
00074
00075
00076 int flag_newer = 1;
00077
00078
00079 int flag_print_main = 0;
00080
00081
00082 int this_class_index = 0;
00083
00084 int class_access_flags = 0;
00085
00086
00087 int flag_javap_compatible = 0;
00088
00089 static void print_access_flags PARAMS ((FILE *, uint16, char));
00090 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
00091 static void print_constant PARAMS ((FILE *, JCF *, int, int));
00092 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
00093 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
00094 static void print_name PARAMS ((FILE*, JCF*, int));
00095 static void print_signature PARAMS ((FILE*, JCF*, int, int));
00096 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
00097 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
00098 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
00099 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
00100 static void process_class PARAMS ((struct JCF *));
00101 static void print_constant_pool PARAMS ((struct JCF *));
00102 static void print_exception_table PARAMS ((struct JCF *,
00103 const unsigned char *entries, int));
00104
00105 #define PRINT_SIGNATURE_RESULT_ONLY 1
00106 #define PRINT_SIGNATURE_ARGS_ONLY 2
00107
00108 static int
00109 DEFUN(utf8_equal_string, (jcf, index, value),
00110 JCF *jcf AND int index AND const char * value)
00111 {
00112 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
00113 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
00114 {
00115 int len = strlen (value);
00116 if (JPOOL_UTF_LENGTH (jcf, index) == len
00117 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
00118 return 1;
00119 }
00120 return 0;
00121 }
00122
00123 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
00124 this_class_index = 0; \
00125 if (flag_print_class_info) \
00126 fprintf (out, \
00127 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
00128 (long) MAGIC, (long) MINOR, (long) MAJOR)
00129
00130 #define HANDLE_START_CONSTANT_POOL(COUNT) \
00131 if (flag_print_constant_pool) \
00132 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
00133
00134 #define HANDLE_SOURCEFILE(INDEX) \
00135 { fprintf (out, "Attribute "); \
00136 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
00137 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
00138 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
00139
00140 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
00141 this_class_index = THIS; \
00142 class_access_flags = ACCESS_FLAGS; \
00143 if (flag_print_class_info) \
00144 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
00145 print_access_flags (out, ACCESS_FLAGS, 'c'); \
00146 fputc ('\n', out); \
00147 fprintf (out, "This class: "); \
00148 if (flag_print_constant_pool) \
00149 fprintf (out, "%d=", THIS); \
00150 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
00151 if (flag_print_constant_pool || SUPER != 0) \
00152 fprintf (out, ", super: "); \
00153 if (flag_print_constant_pool) \
00154 { \
00155 fprintf (out, "%d", SUPER); \
00156 if (SUPER != 0) \
00157 fputc ('=', out); \
00158 } \
00159 if (SUPER != 0) \
00160 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
00161 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
00162 }
00163
00164 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
00165 (flag_print_attributes <= 0)
00166
00167 #define HANDLE_CLASS_INTERFACE(INDEX) \
00168 if (flag_print_class_info) \
00169 { fprintf (out, "- Implements: %d=", INDEX); \
00170 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
00171 fputc ('\n', out); }
00172
00173 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
00174 if (flag_print_fields) \
00175 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
00176
00177 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
00178 if (flag_print_fields) \
00179 { fprintf (out, "Field name:"); \
00180 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
00181 print_access_flags (out, ACCESS_FLAGS, 'f'); \
00182 fprintf (out, " Signature: "); \
00183 if (flag_print_constant_pool) \
00184 fprintf (out, "%d=", SIGNATURE); \
00185 print_signature (out, jcf, SIGNATURE, 0); \
00186 fputc ('\n', out); } \
00187 else \
00188 flag_print_attributes--;
00189
00190 #define HANDLE_END_FIELD() \
00191 if (! flag_print_fields) \
00192 flag_print_attributes++;
00193
00194 #define HANDLE_START_METHODS(METHODS_COUNT) \
00195 if (flag_print_methods) \
00196 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
00197 else \
00198 flag_print_attributes--;
00199
00200
00201 #define HANDLE_END_METHODS() \
00202 if (! flag_print_methods) \
00203 flag_print_attributes++;
00204
00205 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
00206 { \
00207 if (flag_print_methods) \
00208 { \
00209 if (flag_javap_compatible) \
00210 { \
00211 fprintf (out, " "); \
00212 print_access_flags (out, ACCESS_FLAGS, 'm'); \
00213 fputc (' ', out); \
00214 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
00215 fputc (' ', out); \
00216 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
00217 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
00218 fputc ('\n', out); \
00219 } \
00220 else \
00221 { \
00222 fprintf (out, "\nMethod name:"); \
00223 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
00224 print_access_flags (out, ACCESS_FLAGS, 'm'); \
00225 fprintf (out, " Signature: "); \
00226 if (flag_print_constant_pool) \
00227 fprintf (out, "%d=", SIGNATURE); \
00228 print_signature (out, jcf, SIGNATURE, 0); \
00229 fputc ('\n', out); \
00230 } \
00231 } \
00232 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
00233 && utf8_equal_string (jcf, NAME, "main") \
00234 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
00235 && this_class_index > 0 \
00236 && (class_access_flags & ACC_PUBLIC)) \
00237 { \
00238 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
00239 fputc ('\n', out); \
00240 } \
00241 }
00242
00243 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
00244 ( fprintf (out, "Attribute "), \
00245 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
00246 fprintf (out, ", length:%ld", (long) LENGTH) )
00247
00248 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
00249 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
00250 fprintf (out, ", value: "), \
00251 print_constant_ref (out, jcf, VALUE_INDEX), \
00252 fprintf (out, "\n") )
00253
00254 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
00255 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
00256 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
00257 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
00258 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
00259
00260 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
00261 print_exception_table (jcf, ENTRIES, COUNT)
00262
00263 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
00264 { int n = (COUNT); int i; \
00265 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
00266 fprintf (out, ", count: %d\n", n); \
00267 for (i = 0; i < n; i++) {\
00268 int ex_index = JCF_readu2 (jcf); \
00269 fprintf (out, "%3d: ", i); \
00270 print_constant_ref (out, jcf, ex_index); \
00271 fputc ('\n', out); } }
00272
00273 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
00274 { int n = (COUNT); int i; \
00275 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
00276 fprintf (out, ", count: %d\n", n); \
00277 for (i = 0; i < n; i++) {\
00278 int start_pc = JCF_readu2 (jcf); \
00279 int length = JCF_readu2 (jcf); \
00280 int name_index = JCF_readu2 (jcf); \
00281 int signature_index = JCF_readu2 (jcf); \
00282 int slot = JCF_readu2 (jcf); \
00283 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
00284 print_name (out, jcf, name_index); \
00285 fprintf (out, ", type: %d=", signature_index); \
00286 print_signature (out, jcf, signature_index, 0); \
00287 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
00288
00289 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
00290 { int n = (COUNT); int i; \
00291 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
00292 fprintf (out, ", count: %d\n", n); \
00293 if (flag_disassemble_methods) \
00294 for (i = 0; i < n; i++) {\
00295 int start_pc = JCF_readu2 (jcf); \
00296 int line_number = JCF_readu2 (jcf); \
00297 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
00298 else \
00299 JCF_SKIP (jcf, 4 * n); }
00300
00301 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
00302 { int n = (COUNT); \
00303 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
00304 while (n--) \
00305 { \
00306 uint16 inner_class_info_index = JCF_readu2 (jcf); \
00307 uint16 outer_class_info_index = JCF_readu2 (jcf); \
00308 uint16 inner_name_index = JCF_readu2 (jcf); \
00309 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
00310 \
00311 if (flag_print_class_info) \
00312 { \
00313 fprintf (out, "\n class: "); \
00314 if (flag_print_constant_pool) \
00315 fprintf (out, "%d=", inner_class_info_index); \
00316 print_constant_terse (out, jcf, \
00317 inner_class_info_index, CONSTANT_Class); \
00318 fprintf (out, " (%d=", inner_name_index); \
00319 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
00320 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
00321 print_access_flags (out, inner_class_access_flags, 'c'); \
00322 fprintf (out, ", outer class: "); \
00323 if (flag_print_constant_pool) \
00324 fprintf (out, "%d=", outer_class_info_index); \
00325 print_constant_terse (out, jcf, \
00326 outer_class_info_index, CONSTANT_Class); \
00327 } \
00328 } \
00329 if (flag_print_class_info) \
00330 fputc ('\n', out); \
00331 }
00332
00333 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
00334 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
00335 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
00336
00337 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
00338 if (flag_print_attributes > 0) \
00339 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
00340
00341 #include "javaop.h"
00342
00343 static void
00344 DEFUN(print_constant_ref, (stream, jcf, index),
00345 FILE *stream AND JCF *jcf AND int index)
00346 {
00347 fprintf (stream, "#%d=<", index);
00348 if (index <= 0 || index >= JPOOL_SIZE(jcf))
00349 fprintf (stream, "out of range");
00350 else
00351 print_constant (stream, jcf, index, 1);
00352 fprintf (stream, ">");
00353 }
00354
00355
00356
00357
00358
00359 static void
00360 DEFUN (print_access_flags, (stream, flags, context),
00361 FILE *stream AND uint16 flags AND char context)
00362 {
00363 if (flags & ACC_PUBLIC) fprintf (stream, " public");
00364 if (flags & ACC_PRIVATE) fprintf (stream, " private");
00365 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
00366 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
00367 if (flags & ACC_STATIC) fprintf (stream, " static");
00368 if (flags & ACC_FINAL) fprintf (stream, " final");
00369 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
00370 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
00371 if (flags & ACC_NATIVE) fprintf (stream, " native");
00372 if (flags & ACC_SYNCHRONIZED)
00373 {
00374 if (context == 'c')
00375 fprintf (stream, " super");
00376 else
00377 fprintf (stream, " synchronized");
00378 }
00379 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
00380 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
00381 }
00382
00383
00384 static void
00385 DEFUN(print_name, (stream, jcf, name_index),
00386 FILE* stream AND JCF* jcf AND int name_index)
00387 {
00388 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
00389 fprintf (stream, "<not a UTF8 constant>");
00390 else
00391 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
00392 JPOOL_UTF_LENGTH (jcf, name_index));
00393 }
00394
00395
00396
00397
00398 static void
00399 DEFUN(print_constant_terse, (out, jcf, index, expected),
00400 FILE *out AND JCF *jcf AND int index AND int expected)
00401 {
00402 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
00403 fprintf (out, "<constant pool index %d not in range>", index);
00404 else if (JPOOL_TAG (jcf, index) != expected)
00405 {
00406 fprintf (out, "<Unexpected constant type ");
00407 print_constant (out, jcf, index, 1);
00408 fprintf (out, ">");
00409 }
00410 else
00411 print_constant (out, jcf, index, 0);
00412 }
00413
00414
00415
00416
00417
00418
00419 static void
00420 DEFUN(print_constant, (out, jcf, index, verbosity),
00421 FILE *out AND JCF *jcf AND int index AND int verbosity)
00422 {
00423 int j, n;
00424 jlong num;
00425 const char *str;
00426 int kind = JPOOL_TAG (jcf, index);
00427 switch (kind)
00428 {
00429 case CONSTANT_Class:
00430 n = JPOOL_USHORT1 (jcf, index);
00431 if (verbosity > 0)
00432 {
00433 if (verbosity > 1)
00434 fprintf (out, "Class name: %d=", n);
00435 else
00436 fprintf (out, "Class ");
00437 }
00438 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
00439 fprintf (out, "<out of range>");
00440 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
00441 {
00442 int len = JPOOL_UTF_LENGTH (jcf, n);
00443 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
00444 }
00445 else
00446 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
00447 break;
00448 case CONSTANT_Fieldref:
00449 str = "Field"; goto field_or_method;
00450 case CONSTANT_Methodref:
00451 str = "Method"; goto field_or_method;
00452 case CONSTANT_InterfaceMethodref:
00453 str = "InterfaceMethod"; goto field_or_method;
00454 field_or_method:
00455 {
00456 uint16 tclass = JPOOL_USHORT1 (jcf, index);
00457 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
00458 if (verbosity == 2)
00459 fprintf (out, "%sref class: %d=", str, tclass);
00460 else if (verbosity > 0)
00461 fprintf (out, "%s ", str);
00462 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
00463 if (verbosity < 2)
00464 fprintf (out, ".");
00465 else
00466 fprintf (out, " name_and_type: %d=<", name_and_type);
00467 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
00468 if (verbosity == 2)
00469 fputc ('>', out);
00470 }
00471 break;
00472 case CONSTANT_String:
00473 j = JPOOL_USHORT1 (jcf, index);
00474 if (verbosity > 0)
00475 {
00476 if (verbosity > 1)
00477 fprintf (out, "String %d=", j);
00478 else
00479 fprintf (out, "String ");
00480 }
00481 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
00482 break;
00483 case CONSTANT_Integer:
00484 if (verbosity > 0)
00485 fprintf (out, "Integer ");
00486 num = JPOOL_INT (jcf, index);
00487 goto integer;
00488 case CONSTANT_Long:
00489 if (verbosity > 0)
00490 fprintf (out, "Long ");
00491 num = JPOOL_LONG (jcf, index);
00492 goto integer;
00493 integer:
00494 {
00495 char buffer[25];
00496 format_int (buffer, num, 10);
00497 fprintf (out, "%s", buffer);
00498 if (verbosity > 1)
00499 {
00500 format_uint (buffer, (uint64)num, 16);
00501 fprintf (out, "=0x%s", buffer);
00502 }
00503 }
00504 break;
00505 case CONSTANT_Float:
00506 {
00507 jfloat fnum = JPOOL_FLOAT (jcf, index);
00508 fprintf (out, "%s%.10g", verbosity > 0 ? "Float " : "", (double) fnum);
00509 if (verbosity > 1)
00510 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
00511 break;
00512 }
00513 case CONSTANT_Double:
00514 {
00515 jdouble dnum = JPOOL_DOUBLE (jcf, index);
00516 fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
00517 if (verbosity > 1)
00518 {
00519 int32 hi, lo;
00520 hi = JPOOL_UINT (jcf, index);
00521 lo = JPOOL_UINT (jcf, index + 1);
00522 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
00523 }
00524 break;
00525 }
00526 case CONSTANT_NameAndType:
00527 {
00528 uint16 name = JPOOL_USHORT1 (jcf, index);
00529 uint16 sig = JPOOL_USHORT2 (jcf, index);
00530 if (verbosity > 0)
00531 {
00532 if (verbosity > 1)
00533 fprintf (out, "NameAndType name: %d=", name);
00534 else
00535 fprintf (out, "NameAndType ");
00536 }
00537 print_name (out, jcf, name);
00538 if (verbosity <= 1)
00539 fputc (' ', out);
00540 else
00541 fprintf (out, ", signature: %d=", sig);
00542 print_signature (out, jcf, sig, 0);
00543 }
00544 break;
00545 case CONSTANT_Utf8:
00546 {
00547 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
00548 int length = JPOOL_UTF_LENGTH (jcf, index);
00549 if (verbosity > 0)
00550 {
00551 fputs ("Utf8: \"", out);
00552 while (--length >= 0)
00553 jcf_print_char (out, *str++);
00554 }
00555 else
00556 {
00557 fputc ('\"', out);
00558 jcf_print_utf8 (out, str, length);
00559 }
00560 fputc ('\"', out);
00561 }
00562 break;
00563 default:
00564 fprintf (out, "(Unknown constant type %d)", kind);
00565 }
00566 }
00567
00568 static void
00569 DEFUN(print_constant_pool, (jcf),
00570 JCF *jcf)
00571 {
00572 int i;
00573 for (i = 1; i < JPOOL_SIZE(jcf); i++)
00574 {
00575 int kind = JPOOL_TAG (jcf, i);
00576 fprintf (out, "#%d: ", i);
00577 print_constant (out, jcf, i, 2);
00578 fprintf (out, "\n");
00579 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
00580 i++;
00581 }
00582 }
00583
00584 static void
00585 DEFUN(print_signature_type, (stream, ptr, limit),
00586 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
00587 {
00588 int array_size;
00589 if ((*ptr) >= limit)
00590 return;
00591 switch (*(*ptr))
00592 {
00593 case '[':
00594 array_size = -1;
00595 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
00596 {
00597 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
00598 }
00599 print_signature_type (stream, ptr, limit);
00600 if (array_size == -1)
00601 fprintf (stream, "[]");
00602 else
00603 fprintf (stream, "[%d]", array_size);
00604 break;
00605 case '(':
00606 {
00607 int nargs = 0;
00608 fputc (*(*ptr)++, stream);
00609 for (; **ptr != ')' && *ptr < limit; nargs++)
00610 {
00611 if (nargs > 0)
00612 fputc (',', stream);
00613 print_signature_type (stream, ptr, limit);
00614 }
00615 if (*ptr < limit)
00616 {
00617 fputc (*(*ptr)++, stream);
00618 print_signature_type (stream, ptr, limit);
00619 }
00620 else
00621 fprintf (stream, "???");
00622 }
00623 break;
00624
00625 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
00626 case 'C': fprintf (stream, "char"); (*ptr)++; break;
00627 case 'D': fprintf (stream, "double"); (*ptr)++; break;
00628 case 'F': fprintf (stream, "float"); (*ptr)++; break;
00629 case 'S': fprintf (stream, "short"); (*ptr)++; break;
00630 case 'I': fprintf (stream, "int"); (*ptr)++; break;
00631 case 'J': fprintf (stream, "long"); (*ptr)++; break;
00632 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
00633 case 'V': fprintf (stream, "void"); (*ptr)++; break;
00634
00635 case 'L':
00636 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
00637 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
00638 if (*(*ptr) == ';')
00639 (*ptr)++;
00640 break;
00641 default:
00642 jcf_print_char (stream, *(*ptr)++);
00643 }
00644 }
00645
00646 static void
00647 DEFUN(print_signature, (stream, jcf, signature_index, int options),
00648 FILE* stream AND JCF *jcf AND int signature_index AND int options)
00649 {
00650 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
00651 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
00652 else
00653 {
00654 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
00655 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
00656 const unsigned char *limit;
00657 limit = str + length;
00658 if (str >= limit)
00659 fprintf (stream, "<empty signature string>");
00660 else
00661 {
00662 if (options & PRINT_SIGNATURE_RESULT_ONLY)
00663 {
00664 while (str < limit && *str++ != ')') ;
00665 }
00666 if (options & PRINT_SIGNATURE_ARGS_ONLY)
00667 {
00668 str++;
00669 fputc ('(', stream);
00670 while (str < limit && *str != ')')
00671 {
00672 print_signature_type (stream, &str, limit);
00673 if (*str != ')')
00674 fputs (", ", stream);
00675 }
00676 fputc (')', stream);
00677 }
00678 else
00679 {
00680 print_signature_type (stream, &str, limit);
00681 if (str < limit)
00682 {
00683 fprintf (stream, "<junk:");
00684 jcf_print_utf8 (stream, str, limit - str);
00685 fputc ('>', stream);
00686 }
00687 }
00688 }
00689 }
00690 }
00691
00692
00693 static void
00694 DEFUN(print_exception_table, (jcf, entries, count),
00695 JCF *jcf AND const unsigned char *entries AND int count)
00696 {
00697
00698 int i = count;
00699 if (i > 0)
00700 {
00701 const unsigned char *ptr = entries;
00702 fprintf (out, "Exceptions (count: %d):\n", i);
00703 for (; --i >= 0; ptr+= 8)
00704 {
00705 int start_pc = GET_u2 (ptr);
00706 int end_pc = GET_u2 (ptr+2);
00707 int handler_pc = GET_u2 (ptr+4);
00708 int catch_type = GET_u2 (ptr+6);
00709 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
00710 start_pc, end_pc, handler_pc, catch_type);
00711 if (catch_type == 0)
00712 fputs (" /* finally */", out);
00713 else
00714 {
00715 fputc('=', out);
00716 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
00717 }
00718 fputc ('\n', out);
00719 }
00720 }
00721 }
00722
00723 #include "jcf-reader.c"
00724
00725 static void
00726 DEFUN(process_class, (jcf),
00727 JCF *jcf)
00728 {
00729 int code;
00730 if (jcf_parse_preamble (jcf) != 0)
00731 fprintf (stderr, "Not a valid Java .class file.\n");
00732
00733
00734 code = jcf_parse_constant_pool (jcf);
00735 if (code != 0)
00736 {
00737 fprintf (stderr, "error while parsing constant pool\n");
00738 exit (FATAL_EXIT_CODE);
00739 }
00740 code = verify_constant_pool (jcf);
00741 if (code > 0)
00742 {
00743 fprintf (stderr, "error in constant pool entry #%d\n", code);
00744 exit (FATAL_EXIT_CODE);
00745 }
00746 if (flag_print_constant_pool)
00747 print_constant_pool (jcf);
00748
00749 jcf_parse_class (jcf);
00750 code = jcf_parse_fields (jcf);
00751 if (code != 0)
00752 {
00753 fprintf (stderr, "error while parsing fields\n");
00754 exit (FATAL_EXIT_CODE);
00755 }
00756 code = jcf_parse_methods (jcf);
00757 if (code != 0)
00758 {
00759 fprintf (stderr, "error while parsing methods\n");
00760 exit (FATAL_EXIT_CODE);
00761 }
00762 code = jcf_parse_final_attributes (jcf);
00763 if (code != 0)
00764 {
00765 fprintf (stderr, "error while parsing final attributes\n");
00766 exit (FATAL_EXIT_CODE);
00767 }
00768 jcf->filename = NULL;
00769 }
00770
00771
00772
00773
00774 #define LONG_OPT(Num) ((Num) + 128)
00775
00776 #define OPT_classpath LONG_OPT (0)
00777 #define OPT_CLASSPATH OPT_classpath
00778 #define OPT_bootclasspath LONG_OPT (1)
00779 #define OPT_extdirs LONG_OPT (2)
00780 #define OPT_HELP LONG_OPT (3)
00781 #define OPT_VERSION LONG_OPT (4)
00782 #define OPT_JAVAP LONG_OPT (5)
00783
00784 static const struct option options[] =
00785 {
00786 { "classpath", required_argument, NULL, OPT_classpath },
00787 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
00788 { "extdirs", required_argument, NULL, OPT_extdirs },
00789 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
00790 { "help", no_argument, NULL, OPT_HELP },
00791 { "verbose", no_argument, NULL, 'v' },
00792 { "version", no_argument, NULL, OPT_VERSION },
00793 { "javap", no_argument, NULL, OPT_JAVAP },
00794 { "print-main", no_argument, &flag_print_main, 1 },
00795 { NULL, no_argument, NULL, 0 }
00796 };
00797
00798 static void
00799 usage ()
00800 {
00801 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
00802 exit (1);
00803 }
00804
00805 static void
00806 help ()
00807 {
00808 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
00809 printf ("Display contents of a class file in readable form.\n\n");
00810 printf (" -c Disassemble method bodies\n");
00811 printf (" --javap Generate output in `javap' format\n");
00812 printf ("\n");
00813 printf (" --classpath PATH Set path to find .class files\n");
00814 printf (" -IDIR Append directory to class path\n");
00815 printf (" --bootclasspath PATH Override built-in class path\n");
00816 printf (" --extdirs PATH Set extensions directory path\n");
00817 printf (" -o FILE Set output file name\n");
00818 printf ("\n");
00819 printf (" --help Print this help, then exit\n");
00820 printf (" --version Print version number, then exit\n");
00821 printf (" -v, --verbose Print extra information while running\n");
00822 printf ("\n");
00823 printf ("For bug reporting instructions, please see:\n");
00824 printf ("%s.\n", GCCBUGURL);
00825 exit (0);
00826 }
00827
00828 static void
00829 version ()
00830 {
00831 printf ("jcf-dump (GCC) %s\n\n", version_string);
00832 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
00833 printf ("This is free software; see the source for copying conditions. There is NO\n");
00834 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
00835 exit (0);
00836 }
00837
00838 int
00839 DEFUN(main, (argc, argv),
00840 int argc AND char** argv)
00841 {
00842 JCF jcf[1];
00843 int argi, opt;
00844
00845 if (argc <= 1)
00846 {
00847 fprintf (stderr, "jcf-dump: no classes specified\n");
00848 usage ();
00849 }
00850
00851 jcf_path_init ();
00852
00853
00854
00855 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
00856 {
00857 switch (opt)
00858 {
00859 case 0:
00860
00861 break;
00862
00863 case 'o':
00864 output_file = optarg;
00865 break;
00866
00867 case 'I':
00868 jcf_path_include_arg (optarg);
00869 break;
00870
00871 case 'v':
00872 verbose++;
00873 break;
00874
00875 case 'c':
00876 flag_disassemble_methods = 1;
00877 break;
00878
00879 case OPT_classpath:
00880 jcf_path_classpath_arg (optarg);
00881 break;
00882
00883 case OPT_bootclasspath:
00884 jcf_path_bootclasspath_arg (optarg);
00885 break;
00886
00887 case OPT_extdirs:
00888 jcf_path_extdirs_arg (optarg);
00889 break;
00890
00891 case OPT_HELP:
00892 help ();
00893 break;
00894
00895 case OPT_VERSION:
00896 version ();
00897 break;
00898
00899 case OPT_JAVAP:
00900 flag_javap_compatible++;
00901 flag_print_constant_pool = 0;
00902 flag_print_attributes = 0;
00903 break;
00904
00905 default:
00906 usage ();
00907 }
00908 }
00909
00910 if (optind == argc)
00911 {
00912 fprintf (stderr, "jcf-dump: no classes specified\n");
00913 usage ();
00914 }
00915
00916 jcf_path_seal (verbose);
00917
00918 if (flag_print_main)
00919 {
00920 flag_print_fields = 0;
00921 flag_print_methods = 0;
00922 flag_print_constant_pool = 0;
00923 flag_print_attributes = 0;
00924 flag_print_class_info = 0;
00925 }
00926
00927 if (output_file)
00928 {
00929 out = fopen (output_file, "w");
00930 if (! out)
00931 {
00932 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
00933 return FATAL_EXIT_CODE;
00934 }
00935 }
00936 else
00937 out = stdout;
00938
00939 if (optind >= argc)
00940 {
00941 fprintf (out, "Reading .class from <standard input>.\n");
00942 #if JCF_USE_STDIO
00943 open_class ("<stdio>", jcf, stdin, NULL);
00944 #else
00945 open_class ("<stdio>", jcf, 0, NULL);
00946 #endif
00947 process_class (jcf);
00948 }
00949 else
00950 {
00951 for (argi = optind; argi < argc; argi++)
00952 {
00953 char *arg = argv[argi];
00954 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
00955 if (class_filename == NULL)
00956 class_filename = find_classfile (arg, jcf, NULL);
00957 if (class_filename == NULL)
00958 {
00959 perror ("Could not find class");
00960 return FATAL_EXIT_CODE;
00961 }
00962 JCF_FILL (jcf, 4);
00963 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
00964 {
00965 long compressed_size, member_size;
00966 int compression_method, filename_length, extra_length;
00967 int general_purpose_bits;
00968 const char *filename;
00969 int total_length;
00970 if (flag_print_class_info)
00971 fprintf (out, "Reading classes from archive %s.\n",
00972 class_filename);
00973 for (;;)
00974 {
00975 int skip = 0;
00976 jcf_filbuf_t save_filbuf = jcf->filbuf;
00977 long magic = JCF_readu4_le (jcf);
00978 if (magic == 0x02014b50 || magic == 0x06054b50)
00979 break;
00980 if (magic != 0x04034b50)
00981 {
00982 fprintf (stderr, "bad format of .zip/.jar archive\n");
00983 return FATAL_EXIT_CODE;
00984 }
00985 JCF_FILL (jcf, 26);
00986 JCF_SKIP (jcf, 2);
00987 general_purpose_bits = JCF_readu2_le (jcf);
00988 compression_method = JCF_readu2_le (jcf);
00989 JCF_SKIP (jcf, 8);
00990 compressed_size = JCF_readu4_le (jcf);
00991 member_size = JCF_readu4_le (jcf);
00992 filename_length = JCF_readu2_le (jcf);
00993 extra_length = JCF_readu2_le (jcf);
00994 total_length = filename_length + extra_length
00995 + compressed_size;
00996 if (jcf->read_end - jcf->read_ptr < total_length)
00997 jcf_trim_old_input (jcf);
00998 JCF_FILL (jcf, total_length);
00999 filename = jcf->read_ptr;
01000 JCF_SKIP (jcf, filename_length);
01001 JCF_SKIP (jcf, extra_length);
01002 if (filename_length > 0
01003 && filename[filename_length-1] == '/')
01004 {
01005 if (flag_print_class_info)
01006 fprintf (out, "[Skipping directory %.*s]\n",
01007 filename_length, filename);
01008 skip = 1;
01009 }
01010 else if (compression_method != 0)
01011 {
01012 if (flag_print_class_info)
01013 fprintf (out, "[Skipping compressed file %.*s]\n",
01014 filename_length, filename);
01015 skip = 1;
01016 }
01017 else if (member_size < 4
01018 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
01019 {
01020 if (flag_print_class_info)
01021 fprintf (out, "[Skipping non-.class member %.*s]\n",
01022 filename_length, filename);
01023 skip = 1;
01024 }
01025 else
01026 {
01027 if (flag_print_class_info)
01028 fprintf (out, "Reading class member: %.*s.\n",
01029 filename_length, filename);
01030 }
01031 if (skip)
01032 {
01033 JCF_SKIP (jcf, compressed_size);
01034 }
01035 else
01036 {
01037 unsigned char *save_end;
01038 jcf->filbuf = jcf_unexpected_eof;
01039 save_end = jcf->read_end;
01040 jcf->read_end = jcf->read_ptr + compressed_size;
01041 process_class (jcf);
01042 jcf->filbuf = save_filbuf;
01043 jcf->read_end = save_end;
01044 }
01045 }
01046 }
01047 else
01048 {
01049 if (flag_print_class_info)
01050 fprintf (out, "Reading .class from %s.\n", class_filename);
01051 process_class (jcf);
01052 }
01053 JCF_FINISH(jcf);
01054 }
01055 }
01056
01057 return SUCCESS_EXIT_CODE;
01058 }
01059
01060
01061
01062 static void
01063 DEFUN(disassemble_method, (jcf, byte_ops, len),
01064 JCF* jcf AND const unsigned char *byte_ops AND int len)
01065 {
01066 #undef AND
01067 #undef PTR
01068 int PC;
01069 int i;
01070 int saw_wide = 0;
01071 if (flag_disassemble_methods == 0)
01072 return;
01073 #define BCODE byte_ops
01074 for (PC = 0; PC < len;)
01075 {
01076 int oldpc = PC;
01077 int saw_index;
01078 jint INT_temp;
01079 switch (byte_ops[PC++])
01080 {
01081
01082
01083
01084
01085
01086
01087
01088
01089 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
01090 case OPCODE: \
01091 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
01092 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
01093 fputc ('\n', out); \
01094 break;
01095
01096 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
01097 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
01098 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
01099 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
01100
01101 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
01102 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
01103
01104
01105
01106 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
01107 saw_index = 0, i = (OPERAND_VALUE); \
01108 if (oldpc+1 == PC) ; \
01109 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
01110 else fprintf (out, " %d", i);
01111
01112
01113
01114 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
01115 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
01116
01117
01118
01119 #define STORE LOAD
01120
01121
01122 #define STACK(OPERAND_TYPE, OPERAND_VALUE)
01123 #define UNOP(OPERAND_TYPE, OPERAND_VALUE)
01124 #define BINOP(OPERAND_TYPE, OPERAND_VALUE)
01125 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE)
01126 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE)
01127 #define RETURN(OPERAND_TYPE, OPERAND_VALUE)
01128 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE)
01129
01130
01131 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
01132 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
01133
01134
01135 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
01136 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
01137 if (OPERAND_VALUE) \
01138 { int nargs = IMMEDIATE_u1; PC++; \
01139 fprintf (out, " nargs:%d", nargs); }
01140
01141 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
01142 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
01143
01144 #define ARRAY(OPERAND_TYPE, SUBOP) \
01145 ARRAY_##SUBOP(OPERAND_TYPE)
01146
01147 #define ARRAY_LOAD(TYPE)
01148 #define ARRAY_STORE(TYPE)
01149 #define ARRAY_LENGTH(TYPE)
01150 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
01151 #define ARRAY_NEW_NUM \
01152 INT_temp = IMMEDIATE_u1; \
01153 { switch ((int) INT_temp) { \
01154 case 4: fputs (" boolean", out); break; \
01155 case 5: fputs (" char", out); break; \
01156 case 6: fputs (" float", out); break; \
01157 case 7: fputs (" double", out); break; \
01158 case 8: fputs (" byte", out); break; \
01159 case 9: fputs (" short", out); break; \
01160 case 10: fputs (" int", out); break; \
01161 case 11: fputs (" long", out); break; \
01162 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
01163 } }
01164
01165 #define ARRAY_NEW_PTR \
01166 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
01167
01168 #define ARRAY_NEW_MULTI \
01169 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
01170 fprintf (out, " %d", IMMEDIATE_u1);
01171
01172 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
01173 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
01174
01175 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
01176 saw_index = 0, INT_temp = (OPERAND_VALUE); \
01177 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
01178
01179 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
01180 saw_index = 0, INT_temp = (OPERAND_VALUE); \
01181 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
01182
01183 #undef RET
01184 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
01185 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
01186 saw_wide = 0; \
01187 fprintf (out, " %ld", (long) INT_temp);
01188
01189 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
01190 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
01191
01192 #define LOOKUP_SWITCH \
01193 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
01194 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
01195 while (--npairs >= 0) { \
01196 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
01197 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
01198 }
01199
01200 #define TABLE_SWITCH \
01201 { jint default_offset = IMMEDIATE_s4; \
01202 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
01203 fprintf (out, " low=%ld, high=%ld, default=%ld", \
01204 (long) low, (long) high, (long) default_offset+oldpc); \
01205 for (; low <= high; low++) { \
01206 jint offset = IMMEDIATE_s4; \
01207 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
01208 }
01209
01210 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
01211 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
01212
01213 #define SPECIAL_IINC(OPERAND_TYPE) \
01214 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
01215 fprintf (out, " %d", i); \
01216 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
01217 saw_wide = 0; \
01218 fprintf (out, " %d", i)
01219
01220 #define SPECIAL_WIDE(OPERAND_TYPE) \
01221 saw_wide = 1;
01222
01223 #define SPECIAL_EXIT(OPERAND_TYPE)
01224 #define SPECIAL_ENTER(OPERAND_TYPE)
01225 #define SPECIAL_BREAK(OPERAND_TYPE)
01226 #define SPECIAL_THROW(OPERAND_TYPE)
01227
01228 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
01229 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
01230
01231 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
01232 TEST(OPERAND_TYPE, OPERAND_VALUE)
01233
01234 #include "javaop.def"
01235
01236 load_store:
01237 if (oldpc+1 == PC) ;
01238 else
01239 {
01240 saw_wide = 0;
01241 fprintf (out, " %ld", (long) INT_temp);
01242 }
01243 fputc ('\n', out);
01244 break;
01245
01246 default:
01247 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
01248 }
01249 }
01250 }