1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
28 jcf-dump is a program to print out the contents of class files.
29 Usage: jcf-dump [FLAGS] CLASS
31 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
32 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
33 + The name of a .zip or .jar file (which prints all the classes in the
38 Dis-assemble each method.
42 Print nothing if there is no valid "main" method;
43 otherwise, print only the class name.
45 Print output in the style of Sun's javap program. VERY UNFINISHED.
54 #include "java-tree.h"
58 /* Name of output file, if NULL if stdout. */
59 char *output_file = NULL;
63 int flag_disassemble_methods = 0;
64 int flag_print_class_info = 1;
65 int flag_print_constant_pool = 1;
66 int flag_print_fields = 1;
67 int flag_print_methods = 1;
68 int flag_print_attributes = 1;
70 /* Print names of classes that have a "main" method. */
71 int flag_print_main = 0;
73 /* Index in constant pool of this class. */
74 int this_class_index = 0;
76 int class_access_flags = 0;
78 /* Print in format similar to javap. VERY IMCOMPLETE. */
79 int flag_javap_compatible = 0;
81 static void print_access_flags PROTO ((FILE *, uint16, char));
82 static void print_constant_terse PROTO ((FILE*, JCF*, int, int));
83 static void print_constant PROTO ((FILE *, JCF *, int, int));
84 static void print_constant_ref PROTO ((FILE *, JCF *, int));
85 static void disassemble_method PROTO ((JCF*, const unsigned char *, int));
86 static void print_name PROTO ((FILE*, JCF*, int));
87 static void print_signature PROTO ((FILE*, JCF*, int, int));
88 static int utf8_equal_string PROTO ((struct JCF*, int, const char *));
89 static int usage PROTO ((void)) ATTRIBUTE_NORETURN;
90 static void process_class PROTO ((struct JCF *));
91 static void print_constant_pool PROTO ((struct JCF *));
92 static void print_exception_table PROTO ((struct JCF *,
93 const unsigned char *entries, int));
95 #define PRINT_SIGNATURE_RESULT_ONLY 1
96 #define PRINT_SIGNATURE_ARGS_ONLY 2
99 DEFUN(utf8_equal_string, (jcf, index, value),
100 JCF *jcf AND int index AND const char * value)
102 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
103 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
105 int len = strlen (value);
106 if (JPOOL_UTF_LENGTH (jcf, index) == len
107 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
113 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
114 this_class_index = 0; \
115 if (flag_print_class_info) \
117 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
118 (long) MAGIC, (long) MINOR, (long) MAJOR)
120 #define HANDLE_START_CONSTANT_POOL(COUNT) \
121 if (flag_print_constant_pool) \
122 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
124 #define HANDLE_SOURCEFILE(INDEX) \
125 { fprintf (out, "Attribute "); \
126 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
127 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
128 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
130 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
131 this_class_index = THIS; \
132 class_access_flags = ACCESS_FLAGS; \
133 if (flag_print_class_info) \
134 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
135 print_access_flags (out, ACCESS_FLAGS, 'c'); \
137 fprintf (out, "This class: "); \
138 if (flag_print_constant_pool) \
139 fprintf (out, "%d=", THIS); \
140 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
141 if (flag_print_constant_pool || SUPER != 0) \
142 fprintf (out, ", super: "); \
143 if (flag_print_constant_pool) \
145 fprintf (out, "%d", SUPER); \
150 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
151 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
154 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
155 (flag_print_attributes <= 0)
157 #define HANDLE_CLASS_INTERFACE(INDEX) \
158 if (flag_print_class_info) \
159 { fprintf (out, "- Implements: %d=", INDEX); \
160 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
163 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
164 if (flag_print_fields) \
165 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
167 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
168 if (flag_print_fields) \
169 { fprintf (out, "Field name:"); \
170 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
171 print_access_flags (out, ACCESS_FLAGS, 'f'); \
172 fprintf (out, " Signature: "); \
173 if (flag_print_constant_pool) \
174 fprintf (out, "%d=", SIGNATURE); \
175 print_signature (out, jcf, SIGNATURE, 0); \
176 fputc ('\n', out); } \
178 flag_print_attributes--;
180 #define HANDLE_END_FIELD() \
181 if (! flag_print_fields) \
182 flag_print_attributes++;
184 #define HANDLE_START_METHODS(METHODS_COUNT) \
185 if (flag_print_methods) \
186 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
188 flag_print_attributes--;
191 #define HANDLE_END_METHODS() \
192 if (! flag_print_methods) \
193 flag_print_attributes++;
195 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
197 if (flag_print_methods) \
199 if (flag_javap_compatible) \
201 fprintf (out, " "); \
202 print_access_flags (out, ACCESS_FLAGS, 'm'); \
204 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
206 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
207 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
212 fprintf (out, "\nMethod name:"); \
213 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
214 print_access_flags (out, ACCESS_FLAGS, 'm'); \
215 fprintf (out, " Signature: "); \
216 if (flag_print_constant_pool) \
217 fprintf (out, "%d=", SIGNATURE); \
218 print_signature (out, jcf, SIGNATURE, 0); \
222 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
223 && utf8_equal_string (jcf, NAME, "main") \
224 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
225 && this_class_index > 0 \
226 && (class_access_flags & ACC_PUBLIC)) \
228 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
233 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
234 ( fprintf (out, "Attribute "), \
235 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
236 fprintf (out, ", length:%ld", (long) LENGTH) )
238 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
239 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
240 fprintf (out, ", value: "), \
241 print_constant_ref (out, jcf, VALUE_INDEX), \
242 fprintf (out, "\n") )
244 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
245 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
246 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
247 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
248 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
250 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
251 print_exception_table (jcf, ENTRIES, COUNT)
253 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
254 { int n = (COUNT); int i; \
255 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
256 fprintf (out, ", count: %d\n", n); \
257 for (i = 0; i < n; i++) {\
258 int ex_index = JCF_readu2 (jcf); \
259 fprintf (out, "%3d: ", i); \
260 print_constant_ref (out, jcf, ex_index); \
261 fputc ('\n', out); } }
263 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
264 { int n = (COUNT); int i; \
265 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
266 fprintf (out, ", count: %d\n", n); \
267 for (i = 0; i < n; i++) {\
268 int start_pc = JCF_readu2 (jcf); \
269 int length = JCF_readu2 (jcf); \
270 int name_index = JCF_readu2 (jcf); \
271 int signature_index = JCF_readu2 (jcf); \
272 int slot = JCF_readu2 (jcf); \
273 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
274 print_name (out, jcf, name_index); \
275 fprintf (out, ", type: %d=", signature_index); \
276 print_signature (out, jcf, signature_index, 0); \
277 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
279 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
280 { int n = (COUNT); int i; \
281 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
282 fprintf (out, ", count: %d\n", n); \
283 if (flag_disassemble_methods) \
284 for (i = 0; i < n; i++) {\
285 int start_pc = JCF_readu2 (jcf); \
286 int line_number = JCF_readu2 (jcf); \
287 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
289 JCF_SKIP (jcf, 4 * n); }
291 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
292 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
293 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
295 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
296 if (flag_print_attributes > 0) \
297 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
302 DEFUN(print_constant_ref, (stream, jcf, index),
303 FILE *stream AND JCF *jcf AND int index)
305 fprintf (stream, "#%d=<", index);
306 if (index <= 0 || index >= JPOOL_SIZE(jcf))
307 fprintf (stream, "out of range");
309 print_constant (stream, jcf, index, 1);
310 fprintf (stream, ">");
313 /* Print the access flags given by FLAGS.
314 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
315 or 'm' (method flags). */
318 DEFUN (print_access_flags, (stream, flags, context),
319 FILE *stream AND uint16 flags AND char context)
321 if (flags & ACC_PUBLIC) fprintf (stream, " public");
322 if (flags & ACC_PRIVATE) fprintf (stream, " private");
323 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
324 if (flags & ACC_STATIC) fprintf (stream, " static");
325 if (flags & ACC_FINAL) fprintf (stream, " final");
326 if (flags & ACC_SYNCHRONIZED)
329 fprintf (stream, " super");
331 fprintf (stream, " synchronized");
333 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
334 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
335 if (flags & ACC_NATIVE) fprintf (stream, " native");
336 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
337 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
342 DEFUN(print_name, (stream, jcf, name_index),
343 FILE* stream AND JCF* jcf AND int name_index)
345 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
346 fprintf (stream, "<not a UTF8 constant>");
348 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
349 JPOOL_UTF_LENGTH (jcf, name_index));
352 /* If the type of the constant at INDEX matches EXPECTED,
353 print it tersely, otherwise more verbosely. */
356 DEFUN(print_constant_terse, (out, jcf, index, expected),
357 FILE *out AND JCF *jcf AND int index AND int expected)
359 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
360 fprintf (out, "<constant pool index %d not in range>", index);
361 else if (JPOOL_TAG (jcf, index) != expected)
363 fprintf (out, "<Unexpected constant type ");
364 print_constant (out, jcf, index, 1);
368 print_constant (out, jcf, index, 0);
371 /* Print the constant at INDEX in JCF's constant pool.
372 If verbosity==0, print very tersely (no extraneous text).
373 If verbosity==1, prefix the type of the constant.
374 If verbosity==2, add more descriptive text. */
377 DEFUN(print_constant, (out, jcf, index, verbosity),
378 FILE *out AND JCF *jcf AND int index AND int verbosity)
383 int kind = JPOOL_TAG (jcf, index);
387 n = JPOOL_USHORT1 (jcf, index);
391 fprintf (out, "Class name: %d=", n);
393 fprintf (out, "Class ");
395 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
396 fprintf (out, "<out of range>");
397 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
399 int len = JPOOL_UTF_LENGTH (jcf, n);
400 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
403 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
405 case CONSTANT_Fieldref:
406 str = "Field"; goto field_or_method;
407 case CONSTANT_Methodref:
408 str = "Method"; goto field_or_method;
409 case CONSTANT_InterfaceMethodref:
410 str = "InterfaceMethod"; goto field_or_method;
413 uint16 tclass = JPOOL_USHORT1 (jcf, index);
414 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
416 fprintf (out, "%sref class: %d=", str, tclass);
417 else if (verbosity > 0)
418 fprintf (out, "%s ", str);
419 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
423 fprintf (out, " name_and_type: %d=<", name_and_type);
424 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
429 case CONSTANT_String:
430 j = JPOOL_USHORT1 (jcf, index);
434 fprintf (out, "String %d=", j);
436 fprintf (out, "String ");
438 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
440 case CONSTANT_Integer:
442 fprintf (out, "Integer ");
443 num = JPOOL_INT (jcf, index);
447 fprintf (out, "Long ");
448 num = JPOOL_LONG (jcf, index);
453 format_int (buffer, num, 10);
454 fprintf (out, "%s", buffer);
457 format_uint (buffer, (uint64)num, 16);
458 fprintf (out, "=0x%s", buffer);
464 jfloat fnum = JPOOL_FLOAT (jcf, index);
465 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
467 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
470 case CONSTANT_Double:
472 jdouble dnum = JPOOL_DOUBLE (jcf, index);
473 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
477 hi = JPOOL_UINT (jcf, index);
478 lo = JPOOL_UINT (jcf, index + 1);
479 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
483 case CONSTANT_NameAndType:
485 uint16 name = JPOOL_USHORT1 (jcf, index);
486 uint16 sig = JPOOL_USHORT2 (jcf, index);
490 fprintf (out, "NameAndType name: %d=", name);
492 fprintf (out, "NameAndType ");
494 print_name (out, jcf, name);
498 fprintf (out, ", signature: %d=", sig);
499 print_signature (out, jcf, sig, 0);
504 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
505 int length = JPOOL_UTF_LENGTH (jcf, index);
507 { /* Print as 8-bit bytes. */
508 fputs ("Utf8: \"", out);
509 while (--length >= 0)
510 jcf_print_char (out, *str++);
513 { /* Print as Unicode. */
515 jcf_print_utf8 (out, str, length);
521 fprintf (out, "(Unknown constant type %d)", kind);
526 DEFUN(print_constant_pool, (jcf),
530 for (i = 1; i < JPOOL_SIZE(jcf); i++)
532 int kind = JPOOL_TAG (jcf, i);
533 fprintf (out, "#%d: ", i);
534 print_constant (out, jcf, i, 2);
536 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
537 i++; /* These take up two slots in the constant table */
542 DEFUN(print_signature_type, (stream, ptr, limit),
543 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
552 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
554 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
556 print_signature_type (stream, ptr, limit);
557 if (array_size == -1)
558 fprintf (stream, "[]");
560 fprintf (stream, "[%d]", array_size);
565 fputc (*(*ptr)++, stream);
566 for (; **ptr != ')' && *ptr < limit; nargs++)
570 print_signature_type (stream, ptr, limit);
574 fputc (*(*ptr)++, stream);
575 print_signature_type (stream, ptr, limit);
578 fprintf (stream, "???");
582 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
583 case 'C': fprintf (stream, "char"); (*ptr)++; break;
584 case 'D': fprintf (stream, "double"); (*ptr)++; break;
585 case 'F': fprintf (stream, "float"); (*ptr)++; break;
586 case 'S': fprintf (stream, "short"); (*ptr)++; break;
587 case 'I': fprintf (stream, "int"); (*ptr)++; break;
588 case 'J': fprintf (stream, "long"); (*ptr)++; break;
589 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
590 case 'V': fprintf (stream, "void"); (*ptr)++; break;
593 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
594 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
599 jcf_print_char (stream, *(*ptr)++);
604 DEFUN(print_signature, (stream, jcf, signature_index, int options),
605 FILE* stream AND JCF *jcf AND int signature_index AND int options)
607 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
608 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
611 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
612 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
613 const unsigned char *limit;
614 limit = str + length;
616 fprintf (stream, "<empty signature string>");
619 if (options & PRINT_SIGNATURE_RESULT_ONLY)
621 while (str < limit && *str++ != ')') ;
623 if (options & PRINT_SIGNATURE_ARGS_ONLY)
627 while (str < limit && *str != ')')
629 print_signature_type (stream, &str, limit);
631 fputs (", ", stream);
637 print_signature_type (stream, &str, limit);
640 fprintf (stream, "<junk:");
641 jcf_print_utf8 (stream, str, limit - str);
651 DEFUN(print_exception_table, (jcf, entries, count),
652 JCF *jcf AND const unsigned char *entries AND int count)
654 /* Print exception table. */
658 const unsigned char *ptr = entries;
659 fprintf (out, "Exceptions (count: %d):\n", i);
660 for (; --i >= 0; ptr+= 8)
662 int start_pc = GET_u2 (ptr);
663 int end_pc = GET_u2 (ptr+2);
664 int handler_pc = GET_u2 (ptr+4);
665 int catch_type = GET_u2 (ptr+6);
666 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
667 start_pc, end_pc, handler_pc, catch_type);
669 fputs (" /* finally */", out);
673 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
680 #include "jcf-reader.c"
685 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
690 DEFUN(process_class, (jcf),
694 if (jcf_parse_preamble (jcf) != 0)
695 fprintf (stderr, "Not a valid Java .class file.\n");
697 /* Parse and possibly print constant pool */
698 code = jcf_parse_constant_pool (jcf);
701 fprintf (stderr, "error while parsing constant pool\n");
702 exit (FATAL_EXIT_CODE);
704 code = verify_constant_pool (jcf);
707 fprintf (stderr, "error in constant pool entry #%d\n", code);
708 exit (FATAL_EXIT_CODE);
710 if (flag_print_constant_pool)
711 print_constant_pool (jcf);
713 jcf_parse_class (jcf);
714 code = jcf_parse_fields (jcf);
717 fprintf (stderr, "error while parsing fields\n");
718 exit (FATAL_EXIT_CODE);
720 code = jcf_parse_methods (jcf);
723 fprintf (stderr, "error while parsing methods\n");
724 exit (FATAL_EXIT_CODE);
726 code = jcf_parse_final_attributes (jcf);
729 fprintf (stderr, "error while parsing final attributes\n");
730 exit (FATAL_EXIT_CODE);
732 jcf->filename = NULL;
736 DEFUN(main, (argc, argv),
737 int argc AND char** argv)
746 for (argi = 1; argi < argc; argi++)
748 const char *arg = argv[argi];
750 if (arg[0] != '-' || ! strcmp (arg, "--"))
753 /* Just let all arguments be given in either "-" or "--" form. */
757 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
758 output_file = argv[++argi];
759 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
760 jcf_path_classpath_arg (argv[++argi]);
761 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
762 jcf_path_CLASSPATH_arg (argv[++argi]);
763 else if (strncmp (arg, "-I", 2) == 0)
764 jcf_path_include_arg (arg + 2);
765 else if (strcmp (arg, "-verbose") == 0)
767 else if (strcmp (arg, "-print-main") == 0)
769 else if (strcmp (arg, "-c") == 0)
770 flag_disassemble_methods++;
771 else if (strcmp (arg, "-javap") == 0)
773 flag_javap_compatible++;
774 flag_print_constant_pool = 0;
778 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
779 return FATAL_EXIT_CODE;
790 flag_print_fields = 0;
791 flag_print_methods = 0;
792 flag_print_constant_pool = 0;
793 flag_print_attributes = 0;
794 flag_print_class_info = 0;
799 out = fopen (output_file, "w");
802 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
803 return FATAL_EXIT_CODE;
811 fprintf (out, "Reading .class from <standard input>.\n");
813 open_class ("<stdio>", jcf, stdin, NULL);
815 open_class ("<stdio>", jcf, 0, NULL);
821 for (; argi < argc; argi++)
823 char *arg = argv[argi];
824 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
825 if (class_filename == NULL)
826 class_filename = find_classfile (arg, jcf, NULL);
827 if (class_filename == NULL)
829 perror ("Could not find class");
830 return FATAL_EXIT_CODE;
833 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
835 long compressed_size, member_size;
836 int compression_method, filename_length, extra_length;
837 int general_purpose_bits;
838 const char *filename;
840 if (flag_print_class_info)
841 fprintf (out, "Reading classes from archive %s.\n",
846 jcf_filbuf_t save_filbuf = jcf->filbuf;
847 long magic = JCF_readu4_le (jcf);
848 if (magic == 0x02014b50 || magic == 0x06054b50)
849 break; /* got to central directory */
850 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
852 fprintf (stderr, "bad format of .zip/.jar archive\n");
853 return FATAL_EXIT_CODE;
857 general_purpose_bits = JCF_readu2_le (jcf);
858 compression_method = JCF_readu2_le (jcf);
860 compressed_size = JCF_readu4_le (jcf);
861 member_size = JCF_readu4_le (jcf);
862 filename_length = JCF_readu2_le (jcf);
863 extra_length = JCF_readu2_le (jcf);
864 total_length = filename_length + extra_length
866 if (jcf->read_end - jcf->read_ptr < total_length)
867 jcf_trim_old_input (jcf);
868 JCF_FILL (jcf, total_length);
869 filename = jcf->read_ptr;
870 JCF_SKIP (jcf, filename_length);
871 JCF_SKIP (jcf, extra_length);
872 if (filename_length > 0
873 && filename[filename_length-1] == '/')
875 if (flag_print_class_info)
876 fprintf (out, "[Skipping directory %.*s]\n",
877 filename_length, filename);
880 else if (compression_method != 0)
882 if (flag_print_class_info)
883 fprintf (out, "[Skipping compressed file %.*s]\n",
884 filename_length, filename);
887 else if (member_size < 4
888 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
890 if (flag_print_class_info)
891 fprintf (out, "[Skipping non-.class member %.*s]\n",
892 filename_length, filename);
897 if (flag_print_class_info)
898 fprintf (out, "Reading class member: %.*s.\n",
899 filename_length, filename);
903 JCF_SKIP (jcf, compressed_size);
907 unsigned char *save_end;
908 jcf->filbuf = jcf_unexpected_eof;
909 save_end = jcf->read_end;
910 jcf->read_end = jcf->read_ptr + compressed_size;
912 jcf->filbuf = save_filbuf;
913 jcf->read_end = save_end;
919 if (flag_print_class_info)
920 fprintf (out, "Reading .class from %s.\n", class_filename);
927 return SUCCESS_EXIT_CODE;
931 DEFUN(disassemble_method, (jcf, byte_ops, len),
932 JCF* jcf AND const unsigned char *byte_ops AND int len)
934 #undef AND /* Causes problems with opcodes for iand and land. */
939 if (flag_disassemble_methods == 0)
941 #define BCODE byte_ops
942 for (PC = 0; PC < len;)
947 switch (byte_ops[PC++])
950 /* This is the actual code emitted for each of opcodes in javaops.def.
951 The actual opcode-specific stuff is handled by the OPKIND macro.
952 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
953 Those macros are defiend below. The OPKINDs that do not have any
954 inline parameters (such as BINOP) and therefore do mot need anything
955 else to me printed out just use an empty body. */
957 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
959 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
960 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
964 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
965 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
966 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
967 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
969 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
970 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
972 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
973 These all push a constant onto the opcode stack. */
974 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
975 saw_index = 0, i = (OPERAND_VALUE); \
976 if (oldpc+1 == PC) /* nothing */; \
977 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
978 else fprintf (out, " %d", i);
980 /* Print out operand (a local variable index) for LOAD opcodes.
981 These all push local variable onto the opcode stack. */
982 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
983 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
985 /* Handle STORE opcodes same as LOAD opcodes.
986 These all store a value from the opcode stack in a local variable. */
989 /* Handle more kind of opcodes. */
990 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
991 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
992 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
993 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
994 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
995 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
996 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
998 /* Handle putfield and getfield opcodes, with static versions. */
999 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1000 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1002 /* Print operand for invoke opcodes. */
1003 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1004 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1005 if (OPERAND_VALUE) /* for invokeinterface */ \
1006 { int nargs = IMMEDIATE_u1; PC++; \
1007 fprintf (out, " nargs:%d", nargs); }
1009 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1010 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1012 #define ARRAY(OPERAND_TYPE, SUBOP) \
1013 ARRAY_##SUBOP(OPERAND_TYPE)
1014 /* Handle sub-categories of ARRAY opcodes. */
1015 #define ARRAY_LOAD(TYPE) /* nothing */
1016 #define ARRAY_STORE(TYPE) /* nothing */
1017 #define ARRAY_LENGTH(TYPE) /* nothing */
1018 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1019 #define ARRAY_NEW_NUM \
1020 INT_temp = IMMEDIATE_u1; \
1021 { switch ((int) INT_temp) { \
1022 case 4: fputs (" boolean", out); break; \
1023 case 5: fputs (" char", out); break; \
1024 case 6: fputs (" float", out); break; \
1025 case 7: fputs (" double", out); break; \
1026 case 8: fputs (" byte", out); break; \
1027 case 9: fputs (" short", out); break; \
1028 case 10: fputs (" int", out); break; \
1029 case 11: fputs (" long", out); break; \
1030 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1033 #define ARRAY_NEW_PTR \
1034 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1036 #define ARRAY_NEW_MULTI \
1037 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1038 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1040 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1041 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1043 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1044 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1045 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1047 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1048 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1049 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1051 #undef RET /* Defined by config/i386/i386.h */
1052 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1053 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1055 fprintf (out, " %ld", (long) INT_temp);
1057 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1058 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1060 #define LOOKUP_SWITCH \
1061 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1062 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1063 while (--npairs >= 0) { \
1064 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1065 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1068 #define TABLE_SWITCH \
1069 { jint default_offset = IMMEDIATE_s4; \
1070 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1071 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1072 (long) low, (long) high, (long) default_offset+oldpc); \
1073 for (; low <= high; low++) { \
1074 jint offset = IMMEDIATE_s4; \
1075 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1078 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1079 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1081 #define SPECIAL_IINC(OPERAND_TYPE) \
1082 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1083 fprintf (out, " %d", i); \
1084 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1086 fprintf (out, " %d", i)
1088 #define SPECIAL_WIDE(OPERAND_TYPE) \
1091 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1092 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1093 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1094 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1096 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1097 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1099 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1100 TEST(OPERAND_TYPE, OPERAND_VALUE)
1102 #include "javaop.def"
1105 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1109 fprintf (out, " %ld", (long) INT_temp);
1115 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);