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 int 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*, 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));
90 static void process_class PROTO ((struct JCF *));
92 #define PRINT_SIGNATURE_RESULT_ONLY 1
93 #define PRINT_SIGNATURE_ARGS_ONLY 2
96 DEFUN(utf8_equal_string, (jcf, index, value),
97 JCF *jcf AND int index AND const char * value)
99 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
100 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
102 int len = strlen (value);
103 if (JPOOL_UTF_LENGTH (jcf, index) == len
104 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
110 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
111 this_class_index = 0; \
112 if (flag_print_class_info) \
114 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
115 (long) MAGIC, (long) MINOR, (long) MAJOR)
117 #define HANDLE_START_CONSTANT_POOL(COUNT) \
118 if (flag_print_constant_pool) \
119 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
121 #define HANDLE_SOURCEFILE(INDEX) \
122 { fprintf (out, "Attribute "); \
123 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
124 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
125 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
127 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
128 this_class_index = THIS; \
129 class_access_flags = ACCESS_FLAGS; \
130 if (flag_print_class_info) \
131 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
132 print_access_flags (out, ACCESS_FLAGS, 'c'); \
134 fprintf (out, "This class: "); \
135 if (flag_print_constant_pool) \
136 fprintf (out, "%d=", THIS); \
137 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
138 if (flag_print_constant_pool || SUPER != 0) \
139 fprintf (out, ", super: "); \
140 if (flag_print_constant_pool) \
142 fprintf (out, "%d", SUPER); \
147 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
148 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
151 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
152 (flag_print_attributes <= 0)
154 #define HANDLE_CLASS_INTERFACE(INDEX) \
155 if (flag_print_class_info) \
156 { fprintf (out, "- Implements: %d=", INDEX); \
157 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
160 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
161 if (flag_print_fields) \
162 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
164 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
165 if (flag_print_fields) \
166 { fprintf (out, "Field name:"); \
167 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
168 print_access_flags (out, ACCESS_FLAGS, 'f'); \
169 fprintf (out, " Signature: "); \
170 if (flag_print_constant_pool) \
171 fprintf (out, "%d=", SIGNATURE); \
172 print_signature (out, jcf, SIGNATURE, 0); \
173 fputc ('\n', out); } \
175 flag_print_attributes--;
177 #define HANDLE_END_FIELD() \
178 if (! flag_print_fields) \
179 flag_print_attributes++;
181 #define HANDLE_START_METHODS(METHODS_COUNT) \
182 if (flag_print_methods) \
183 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
185 flag_print_attributes--;
188 #define HANDLE_END_METHODS() \
189 if (! flag_print_methods) \
190 flag_print_attributes++;
192 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
194 if (flag_print_methods) \
196 if (flag_javap_compatible) \
198 fprintf (out, " "); \
199 print_access_flags (out, ACCESS_FLAGS, 'm'); \
201 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
203 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
204 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
209 fprintf (out, "\nMethod name:"); \
210 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
211 print_access_flags (out, ACCESS_FLAGS, 'm'); \
212 fprintf (out, " Signature: "); \
213 if (flag_print_constant_pool) \
214 fprintf (out, "%d=", SIGNATURE); \
215 print_signature (out, jcf, SIGNATURE, 0); \
219 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
220 && utf8_equal_string (jcf, NAME, "main") \
221 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
222 && this_class_index > 0 \
223 && (class_access_flags & ACC_PUBLIC)) \
225 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
230 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
231 ( fprintf (out, "Attribute "), \
232 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
233 fprintf (out, ", length:%ld", (long) LENGTH) )
235 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
236 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
237 fprintf (out, ", value: "), \
238 print_constant_ref (out, jcf, VALUE_INDEX), \
239 fprintf (out, "\n") )
241 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
242 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
243 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
244 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
245 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
247 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
248 print_exception_table (jcf, ENTRIES, COUNT)
250 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
251 { int n = (COUNT); int i; \
252 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
253 fprintf (out, ", count: %d\n", n); \
254 for (i = 0; i < n; i++) {\
255 int ex_index = JCF_readu2 (jcf); \
256 fprintf (out, "%3d: ", i); \
257 print_constant_ref (out, jcf, ex_index); \
258 fputc ('\n', out); } }
260 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
261 { int n = (COUNT); int i; \
262 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
263 fprintf (out, ", count: %d\n", n); \
264 for (i = 0; i < n; i++) {\
265 int start_pc = JCF_readu2 (jcf); \
266 int length = JCF_readu2 (jcf); \
267 int name_index = JCF_readu2 (jcf); \
268 int signature_index = JCF_readu2 (jcf); \
269 int slot = JCF_readu2 (jcf); \
270 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
271 print_name (out, jcf, name_index); \
272 fprintf (out, ", type: %d=", signature_index); \
273 print_signature (out, jcf, signature_index, 0); \
274 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
276 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
277 { int n = (COUNT); int i; \
278 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
279 fprintf (out, ", count: %d\n", n); \
280 if (flag_disassemble_methods) \
281 for (i = 0; i < n; i++) {\
282 int start_pc = JCF_readu2 (jcf); \
283 int line_number = JCF_readu2 (jcf); \
284 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
286 JCF_SKIP (jcf, 4 * n); }
288 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
289 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
290 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
292 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
293 if (flag_print_attributes > 0) \
294 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
299 DEFUN(print_constant_ref, (stream, jcf, index),
300 FILE *stream AND JCF *jcf AND int index)
302 fprintf (stream, "#%d=<", index);
303 if (index <= 0 || index >= JPOOL_SIZE(jcf))
304 fprintf (stream, "out of range");
306 print_constant (stream, jcf, index, 1);
307 fprintf (stream, ">");
310 /* Print the access flags given by FLAGS.
311 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
312 or 'm' (method flags). */
315 DEFUN (print_access_flags, (stream, flags, context),
316 FILE *stream AND uint16 flags AND char context)
318 if (flags & ACC_PUBLIC) fprintf (stream, " public");
319 if (flags & ACC_PRIVATE) fprintf (stream, " private");
320 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
321 if (flags & ACC_STATIC) fprintf (stream, " static");
322 if (flags & ACC_FINAL) fprintf (stream, " final");
323 if (flags & ACC_SYNCHRONIZED)
325 fprintf (stream, " super");
327 fprintf (stream, " synchronized");
328 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
329 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
330 if (flags & ACC_NATIVE) fprintf (stream, " native");
331 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
332 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
337 DEFUN(print_name, (stream, jcf, name_index),
338 FILE* stream AND JCF* jcf AND int name_index)
340 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
341 fprintf (stream, "<not a UTF8 constant>");
343 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
344 JPOOL_UTF_LENGTH (jcf, name_index));
347 /* If the type of the constant at INDEX matches EXPECTED,
348 print it tersely, otherwise more verbosely. */
351 DEFUN(print_constant_terse, (out, jcf, index, expected),
352 FILE *out AND JCF *jcf AND int index AND int expected)
354 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
355 fprintf (out, "<constant pool index %d not in range>", index);
356 else if (JPOOL_TAG (jcf, index) != expected)
358 fprintf (out, "<Unexpected constant type ");
359 print_constant (out, jcf, index, 1);
363 print_constant (out, jcf, index, 0);
366 /* Print the constant at INDEX in JCF's constant pool.
367 If verbosity==0, print very tersely (no extraneous text).
368 If verbosity==1, prefix the type of the constant.
369 If verbosity==2, add more descriptive text. */
372 DEFUN(print_constant, (out, jcf, index, verbosity),
373 FILE *out AND JCF *jcf AND int index AND int verbosity)
378 int kind = JPOOL_TAG (jcf, index);
382 n = JPOOL_USHORT1 (jcf, index);
384 fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n);
385 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
386 fprintf (out, "<out of range>");
387 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
389 int len = JPOOL_UTF_LENGTH (jcf, n);
390 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
393 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
395 case CONSTANT_Fieldref:
396 str = "Field"; goto field_or_method;
397 case CONSTANT_Methodref:
398 str = "Method"; goto field_or_method;
399 case CONSTANT_InterfaceMethodref:
400 str = "InterfaceMethod"; goto field_or_method;
403 uint16 tclass = JPOOL_USHORT1 (jcf, index);
404 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
406 fprintf (out, "%sref class: %d=", str, tclass);
407 else if (verbosity > 0)
408 fprintf (out, "%s ", str);
409 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
410 fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<",
412 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
417 case CONSTANT_String:
418 j = JPOOL_USHORT1 (jcf, index);
420 fprintf (out, verbosity > 1 ? "String %d=" : "String ", j);
421 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
423 case CONSTANT_Integer:
425 fprintf (out, "Integer ");
426 num = JPOOL_INT (jcf, index);
430 fprintf (out, "Long ");
431 num = JPOOL_LONG (jcf, index);
436 format_int (buffer, num, 10);
437 fprintf (out, "%s", buffer);
440 format_uint (buffer, (uint64)num, 16);
441 fprintf (out, "=0x%s", buffer);
447 jfloat fnum = JPOOL_FLOAT (jcf, index);
448 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
450 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
453 case CONSTANT_Double:
455 jdouble dnum = JPOOL_DOUBLE (jcf, index);
456 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
460 hi = JPOOL_UINT (jcf, index);
461 lo = JPOOL_UINT (jcf, index + 1);
462 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
466 case CONSTANT_NameAndType:
468 uint16 name = JPOOL_USHORT1 (jcf, index);
469 uint16 sig = JPOOL_USHORT2 (jcf, index);
471 fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ",
472 "NameAndType", name);
473 print_name (out, jcf, name);
477 fprintf (out, ", signature: %d=", sig);
478 print_signature (out, jcf, sig, 0);
483 register unsigned char *str = JPOOL_UTF_DATA (jcf, index);
484 int length = JPOOL_UTF_LENGTH (jcf, index);
486 { /* Print as 8-bit bytes. */
487 fputs ("Utf8: \"", out);
488 while (--length >= 0)
489 jcf_print_char (out, *str++);
492 { /* Print as Unicode. */
494 jcf_print_utf8 (out, str, length);
500 fprintf (out, "(Unknown constant type %d)", kind);
505 DEFUN(print_constant_pool, (jcf),
509 for (i = 1; i < JPOOL_SIZE(jcf); i++)
511 int kind = JPOOL_TAG (jcf, i);
512 fprintf (out, "#%d: ", i);
513 print_constant (out, jcf, i, 2);
515 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
516 i++; /* These take up two slots in the constant table */
521 DEFUN(print_signature_type, (stream, ptr, limit),
522 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
531 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
533 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
535 print_signature_type (stream, ptr, limit);
536 if (array_size == -1)
537 fprintf (stream, "[]");
539 fprintf (stream, "[%d]", array_size);
544 fputc (*(*ptr)++, stream);
545 for (; **ptr != ')' && *ptr < limit; nargs++)
549 print_signature_type (stream, ptr, limit);
553 fputc (*(*ptr)++, stream);
554 print_signature_type (stream, ptr, limit);
557 fprintf (stream, "???");
561 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
562 case 'C': fprintf (stream, "char"); (*ptr)++; break;
563 case 'D': fprintf (stream, "double"); (*ptr)++; break;
564 case 'F': fprintf (stream, "float"); (*ptr)++; break;
565 case 'S': fprintf (stream, "short"); (*ptr)++; break;
566 case 'I': fprintf (stream, "int"); (*ptr)++; break;
567 case 'J': fprintf (stream, "long"); (*ptr)++; break;
568 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
569 case 'V': fprintf (stream, "void"); (*ptr)++; break;
572 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
573 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
578 jcf_print_char (stream, *(*ptr)++);
583 DEFUN(print_signature, (stream, jcf, signature_index, int options),
584 FILE* stream AND JCF *jcf AND int signature_index AND int options)
586 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
587 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
590 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
591 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
592 const unsigned char *limit;
593 limit = str + length;
595 fprintf (stream, "<empty signature string>");
598 if (options & PRINT_SIGNATURE_RESULT_ONLY)
600 while (str < limit && *str++ != ')') ;
602 if (options & PRINT_SIGNATURE_ARGS_ONLY)
606 while (str < limit && *str != ')')
608 print_signature_type (stream, &str, limit);
610 fputs (", ", stream);
616 print_signature_type (stream, &str, limit);
619 fprintf (stream, "<junk:");
620 jcf_print_utf8 (stream, str, limit - str);
630 DEFUN(print_exception_table, (jcf, entries, count),
631 JCF *jcf AND unsigned char *entries AND int count)
633 /* Print exception table. */
637 unsigned char *ptr = entries;
638 fprintf (out, "Exceptions (count: %d):\n", i);
639 for (; --i >= 0; ptr+= 8)
641 int start_pc = GET_u2 (ptr);
642 int end_pc = GET_u2 (ptr+2);
643 int handler_pc = GET_u2 (ptr+4);
644 int catch_type = GET_u2 (ptr+6);
645 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
646 start_pc, end_pc, handler_pc, catch_type);
648 fputs (" /* finally */", out);
652 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
659 #include "jcf-reader.c"
664 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
669 DEFUN(process_class, (jcf),
673 if (jcf_parse_preamble (jcf) != 0)
674 fprintf (stderr, "Not a valid Java .class file.\n");
676 /* Parse and possibly print constant pool */
677 code = jcf_parse_constant_pool (jcf);
680 fprintf (stderr, "error while parsing constant pool\n");
681 exit (FATAL_EXIT_CODE);
683 code = verify_constant_pool (jcf);
686 fprintf (stderr, "error in constant pool entry #%d\n", code);
687 exit (FATAL_EXIT_CODE);
689 if (flag_print_constant_pool)
690 print_constant_pool (jcf);
692 jcf_parse_class (jcf);
693 code = jcf_parse_fields (jcf);
696 fprintf (stderr, "error while parsing fields\n");
697 exit (FATAL_EXIT_CODE);
699 code = jcf_parse_methods (jcf);
702 fprintf (stderr, "error while parsing methods\n");
703 exit (FATAL_EXIT_CODE);
705 code = jcf_parse_final_attributes (jcf);
708 fprintf (stderr, "error while parsing final attributes\n");
709 exit (FATAL_EXIT_CODE);
711 jcf->filename = NULL;
715 DEFUN(main, (argc, argv),
716 int argc AND char** argv)
725 for (argi = 1; argi < argc; argi++)
727 char *arg = argv[argi];
729 if (arg[0] != '-' || ! strcmp (arg, "--"))
732 /* Just let all arguments be given in either "-" or "--" form. */
736 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
737 output_file = argv[++argi];
738 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
739 jcf_path_classpath_arg (argv[++argi]);
740 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
741 jcf_path_CLASSPATH_arg (argv[++argi]);
742 else if (strncmp (arg, "-I", 2) == 0)
743 jcf_path_include_arg (arg + 2);
744 else if (strcmp (arg, "-verbose") == 0)
746 else if (strcmp (arg, "-print-main") == 0)
748 else if (strcmp (arg, "-c") == 0)
749 flag_disassemble_methods++;
750 else if (strcmp (arg, "-javap") == 0)
752 flag_javap_compatible++;
753 flag_print_constant_pool = 0;
757 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
758 exit (FATAL_EXIT_CODE);
769 flag_print_fields = 0;
770 flag_print_methods = 0;
771 flag_print_constant_pool = 0;
772 flag_print_attributes = 0;
773 flag_print_class_info = 0;
778 out = fopen (output_file, "w");
781 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
782 exit (FATAL_EXIT_CODE);
790 fprintf (out, "Reading .class from <standard input>.\n");
792 open_class ("<stdio>", jcf, stdin, NULL);
794 open_class ("<stdio>", jcf, 0, NULL);
800 for (; argi < argc; argi++)
802 char *arg = argv[argi];
803 char* class_filename = find_class (arg, strlen (arg), jcf, 0);
804 if (class_filename == NULL)
805 class_filename = find_classfile (arg, jcf, NULL);
806 if (class_filename == NULL)
808 perror ("Could not find class");
809 exit (FATAL_EXIT_CODE);
812 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
814 long compressed_size, member_size;
815 int compression_method, filename_length, extra_length;
816 int general_purpose_bits;
819 if (flag_print_class_info)
820 fprintf (out, "Reading classes from archive %s.\n",
825 jcf_filbuf_t save_filbuf = jcf->filbuf;
826 long magic = JCF_readu4_le (jcf);
827 if (magic == 0x02014b50 || magic == 0x06054b50)
828 break; /* got to central directory */
829 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
831 fprintf (stderr, "bad format of .zip/.jar archive\n");
832 exit (FATAL_EXIT_CODE);
836 general_purpose_bits = JCF_readu2_le (jcf);
837 compression_method = JCF_readu2_le (jcf);
839 compressed_size = JCF_readu4_le (jcf);
840 member_size = JCF_readu4_le (jcf);
841 filename_length = JCF_readu2_le (jcf);
842 extra_length = JCF_readu2_le (jcf);
843 total_length = filename_length + extra_length
845 if (jcf->read_end - jcf->read_ptr < total_length)
846 jcf_trim_old_input (jcf);
847 JCF_FILL (jcf, total_length);
848 filename = jcf->read_ptr;
849 JCF_SKIP (jcf, filename_length);
850 JCF_SKIP (jcf, extra_length);
851 if (filename_length > 0
852 && filename[filename_length-1] == '/')
854 if (flag_print_class_info)
855 fprintf (out, "[Skipping directory %.*s]\n",
856 filename_length, filename);
859 else if (compression_method != 0)
861 if (flag_print_class_info)
862 fprintf (out, "[Skipping compressed file %.*s]\n",
863 filename_length, filename);
866 else if (member_size < 4
867 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
869 if (flag_print_class_info)
870 fprintf (out, "[Skipping non-.class member %.*s]\n",
871 filename_length, filename);
876 if (flag_print_class_info)
877 fprintf (out, "Reading class member: %.*s.\n",
878 filename_length, filename);
882 JCF_SKIP (jcf, compressed_size);
886 unsigned char *save_end;
887 jcf->filbuf = jcf_unexpected_eof;
888 save_end = jcf->read_end;
889 jcf->read_end = jcf->read_ptr + compressed_size;
891 jcf->filbuf = save_filbuf;
892 jcf->read_end = save_end;
898 if (flag_print_class_info)
899 fprintf (out, "Reading .class from %s.\n", class_filename);
906 exit (SUCCESS_EXIT_CODE);
910 DEFUN(disassemble_method, (jcf, byte_ops, len),
911 JCF* jcf AND unsigned char *byte_ops AND int len)
913 #undef AND /* Causes problems with opcodes for iand and land. */
918 if (flag_disassemble_methods == 0)
920 #define BCODE byte_ops
921 for (PC = 0; PC < len;)
926 switch (byte_ops[PC++])
929 /* This is the actual code emitted for each of opcodes in javaops.def.
930 The actual opcode-specific stuff is handled by the OPKIND macro.
931 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
932 Those macros are defiend below. The OPKINDs that do not have any
933 inline parameters (such as BINOP) and therefore do mot need anything
934 else to me printed out just use an empty body. */
936 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
938 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
939 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
943 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
944 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
945 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
946 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
948 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
949 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
951 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
952 These all push a constant onto the opcode stack. */
953 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
954 saw_index = 0, i = (OPERAND_VALUE); \
955 if (oldpc+1 == PC) /* nothing */; \
956 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
957 else fprintf (out, " %d", i);
959 /* Print out operand (a local variable index) for LOAD opcodes.
960 These all push local variable onto the opcode stack. */
961 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
962 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
964 /* Handle STORE opcodes same as LOAD opcodes.
965 These all store a value from the opcode stack in a local variable. */
968 /* Handle more kind of opcodes. */
969 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
970 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
971 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
972 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
973 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
974 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
975 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
977 /* Handle putfield and getfield opcodes, with static versions. */
978 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
979 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
981 /* Print operand for invoke opcodes. */
982 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
983 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
984 if (OPERAND_VALUE) /* for invokeinterface */ \
985 { int nargs = IMMEDIATE_u1; PC++; \
986 fprintf (out, " nargs:%d", nargs); }
988 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
989 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
991 #define ARRAY(OPERAND_TYPE, SUBOP) \
992 ARRAY_##SUBOP(OPERAND_TYPE)
993 /* Handle sub-categories of ARRAY opcodes. */
994 #define ARRAY_LOAD(TYPE) /* nothing */
995 #define ARRAY_STORE(TYPE) /* nothing */
996 #define ARRAY_LENGTH(TYPE) /* nothing */
997 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
998 #define ARRAY_NEW_NUM \
999 INT_temp = IMMEDIATE_u1; \
1001 switch (INT_temp) { \
1002 case 4: str = "boolean"; break; \
1003 case 5: str = "char"; break; \
1004 case 6: str = "float"; break; \
1005 case 7: str = "double"; break; \
1006 case 8: str = "byte"; break; \
1007 case 9: str = "short"; break; \
1008 case 10: str = "int"; break; \
1009 case 11: str = "long"; break; \
1010 default: str = "<unknown type code %d>"; break; \
1012 fputc (' ', out); fprintf (out, str, INT_temp); }
1014 #define ARRAY_NEW_PTR \
1015 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1017 #define ARRAY_NEW_MULTI \
1018 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1019 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1021 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1022 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1024 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1025 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1026 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1028 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1029 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1030 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1032 #undef RET /* Defined by config/i386/i386.h */
1033 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1034 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1036 fprintf (out, " %ld", (long) INT_temp);
1038 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1039 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1041 #define LOOKUP_SWITCH \
1042 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1043 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1044 while (--npairs >= 0) { \
1045 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1046 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1049 #define TABLE_SWITCH \
1050 { jint default_offset = IMMEDIATE_s4; \
1051 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1052 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1053 (long) low, (long) high, (long) default_offset+oldpc); \
1054 for (; low <= high; low++) { \
1055 jint offset = IMMEDIATE_s4; \
1056 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1059 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1060 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1062 #define SPECIAL_IINC(OPERAND_TYPE) \
1063 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1064 fprintf (out, " %d", i); \
1065 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1067 fprintf (out, " %d", i)
1069 #define SPECIAL_WIDE(OPERAND_TYPE) \
1072 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1073 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1074 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1075 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1077 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1078 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1080 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1081 TEST(OPERAND_TYPE, OPERAND_VALUE)
1083 #include "javaop.def"
1086 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1090 fprintf (out, " %ld", (long) INT_temp);
1096 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);