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, 2003, 2004
5 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
24 Java and all Java-based marks are trademarks or registered trademarks
25 of Sun Microsystems, Inc. in the United States and other countries.
26 The Free Software Foundation is independent of Sun Microsystems, Inc. */
28 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
31 jcf-dump is a program to print out the contents of class files.
32 Usage: jcf-dump [FLAGS] CLASS
34 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
35 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
36 + The name of a .zip or .jar file (which prints all the classes in the
41 Dis-assemble each method.
45 Print nothing if there is no valid "main" method;
46 otherwise, print only the class name.
48 Print output in the style of Sun's javap program. VERY UNFINISHED.
54 #include "coretypes.h"
61 #include "java-tree.h"
70 /* Name of output file, if NULL if stdout. */
71 char *output_file = NULL;
75 int flag_disassemble_methods = 0;
76 int flag_print_class_info = 1;
77 int flag_print_constant_pool = 1;
78 int flag_print_fields = 1;
79 int flag_print_methods = 1;
80 int flag_print_attributes = 1;
82 /* When nonzero, warn when source file is newer than matching class
86 /* Print names of classes that have a "main" method. */
87 int flag_print_main = 0;
89 /* Index in constant pool of this class. */
90 int this_class_index = 0;
92 int class_access_flags = 0;
94 /* Print in format similar to javap. VERY IMCOMPLETE. */
95 int flag_javap_compatible = 0;
97 static void print_access_flags (FILE *, uint16, char);
98 static void print_constant_terse (FILE*, JCF*, int, int);
99 static void print_constant (FILE *, JCF *, int, int);
100 static void print_constant_ref (FILE *, JCF *, int);
101 static void disassemble_method (JCF*, const unsigned char *, int);
102 static void print_name (FILE*, JCF*, int);
103 static void print_signature (FILE*, JCF*, int, int);
104 static int utf8_equal_string (struct JCF*, int, const char *);
105 static void usage (void) ATTRIBUTE_NORETURN;
106 static void help (void) ATTRIBUTE_NORETURN;
107 static void version (void) ATTRIBUTE_NORETURN;
108 static void process_class (struct JCF *);
109 static void print_constant_pool (struct JCF *);
110 static void print_exception_table (struct JCF *, const unsigned char *entries,
113 #define PRINT_SIGNATURE_RESULT_ONLY 1
114 #define PRINT_SIGNATURE_ARGS_ONLY 2
117 utf8_equal_string (JCF *jcf, int index, const char * value)
119 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
120 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
122 int len = strlen (value);
123 if (JPOOL_UTF_LENGTH (jcf, index) == len
124 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
130 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
131 this_class_index = 0; \
132 if (flag_print_class_info) \
134 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
135 (long) MAGIC, (long) MINOR, (long) MAJOR)
137 #define HANDLE_START_CONSTANT_POOL(COUNT) \
138 if (flag_print_constant_pool) \
139 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
141 #define HANDLE_SOURCEFILE(INDEX) \
142 { fprintf (out, "Attribute "); \
143 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
144 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
145 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
147 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
148 this_class_index = THIS; \
149 class_access_flags = ACCESS_FLAGS; \
150 if (flag_print_class_info) \
151 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
152 print_access_flags (out, ACCESS_FLAGS, 'c'); \
154 fprintf (out, "This class: "); \
155 if (flag_print_constant_pool) \
156 fprintf (out, "%d=", THIS); \
157 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
158 if (flag_print_constant_pool || SUPER != 0) \
159 fprintf (out, ", super: "); \
160 if (flag_print_constant_pool) \
162 fprintf (out, "%d", SUPER); \
167 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
168 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
171 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
172 (flag_print_attributes <= 0)
174 #define HANDLE_CLASS_INTERFACE(INDEX) \
175 if (flag_print_class_info) \
176 { fprintf (out, "- Implements: %d=", INDEX); \
177 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
180 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
181 if (flag_print_fields) \
182 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
184 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
185 if (flag_print_fields) \
186 { fprintf (out, "Field name:"); \
187 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
188 print_access_flags (out, ACCESS_FLAGS, 'f'); \
189 fprintf (out, " Signature: "); \
190 if (flag_print_constant_pool) \
191 fprintf (out, "%d=", SIGNATURE); \
192 print_signature (out, jcf, SIGNATURE, 0); \
193 fputc ('\n', out); } \
195 flag_print_attributes--;
197 #define HANDLE_END_FIELD() \
198 if (! flag_print_fields) \
199 flag_print_attributes++;
201 #define HANDLE_START_METHODS(METHODS_COUNT) \
202 if (flag_print_methods) \
203 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
205 flag_print_attributes--;
208 #define HANDLE_END_METHODS() \
209 if (! flag_print_methods) \
210 flag_print_attributes++;
212 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
214 if (flag_print_methods) \
216 if (flag_javap_compatible) \
218 fprintf (out, " "); \
219 print_access_flags (out, ACCESS_FLAGS, 'm'); \
221 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
223 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
224 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
229 fprintf (out, "\nMethod name:"); \
230 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
231 print_access_flags (out, ACCESS_FLAGS, 'm'); \
232 fprintf (out, " Signature: "); \
233 if (flag_print_constant_pool) \
234 fprintf (out, "%d=", SIGNATURE); \
235 print_signature (out, jcf, SIGNATURE, 0); \
239 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
240 && utf8_equal_string (jcf, NAME, "main") \
241 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
242 && this_class_index > 0 \
243 && (class_access_flags & ACC_PUBLIC)) \
245 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
250 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
251 ( fprintf (out, "Attribute "), \
252 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
253 fprintf (out, ", length:%ld", (long) LENGTH) )
255 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
256 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
257 fprintf (out, ", value: "), \
258 print_constant_ref (out, jcf, VALUE_INDEX), \
259 fprintf (out, "\n") )
261 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
262 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
263 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
264 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
265 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
267 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
268 print_exception_table (jcf, ENTRIES, COUNT)
270 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
271 { int n = (COUNT); int i; \
272 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
273 fprintf (out, ", count: %d\n", n); \
274 for (i = 0; i < n; i++) {\
275 int ex_index = JCF_readu2 (jcf); \
276 fprintf (out, "%3d: ", i); \
277 print_constant_ref (out, jcf, ex_index); \
278 fputc ('\n', out); } }
280 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
281 { int n = (COUNT); int i; \
282 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
283 fprintf (out, ", count: %d\n", n); \
284 for (i = 0; i < n; i++) {\
285 int start_pc = JCF_readu2 (jcf); \
286 int length = JCF_readu2 (jcf); \
287 int name_index = JCF_readu2 (jcf); \
288 int signature_index = JCF_readu2 (jcf); \
289 int slot = JCF_readu2 (jcf); \
290 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
291 print_name (out, jcf, name_index); \
292 fprintf (out, ", type: %d=", signature_index); \
293 print_signature (out, jcf, signature_index, 0); \
294 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
296 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
297 { int n = (COUNT); int i; \
298 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
299 fprintf (out, ", count: %d\n", n); \
300 if (flag_disassemble_methods) \
301 for (i = 0; i < n; i++) {\
302 int start_pc = JCF_readu2 (jcf); \
303 int line_number = JCF_readu2 (jcf); \
304 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
306 JCF_SKIP (jcf, 4 * n); }
308 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
310 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
313 uint16 inner_class_info_index = JCF_readu2 (jcf); \
314 uint16 outer_class_info_index = JCF_readu2 (jcf); \
315 uint16 inner_name_index = JCF_readu2 (jcf); \
316 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
318 if (flag_print_class_info) \
320 fprintf (out, "\n class: "); \
321 if (flag_print_constant_pool) \
322 fprintf (out, "%d=", inner_class_info_index); \
323 print_constant_terse (out, jcf, \
324 inner_class_info_index, CONSTANT_Class); \
325 fprintf (out, " (%d=", inner_name_index); \
326 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
327 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
328 print_access_flags (out, inner_class_access_flags, 'c'); \
329 fprintf (out, ", outer class: "); \
330 if (flag_print_constant_pool) \
331 fprintf (out, "%d=", outer_class_info_index); \
332 print_constant_terse (out, jcf, \
333 outer_class_info_index, CONSTANT_Class); \
336 if (flag_print_class_info) \
340 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
341 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
342 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
344 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
345 if (flag_print_attributes > 0) \
346 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
351 print_constant_ref (FILE *stream, JCF *jcf, int index)
353 fprintf (stream, "#%d=<", index);
354 if (index <= 0 || index >= JPOOL_SIZE(jcf))
355 fprintf (stream, "out of range");
357 print_constant (stream, jcf, index, 1);
358 fprintf (stream, ">");
361 /* Print the access flags given by FLAGS.
362 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
363 or 'm' (method flags). */
366 print_access_flags (FILE *stream, uint16 flags, char context)
368 if (flags & ACC_PUBLIC) fprintf (stream, " public");
369 if (flags & ACC_PRIVATE) fprintf (stream, " private");
370 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
371 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
372 if (flags & ACC_STATIC) fprintf (stream, " static");
373 if (flags & ACC_FINAL) fprintf (stream, " final");
374 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
375 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
376 if (flags & ACC_NATIVE) fprintf (stream, " native");
377 if (flags & ACC_SYNCHRONIZED)
380 fprintf (stream, " super");
382 fprintf (stream, " synchronized");
384 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
385 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
390 print_name (FILE* stream, JCF* jcf, int name_index)
392 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
393 fprintf (stream, "<not a UTF8 constant>");
395 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
396 JPOOL_UTF_LENGTH (jcf, name_index));
399 /* If the type of the constant at INDEX matches EXPECTED,
400 print it tersely, otherwise more verbosely. */
403 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
405 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
406 fprintf (out, "<constant pool index %d not in range>", index);
407 else if (JPOOL_TAG (jcf, index) != expected)
409 fprintf (out, "<Unexpected constant type ");
410 print_constant (out, jcf, index, 1);
414 print_constant (out, jcf, index, 0);
417 /* Print the constant at INDEX in JCF's constant pool.
418 If verbosity==0, print very tersely (no extraneous text).
419 If verbosity==1, prefix the type of the constant.
420 If verbosity==2, add more descriptive text. */
423 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
428 int kind = JPOOL_TAG (jcf, index);
432 n = JPOOL_USHORT1 (jcf, index);
436 fprintf (out, "Class name: %d=", n);
438 fprintf (out, "Class ");
440 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
441 fprintf (out, "<out of range>");
442 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
444 int len = JPOOL_UTF_LENGTH (jcf, n);
445 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
448 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
450 case CONSTANT_Fieldref:
451 str = "Field"; goto field_or_method;
452 case CONSTANT_Methodref:
453 str = "Method"; goto field_or_method;
454 case CONSTANT_InterfaceMethodref:
455 str = "InterfaceMethod"; goto field_or_method;
458 uint16 tclass = JPOOL_USHORT1 (jcf, index);
459 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
461 fprintf (out, "%sref class: %d=", str, tclass);
462 else if (verbosity > 0)
463 fprintf (out, "%s ", str);
464 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
468 fprintf (out, " name_and_type: %d=<", name_and_type);
469 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
474 case CONSTANT_String:
475 j = JPOOL_USHORT1 (jcf, index);
479 fprintf (out, "String %d=", j);
481 fprintf (out, "String ");
483 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
485 case CONSTANT_Integer:
487 fprintf (out, "Integer ");
488 num = JPOOL_INT (jcf, index);
492 fprintf (out, "Long ");
493 num = JPOOL_LONG (jcf, index);
498 format_int (buffer, num, 10);
499 fprintf (out, "%s", buffer);
502 format_uint (buffer, (uint64)num, 16);
503 fprintf (out, "=0x%s", buffer);
509 jfloat fnum = JPOOL_FLOAT (jcf, index);
512 fputs ("Float ", out);
517 if (JFLOAT_FINITE (fnum))
520 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
522 uint32 mantissa = fnum.mantissa;
523 if (fnum.exponent == 0)
527 /* Normal; add the implicit bit. */
528 mantissa |= ((uint32)1 << 23);
530 f = frexp (mantissa, &dummy);
531 f = ldexp (f, exponent + 1);
532 fprintf (out, "%.10g", f);
536 if (fnum.mantissa == 0)
538 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
539 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
541 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
545 fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
549 case CONSTANT_Double:
551 jdouble dnum = JPOOL_DOUBLE (jcf, index);
554 fputs ("Double ", out);
559 if (JDOUBLE_FINITE (dnum))
562 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
564 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
566 if (dnum.exponent == 0)
570 /* Normal; add the implicit bit. */
571 mantissa |= ((uint64)1 << 52);
573 d = frexp (mantissa, &dummy);
574 d = ldexp (d, exponent + 1);
575 fprintf (out, "%.20g", d);
579 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
580 mantissa = (mantissa << 32) + dnum.mantissa1;
582 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
584 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
585 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
587 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
592 hi = JPOOL_UINT (jcf, index);
593 lo = JPOOL_UINT (jcf, index + 1);
594 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
598 case CONSTANT_NameAndType:
600 uint16 name = JPOOL_USHORT1 (jcf, index);
601 uint16 sig = JPOOL_USHORT2 (jcf, index);
605 fprintf (out, "NameAndType name: %d=", name);
607 fprintf (out, "NameAndType ");
609 print_name (out, jcf, name);
613 fprintf (out, ", signature: %d=", sig);
614 print_signature (out, jcf, sig, 0);
619 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
620 int length = JPOOL_UTF_LENGTH (jcf, index);
622 { /* Print as 8-bit bytes. */
623 fputs ("Utf8: \"", out);
624 while (--length >= 0)
625 jcf_print_char (out, *str++);
628 { /* Print as Unicode. */
630 jcf_print_utf8 (out, str, length);
636 fprintf (out, "(Unknown constant type %d)", kind);
641 print_constant_pool (JCF *jcf)
644 for (i = 1; i < JPOOL_SIZE(jcf); i++)
646 int kind = JPOOL_TAG (jcf, i);
647 fprintf (out, "#%d: ", i);
648 print_constant (out, jcf, i, 2);
650 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
651 i++; /* These take up two slots in the constant table */
656 print_signature_type (FILE* stream, const unsigned char **ptr,
657 const unsigned char *limit)
666 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
668 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
670 print_signature_type (stream, ptr, limit);
671 if (array_size == -1)
672 fprintf (stream, "[]");
674 fprintf (stream, "[%d]", array_size);
679 fputc (*(*ptr)++, stream);
680 for (; **ptr != ')' && *ptr < limit; nargs++)
684 print_signature_type (stream, ptr, limit);
688 fputc (*(*ptr)++, stream);
689 print_signature_type (stream, ptr, limit);
692 fprintf (stream, "???");
696 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
697 case 'C': fprintf (stream, "char"); (*ptr)++; break;
698 case 'D': fprintf (stream, "double"); (*ptr)++; break;
699 case 'F': fprintf (stream, "float"); (*ptr)++; break;
700 case 'S': fprintf (stream, "short"); (*ptr)++; break;
701 case 'I': fprintf (stream, "int"); (*ptr)++; break;
702 case 'J': fprintf (stream, "long"); (*ptr)++; break;
703 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
704 case 'V': fprintf (stream, "void"); (*ptr)++; break;
707 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
708 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
713 jcf_print_char (stream, *(*ptr)++);
718 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
720 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
721 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
724 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
725 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
726 const unsigned char *limit;
727 limit = str + length;
729 fprintf (stream, "<empty signature string>");
732 if (options & PRINT_SIGNATURE_RESULT_ONLY)
734 while (str < limit && *str++ != ')') ;
736 if (options & PRINT_SIGNATURE_ARGS_ONLY)
740 while (str < limit && *str != ')')
742 print_signature_type (stream, &str, limit);
744 fputs (", ", stream);
750 print_signature_type (stream, &str, limit);
753 fprintf (stream, "<junk:");
754 jcf_print_utf8 (stream, str, limit - str);
764 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
766 /* Print exception table. */
770 const unsigned char *ptr = entries;
771 fprintf (out, "Exceptions (count: %d):\n", i);
772 for (; --i >= 0; ptr+= 8)
774 int start_pc = GET_u2 (ptr);
775 int end_pc = GET_u2 (ptr+2);
776 int handler_pc = GET_u2 (ptr+4);
777 int catch_type = GET_u2 (ptr+6);
778 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
779 start_pc, end_pc, handler_pc, catch_type);
781 fputs (" /* finally */", out);
785 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
792 #include "jcf-reader.c"
795 process_class (JCF *jcf)
798 if (jcf_parse_preamble (jcf) != 0)
799 fprintf (stderr, _("Not a valid Java .class file.\n"));
801 /* Parse and possibly print constant pool */
802 code = jcf_parse_constant_pool (jcf);
805 fprintf (stderr, _("error while parsing constant pool\n"));
806 exit (FATAL_EXIT_CODE);
808 code = verify_constant_pool (jcf);
811 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
812 exit (FATAL_EXIT_CODE);
814 if (flag_print_constant_pool)
815 print_constant_pool (jcf);
817 jcf_parse_class (jcf);
818 code = jcf_parse_fields (jcf);
821 fprintf (stderr, _("error while parsing fields\n"));
822 exit (FATAL_EXIT_CODE);
824 code = jcf_parse_methods (jcf);
827 fprintf (stderr, _("error while parsing methods\n"));
828 exit (FATAL_EXIT_CODE);
830 code = jcf_parse_final_attributes (jcf);
833 fprintf (stderr, _("error while parsing final attributes\n"));
834 exit (FATAL_EXIT_CODE);
836 jcf->filename = NULL;
841 /* This is used to mark options with no short value. */
842 #define LONG_OPT(Num) ((Num) + 128)
844 #define OPT_classpath LONG_OPT (0)
845 #define OPT_CLASSPATH OPT_classpath
846 #define OPT_bootclasspath LONG_OPT (1)
847 #define OPT_extdirs LONG_OPT (2)
848 #define OPT_HELP LONG_OPT (3)
849 #define OPT_VERSION LONG_OPT (4)
850 #define OPT_JAVAP LONG_OPT (5)
852 static const struct option options[] =
854 { "classpath", required_argument, NULL, OPT_classpath },
855 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
856 { "extdirs", required_argument, NULL, OPT_extdirs },
857 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
858 { "help", no_argument, NULL, OPT_HELP },
859 { "verbose", no_argument, NULL, 'v' },
860 { "version", no_argument, NULL, OPT_VERSION },
861 { "javap", no_argument, NULL, OPT_JAVAP },
862 { "print-main", no_argument, &flag_print_main, 1 },
863 { NULL, no_argument, NULL, 0 }
869 fprintf (stderr, _("Try `jcf-dump --help' for more information.\n"));
876 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
877 printf (_("Display contents of a class file in readable form.\n\n"));
878 printf (_(" -c Disassemble method bodies\n"));
879 printf (_(" --javap Generate output in `javap' format\n"));
881 printf (_(" --classpath PATH Set path to find .class files\n"));
882 printf (_(" -IDIR Append directory to class path\n"));
883 printf (_(" --bootclasspath PATH Override built-in class path\n"));
884 printf (_(" --extdirs PATH Set extensions directory path\n"));
885 printf (_(" -o FILE Set output file name\n"));
887 printf (_(" --help Print this help, then exit\n"));
888 printf (_(" --version Print version number, then exit\n"));
889 printf (_(" -v, --verbose Print extra information while running\n"));
891 printf (_("For bug reporting instructions, please see:\n"
892 "%s.\n"), bug_report_url);
899 printf ("jcf-dump (GCC) %s\n\n", version_string);
900 printf ("Copyright %s 2004 Free Software Foundation, Inc.\n", _("(C)"));
901 printf (_("This is free software; see the source for copying conditions. There is NO\n"
902 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
907 main (int argc, char** argv)
916 fprintf (stderr, _("jcf-dump: no classes specified\n"));
922 /* We use getopt_long_only to allow single `-' long options. For
923 some of our options this is more natural. */
924 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
929 /* Already handled. */
933 output_file = optarg;
937 jcf_path_include_arg (optarg);
945 flag_disassemble_methods = 1;
949 jcf_path_classpath_arg (optarg);
952 case OPT_bootclasspath:
953 jcf_path_bootclasspath_arg (optarg);
957 jcf_path_extdirs_arg (optarg);
969 flag_javap_compatible++;
970 flag_print_constant_pool = 0;
971 flag_print_attributes = 0;
981 fprintf (stderr, _("jcf-dump: no classes specified\n"));
985 jcf_path_seal (verbose);
989 flag_print_fields = 0;
990 flag_print_methods = 0;
991 flag_print_constant_pool = 0;
992 flag_print_attributes = 0;
993 flag_print_class_info = 0;
998 out = fopen (output_file, "w");
1001 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1002 return FATAL_EXIT_CODE;
1010 fprintf (out, "Reading .class from <standard input>.\n");
1011 open_class ("<stdio>", jcf, 0, NULL);
1012 process_class (jcf);
1016 for (argi = optind; argi < argc; argi++)
1018 char *arg = argv[argi];
1019 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1020 if (class_filename == NULL)
1021 class_filename = find_classfile (arg, jcf, NULL);
1022 if (class_filename == NULL)
1024 perror ("Could not find class");
1025 return FATAL_EXIT_CODE;
1028 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1030 long compressed_size, member_size;
1031 int compression_method, filename_length, extra_length;
1032 int general_purpose_bits;
1033 const char *filename;
1035 if (flag_print_class_info)
1036 fprintf (out, "Reading classes from archive %s.\n",
1041 jcf_filbuf_t save_filbuf = jcf->filbuf;
1042 long magic = JCF_readu4_le (jcf);
1043 if (magic == 0x02014b50 || magic == 0x06054b50)
1044 break; /* got to central directory */
1045 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1047 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1048 return FATAL_EXIT_CODE;
1052 general_purpose_bits = JCF_readu2_le (jcf);
1053 compression_method = JCF_readu2_le (jcf);
1055 compressed_size = JCF_readu4_le (jcf);
1056 member_size = JCF_readu4_le (jcf);
1057 filename_length = JCF_readu2_le (jcf);
1058 extra_length = JCF_readu2_le (jcf);
1059 total_length = filename_length + extra_length
1061 if (jcf->read_end - jcf->read_ptr < total_length)
1062 jcf_trim_old_input (jcf);
1063 JCF_FILL (jcf, total_length);
1064 filename = jcf->read_ptr;
1065 JCF_SKIP (jcf, filename_length);
1066 JCF_SKIP (jcf, extra_length);
1067 if (filename_length > 0
1068 && filename[filename_length-1] == '/')
1070 if (flag_print_class_info)
1071 fprintf (out, "[Skipping directory %.*s]\n",
1072 filename_length, filename);
1075 else if (compression_method != 0)
1077 if (flag_print_class_info)
1078 fprintf (out, "[Skipping compressed file %.*s]\n",
1079 filename_length, filename);
1082 else if (member_size < 4
1083 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1085 if (flag_print_class_info)
1086 fprintf (out, "[Skipping non-.class member %.*s]\n",
1087 filename_length, filename);
1092 if (flag_print_class_info)
1093 fprintf (out, "Reading class member: %.*s.\n",
1094 filename_length, filename);
1098 JCF_SKIP (jcf, compressed_size);
1102 unsigned char *save_end;
1103 jcf->filbuf = jcf_unexpected_eof;
1104 save_end = jcf->read_end;
1105 jcf->read_end = jcf->read_ptr + compressed_size;
1106 process_class (jcf);
1107 jcf->filbuf = save_filbuf;
1108 jcf->read_end = save_end;
1114 if (flag_print_class_info)
1115 fprintf (out, "Reading .class from %s.\n", class_filename);
1116 process_class (jcf);
1122 return SUCCESS_EXIT_CODE;
1128 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1134 if (flag_disassemble_methods == 0)
1136 #define BCODE byte_ops
1137 for (PC = 0; PC < len;)
1142 switch (byte_ops[PC++])
1145 /* This is the actual code emitted for each of opcodes in javaops.def.
1146 The actual opcode-specific stuff is handled by the OPKIND macro.
1147 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1148 Those macros are defined below. The OPKINDs that do not have any
1149 inline parameters (such as BINOP) and therefore do mot need anything
1150 else to me printed out just use an empty body. */
1152 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1154 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1155 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1156 fputc ('\n', out); \
1159 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1160 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1161 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1162 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1164 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1165 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1)) : 1)
1167 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1168 These all push a constant onto the opcode stack. */
1169 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1170 saw_index = 0, i = (OPERAND_VALUE); \
1171 if (oldpc+1 == PC) /* nothing */; \
1172 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1173 else fprintf (out, " %d", i);
1175 /* Print out operand (a local variable index) for LOAD opcodes.
1176 These all push local variable onto the opcode stack. */
1177 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1178 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1180 /* Handle STORE opcodes same as LOAD opcodes.
1181 These all store a value from the opcode stack in a local variable. */
1184 /* Handle more kind of opcodes. */
1185 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1186 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1187 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1188 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1189 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1190 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1191 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1193 /* Handle putfield and getfield opcodes, with static versions. */
1194 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1195 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1197 /* Print operand for invoke opcodes. */
1198 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1199 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1200 if (OPERAND_VALUE) /* for invokeinterface */ \
1201 { int nargs = IMMEDIATE_u1; PC++; \
1202 fprintf (out, " nargs:%d", nargs); }
1204 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1205 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1207 #define ARRAY(OPERAND_TYPE, SUBOP) \
1208 ARRAY_##SUBOP(OPERAND_TYPE)
1209 /* Handle sub-categories of ARRAY opcodes. */
1210 #define ARRAY_LOAD(TYPE) /* nothing */
1211 #define ARRAY_STORE(TYPE) /* nothing */
1212 #define ARRAY_LENGTH(TYPE) /* nothing */
1213 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1214 #define ARRAY_NEW_NUM \
1215 INT_temp = IMMEDIATE_u1; \
1216 { switch ((int) INT_temp) { \
1217 case 4: fputs (" boolean", out); break; \
1218 case 5: fputs (" char", out); break; \
1219 case 6: fputs (" float", out); break; \
1220 case 7: fputs (" double", out); break; \
1221 case 8: fputs (" byte", out); break; \
1222 case 9: fputs (" short", out); break; \
1223 case 10: fputs (" int", out); break; \
1224 case 11: fputs (" long", out); break; \
1225 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1228 #define ARRAY_NEW_PTR \
1229 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1231 #define ARRAY_NEW_MULTI \
1232 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1233 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1235 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1236 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1238 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1239 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1240 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1242 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1243 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1244 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1246 #undef RET /* Defined by config/i386/i386.h */
1247 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1248 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1250 fprintf (out, " %ld", (long) INT_temp);
1252 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1253 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1255 #define LOOKUP_SWITCH \
1256 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1257 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1258 while (--npairs >= 0) { \
1259 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1260 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1263 #define TABLE_SWITCH \
1264 { jint default_offset = IMMEDIATE_s4; \
1265 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1266 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1267 (long) low, (long) high, (long) default_offset+oldpc); \
1268 for (; low <= high; low++) { \
1269 jint offset = IMMEDIATE_s4; \
1270 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1273 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1274 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1276 #define SPECIAL_IINC(OPERAND_TYPE) \
1277 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1278 fprintf (out, " %d", i); \
1279 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1281 fprintf (out, " %d", i)
1283 #define SPECIAL_WIDE(OPERAND_TYPE) \
1286 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1287 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1288 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1289 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1291 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1292 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1294 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1295 TEST(OPERAND_TYPE, OPERAND_VALUE)
1297 #include "javaop.def"
1300 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1304 fprintf (out, " %ld", (long) INT_temp);
1310 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);