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)++)
524 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
526 print_signature_type (stream, ptr, limit);
527 if (array_size == -1)
528 fprintf (stream, "[]");
530 fprintf (stream, "[%d]", array_size);
535 fputc (*(*ptr)++, stream);
536 for (; **ptr != ')' && *ptr < limit; nargs++)
540 print_signature_type (stream, ptr, limit);
544 fputc (*(*ptr)++, stream);
545 print_signature_type (stream, ptr, limit);
548 fprintf (stream, "???");
552 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
553 case 'C': fprintf (stream, "char"); (*ptr)++; break;
554 case 'D': fprintf (stream, "double"); (*ptr)++; break;
555 case 'F': fprintf (stream, "float"); (*ptr)++; break;
556 case 'S': fprintf (stream, "short"); (*ptr)++; break;
557 case 'I': fprintf (stream, "int"); (*ptr)++; break;
558 case 'J': fprintf (stream, "long"); (*ptr)++; break;
559 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
560 case 'V': fprintf (stream, "void"); (*ptr)++; break;
563 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
564 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
569 jcf_print_char (stream, *(*ptr)++);
574 DEFUN(print_signature, (stream, jcf, signature_index, int options),
575 FILE* stream AND JCF *jcf AND int signature_index AND int options)
577 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
578 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
581 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
582 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
583 const unsigned char *limit;
584 limit = str + length;
586 fprintf (stream, "<empty signature string>");
589 if (options & PRINT_SIGNATURE_RESULT_ONLY)
591 while (str < limit && *str++ != ')') ;
593 if (options & PRINT_SIGNATURE_ARGS_ONLY)
597 while (str < limit && *str != ')')
599 print_signature_type (stream, &str, limit);
601 fputs (", ", stream);
607 print_signature_type (stream, &str, limit);
610 fprintf (stream, "<junk:");
611 jcf_print_utf8 (stream, str, limit - str);
621 DEFUN(print_exception_table, (jcf, entries, count),
622 JCF *jcf AND unsigned char *entries AND int count)
624 /* Print exception table. */
628 unsigned char *ptr = entries;
629 fprintf (out, "Exceptions (count: %d):\n", i);
630 for (; --i >= 0; ptr+= 8)
632 int start_pc = GET_u2 (ptr);
633 int end_pc = GET_u2 (ptr+2);
634 int handler_pc = GET_u2 (ptr+4);
635 int catch_type = GET_u2 (ptr+6);
636 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
637 start_pc, end_pc, handler_pc, catch_type);
639 fputs (" /* finally */", out);
643 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
650 #include "jcf-reader.c"
655 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
660 DEFUN(process_class, (jcf),
664 if (jcf_parse_preamble (jcf) != 0)
665 fprintf (stderr, "Not a valid Java .class file.\n");
667 /* Parse and possibly print constant pool */
668 code = jcf_parse_constant_pool (jcf);
671 fprintf (stderr, "error while parsing constant pool\n");
672 exit (FATAL_EXIT_CODE);
674 code = verify_constant_pool (jcf);
677 fprintf (stderr, "error in constant pool entry #%d\n", code);
678 exit (FATAL_EXIT_CODE);
680 if (flag_print_constant_pool)
681 print_constant_pool (jcf);
683 jcf_parse_class (jcf);
684 code = jcf_parse_fields (jcf);
687 fprintf (stderr, "error while parsing fields\n");
688 exit (FATAL_EXIT_CODE);
690 code = jcf_parse_methods (jcf);
693 fprintf (stderr, "error while parsing methods\n");
694 exit (FATAL_EXIT_CODE);
696 code = jcf_parse_final_attributes (jcf);
699 fprintf (stderr, "error while parsing final attributes\n");
700 exit (FATAL_EXIT_CODE);
702 jcf->filename = NULL;
706 DEFUN(main, (argc, argv),
707 int argc AND char** argv)
716 for (argi = 1; argi < argc; argi++)
718 char *arg = argv[argi];
720 if (arg[0] != '-' || ! strcmp (arg, "--"))
723 /* Just let all arguments be given in either "-" or "--" form. */
727 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
728 output_file = argv[++argi];
729 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
730 jcf_path_classpath_arg (argv[++argi]);
731 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
732 jcf_path_CLASSPATH_arg (argv[++argi]);
733 else if (strncmp (arg, "-I", 2) == 0)
734 jcf_path_include_arg (arg + 2);
735 else if (strcmp (arg, "-verbose") == 0)
737 else if (strcmp (arg, "-print-main") == 0)
739 else if (strcmp (arg, "-c") == 0)
740 flag_disassemble_methods++;
741 else if (strcmp (arg, "-javap") == 0)
743 flag_javap_compatible++;
744 flag_print_constant_pool = 0;
748 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
749 exit (FATAL_EXIT_CODE);
760 flag_print_fields = 0;
761 flag_print_methods = 0;
762 flag_print_constant_pool = 0;
763 flag_print_attributes = 0;
764 flag_print_class_info = 0;
769 out = fopen (output_file, "w");
772 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
773 exit (FATAL_EXIT_CODE);
781 fprintf (out, "Reading .class from <standard input>.\n");
783 open_class ("<stdio>", jcf, stdin, NULL);
785 open_class ("<stdio>", jcf, 0, NULL);
791 for (; argi < argc; argi++)
793 char *arg = argv[argi];
794 char* class_filename = find_class (arg, strlen (arg), jcf, 0);
795 if (class_filename == NULL)
796 class_filename = find_classfile (arg, jcf, NULL);
797 if (class_filename == NULL)
799 perror ("Could not find class");
800 exit (FATAL_EXIT_CODE);
803 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
805 long compressed_size, member_size;
806 int compression_method, filename_length, extra_length;
807 int general_purpose_bits;
810 if (flag_print_class_info)
811 fprintf (out, "Reading classes from archive %s.\n",
816 jcf_filbuf_t save_filbuf = jcf->filbuf;
817 long magic = JCF_readu4_le (jcf);
818 if (magic == 0x02014b50 || magic == 0x06054b50)
819 break; /* got to central directory */
820 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
822 fprintf (stderr, "bad format of .zip/.jar archive\n");
823 exit (FATAL_EXIT_CODE);
827 general_purpose_bits = JCF_readu2_le (jcf);
828 compression_method = JCF_readu2_le (jcf);
830 compressed_size = JCF_readu4_le (jcf);
831 member_size = JCF_readu4_le (jcf);
832 filename_length = JCF_readu2_le (jcf);
833 extra_length = JCF_readu2_le (jcf);
834 total_length = filename_length + extra_length
836 if (jcf->read_end - jcf->read_ptr < total_length)
837 jcf_trim_old_input (jcf);
838 JCF_FILL (jcf, total_length);
839 filename = jcf->read_ptr;
840 JCF_SKIP (jcf, filename_length);
841 JCF_SKIP (jcf, extra_length);
842 if (filename_length > 0
843 && filename[filename_length-1] == '/')
845 if (flag_print_class_info)
846 fprintf (out, "[Skipping directory %.*s]\n",
847 filename_length, filename);
850 else if (compression_method != 0)
852 if (flag_print_class_info)
853 fprintf (out, "[Skipping compressed file %.*s]\n",
854 filename_length, filename);
857 else if (member_size < 4
858 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
860 if (flag_print_class_info)
861 fprintf (out, "[Skipping non-.class member %.*s]\n",
862 filename_length, filename);
867 if (flag_print_class_info)
868 fprintf (out, "Reading class member: %.*s.\n",
869 filename_length, filename);
873 JCF_SKIP (jcf, compressed_size);
877 unsigned char *save_end;
878 jcf->filbuf = jcf_unexpected_eof;
879 save_end = jcf->read_end;
880 jcf->read_end = jcf->read_ptr + compressed_size;
882 jcf->filbuf = save_filbuf;
883 jcf->read_end = save_end;
889 if (flag_print_class_info)
890 fprintf (out, "Reading .class from %s.\n", class_filename);
897 exit (SUCCESS_EXIT_CODE);
901 DEFUN(disassemble_method, (jcf, byte_ops, len),
902 JCF* jcf AND unsigned char *byte_ops AND int len)
904 #undef AND /* Causes problems with opcodes for iand and land. */
909 if (flag_disassemble_methods == 0)
911 #define BCODE byte_ops
912 for (PC = 0; PC < len;)
918 switch (byte_ops[PC++])
921 /* This is the actual code emitted for each of opcodes in javaops.def.
922 The actual opcode-specific stuff is handled by the OPKIND macro.
923 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
924 Those macros are defiend below. The OPKINDs that do not have any
925 inline parameters (such as BINOP) and therefore do mot need anything
926 else to me printed out just use an empty body. */
928 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
930 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
931 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
935 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
936 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
937 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
938 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
940 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
941 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
943 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
944 These all push a constant onto the opcode stack. */
945 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
946 saw_index = 0, i = (OPERAND_VALUE); \
947 if (oldpc+1 == PC) /* nothing */; \
948 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
949 else fprintf (out, " %d", i);
951 /* Print out operand (a local variable index) for LOAD opcodes.
952 These all push local variable onto the opcode stack. */
953 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
954 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
956 /* Handle STORE opcodes same as LOAD opcodes.
957 These all store a value from the opcode stack in a local variable. */
960 /* Handle more kind of opcodes. */
961 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
962 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
963 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
964 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
965 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
966 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
967 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
969 /* Handle putfield and getfield opcodes, with static versions. */
970 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
971 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
973 /* Print operand for invoke opcodes. */
974 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
975 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
976 if (OPERAND_VALUE) /* for invokeinterface */ \
977 { int nargs = IMMEDIATE_u1; PC++; \
978 fprintf (out, " nargs:%d", nargs); }
980 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
981 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
983 #define ARRAY(OPERAND_TYPE, SUBOP) \
984 ARRAY_##SUBOP(OPERAND_TYPE)
985 /* Handle sub-categories of ARRAY opcodes. */
986 #define ARRAY_LOAD(TYPE) /* nothing */
987 #define ARRAY_STORE(TYPE) /* nothing */
988 #define ARRAY_LENGTH(TYPE) /* nothing */
989 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
990 #define ARRAY_NEW_NUM \
991 INT_temp = IMMEDIATE_u1; \
993 switch (INT_temp) { \
994 case 4: str = "boolean"; break; \
995 case 5: str = "char"; break; \
996 case 6: str = "float"; break; \
997 case 7: str = "double"; break; \
998 case 8: str = "byte"; break; \
999 case 9: str = "short"; break; \
1000 case 10: str = "int"; break; \
1001 case 11: str = "long"; break; \
1002 default: str = "<unknown type code %d>"; break; \
1004 fputc (' ', out); fprintf (out, str, INT_temp); }
1006 #define ARRAY_NEW_PTR \
1007 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1009 #define ARRAY_NEW_MULTI \
1010 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1011 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1013 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1014 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1016 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1017 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1018 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1020 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1021 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1022 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1024 #undef RET /* Defined by config/i386/i386.h */
1025 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1026 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1028 fprintf (out, " %d", INT_temp);
1030 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1031 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1033 #define LOOKUP_SWITCH \
1034 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1035 fprintf (out, " npairs=%d, default=%d", npairs, default_offset+oldpc); \
1036 while (--npairs >= 0) { \
1037 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1038 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1041 #define TABLE_SWITCH \
1042 { jint default_offset = IMMEDIATE_s4; \
1043 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1044 fprintf (out, " low=%d, high=%d, default=%d", \
1045 low, high, default_offset+oldpc); \
1046 for (; low <= high; low++) { \
1047 jint offset = IMMEDIATE_s4; \
1048 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1051 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1052 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1054 #define SPECIAL_IINC(OPERAND_TYPE) \
1055 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1056 fprintf (out, " %d", i); \
1057 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1059 fprintf (out, " %d", i)
1061 #define SPECIAL_WIDE(OPERAND_TYPE) \
1064 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1065 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1066 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1067 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1069 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1070 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1072 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1073 TEST(OPERAND_TYPE, OPERAND_VALUE)
1075 #include "javaop.def"
1078 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1082 fprintf (out, " %d", INT_temp);
1088 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);