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 OPT_classpath
778 #define OPT_bootclasspath LONG_OPT (1)
779 #define OPT_extdirs LONG_OPT (2)
780 #define OPT_HELP LONG_OPT (3)
781 #define OPT_VERSION LONG_OPT (4)
782 #define OPT_JAVAP LONG_OPT (5)
784 static const struct option options[] =
786 { "classpath", required_argument, NULL, OPT_classpath },
787 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
788 { "extdirs", required_argument, NULL, OPT_extdirs },
789 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
790 { "help", no_argument, NULL, OPT_HELP },
791 { "verbose", no_argument, NULL, 'v' },
792 { "version", no_argument, NULL, OPT_VERSION },
793 { "javap", no_argument, NULL, OPT_JAVAP },
794 { "print-main", no_argument, &flag_print_main, 1 },
795 { NULL, no_argument, NULL, 0 }
801 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
808 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
809 printf ("Display contents of a class file in readable form.\n\n");
810 printf (" -c Disassemble method bodies\n");
811 printf (" --javap Generate output in `javap' format\n");
813 printf (" --classpath PATH Set path to find .class files\n");
814 printf (" -IDIR Append directory to class path\n");
815 printf (" --bootclasspath PATH Override built-in class path\n");
816 printf (" --extdirs PATH Set extensions directory path\n");
817 printf (" -o FILE Set output file name\n");
819 printf (" --help Print this help, then exit\n");
820 printf (" --version Print version number, then exit\n");
821 printf (" -v, --verbose Print extra information while running\n");
823 printf ("For bug reporting instructions, please see:\n");
824 printf ("%s.\n", GCCBUGURL);
831 printf ("jcf-dump (GCC) %s\n\n", version_string);
832 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
833 printf ("This is free software; see the source for copying conditions. There is NO\n");
834 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
839 DEFUN(main, (argc, argv),
840 int argc AND char** argv)
847 fprintf (stderr, "jcf-dump: no classes specified\n");
853 /* We use getopt_long_only to allow single `-' long options. For
854 some of our options this is more natural. */
855 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
860 /* Already handled. */
864 output_file = optarg;
868 jcf_path_include_arg (optarg);
876 flag_disassemble_methods = 1;
880 jcf_path_classpath_arg (optarg);
883 case OPT_bootclasspath:
884 jcf_path_bootclasspath_arg (optarg);
888 jcf_path_extdirs_arg (optarg);
900 flag_javap_compatible++;
901 flag_print_constant_pool = 0;
902 flag_print_attributes = 0;
912 fprintf (stderr, "jcf-dump: no classes specified\n");
916 jcf_path_seal (verbose);
920 flag_print_fields = 0;
921 flag_print_methods = 0;
922 flag_print_constant_pool = 0;
923 flag_print_attributes = 0;
924 flag_print_class_info = 0;
929 out = fopen (output_file, "w");
932 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
933 return FATAL_EXIT_CODE;
941 fprintf (out, "Reading .class from <standard input>.\n");
942 open_class ("<stdio>", jcf, 0, NULL);
947 for (argi = optind; argi < argc; argi++)
949 char *arg = argv[argi];
950 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
951 if (class_filename == NULL)
952 class_filename = find_classfile (arg, jcf, NULL);
953 if (class_filename == NULL)
955 perror ("Could not find class");
956 return FATAL_EXIT_CODE;
959 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
961 long compressed_size, member_size;
962 int compression_method, filename_length, extra_length;
963 int general_purpose_bits;
964 const char *filename;
966 if (flag_print_class_info)
967 fprintf (out, "Reading classes from archive %s.\n",
972 jcf_filbuf_t save_filbuf = jcf->filbuf;
973 long magic = JCF_readu4_le (jcf);
974 if (magic == 0x02014b50 || magic == 0x06054b50)
975 break; /* got to central directory */
976 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
978 fprintf (stderr, "bad format of .zip/.jar archive\n");
979 return FATAL_EXIT_CODE;
983 general_purpose_bits = JCF_readu2_le (jcf);
984 compression_method = JCF_readu2_le (jcf);
986 compressed_size = JCF_readu4_le (jcf);
987 member_size = JCF_readu4_le (jcf);
988 filename_length = JCF_readu2_le (jcf);
989 extra_length = JCF_readu2_le (jcf);
990 total_length = filename_length + extra_length
992 if (jcf->read_end - jcf->read_ptr < total_length)
993 jcf_trim_old_input (jcf);
994 JCF_FILL (jcf, total_length);
995 filename = jcf->read_ptr;
996 JCF_SKIP (jcf, filename_length);
997 JCF_SKIP (jcf, extra_length);
998 if (filename_length > 0
999 && filename[filename_length-1] == '/')
1001 if (flag_print_class_info)
1002 fprintf (out, "[Skipping directory %.*s]\n",
1003 filename_length, filename);
1006 else if (compression_method != 0)
1008 if (flag_print_class_info)
1009 fprintf (out, "[Skipping compressed file %.*s]\n",
1010 filename_length, filename);
1013 else if (member_size < 4
1014 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1016 if (flag_print_class_info)
1017 fprintf (out, "[Skipping non-.class member %.*s]\n",
1018 filename_length, filename);
1023 if (flag_print_class_info)
1024 fprintf (out, "Reading class member: %.*s.\n",
1025 filename_length, filename);
1029 JCF_SKIP (jcf, compressed_size);
1033 unsigned char *save_end;
1034 jcf->filbuf = jcf_unexpected_eof;
1035 save_end = jcf->read_end;
1036 jcf->read_end = jcf->read_ptr + compressed_size;
1037 process_class (jcf);
1038 jcf->filbuf = save_filbuf;
1039 jcf->read_end = save_end;
1045 if (flag_print_class_info)
1046 fprintf (out, "Reading .class from %s.\n", class_filename);
1047 process_class (jcf);
1053 return SUCCESS_EXIT_CODE;
1059 DEFUN(disassemble_method, (jcf, byte_ops, len),
1060 JCF* jcf AND const unsigned char *byte_ops AND int len)
1062 #undef AND /* Causes problems with opcodes for iand and land. */
1067 if (flag_disassemble_methods == 0)
1069 #define BCODE byte_ops
1070 for (PC = 0; PC < len;)
1075 switch (byte_ops[PC++])
1078 /* This is the actual code emitted for each of opcodes in javaops.def.
1079 The actual opcode-specific stuff is handled by the OPKIND macro.
1080 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1081 Those macros are defiend below. The OPKINDs that do not have any
1082 inline parameters (such as BINOP) and therefore do mot need anything
1083 else to me printed out just use an empty body. */
1085 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1087 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1088 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1089 fputc ('\n', out); \
1092 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1093 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1094 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1095 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1097 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1098 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1100 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1101 These all push a constant onto the opcode stack. */
1102 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1103 saw_index = 0, i = (OPERAND_VALUE); \
1104 if (oldpc+1 == PC) /* nothing */; \
1105 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1106 else fprintf (out, " %d", i);
1108 /* Print out operand (a local variable index) for LOAD opcodes.
1109 These all push local variable onto the opcode stack. */
1110 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1111 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1113 /* Handle STORE opcodes same as LOAD opcodes.
1114 These all store a value from the opcode stack in a local variable. */
1117 /* Handle more kind of opcodes. */
1118 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1119 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1120 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1121 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1122 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1123 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1124 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1126 /* Handle putfield and getfield opcodes, with static versions. */
1127 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1128 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1130 /* Print operand for invoke opcodes. */
1131 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1132 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1133 if (OPERAND_VALUE) /* for invokeinterface */ \
1134 { int nargs = IMMEDIATE_u1; PC++; \
1135 fprintf (out, " nargs:%d", nargs); }
1137 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1138 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1140 #define ARRAY(OPERAND_TYPE, SUBOP) \
1141 ARRAY_##SUBOP(OPERAND_TYPE)
1142 /* Handle sub-categories of ARRAY opcodes. */
1143 #define ARRAY_LOAD(TYPE) /* nothing */
1144 #define ARRAY_STORE(TYPE) /* nothing */
1145 #define ARRAY_LENGTH(TYPE) /* nothing */
1146 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1147 #define ARRAY_NEW_NUM \
1148 INT_temp = IMMEDIATE_u1; \
1149 { switch ((int) INT_temp) { \
1150 case 4: fputs (" boolean", out); break; \
1151 case 5: fputs (" char", out); break; \
1152 case 6: fputs (" float", out); break; \
1153 case 7: fputs (" double", out); break; \
1154 case 8: fputs (" byte", out); break; \
1155 case 9: fputs (" short", out); break; \
1156 case 10: fputs (" int", out); break; \
1157 case 11: fputs (" long", out); break; \
1158 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1161 #define ARRAY_NEW_PTR \
1162 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1164 #define ARRAY_NEW_MULTI \
1165 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1166 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1168 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1169 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1171 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1172 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1173 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1175 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1176 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1177 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1179 #undef RET /* Defined by config/i386/i386.h */
1180 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1181 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1183 fprintf (out, " %ld", (long) INT_temp);
1185 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1186 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1188 #define LOOKUP_SWITCH \
1189 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1190 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1191 while (--npairs >= 0) { \
1192 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1193 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1196 #define TABLE_SWITCH \
1197 { jint default_offset = IMMEDIATE_s4; \
1198 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1199 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1200 (long) low, (long) high, (long) default_offset+oldpc); \
1201 for (; low <= high; low++) { \
1202 jint offset = IMMEDIATE_s4; \
1203 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1206 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1207 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1209 #define SPECIAL_IINC(OPERAND_TYPE) \
1210 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1211 fprintf (out, " %d", i); \
1212 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1214 fprintf (out, " %d", i)
1216 #define SPECIAL_WIDE(OPERAND_TYPE) \
1219 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1220 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1221 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1222 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1224 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1225 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1227 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1228 TEST(OPERAND_TYPE, OPERAND_VALUE)
1230 #include "javaop.def"
1233 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1237 fprintf (out, " %ld", (long) INT_temp);
1243 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);