1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998 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:%d, #%d=", 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:%d", 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, ">", index);
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);
582 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
583 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
584 const unsigned char *limit;
585 limit = str + length;
587 fprintf (stream, "<empty signature string>");
590 if (options & PRINT_SIGNATURE_RESULT_ONLY)
592 while (str < limit && *str++ != ')') ;
594 if (options & PRINT_SIGNATURE_ARGS_ONLY)
598 while (str < limit && *str != ')')
600 print_signature_type (stream, &str, limit);
602 fputs (", ", stream);
608 print_signature_type (stream, &str, limit);
611 fprintf (stream, "<junk:");
612 jcf_print_utf8 (stream, str, limit - str);
622 DEFUN(print_exception_table, (jcf, entries, count),
623 JCF *jcf AND unsigned char *entries AND int count)
625 /* Print exception table. */
629 unsigned char *ptr = entries;
630 fprintf (out, "Exceptions (count: %d):\n", i);
631 for (; --i >= 0; ptr+= 8)
633 int start_pc = GET_u2 (ptr);
634 int end_pc = GET_u2 (ptr+2);
635 int handler_pc = GET_u2 (ptr+4);
636 int catch_type = GET_u2 (ptr+6);
637 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
638 start_pc, end_pc, handler_pc, catch_type);
640 fputs (" /* finally */", out);
644 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
651 #include "jcf-reader.c"
656 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
661 DEFUN(process_class, (jcf),
665 if (jcf_parse_preamble (jcf) != 0)
666 fprintf (stderr, "Not a valid Java .class file.\n");
668 /* Parse and possibly print constant pool */
669 code = jcf_parse_constant_pool (jcf);
672 fprintf (stderr, "error while parsing constant pool\n");
673 exit (FATAL_EXIT_CODE);
675 code = verify_constant_pool (jcf);
678 fprintf (stderr, "error in constant pool entry #%d\n", code);
679 exit (FATAL_EXIT_CODE);
681 if (flag_print_constant_pool)
682 print_constant_pool (jcf);
684 jcf_parse_class (jcf);
685 code = jcf_parse_fields (jcf);
688 fprintf (stderr, "error while parsing fields\n");
689 exit (FATAL_EXIT_CODE);
691 code = jcf_parse_methods (jcf);
694 fprintf (stderr, "error while parsing methods\n");
695 exit (FATAL_EXIT_CODE);
697 code = jcf_parse_final_attributes (jcf);
700 fprintf (stderr, "error while parsing final attributes\n");
701 exit (FATAL_EXIT_CODE);
703 jcf->filename = NULL;
707 DEFUN(main, (argc, argv),
708 int argc AND char** argv)
717 for (argi = 1; argi < argc; argi++)
719 char *arg = argv[argi];
721 if (arg[0] != '-' || ! strcmp (arg, "--"))
724 /* Just let all arguments be given in either "-" or "--" form. */
728 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
729 output_file = argv[++argi];
730 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
731 jcf_path_classpath_arg (argv[++argi]);
732 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
733 jcf_path_CLASSPATH_arg (argv[++argi]);
734 else if (strncmp (arg, "-I", 2) == 0)
735 jcf_path_include_arg (arg + 2);
736 else if (strcmp (arg, "-verbose") == 0)
738 else if (strcmp (arg, "-print-main") == 0)
740 else if (strcmp (arg, "-c") == 0)
741 flag_disassemble_methods++;
742 else if (strcmp (arg, "-javap") == 0)
744 flag_javap_compatible++;
745 flag_print_constant_pool = 0;
749 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
750 exit (FATAL_EXIT_CODE);
761 flag_print_fields = 0;
762 flag_print_methods = 0;
763 flag_print_constant_pool = 0;
764 flag_print_attributes = 0;
765 flag_print_class_info = 0;
770 out = fopen (output_file, "w");
773 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
774 exit (FATAL_EXIT_CODE);
782 fprintf (out, "Reading .class from <standard input>.\n");
784 open_class ("<stdio>", jcf, stdin, NULL);
786 open_class ("<stdio>", jcf, 0, NULL);
792 for (; argi < argc; argi++)
794 char *arg = argv[argi];
795 char* class_filename = find_class (arg, strlen (arg), jcf, 1);
796 if (class_filename == NULL)
797 class_filename = find_classfile (arg, jcf, NULL);
798 if (class_filename == NULL)
800 perror ("Could not find class");
801 exit (FATAL_EXIT_CODE);
804 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
806 long compressed_size, member_size;
807 int compression_method, filename_length, extra_length;
808 int general_purpose_bits;
811 if (flag_print_class_info)
812 fprintf (out, "Reading classes from archive %s.\n",
817 jcf_filbuf_t save_filbuf = jcf->filbuf;
818 long magic = JCF_readu4_le (jcf);
819 if (magic == 0x02014b50 || magic == 0x06054b50)
820 break; /* got to central directory */
821 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
823 fprintf (stderr, "bad format of .zip/.jar archive\n");
824 exit (FATAL_EXIT_CODE);
828 general_purpose_bits = JCF_readu2_le (jcf);
829 compression_method = JCF_readu2_le (jcf);
831 compressed_size = JCF_readu4_le (jcf);
832 member_size = JCF_readu4_le (jcf);
833 filename_length = JCF_readu2_le (jcf);
834 extra_length = JCF_readu2_le (jcf);
835 total_length = filename_length + extra_length
837 if (jcf->read_end - jcf->read_ptr < total_length)
838 jcf_trim_old_input (jcf);
839 JCF_FILL (jcf, total_length);
840 filename = jcf->read_ptr;
841 JCF_SKIP (jcf, filename_length);
842 JCF_SKIP (jcf, extra_length);
843 if (filename_length > 0
844 && filename[filename_length-1] == '/')
846 if (flag_print_class_info)
847 fprintf (out, "[Skipping directory %.*s]\n",
848 filename_length, filename);
851 else if (compression_method != 0)
853 if (flag_print_class_info)
854 fprintf (out, "[Skipping compressed file %.*s]\n",
855 filename_length, filename);
858 else if (member_size < 4
859 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
861 if (flag_print_class_info)
862 fprintf (out, "[Skipping non-.class member %.*s]\n",
863 filename_length, filename);
868 if (flag_print_class_info)
869 fprintf (out, "Reading class member: %.*s.\n",
870 filename_length, filename);
874 JCF_SKIP (jcf, compressed_size);
878 unsigned char *save_end;
879 jcf->filbuf = jcf_unexpected_eof;
880 save_end = jcf->read_end;
881 jcf->read_end = jcf->read_ptr + compressed_size;
883 jcf->filbuf = save_filbuf;
884 jcf->read_end = save_end;
890 if (flag_print_class_info)
891 fprintf (out, "Reading .class from %s.\n", class_filename);
898 exit (SUCCESS_EXIT_CODE);
902 DEFUN(disassemble_method, (jcf, byte_ops, len),
903 JCF* jcf AND unsigned char *byte_ops AND int len)
905 #undef AND /* Causes problems with opcodes for iand and land. */
910 if (flag_disassemble_methods == 0)
912 #define BCODE byte_ops
913 for (PC = 0; PC < len;)
921 switch (byte_ops[PC++])
924 /* This is the actual code emitted for each of opcodes in javaops.def.
925 The actual opcode-specific stuff is handled by the OPKIND macro.
926 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
927 Those macros are defiend below. The OPKINDs that do not have any
928 inline parameters (such as BINOP) and therefore do mot need anything
929 else to me printed out just use an empty body. */
931 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
933 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
934 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
938 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
939 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
940 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
941 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
943 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
944 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
946 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
947 These all push a constant onto the opcode stack. */
948 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
949 saw_index = 0, INT_temp = (OPERAND_VALUE); \
950 if (oldpc+1 == PC) /* nothing */; \
951 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, INT_temp); \
952 else fprintf (out, " %d", INT_temp);
954 /* Print out operand (a local variable index) for LOAD opcodes.
955 These all push local variable onto the opcode stack. */
956 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
957 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
959 /* Handle STORE opcodes same as LOAD opcodes.
960 These all store a value from the opcode stack in a local variable. */
963 /* Handle more kind of opcodes. */
964 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
965 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
966 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
967 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
968 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
969 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
970 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
972 /* Handle putfield and getfield opcodes, with static versions. */
973 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
974 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
976 /* Print operand for invoke opcodes. */
977 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
978 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
979 if (OPERAND_VALUE) /* for invokeinterface */ \
980 { int nargs = IMMEDIATE_u1; PC++; \
981 fprintf (out, " nargs:%d", nargs); }
983 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
984 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
986 #define ARRAY(OPERAND_TYPE, SUBOP) \
987 ARRAY_##SUBOP(OPERAND_TYPE)
988 /* Handle sub-categories of ARRAY opcodes. */
989 #define ARRAY_LOAD(TYPE) /* nothing */
990 #define ARRAY_STORE(TYPE) /* nothing */
991 #define ARRAY_LENGTH(TYPE) /* nothing */
992 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
993 #define ARRAY_NEW_NUM \
994 INT_temp = IMMEDIATE_u1; \
996 switch (INT_temp) { \
997 case 4: str = "boolean"; break; \
998 case 5: str = "char"; break; \
999 case 6: str = "float"; break; \
1000 case 7: str = "double"; break; \
1001 case 8: str = "byte"; break; \
1002 case 9: str = "short"; break; \
1003 case 10: str = "int"; break; \
1004 case 11: str = "long"; break; \
1005 default: str = "<unknown type code %d>"; break; \
1007 fputc (' ', out); fprintf (out, str, INT_temp); }
1009 #define ARRAY_NEW_PTR \
1010 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1012 #define ARRAY_NEW_MULTI \
1013 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1014 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1016 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1017 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1019 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1020 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1021 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1023 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1024 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1025 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
1027 #undef RET /* Defined by config/i386/i386.h */
1028 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1029 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1031 fprintf (out, " %d", INT_temp);
1033 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1034 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1036 #define LOOKUP_SWITCH \
1037 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1038 fprintf (out, " npairs=%d, default=%d", npairs, default_offset+oldpc); \
1039 while (--npairs >= 0) { \
1040 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1041 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1044 #define TABLE_SWITCH \
1045 { jint default_offset = IMMEDIATE_s4; \
1046 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1047 fprintf (out, " low=%d, high=%d, default=%d", \
1048 low, high, default_offset+oldpc); \
1049 for (; low <= high; low++) { \
1050 jint offset = IMMEDIATE_s4; \
1051 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1054 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1055 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1057 #define SPECIAL_IINC(OPERAND_TYPE) \
1058 INT_temp = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1059 fprintf (out, " %d", INT_temp); \
1060 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1062 fprintf (out, " %d", INT_temp)
1064 #define SPECIAL_WIDE(OPERAND_TYPE) \
1067 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1068 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1069 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1070 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1072 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1073 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1075 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1076 TEST(OPERAND_TYPE, OPERAND_VALUE)
1078 #include "javaop.def"
1081 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1085 fprintf (out, " %d", INT_temp);
1091 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);