1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 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"
62 /* Name of output file, if NULL if stdout. */
63 char *output_file = NULL;
67 int flag_disassemble_methods = 0;
68 int flag_print_class_info = 1;
69 int flag_print_constant_pool = 1;
70 int flag_print_fields = 1;
71 int flag_print_methods = 1;
72 int flag_print_attributes = 1;
74 /* When non zero, warn when source file is newer than matching class
78 /* Print names of classes that have a "main" method. */
79 int flag_print_main = 0;
81 /* Index in constant pool of this class. */
82 int this_class_index = 0;
84 int class_access_flags = 0;
86 /* Print in format similar to javap. VERY IMCOMPLETE. */
87 int flag_javap_compatible = 0;
89 static void print_access_flags PARAMS ((FILE *, uint16, char));
90 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
91 static void print_constant PARAMS ((FILE *, JCF *, int, int));
92 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
93 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
94 static void print_name PARAMS ((FILE*, JCF*, int));
95 static void print_signature PARAMS ((FILE*, JCF*, int, int));
96 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
97 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
98 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
99 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
100 static void process_class PARAMS ((struct JCF *));
101 static void print_constant_pool PARAMS ((struct JCF *));
102 static void print_exception_table PARAMS ((struct JCF *,
103 const unsigned char *entries, int));
105 #define PRINT_SIGNATURE_RESULT_ONLY 1
106 #define PRINT_SIGNATURE_ARGS_ONLY 2
109 DEFUN(utf8_equal_string, (jcf, index, value),
110 JCF *jcf AND int index AND const char * value)
112 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
113 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
115 int len = strlen (value);
116 if (JPOOL_UTF_LENGTH (jcf, index) == len
117 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
123 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
124 this_class_index = 0; \
125 if (flag_print_class_info) \
127 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
128 (long) MAGIC, (long) MINOR, (long) MAJOR)
130 #define HANDLE_START_CONSTANT_POOL(COUNT) \
131 if (flag_print_constant_pool) \
132 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
134 #define HANDLE_SOURCEFILE(INDEX) \
135 { fprintf (out, "Attribute "); \
136 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
137 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
138 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
140 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
141 this_class_index = THIS; \
142 class_access_flags = ACCESS_FLAGS; \
143 if (flag_print_class_info) \
144 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
145 print_access_flags (out, ACCESS_FLAGS, 'c'); \
147 fprintf (out, "This class: "); \
148 if (flag_print_constant_pool) \
149 fprintf (out, "%d=", THIS); \
150 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
151 if (flag_print_constant_pool || SUPER != 0) \
152 fprintf (out, ", super: "); \
153 if (flag_print_constant_pool) \
155 fprintf (out, "%d", SUPER); \
160 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
161 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
164 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
165 (flag_print_attributes <= 0)
167 #define HANDLE_CLASS_INTERFACE(INDEX) \
168 if (flag_print_class_info) \
169 { fprintf (out, "- Implements: %d=", INDEX); \
170 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
173 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
174 if (flag_print_fields) \
175 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
177 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
178 if (flag_print_fields) \
179 { fprintf (out, "Field name:"); \
180 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
181 print_access_flags (out, ACCESS_FLAGS, 'f'); \
182 fprintf (out, " Signature: "); \
183 if (flag_print_constant_pool) \
184 fprintf (out, "%d=", SIGNATURE); \
185 print_signature (out, jcf, SIGNATURE, 0); \
186 fputc ('\n', out); } \
188 flag_print_attributes--;
190 #define HANDLE_END_FIELD() \
191 if (! flag_print_fields) \
192 flag_print_attributes++;
194 #define HANDLE_START_METHODS(METHODS_COUNT) \
195 if (flag_print_methods) \
196 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
198 flag_print_attributes--;
201 #define HANDLE_END_METHODS() \
202 if (! flag_print_methods) \
203 flag_print_attributes++;
205 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
207 if (flag_print_methods) \
209 if (flag_javap_compatible) \
211 fprintf (out, " "); \
212 print_access_flags (out, ACCESS_FLAGS, 'm'); \
214 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
216 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
217 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
222 fprintf (out, "\nMethod name:"); \
223 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
224 print_access_flags (out, ACCESS_FLAGS, 'm'); \
225 fprintf (out, " Signature: "); \
226 if (flag_print_constant_pool) \
227 fprintf (out, "%d=", SIGNATURE); \
228 print_signature (out, jcf, SIGNATURE, 0); \
232 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
233 && utf8_equal_string (jcf, NAME, "main") \
234 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
235 && this_class_index > 0 \
236 && (class_access_flags & ACC_PUBLIC)) \
238 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
243 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
244 ( fprintf (out, "Attribute "), \
245 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
246 fprintf (out, ", length:%ld", (long) LENGTH) )
248 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
249 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
250 fprintf (out, ", value: "), \
251 print_constant_ref (out, jcf, VALUE_INDEX), \
252 fprintf (out, "\n") )
254 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
255 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
256 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
257 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
258 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
260 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
261 print_exception_table (jcf, ENTRIES, COUNT)
263 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
264 { int n = (COUNT); int i; \
265 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
266 fprintf (out, ", count: %d\n", n); \
267 for (i = 0; i < n; i++) {\
268 int ex_index = JCF_readu2 (jcf); \
269 fprintf (out, "%3d: ", i); \
270 print_constant_ref (out, jcf, ex_index); \
271 fputc ('\n', out); } }
273 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
274 { int n = (COUNT); int i; \
275 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
276 fprintf (out, ", count: %d\n", n); \
277 for (i = 0; i < n; i++) {\
278 int start_pc = JCF_readu2 (jcf); \
279 int length = JCF_readu2 (jcf); \
280 int name_index = JCF_readu2 (jcf); \
281 int signature_index = JCF_readu2 (jcf); \
282 int slot = JCF_readu2 (jcf); \
283 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
284 print_name (out, jcf, name_index); \
285 fprintf (out, ", type: %d=", signature_index); \
286 print_signature (out, jcf, signature_index, 0); \
287 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
289 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
290 { int n = (COUNT); int i; \
291 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
292 fprintf (out, ", count: %d\n", n); \
293 if (flag_disassemble_methods) \
294 for (i = 0; i < n; i++) {\
295 int start_pc = JCF_readu2 (jcf); \
296 int line_number = JCF_readu2 (jcf); \
297 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
299 JCF_SKIP (jcf, 4 * n); }
301 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
303 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
306 uint16 inner_class_info_index = JCF_readu2 (jcf); \
307 uint16 outer_class_info_index = JCF_readu2 (jcf); \
308 uint16 inner_name_index = JCF_readu2 (jcf); \
309 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
311 if (flag_print_class_info) \
313 fprintf (out, "\n class: "); \
314 if (flag_print_constant_pool) \
315 fprintf (out, "%d=", inner_class_info_index); \
316 print_constant_terse (out, jcf, \
317 inner_class_info_index, CONSTANT_Class); \
318 fprintf (out, " (%d=", inner_name_index); \
319 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
320 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
321 print_access_flags (out, inner_class_access_flags, 'c'); \
322 fprintf (out, ", outer class: "); \
323 if (flag_print_constant_pool) \
324 fprintf (out, "%d=", outer_class_info_index); \
325 print_constant_terse (out, jcf, \
326 outer_class_info_index, CONSTANT_Class); \
329 if (flag_print_class_info) \
333 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
334 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
335 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
337 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
338 if (flag_print_attributes > 0) \
339 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
344 DEFUN(print_constant_ref, (stream, jcf, index),
345 FILE *stream AND JCF *jcf AND int index)
347 fprintf (stream, "#%d=<", index);
348 if (index <= 0 || index >= JPOOL_SIZE(jcf))
349 fprintf (stream, "out of range");
351 print_constant (stream, jcf, index, 1);
352 fprintf (stream, ">");
355 /* Print the access flags given by FLAGS.
356 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
357 or 'm' (method flags). */
360 DEFUN (print_access_flags, (stream, flags, context),
361 FILE *stream AND uint16 flags AND char context)
363 if (flags & ACC_PUBLIC) fprintf (stream, " public");
364 if (flags & ACC_PRIVATE) fprintf (stream, " private");
365 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
366 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
367 if (flags & ACC_STATIC) fprintf (stream, " static");
368 if (flags & ACC_FINAL) fprintf (stream, " final");
369 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
370 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
371 if (flags & ACC_NATIVE) fprintf (stream, " native");
372 if (flags & ACC_SYNCHRONIZED)
375 fprintf (stream, " super");
377 fprintf (stream, " synchronized");
379 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
380 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
385 DEFUN(print_name, (stream, jcf, name_index),
386 FILE* stream AND JCF* jcf AND int name_index)
388 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
389 fprintf (stream, "<not a UTF8 constant>");
391 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
392 JPOOL_UTF_LENGTH (jcf, name_index));
395 /* If the type of the constant at INDEX matches EXPECTED,
396 print it tersely, otherwise more verbosely. */
399 DEFUN(print_constant_terse, (out, jcf, index, expected),
400 FILE *out AND JCF *jcf AND int index AND int expected)
402 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
403 fprintf (out, "<constant pool index %d not in range>", index);
404 else if (JPOOL_TAG (jcf, index) != expected)
406 fprintf (out, "<Unexpected constant type ");
407 print_constant (out, jcf, index, 1);
411 print_constant (out, jcf, index, 0);
414 /* Print the constant at INDEX in JCF's constant pool.
415 If verbosity==0, print very tersely (no extraneous text).
416 If verbosity==1, prefix the type of the constant.
417 If verbosity==2, add more descriptive text. */
420 DEFUN(print_constant, (out, jcf, index, verbosity),
421 FILE *out AND JCF *jcf AND int index AND int verbosity)
426 int kind = JPOOL_TAG (jcf, index);
430 n = JPOOL_USHORT1 (jcf, index);
434 fprintf (out, "Class name: %d=", n);
436 fprintf (out, "Class ");
438 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
439 fprintf (out, "<out of range>");
440 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
442 int len = JPOOL_UTF_LENGTH (jcf, n);
443 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
446 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
448 case CONSTANT_Fieldref:
449 str = "Field"; goto field_or_method;
450 case CONSTANT_Methodref:
451 str = "Method"; goto field_or_method;
452 case CONSTANT_InterfaceMethodref:
453 str = "InterfaceMethod"; goto field_or_method;
456 uint16 tclass = JPOOL_USHORT1 (jcf, index);
457 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
459 fprintf (out, "%sref class: %d=", str, tclass);
460 else if (verbosity > 0)
461 fprintf (out, "%s ", str);
462 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
466 fprintf (out, " name_and_type: %d=<", name_and_type);
467 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
472 case CONSTANT_String:
473 j = JPOOL_USHORT1 (jcf, index);
477 fprintf (out, "String %d=", j);
479 fprintf (out, "String ");
481 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
483 case CONSTANT_Integer:
485 fprintf (out, "Integer ");
486 num = JPOOL_INT (jcf, index);
490 fprintf (out, "Long ");
491 num = JPOOL_LONG (jcf, index);
496 format_int (buffer, num, 10);
497 fprintf (out, "%s", buffer);
500 format_uint (buffer, (uint64)num, 16);
501 fprintf (out, "=0x%s", buffer);
507 jfloat fnum = JPOOL_FLOAT (jcf, index);
508 fprintf (out, "%s%.10g", verbosity > 0 ? "Float " : "", (double) fnum);
510 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
513 case CONSTANT_Double:
515 jdouble dnum = JPOOL_DOUBLE (jcf, index);
516 fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
520 hi = JPOOL_UINT (jcf, index);
521 lo = JPOOL_UINT (jcf, index + 1);
522 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
526 case CONSTANT_NameAndType:
528 uint16 name = JPOOL_USHORT1 (jcf, index);
529 uint16 sig = JPOOL_USHORT2 (jcf, index);
533 fprintf (out, "NameAndType name: %d=", name);
535 fprintf (out, "NameAndType ");
537 print_name (out, jcf, name);
541 fprintf (out, ", signature: %d=", sig);
542 print_signature (out, jcf, sig, 0);
547 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
548 int length = JPOOL_UTF_LENGTH (jcf, index);
550 { /* Print as 8-bit bytes. */
551 fputs ("Utf8: \"", out);
552 while (--length >= 0)
553 jcf_print_char (out, *str++);
556 { /* Print as Unicode. */
558 jcf_print_utf8 (out, str, length);
564 fprintf (out, "(Unknown constant type %d)", kind);
569 DEFUN(print_constant_pool, (jcf),
573 for (i = 1; i < JPOOL_SIZE(jcf); i++)
575 int kind = JPOOL_TAG (jcf, i);
576 fprintf (out, "#%d: ", i);
577 print_constant (out, jcf, i, 2);
579 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
580 i++; /* These take up two slots in the constant table */
585 DEFUN(print_signature_type, (stream, ptr, limit),
586 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
595 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
597 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
599 print_signature_type (stream, ptr, limit);
600 if (array_size == -1)
601 fprintf (stream, "[]");
603 fprintf (stream, "[%d]", array_size);
608 fputc (*(*ptr)++, stream);
609 for (; **ptr != ')' && *ptr < limit; nargs++)
613 print_signature_type (stream, ptr, limit);
617 fputc (*(*ptr)++, stream);
618 print_signature_type (stream, ptr, limit);
621 fprintf (stream, "???");
625 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
626 case 'C': fprintf (stream, "char"); (*ptr)++; break;
627 case 'D': fprintf (stream, "double"); (*ptr)++; break;
628 case 'F': fprintf (stream, "float"); (*ptr)++; break;
629 case 'S': fprintf (stream, "short"); (*ptr)++; break;
630 case 'I': fprintf (stream, "int"); (*ptr)++; break;
631 case 'J': fprintf (stream, "long"); (*ptr)++; break;
632 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
633 case 'V': fprintf (stream, "void"); (*ptr)++; break;
636 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
637 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
642 jcf_print_char (stream, *(*ptr)++);
647 DEFUN(print_signature, (stream, jcf, signature_index, int options),
648 FILE* stream AND JCF *jcf AND int signature_index AND int options)
650 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
651 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
654 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
655 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
656 const unsigned char *limit;
657 limit = str + length;
659 fprintf (stream, "<empty signature string>");
662 if (options & PRINT_SIGNATURE_RESULT_ONLY)
664 while (str < limit && *str++ != ')') ;
666 if (options & PRINT_SIGNATURE_ARGS_ONLY)
670 while (str < limit && *str != ')')
672 print_signature_type (stream, &str, limit);
674 fputs (", ", stream);
680 print_signature_type (stream, &str, limit);
683 fprintf (stream, "<junk:");
684 jcf_print_utf8 (stream, str, limit - str);
694 DEFUN(print_exception_table, (jcf, entries, count),
695 JCF *jcf AND const unsigned char *entries AND int count)
697 /* Print exception table. */
701 const unsigned char *ptr = entries;
702 fprintf (out, "Exceptions (count: %d):\n", i);
703 for (; --i >= 0; ptr+= 8)
705 int start_pc = GET_u2 (ptr);
706 int end_pc = GET_u2 (ptr+2);
707 int handler_pc = GET_u2 (ptr+4);
708 int catch_type = GET_u2 (ptr+6);
709 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
710 start_pc, end_pc, handler_pc, catch_type);
712 fputs (" /* finally */", out);
716 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
723 #include "jcf-reader.c"
726 DEFUN(process_class, (jcf),
730 if (jcf_parse_preamble (jcf) != 0)
731 fprintf (stderr, "Not a valid Java .class file.\n");
733 /* Parse and possibly print constant pool */
734 code = jcf_parse_constant_pool (jcf);
737 fprintf (stderr, "error while parsing constant pool\n");
738 exit (FATAL_EXIT_CODE);
740 code = verify_constant_pool (jcf);
743 fprintf (stderr, "error in constant pool entry #%d\n", code);
744 exit (FATAL_EXIT_CODE);
746 if (flag_print_constant_pool)
747 print_constant_pool (jcf);
749 jcf_parse_class (jcf);
750 code = jcf_parse_fields (jcf);
753 fprintf (stderr, "error while parsing fields\n");
754 exit (FATAL_EXIT_CODE);
756 code = jcf_parse_methods (jcf);
759 fprintf (stderr, "error while parsing methods\n");
760 exit (FATAL_EXIT_CODE);
762 code = jcf_parse_final_attributes (jcf);
765 fprintf (stderr, "error while parsing final attributes\n");
766 exit (FATAL_EXIT_CODE);
768 jcf->filename = NULL;
773 /* This is used to mark options with no short value. */
774 #define LONG_OPT(Num) ((Num) + 128)
776 #define OPT_classpath LONG_OPT (0)
777 #define OPT_CLASSPATH LONG_OPT (1)
778 #define OPT_HELP LONG_OPT (2)
779 #define OPT_VERSION LONG_OPT (3)
780 #define OPT_JAVAP LONG_OPT (4)
782 static const struct option options[] =
784 { "classpath", required_argument, NULL, OPT_classpath },
785 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
786 { "help", no_argument, NULL, OPT_HELP },
787 { "verbose", no_argument, NULL, 'v' },
788 { "version", no_argument, NULL, OPT_VERSION },
789 { "javap", no_argument, NULL, OPT_JAVAP },
790 { "print-main", no_argument, &flag_print_main, 1 },
791 { NULL, no_argument, NULL, 0 }
797 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
804 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
805 printf ("Display contents of a class file in readable form.\n\n");
806 printf (" -c Disassemble method bodies\n");
807 printf (" --javap Generate output in `javap' format\n");
809 printf (" --classpath PATH Set path to find .class files\n");
810 printf (" --CLASSPATH PATH Set path to find .class files\n");
811 printf (" -IDIR Append directory to class path\n");
812 printf (" -o FILE Set output file name\n");
814 printf (" --help Print this help, then exit\n");
815 printf (" --version Print version number, then exit\n");
816 printf (" -v, --verbose Print extra information while running\n");
818 printf ("For bug reporting instructions, please see:\n");
819 printf ("%s.\n", GCCBUGURL);
826 printf ("jcf-dump (GCC) %s\n\n", version_string);
827 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
828 printf ("This is free software; see the source for copying conditions. There is NO\n");
829 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
834 DEFUN(main, (argc, argv),
835 int argc AND char** argv)
842 fprintf (stderr, "jcf-dump: no classes specified\n");
848 /* We use getopt_long_only to allow single `-' long options. For
849 some of our options this is more natural. */
850 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
855 /* Already handled. */
859 output_file = optarg;
863 jcf_path_include_arg (optarg);
871 flag_disassemble_methods = 1;
875 jcf_path_classpath_arg (optarg);
879 jcf_path_CLASSPATH_arg (optarg);
891 flag_javap_compatible++;
892 flag_print_constant_pool = 0;
893 flag_print_attributes = 0;
903 fprintf (stderr, "jcf-dump: no classes specified\n");
907 jcf_path_seal (verbose);
911 flag_print_fields = 0;
912 flag_print_methods = 0;
913 flag_print_constant_pool = 0;
914 flag_print_attributes = 0;
915 flag_print_class_info = 0;
920 out = fopen (output_file, "w");
923 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
924 return FATAL_EXIT_CODE;
932 fprintf (out, "Reading .class from <standard input>.\n");
934 open_class ("<stdio>", jcf, stdin, NULL);
936 open_class ("<stdio>", jcf, 0, NULL);
942 for (argi = optind; argi < argc; argi++)
944 char *arg = argv[argi];
945 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
946 if (class_filename == NULL)
947 class_filename = find_classfile (arg, jcf, NULL);
948 if (class_filename == NULL)
950 perror ("Could not find class");
951 return FATAL_EXIT_CODE;
954 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
956 long compressed_size, member_size;
957 int compression_method, filename_length, extra_length;
958 int general_purpose_bits;
959 const char *filename;
961 if (flag_print_class_info)
962 fprintf (out, "Reading classes from archive %s.\n",
967 jcf_filbuf_t save_filbuf = jcf->filbuf;
968 long magic = JCF_readu4_le (jcf);
969 if (magic == 0x02014b50 || magic == 0x06054b50)
970 break; /* got to central directory */
971 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
973 fprintf (stderr, "bad format of .zip/.jar archive\n");
974 return FATAL_EXIT_CODE;
978 general_purpose_bits = JCF_readu2_le (jcf);
979 compression_method = JCF_readu2_le (jcf);
981 compressed_size = JCF_readu4_le (jcf);
982 member_size = JCF_readu4_le (jcf);
983 filename_length = JCF_readu2_le (jcf);
984 extra_length = JCF_readu2_le (jcf);
985 total_length = filename_length + extra_length
987 if (jcf->read_end - jcf->read_ptr < total_length)
988 jcf_trim_old_input (jcf);
989 JCF_FILL (jcf, total_length);
990 filename = jcf->read_ptr;
991 JCF_SKIP (jcf, filename_length);
992 JCF_SKIP (jcf, extra_length);
993 if (filename_length > 0
994 && filename[filename_length-1] == '/')
996 if (flag_print_class_info)
997 fprintf (out, "[Skipping directory %.*s]\n",
998 filename_length, filename);
1001 else if (compression_method != 0)
1003 if (flag_print_class_info)
1004 fprintf (out, "[Skipping compressed file %.*s]\n",
1005 filename_length, filename);
1008 else if (member_size < 4
1009 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1011 if (flag_print_class_info)
1012 fprintf (out, "[Skipping non-.class member %.*s]\n",
1013 filename_length, filename);
1018 if (flag_print_class_info)
1019 fprintf (out, "Reading class member: %.*s.\n",
1020 filename_length, filename);
1024 JCF_SKIP (jcf, compressed_size);
1028 unsigned char *save_end;
1029 jcf->filbuf = jcf_unexpected_eof;
1030 save_end = jcf->read_end;
1031 jcf->read_end = jcf->read_ptr + compressed_size;
1032 process_class (jcf);
1033 jcf->filbuf = save_filbuf;
1034 jcf->read_end = save_end;
1040 if (flag_print_class_info)
1041 fprintf (out, "Reading .class from %s.\n", class_filename);
1042 process_class (jcf);
1048 return SUCCESS_EXIT_CODE;
1054 DEFUN(disassemble_method, (jcf, byte_ops, len),
1055 JCF* jcf AND const unsigned char *byte_ops AND int len)
1057 #undef AND /* Causes problems with opcodes for iand and land. */
1062 if (flag_disassemble_methods == 0)
1064 #define BCODE byte_ops
1065 for (PC = 0; PC < len;)
1070 switch (byte_ops[PC++])
1073 /* This is the actual code emitted for each of opcodes in javaops.def.
1074 The actual opcode-specific stuff is handled by the OPKIND macro.
1075 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1076 Those macros are defiend below. The OPKINDs that do not have any
1077 inline parameters (such as BINOP) and therefore do mot need anything
1078 else to me printed out just use an empty body. */
1080 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1082 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1083 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1084 fputc ('\n', out); \
1087 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1088 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1089 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1090 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1092 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1093 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1095 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1096 These all push a constant onto the opcode stack. */
1097 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1098 saw_index = 0, i = (OPERAND_VALUE); \
1099 if (oldpc+1 == PC) /* nothing */; \
1100 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1101 else fprintf (out, " %d", i);
1103 /* Print out operand (a local variable index) for LOAD opcodes.
1104 These all push local variable onto the opcode stack. */
1105 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1106 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1108 /* Handle STORE opcodes same as LOAD opcodes.
1109 These all store a value from the opcode stack in a local variable. */
1112 /* Handle more kind of opcodes. */
1113 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1114 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1115 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1116 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1117 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1118 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1119 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1121 /* Handle putfield and getfield opcodes, with static versions. */
1122 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1123 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1125 /* Print operand for invoke opcodes. */
1126 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1127 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1128 if (OPERAND_VALUE) /* for invokeinterface */ \
1129 { int nargs = IMMEDIATE_u1; PC++; \
1130 fprintf (out, " nargs:%d", nargs); }
1132 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1133 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1135 #define ARRAY(OPERAND_TYPE, SUBOP) \
1136 ARRAY_##SUBOP(OPERAND_TYPE)
1137 /* Handle sub-categories of ARRAY opcodes. */
1138 #define ARRAY_LOAD(TYPE) /* nothing */
1139 #define ARRAY_STORE(TYPE) /* nothing */
1140 #define ARRAY_LENGTH(TYPE) /* nothing */
1141 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1142 #define ARRAY_NEW_NUM \
1143 INT_temp = IMMEDIATE_u1; \
1144 { switch ((int) INT_temp) { \
1145 case 4: fputs (" boolean", out); break; \
1146 case 5: fputs (" char", out); break; \
1147 case 6: fputs (" float", out); break; \
1148 case 7: fputs (" double", out); break; \
1149 case 8: fputs (" byte", out); break; \
1150 case 9: fputs (" short", out); break; \
1151 case 10: fputs (" int", out); break; \
1152 case 11: fputs (" long", out); break; \
1153 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1156 #define ARRAY_NEW_PTR \
1157 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1159 #define ARRAY_NEW_MULTI \
1160 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1161 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1163 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1164 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1166 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1167 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1168 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1170 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1171 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1172 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1174 #undef RET /* Defined by config/i386/i386.h */
1175 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1176 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1178 fprintf (out, " %ld", (long) INT_temp);
1180 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1181 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1183 #define LOOKUP_SWITCH \
1184 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1185 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1186 while (--npairs >= 0) { \
1187 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1188 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1191 #define TABLE_SWITCH \
1192 { jint default_offset = IMMEDIATE_s4; \
1193 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1194 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1195 (long) low, (long) high, (long) default_offset+oldpc); \
1196 for (; low <= high; low++) { \
1197 jint offset = IMMEDIATE_s4; \
1198 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1201 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1202 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1204 #define SPECIAL_IINC(OPERAND_TYPE) \
1205 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1206 fprintf (out, " %d", i); \
1207 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1209 fprintf (out, " %d", i)
1211 #define SPECIAL_WIDE(OPERAND_TYPE) \
1214 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1215 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1216 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1217 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1219 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1220 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1222 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1223 TEST(OPERAND_TYPE, OPERAND_VALUE)
1225 #include "javaop.def"
1228 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1232 fprintf (out, " %ld", (long) INT_temp);
1238 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);