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.
57 /* Name of output file, if NULL if stdout. */
58 char *output_file = NULL;
62 int flag_disassemble_methods = 0;
63 int flag_print_class_info = 1;
64 int flag_print_constant_pool = 1;
65 int flag_print_fields = 1;
66 int flag_print_methods = 1;
67 int flag_print_attributes = 1;
69 /* Print names of classes that have a "main" method. */
70 int flag_print_main = 0;
72 /* Index in constant pool of this class. */
73 int this_class_index = 0;
75 int class_access_flags = 0;
77 /* Print in format similar to javap. VERY IMCOMPLETE. */
78 int flag_javap_compatible = 0;
80 static int print_access_flags PROTO ((FILE *, uint16));
81 static void print_constant_terse PROTO ((FILE*, JCF*, int, int));
82 static void print_constant PROTO ((FILE *, JCF *, int, int));
83 static void print_constant_ref PROTO ((FILE *, JCF *, int));
84 static void disassemble_method PROTO ((JCF*, unsigned char *, int));
85 static void print_name PROTO ((FILE*, JCF*, int));
86 static void print_signature PROTO ((FILE*, JCF*, int, int));
88 #define PRINT_SIGNATURE_RESULT_ONLY 1
89 #define PRINT_SIGNATURE_ARGS_ONLY 2
91 extern char* open_class();
94 DEFUN(utf8_equal_string, (jcf, index, value),
95 JCF *jcf AND int index AND char * value)
97 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
98 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
100 int len = strlen (value);
101 if (JPOOL_UTF_LENGTH (jcf, index) == len
102 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
108 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
109 this_class_index = 0; \
110 if (flag_print_class_info) \
112 "Magic number: 0x%0x, minor_version: %d, major_version: %d.\n", \
115 #define HANDLE_START_CONSTANT_POOL(COUNT) \
116 if (flag_print_constant_pool) \
117 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
119 #define HANDLE_SOURCEFILE(INDEX) \
120 { fprintf (out, "Attribute "); \
121 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
122 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
123 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
125 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
126 this_class_index = THIS; \
127 class_access_flags = ACCESS_FLAGS; \
128 if (flag_print_class_info) \
129 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
130 print_access_flags (out, ACCESS_FLAGS); \
132 fprintf (out, "This class: "); \
133 if (flag_print_constant_pool) \
134 fprintf (out, "%d=", THIS); \
135 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
136 if (flag_print_constant_pool || SUPER != 0) \
137 fprintf (out, ", super: "); \
138 if (flag_print_constant_pool) \
140 fprintf (out, "%d", SUPER); \
145 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
146 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
149 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
150 (flag_print_attributes <= 0)
152 #define HANDLE_CLASS_INTERFACE(INDEX) \
153 if (flag_print_class_info) \
154 { fprintf (out, "- Implements: %d=", INDEX); \
155 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
158 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
159 if (flag_print_fields) \
160 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
162 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
163 if (flag_print_fields) \
164 { fprintf (out, "Field name:"); \
165 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
166 print_access_flags (out, ACCESS_FLAGS); \
167 fprintf (out, " Signature: "); \
168 if (flag_print_constant_pool) \
169 fprintf (out, "%d=", SIGNATURE); \
170 print_signature (out, jcf, SIGNATURE, 0); \
171 fputc ('\n', out); } \
173 flag_print_attributes--;
175 #define HANDLE_END_FIELD() \
176 if (! flag_print_fields) \
177 flag_print_attributes++;
179 #define HANDLE_START_METHODS(METHODS_COUNT) \
180 if (flag_print_methods) \
181 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
183 flag_print_attributes--;
186 #define HANDLE_END_METHODS() \
187 if (! flag_print_methods) \
188 flag_print_attributes++;
190 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
192 if (flag_print_methods) \
194 if (flag_javap_compatible) \
196 fprintf (out, " "); \
197 print_access_flags (out, ACCESS_FLAGS); \
199 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
201 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
202 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
207 fprintf (out, "\nMethod name:"); \
208 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
209 print_access_flags (out, ACCESS_FLAGS); \
210 fprintf (out, " Signature: "); \
211 if (flag_print_constant_pool) \
212 fprintf (out, "%d=", SIGNATURE); \
213 print_signature (out, jcf, SIGNATURE, 0); \
217 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
218 && utf8_equal_string (jcf, NAME, "main") \
219 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
220 && this_class_index > 0 \
221 && (class_access_flags & ACC_PUBLIC)) \
223 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
228 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
229 ( fprintf (out, "Attribute "), \
230 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
231 fprintf (out, ", length:%ld", (long) LENGTH) )
233 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
234 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
235 fprintf (out, ", value: "), \
236 print_constant_ref (out, jcf, VALUE_INDEX), \
237 fprintf (out, "\n") )
239 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
240 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
241 fprintf (out, ", max_stack:%d, max_locals:%d, code_length:%d\n", \
242 MAX_STACK, MAX_LOCALS, CODE_LENGTH); \
243 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
245 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
246 print_exception_table (jcf, ENTRIES, COUNT)
248 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
249 { int n = (COUNT); int i; \
250 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
251 fprintf (out, ", count: %d\n", n); \
252 for (i = 0; i < n; i++) {\
253 int ex_index = JCF_readu2 (jcf); \
254 fprintf (out, "%3d: ", i); \
255 print_constant_ref (out, jcf, ex_index); \
256 fputc ('\n', out); } }
258 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
259 { int n = (COUNT); int i; \
260 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
261 fprintf (out, ", count: %d\n", n); \
262 for (i = 0; i < n; i++) {\
263 int start_pc = JCF_readu2 (jcf); \
264 int length = JCF_readu2 (jcf); \
265 int name_index = JCF_readu2 (jcf); \
266 int signature_index = JCF_readu2 (jcf); \
267 int slot = JCF_readu2 (jcf); \
268 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
269 print_name (out, jcf, name_index); \
270 fprintf (out, ", type: %d=", signature_index); \
271 print_signature (out, jcf, signature_index, 0); \
272 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
274 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
275 { int n = (COUNT); int i; \
276 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
277 fprintf (out, ", count: %d\n", n); \
278 if (flag_disassemble_methods) \
279 for (i = 0; i < n; i++) {\
280 int start_pc = JCF_readu2 (jcf); \
281 int line_number = JCF_readu2 (jcf); \
282 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
284 JCF_SKIP (jcf, 4 * n); }
286 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
287 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
288 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
290 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
291 if (flag_print_attributes > 0) \
292 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
297 DEFUN(print_constant_ref, (stream, jcf, index),
298 FILE *stream AND JCF *jcf AND int index)
300 fprintf (stream, "#%d=<", index);
301 if (index <= 0 || index >= JPOOL_SIZE(jcf))
302 fprintf (stream, "out of range");
304 print_constant (stream, jcf, index, 1);
305 fprintf (stream, ">");
309 DEFUN (print_access_flags, (stream, flags),
310 FILE *stream AND uint16 flags)
312 if (flags & ACC_PUBLIC) fprintf (stream, " public");
313 if (flags & ACC_PRIVATE) fprintf (stream, " private");
314 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
315 if (flags & ACC_STATIC) fprintf (stream, " static");
316 if (flags & ACC_FINAL) fprintf (stream, " final");
317 if (flags & ACC_SYNCHRONIZED) fprintf (stream, " synchronized");
318 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
319 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
320 if (flags & ACC_NATIVE) fprintf (stream, " native");
321 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
322 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
327 DEFUN(print_name, (stream, jcf, name_index),
328 FILE* stream AND JCF* jcf AND int name_index)
330 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
331 fprintf (stream, "<not a UTF8 constant>");
333 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
334 JPOOL_UTF_LENGTH (jcf, name_index));
337 /* If the type of the constant at INDEX matches EXPECTED,
338 print it tersely, otherwise more verbosely. */
341 DEFUN(print_constant_terse, (out, jcf, index, expected),
342 FILE *out AND JCF *jcf AND int index AND int expected)
344 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
345 fprintf (out, "<constant pool index %d not in range>", index);
346 else if (JPOOL_TAG (jcf, index) != expected)
348 fprintf (out, "<Unexpected constant type ");
349 print_constant (out, jcf, index, 1);
353 print_constant (out, jcf, index, 0);
356 /* Print the constant at INDEX in JCF's constant pool.
357 If verbosity==0, print very tersely (no extraneous text).
358 If verbosity==1, prefix the type of the constant.
359 If verbosity==2, add more descriptive text. */
362 DEFUN(print_constant, (out, jcf, index, verbosity),
363 FILE *out AND JCF *jcf AND int index AND int verbosity)
368 int kind = JPOOL_TAG (jcf, index);
372 n = JPOOL_USHORT1 (jcf, index);
374 fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n);
375 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
376 fprintf (out, "<out of range>");
377 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
379 int len = JPOOL_UTF_LENGTH (jcf, n);
380 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
383 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
385 case CONSTANT_Fieldref:
386 str = "Field"; goto field_or_method;
387 case CONSTANT_Methodref:
388 str = "Method"; goto field_or_method;
389 case CONSTANT_InterfaceMethodref:
390 str = "InterfaceMethod"; goto field_or_method;
393 uint16 tclass = JPOOL_USHORT1 (jcf, index);
394 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
396 fprintf (out, "%sref class: %d=", str, tclass);
397 else if (verbosity > 0)
398 fprintf (out, "%s ", str);
399 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
400 fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<",
402 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
407 case CONSTANT_String:
408 j = JPOOL_USHORT1 (jcf, index);
410 fprintf (out, verbosity > 1 ? "String %d=" : "String ", j);
411 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
413 case CONSTANT_Integer:
415 fprintf (out, "Integer ");
416 num = JPOOL_INT (jcf, index);
420 fprintf (out, "Long ");
421 num = JPOOL_LONG (jcf, index);
426 format_int (buffer, num, 10);
427 fprintf (out, "%s", buffer);
430 format_uint (buffer, (uint64)num, 16);
431 fprintf (out, "=0x%s", buffer);
437 jfloat fnum = JPOOL_FLOAT (jcf, index);
438 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
440 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
443 case CONSTANT_Double:
445 jdouble dnum = JPOOL_DOUBLE (jcf, index);
446 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
450 hi = JPOOL_UINT (jcf, index);
451 lo = JPOOL_UINT (jcf, index + 1);
452 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
456 case CONSTANT_NameAndType:
458 uint16 name = JPOOL_USHORT1 (jcf, index);
459 uint16 sig = JPOOL_USHORT2 (jcf, index);
461 fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ",
462 "NameAndType", name);
463 print_name (out, jcf, name);
467 fprintf (out, ", signature: %d=", sig);
468 print_signature (out, jcf, sig, 0);
473 register unsigned char *str = JPOOL_UTF_DATA (jcf, index);
474 int length = JPOOL_UTF_LENGTH (jcf, index);
476 { /* Print as 8-bit bytes. */
477 fputs ("Utf8: \"", out);
478 while (--length >= 0)
479 jcf_print_char (out, *str++);
482 { /* Print as Unicode. */
484 jcf_print_utf8 (out, str, length);
490 fprintf (out, "(Unknown constant type %d)", kind);
495 DEFUN(print_constant_pool, (jcf),
499 for (i = 1; i < JPOOL_SIZE(jcf); i++)
501 int kind = JPOOL_TAG (jcf, i);
502 fprintf (out, "#%d: ", i);
503 print_constant (out, jcf, i, 2);
505 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
506 i++; /* These take up two slots in the constant table */
511 DEFUN(print_signature_type, (stream, ptr, limit),
512 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
521 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
523 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
525 print_signature_type (stream, ptr, limit);
526 if (array_size == -1)
527 fprintf (stream, "[]");
529 fprintf (stream, "[%d]", array_size);
534 fputc (*(*ptr)++, stream);
535 for (; **ptr != ')' && *ptr < limit; nargs++)
539 print_signature_type (stream, ptr, limit);
543 fputc (*(*ptr)++, stream);
544 print_signature_type (stream, ptr, limit);
547 fprintf (stream, "???");
551 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
552 case 'C': fprintf (stream, "char"); (*ptr)++; break;
553 case 'D': fprintf (stream, "double"); (*ptr)++; break;
554 case 'F': fprintf (stream, "float"); (*ptr)++; break;
555 case 'S': fprintf (stream, "short"); (*ptr)++; break;
556 case 'I': fprintf (stream, "int"); (*ptr)++; break;
557 case 'J': fprintf (stream, "long"); (*ptr)++; break;
558 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
559 case 'V': fprintf (stream, "void"); (*ptr)++; break;
562 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
563 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
568 jcf_print_char (stream, *(*ptr)++);
573 DEFUN(print_signature, (stream, jcf, signature_index, int options),
574 FILE* stream AND JCF *jcf AND int signature_index AND int options)
576 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
577 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
580 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
581 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
582 const unsigned char *limit;
583 limit = str + length;
585 fprintf (stream, "<empty signature string>");
588 if (options & PRINT_SIGNATURE_RESULT_ONLY)
590 while (str < limit && *str++ != ')') ;
592 if (options & PRINT_SIGNATURE_ARGS_ONLY)
596 while (str < limit && *str != ')')
598 print_signature_type (stream, &str, limit);
600 fputs (", ", stream);
606 print_signature_type (stream, &str, limit);
609 fprintf (stream, "<junk:");
610 jcf_print_utf8 (stream, str, limit - str);
620 DEFUN(print_exception_table, (jcf, entries, count),
621 JCF *jcf AND unsigned char *entries AND int count)
623 /* Print exception table. */
627 unsigned char *ptr = entries;
628 fprintf (out, "Exceptions (count: %d):\n", i);
629 for (; --i >= 0; ptr+= 8)
631 int start_pc = GET_u2 (ptr);
632 int end_pc = GET_u2 (ptr+2);
633 int handler_pc = GET_u2 (ptr+4);
634 int catch_type = GET_u2 (ptr+6);
635 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
636 start_pc, end_pc, handler_pc, catch_type);
638 fputs (" /* finally */", out);
642 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
649 #include "jcf-reader.c"
654 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
659 DEFUN(process_class, (jcf),
663 if (jcf_parse_preamble (jcf) != 0)
664 fprintf (stderr, "Not a valid Java .class file.\n");
666 /* Parse and possibly print constant pool */
667 code = jcf_parse_constant_pool (jcf);
670 fprintf (stderr, "error while parsing constant pool\n");
671 exit (FATAL_EXIT_CODE);
673 code = verify_constant_pool (jcf);
676 fprintf (stderr, "error in constant pool entry #%d\n", code);
677 exit (FATAL_EXIT_CODE);
679 if (flag_print_constant_pool)
680 print_constant_pool (jcf);
682 jcf_parse_class (jcf);
683 code = jcf_parse_fields (jcf);
686 fprintf (stderr, "error while parsing fields\n");
687 exit (FATAL_EXIT_CODE);
689 code = jcf_parse_methods (jcf);
692 fprintf (stderr, "error while parsing methods\n");
693 exit (FATAL_EXIT_CODE);
695 code = jcf_parse_final_attributes (jcf);
698 fprintf (stderr, "error while parsing final attributes\n");
699 exit (FATAL_EXIT_CODE);
701 jcf->filename = NULL;
705 DEFUN(main, (argc, argv),
706 int argc AND char** argv)
715 for (argi = 1; argi < argc; argi++)
717 char *arg = argv[argi];
719 if (arg[0] != '-' || ! strcmp (arg, "--"))
722 /* Just let all arguments be given in either "-" or "--" form. */
726 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
727 output_file = argv[++argi];
728 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
729 jcf_path_classpath_arg (argv[++argi]);
730 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
731 jcf_path_CLASSPATH_arg (argv[++argi]);
732 else if (strncmp (arg, "-I", 2) == 0)
733 jcf_path_include_arg (arg + 2);
734 else if (strcmp (arg, "-verbose") == 0)
736 else if (strcmp (arg, "-print-main") == 0)
738 else if (strcmp (arg, "-c") == 0)
739 flag_disassemble_methods++;
740 else if (strcmp (arg, "-javap") == 0)
742 flag_javap_compatible++;
743 flag_print_constant_pool = 0;
747 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
748 exit (FATAL_EXIT_CODE);
759 flag_print_fields = 0;
760 flag_print_methods = 0;
761 flag_print_constant_pool = 0;
762 flag_print_attributes = 0;
763 flag_print_class_info = 0;
768 out = fopen (output_file, "w");
771 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
772 exit (FATAL_EXIT_CODE);
780 fprintf (out, "Reading .class from <standard input>.\n");
782 open_class ("<stdio>", jcf, stdin, NULL);
784 open_class ("<stdio>", jcf, 0, NULL);
790 for (; argi < argc; argi++)
792 char *arg = argv[argi];
793 char* class_filename = find_class (arg, strlen (arg), jcf, 0);
794 if (class_filename == NULL)
795 class_filename = find_classfile (arg, jcf, NULL);
796 if (class_filename == NULL)
798 perror ("Could not find class");
799 exit (FATAL_EXIT_CODE);
802 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
804 long compressed_size, member_size;
805 int compression_method, filename_length, extra_length;
806 int general_purpose_bits;
809 if (flag_print_class_info)
810 fprintf (out, "Reading classes from archive %s.\n",
815 jcf_filbuf_t save_filbuf = jcf->filbuf;
816 long magic = JCF_readu4_le (jcf);
817 if (magic == 0x02014b50 || magic == 0x06054b50)
818 break; /* got to central directory */
819 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
821 fprintf (stderr, "bad format of .zip/.jar archive\n");
822 exit (FATAL_EXIT_CODE);
826 general_purpose_bits = JCF_readu2_le (jcf);
827 compression_method = JCF_readu2_le (jcf);
829 compressed_size = JCF_readu4_le (jcf);
830 member_size = JCF_readu4_le (jcf);
831 filename_length = JCF_readu2_le (jcf);
832 extra_length = JCF_readu2_le (jcf);
833 total_length = filename_length + extra_length
835 if (jcf->read_end - jcf->read_ptr < total_length)
836 jcf_trim_old_input (jcf);
837 JCF_FILL (jcf, total_length);
838 filename = jcf->read_ptr;
839 JCF_SKIP (jcf, filename_length);
840 JCF_SKIP (jcf, extra_length);
841 if (filename_length > 0
842 && filename[filename_length-1] == '/')
844 if (flag_print_class_info)
845 fprintf (out, "[Skipping directory %.*s]\n",
846 filename_length, filename);
849 else if (compression_method != 0)
851 if (flag_print_class_info)
852 fprintf (out, "[Skipping compressed file %.*s]\n",
853 filename_length, filename);
856 else if (member_size < 4
857 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
859 if (flag_print_class_info)
860 fprintf (out, "[Skipping non-.class member %.*s]\n",
861 filename_length, filename);
866 if (flag_print_class_info)
867 fprintf (out, "Reading class member: %.*s.\n",
868 filename_length, filename);
872 JCF_SKIP (jcf, compressed_size);
876 unsigned char *save_end;
877 jcf->filbuf = jcf_unexpected_eof;
878 save_end = jcf->read_end;
879 jcf->read_end = jcf->read_ptr + compressed_size;
881 jcf->filbuf = save_filbuf;
882 jcf->read_end = save_end;
888 if (flag_print_class_info)
889 fprintf (out, "Reading .class from %s.\n", class_filename);
896 exit (SUCCESS_EXIT_CODE);
900 DEFUN(disassemble_method, (jcf, byte_ops, len),
901 JCF* jcf AND unsigned char *byte_ops AND int len)
903 #undef AND /* Causes problems with opcodes for iand and land. */
908 if (flag_disassemble_methods == 0)
910 #define BCODE byte_ops
911 for (PC = 0; PC < len;)
916 switch (byte_ops[PC++])
919 /* This is the actual code emitted for each of opcodes in javaops.def.
920 The actual opcode-specific stuff is handled by the OPKIND macro.
921 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
922 Those macros are defiend below. The OPKINDs that do not have any
923 inline parameters (such as BINOP) and therefore do mot need anything
924 else to me printed out just use an empty body. */
926 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
928 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
929 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
933 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
934 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
935 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
936 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
938 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
939 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
941 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
942 These all push a constant onto the opcode stack. */
943 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
944 saw_index = 0, i = (OPERAND_VALUE); \
945 if (oldpc+1 == PC) /* nothing */; \
946 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
947 else fprintf (out, " %d", i);
949 /* Print out operand (a local variable index) for LOAD opcodes.
950 These all push local variable onto the opcode stack. */
951 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
952 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
954 /* Handle STORE opcodes same as LOAD opcodes.
955 These all store a value from the opcode stack in a local variable. */
958 /* Handle more kind of opcodes. */
959 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
960 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
961 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
962 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
963 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
964 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
965 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
967 /* Handle putfield and getfield opcodes, with static versions. */
968 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
969 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
971 /* Print operand for invoke opcodes. */
972 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
973 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
974 if (OPERAND_VALUE) /* for invokeinterface */ \
975 { int nargs = IMMEDIATE_u1; PC++; \
976 fprintf (out, " nargs:%d", nargs); }
978 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
979 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
981 #define ARRAY(OPERAND_TYPE, SUBOP) \
982 ARRAY_##SUBOP(OPERAND_TYPE)
983 /* Handle sub-categories of ARRAY opcodes. */
984 #define ARRAY_LOAD(TYPE) /* nothing */
985 #define ARRAY_STORE(TYPE) /* nothing */
986 #define ARRAY_LENGTH(TYPE) /* nothing */
987 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
988 #define ARRAY_NEW_NUM \
989 INT_temp = IMMEDIATE_u1; \
991 switch (INT_temp) { \
992 case 4: str = "boolean"; break; \
993 case 5: str = "char"; break; \
994 case 6: str = "float"; break; \
995 case 7: str = "double"; break; \
996 case 8: str = "byte"; break; \
997 case 9: str = "short"; break; \
998 case 10: str = "int"; break; \
999 case 11: str = "long"; break; \
1000 default: str = "<unknown type code %d>"; break; \
1002 fputc (' ', out); fprintf (out, str, INT_temp); }
1004 #define ARRAY_NEW_PTR \
1005 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1007 #define ARRAY_NEW_MULTI \
1008 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1009 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1011 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1012 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1014 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1015 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1016 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1018 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1019 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1020 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1022 #undef RET /* Defined by config/i386/i386.h */
1023 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1024 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1026 fprintf (out, " %d", INT_temp);
1028 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1029 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1031 #define LOOKUP_SWITCH \
1032 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1033 fprintf (out, " npairs=%d, default=%d", npairs, default_offset+oldpc); \
1034 while (--npairs >= 0) { \
1035 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1036 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1039 #define TABLE_SWITCH \
1040 { jint default_offset = IMMEDIATE_s4; \
1041 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1042 fprintf (out, " low=%d, high=%d, default=%d", \
1043 low, high, default_offset+oldpc); \
1044 for (; low <= high; low++) { \
1045 jint offset = IMMEDIATE_s4; \
1046 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1049 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1050 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1052 #define SPECIAL_IINC(OPERAND_TYPE) \
1053 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1054 fprintf (out, " %d", i); \
1055 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1057 fprintf (out, " %d", i)
1059 #define SPECIAL_WIDE(OPERAND_TYPE) \
1062 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1063 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1064 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1065 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1067 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1068 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1070 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1071 TEST(OPERAND_TYPE, OPERAND_VALUE)
1073 #include "javaop.def"
1076 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1080 fprintf (out, " %d", INT_temp);
1086 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);