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, 2005
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 = 0;
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 INCOMPLETE. */
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 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
156 if (flag_print_constant_pool || SUPER != 0) \
157 fprintf (out, ", super: "); \
158 if (flag_print_constant_pool) \
160 fprintf (out, "%d", SUPER); \
165 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
166 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
169 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
170 (flag_print_attributes <= 0)
172 #define HANDLE_CLASS_INTERFACE(INDEX) \
173 if (flag_print_class_info) \
174 { fprintf (out, "- Implements: "); \
175 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
178 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
179 if (flag_print_fields) \
180 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
182 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
183 if (flag_print_fields) \
184 { fprintf (out, "Field name:"); \
185 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
186 print_access_flags (out, ACCESS_FLAGS, 'f'); \
187 fprintf (out, " Signature: "); \
188 if (flag_print_constant_pool) \
189 fprintf (out, "%d=", SIGNATURE); \
190 print_signature (out, jcf, SIGNATURE, 0); \
191 fputc ('\n', out); } \
193 flag_print_attributes--;
195 #define HANDLE_END_FIELD() \
196 if (! flag_print_fields) \
197 flag_print_attributes++;
199 #define HANDLE_START_METHODS(METHODS_COUNT) \
200 if (flag_print_methods) \
201 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
203 flag_print_attributes--;
206 #define HANDLE_END_METHODS() \
207 if (! flag_print_methods) \
208 flag_print_attributes++;
210 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
212 if (flag_print_methods) \
214 if (flag_javap_compatible) \
216 fprintf (out, " "); \
217 print_access_flags (out, ACCESS_FLAGS, 'm'); \
219 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
221 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
222 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
227 fprintf (out, "\nMethod name:"); \
228 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
229 print_access_flags (out, ACCESS_FLAGS, 'm'); \
230 fprintf (out, " Signature: "); \
231 if (flag_print_constant_pool) \
232 fprintf (out, "%d=", SIGNATURE); \
233 print_signature (out, jcf, SIGNATURE, 0); \
237 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
238 && utf8_equal_string (jcf, NAME, "main") \
239 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
240 && this_class_index > 0 \
241 && (class_access_flags & ACC_PUBLIC)) \
243 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
248 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
249 ( fprintf (out, "Attribute "), \
250 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
251 fprintf (out, ", length:%ld", (long) LENGTH) )
253 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
254 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
255 fprintf (out, ", value: "), \
256 print_constant_ref (out, jcf, VALUE_INDEX), \
257 fprintf (out, "\n") )
259 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
260 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
261 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
262 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
263 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
265 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
266 print_exception_table (jcf, ENTRIES, COUNT)
268 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
269 { int n = (COUNT); int i; \
270 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
271 fprintf (out, ", count: %d\n", n); \
272 for (i = 0; i < n; i++) {\
273 int ex_index = JCF_readu2 (jcf); \
274 fprintf (out, "%3d: ", i); \
275 print_constant_ref (out, jcf, ex_index); \
276 fputc ('\n', out); } }
278 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
279 { int n = (COUNT); int i; \
280 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
281 fprintf (out, ", count: %d\n", n); \
282 for (i = 0; i < n; i++) {\
283 int start_pc = JCF_readu2 (jcf); \
284 int length = JCF_readu2 (jcf); \
285 int name_index = JCF_readu2 (jcf); \
286 int signature_index = JCF_readu2 (jcf); \
287 int slot = JCF_readu2 (jcf); \
288 fprintf (out, " slot#%d: name: ", slot); \
289 if (flag_print_constant_pool) \
290 fprintf (out, "%d=", name_index); \
291 print_name (out, jcf, name_index); \
292 fprintf (out, ", type: "); \
293 if (flag_print_constant_pool) \
294 fprintf (out, "%d=", signature_index); \
295 print_signature (out, jcf, signature_index, 0); \
296 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
298 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
299 { int n = (COUNT); int i; \
300 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
301 fprintf (out, ", count: %d\n", n); \
302 if (flag_disassemble_methods) \
303 for (i = 0; i < n; i++) {\
304 int start_pc = JCF_readu2 (jcf); \
305 int line_number = JCF_readu2 (jcf); \
306 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
308 JCF_SKIP (jcf, 4 * n); }
310 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
312 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
315 uint16 inner_class_info_index = JCF_readu2 (jcf); \
316 uint16 outer_class_info_index = JCF_readu2 (jcf); \
317 uint16 inner_name_index = JCF_readu2 (jcf); \
318 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
320 if (flag_print_class_info) \
322 fprintf (out, "\n inner: "); \
323 print_constant_terse_with_index (out, jcf, \
324 inner_class_info_index, CONSTANT_Class); \
325 if (inner_name_index == 0) \
326 fprintf (out, " (anonymous)"); \
327 else if (verbose || flag_print_constant_pool) \
329 fprintf (out, " ("); \
330 print_constant_terse_with_index (out, jcf, inner_name_index, \
334 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
335 print_access_flags (out, inner_class_access_flags, 'c'); \
336 fprintf (out, ", outer class: "); \
337 print_constant_terse_with_index (out, jcf, \
338 outer_class_info_index, CONSTANT_Class); \
341 if (flag_print_class_info) \
345 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
346 { int i, n = (LENGTH), c = 0; \
347 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
349 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
350 if (c != '\r' && c != '\n') fputc('\n', out); }
352 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
353 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
354 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
356 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
357 if (flag_print_attributes > 0) \
358 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
363 print_constant_ref (FILE *stream, JCF *jcf, int index)
365 if (index <= 0 || index >= JPOOL_SIZE(jcf))
366 fprintf (stream, "<out of range>");
369 if (flag_print_constant_pool)
370 fprintf (stream, "#%d=", index);
372 print_constant (stream, jcf, index, 1);
377 /* Print the access flags given by FLAGS.
378 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
379 or 'm' (method flags). */
382 print_access_flags (FILE *stream, uint16 flags, char context)
384 if (flags & ACC_PUBLIC) fprintf (stream, " public");
385 if (flags & ACC_PRIVATE) fprintf (stream, " private");
386 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
387 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
388 if (flags & ACC_STATIC) fprintf (stream, " static");
389 if (flags & ACC_FINAL) fprintf (stream, " final");
390 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
391 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
392 if (flags & ACC_NATIVE) fprintf (stream, " native");
393 if (flags & ACC_SYNCHRONIZED)
396 fprintf (stream, " super");
398 fprintf (stream, " synchronized");
400 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
401 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
406 print_name (FILE* stream, JCF* jcf, int name_index)
408 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
409 fprintf (stream, "<not a UTF8 constant>");
411 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
412 JPOOL_UTF_LENGTH (jcf, name_index));
415 /* If the type of the constant at INDEX matches EXPECTED,
416 print it tersely, otherwise more verbosely. */
419 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
421 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
422 fprintf (out, "<constant pool index %d not in range>", index);
423 else if (JPOOL_TAG (jcf, index) != expected)
425 fprintf (out, "<Unexpected constant type ");
426 print_constant (out, jcf, index, 1);
430 print_constant (out, jcf, index, 0);
434 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
436 if (flag_print_constant_pool)
437 fprintf (out, "%d=", index);
438 print_constant_terse (out, jcf, index, expected);
441 /* Print the constant at INDEX in JCF's constant pool.
442 If verbosity==0, print very tersely (no extraneous text).
443 If verbosity==1, prefix the type of the constant.
444 If verbosity==2, add more descriptive text. */
447 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
452 int kind = JPOOL_TAG (jcf, index);
456 n = JPOOL_USHORT1 (jcf, index);
460 fprintf (out, "Class name: %d=", n);
462 fprintf (out, "Class ");
464 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
465 fprintf (out, "<out of range>");
466 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
468 int len = JPOOL_UTF_LENGTH (jcf, n);
469 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
472 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
474 case CONSTANT_Fieldref:
475 str = "Field"; goto field_or_method;
476 case CONSTANT_Methodref:
477 str = "Method"; goto field_or_method;
478 case CONSTANT_InterfaceMethodref:
479 str = "InterfaceMethod"; goto field_or_method;
482 uint16 tclass = JPOOL_USHORT1 (jcf, index);
483 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
485 fprintf (out, "%sref class: %d=", str, tclass);
486 else if (verbosity > 0)
487 fprintf (out, "%s ", str);
488 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
492 fprintf (out, " name_and_type: %d=<", name_and_type);
493 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
498 case CONSTANT_String:
499 j = JPOOL_USHORT1 (jcf, index);
503 fprintf (out, "String %d=", j);
505 fprintf (out, "String ");
507 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
509 case CONSTANT_Integer:
511 fprintf (out, "Integer ");
512 num = JPOOL_INT (jcf, index);
516 fprintf (out, "Long ");
517 num = JPOOL_LONG (jcf, index);
522 format_int (buffer, num, 10);
523 fprintf (out, "%s", buffer);
526 format_uint (buffer, (uint64)num, 16);
527 fprintf (out, "=0x%s", buffer);
533 jfloat fnum = JPOOL_FLOAT (jcf, index);
536 fputs ("Float ", out);
541 if (JFLOAT_FINITE (fnum))
544 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
546 uint32 mantissa = fnum.mantissa;
547 if (fnum.exponent == 0)
551 /* Normal; add the implicit bit. */
552 mantissa |= ((uint32)1 << 23);
554 f = frexp (mantissa, &dummy);
555 f = ldexp (f, exponent + 1);
556 fprintf (out, "%.10g", f);
560 if (fnum.mantissa == 0)
562 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
563 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
565 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
569 fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
573 case CONSTANT_Double:
575 jdouble dnum = JPOOL_DOUBLE (jcf, index);
578 fputs ("Double ", out);
583 if (JDOUBLE_FINITE (dnum))
586 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
588 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
590 if (dnum.exponent == 0)
594 /* Normal; add the implicit bit. */
595 mantissa |= ((uint64)1 << 52);
597 d = frexp (mantissa, &dummy);
598 d = ldexp (d, exponent + 1);
599 fprintf (out, "%.20g", d);
603 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
604 mantissa = (mantissa << 32) + dnum.mantissa1;
606 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
608 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
609 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
611 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
616 hi = JPOOL_UINT (jcf, index);
617 lo = JPOOL_UINT (jcf, index + 1);
618 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
622 case CONSTANT_NameAndType:
624 uint16 name = JPOOL_USHORT1 (jcf, index);
625 uint16 sig = JPOOL_USHORT2 (jcf, index);
629 fprintf (out, "NameAndType name: %d=", name);
631 fprintf (out, "NameAndType ");
633 print_name (out, jcf, name);
637 fprintf (out, ", signature: %d=", sig);
638 print_signature (out, jcf, sig, 0);
643 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
644 int length = JPOOL_UTF_LENGTH (jcf, index);
646 { /* Print as 8-bit bytes. */
647 fputs ("Utf8: \"", out);
648 while (--length >= 0)
649 jcf_print_char (out, *str++);
652 { /* Print as Unicode. */
654 jcf_print_utf8 (out, str, length);
660 fprintf (out, "(Unknown constant type %d)", kind);
665 print_constant_pool (JCF *jcf)
668 for (i = 1; i < JPOOL_SIZE(jcf); i++)
670 int kind = JPOOL_TAG (jcf, i);
671 fprintf (out, "#%d: ", i);
672 print_constant (out, jcf, i, 2);
674 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
675 i++; /* These take up two slots in the constant table */
680 print_signature_type (FILE* stream, const unsigned char **ptr,
681 const unsigned char *limit)
690 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
692 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
694 print_signature_type (stream, ptr, limit);
695 if (array_size == -1)
696 fprintf (stream, "[]");
698 fprintf (stream, "[%d]", array_size);
703 fputc (*(*ptr)++, stream);
704 for (; **ptr != ')' && *ptr < limit; nargs++)
708 print_signature_type (stream, ptr, limit);
712 fputc (*(*ptr)++, stream);
713 print_signature_type (stream, ptr, limit);
716 fprintf (stream, "???");
720 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
721 case 'C': fprintf (stream, "char"); (*ptr)++; break;
722 case 'D': fprintf (stream, "double"); (*ptr)++; break;
723 case 'F': fprintf (stream, "float"); (*ptr)++; break;
724 case 'S': fprintf (stream, "short"); (*ptr)++; break;
725 case 'I': fprintf (stream, "int"); (*ptr)++; break;
726 case 'J': fprintf (stream, "long"); (*ptr)++; break;
727 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
728 case 'V': fprintf (stream, "void"); (*ptr)++; break;
731 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
732 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
737 jcf_print_char (stream, *(*ptr)++);
742 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
744 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
745 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
748 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
749 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
750 const unsigned char *limit;
751 limit = str + length;
753 fprintf (stream, "<empty signature string>");
756 if (options & PRINT_SIGNATURE_RESULT_ONLY)
758 while (str < limit && *str++ != ')') ;
760 if (options & PRINT_SIGNATURE_ARGS_ONLY)
764 while (str < limit && *str != ')')
766 print_signature_type (stream, &str, limit);
768 fputs (", ", stream);
774 print_signature_type (stream, &str, limit);
777 fprintf (stream, "<junk:");
778 jcf_print_utf8 (stream, str, limit - str);
788 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
790 /* Print exception table. */
794 const unsigned char *ptr = entries;
795 fprintf (out, "Exceptions (count: %d):\n", i);
796 for (; --i >= 0; ptr+= 8)
798 int start_pc = GET_u2 (ptr);
799 int end_pc = GET_u2 (ptr+2);
800 int handler_pc = GET_u2 (ptr+4);
801 int catch_type = GET_u2 (ptr+6);
802 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
803 start_pc, end_pc, handler_pc);
805 fputs ("0 /* finally */", out);
807 print_constant_terse_with_index (out, jcf,
808 catch_type, CONSTANT_Class);
814 #include "jcf-reader.c"
817 process_class (JCF *jcf)
820 if (jcf_parse_preamble (jcf) != 0)
821 fprintf (stderr, _("Not a valid Java .class file.\n"));
823 /* Parse and possibly print constant pool */
824 code = jcf_parse_constant_pool (jcf);
827 fprintf (stderr, _("error while parsing constant pool\n"));
828 exit (FATAL_EXIT_CODE);
830 code = verify_constant_pool (jcf);
833 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
834 exit (FATAL_EXIT_CODE);
836 if (flag_print_constant_pool)
837 print_constant_pool (jcf);
839 jcf_parse_class (jcf);
840 code = jcf_parse_fields (jcf);
843 fprintf (stderr, _("error while parsing fields\n"));
844 exit (FATAL_EXIT_CODE);
846 code = jcf_parse_methods (jcf);
849 fprintf (stderr, _("error while parsing methods\n"));
850 exit (FATAL_EXIT_CODE);
852 code = jcf_parse_final_attributes (jcf);
855 fprintf (stderr, _("error while parsing final attributes\n"));
856 exit (FATAL_EXIT_CODE);
858 jcf->filename = NULL;
863 /* This is used to mark options with no short value. */
864 #define LONG_OPT(Num) ((Num) + 128)
866 #define OPT_classpath LONG_OPT (0)
867 #define OPT_CLASSPATH OPT_classpath
868 #define OPT_bootclasspath LONG_OPT (1)
869 #define OPT_extdirs LONG_OPT (2)
870 #define OPT_HELP LONG_OPT (3)
871 #define OPT_VERSION LONG_OPT (4)
872 #define OPT_JAVAP LONG_OPT (5)
874 static const struct option options[] =
876 { "classpath", required_argument, NULL, OPT_classpath },
877 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
878 { "extdirs", required_argument, NULL, OPT_extdirs },
879 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
880 { "help", no_argument, NULL, OPT_HELP },
881 { "verbose", no_argument, NULL, 'v' },
882 { "version", no_argument, NULL, OPT_VERSION },
883 { "javap", no_argument, NULL, OPT_JAVAP },
884 { "print-main", no_argument, &flag_print_main, 1 },
885 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
886 { NULL, no_argument, NULL, 0 }
892 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
899 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
900 printf (_("Display contents of a class file in readable form.\n\n"));
901 printf (_(" -c Disassemble method bodies\n"));
902 printf (_(" --javap Generate output in 'javap' format\n"));
904 printf (_(" --classpath PATH Set path to find .class files\n"));
905 printf (_(" -IDIR Append directory to class path\n"));
906 printf (_(" --bootclasspath PATH Override built-in class path\n"));
907 printf (_(" --extdirs PATH Set extensions directory path\n"));
908 printf (_(" -o FILE Set output file name\n"));
910 printf (_(" --help Print this help, then exit\n"));
911 printf (_(" --version Print version number, then exit\n"));
912 printf (_(" -v, --verbose Print extra information while running\n"));
914 printf (_("For bug reporting instructions, please see:\n"
915 "%s.\n"), bug_report_url);
922 printf ("jcf-dump (GCC) %s\n\n", version_string);
923 printf ("Copyright %s 2004 Free Software Foundation, Inc.\n", _("(C)"));
924 printf (_("This is free software; see the source for copying conditions. There is NO\n"
925 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
930 main (int argc, char** argv)
939 fprintf (stderr, _("jcf-dump: no classes specified\n"));
945 /* We use getopt_long_only to allow single `-' long options. For
946 some of our options this is more natural. */
947 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
952 /* Already handled. */
956 output_file = optarg;
960 jcf_path_include_arg (optarg);
968 flag_disassemble_methods = 1;
972 jcf_path_classpath_arg (optarg);
975 case OPT_bootclasspath:
976 jcf_path_bootclasspath_arg (optarg);
980 jcf_path_extdirs_arg (optarg);
992 flag_javap_compatible++;
993 flag_print_constant_pool = 0;
994 flag_print_attributes = 0;
1002 if (verbose && ! flag_javap_compatible)
1003 flag_print_constant_pool = 1;
1007 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1011 jcf_path_seal (verbose);
1013 if (flag_print_main)
1015 flag_print_fields = 0;
1016 flag_print_methods = 0;
1017 flag_print_constant_pool = 0;
1018 flag_print_attributes = 0;
1019 flag_print_class_info = 0;
1024 out = fopen (output_file, "w");
1027 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1028 return FATAL_EXIT_CODE;
1036 fprintf (out, "Reading .class from <standard input>.\n");
1037 open_class ("<stdio>", jcf, 0, NULL);
1038 process_class (jcf);
1042 for (argi = optind; argi < argc; argi++)
1044 char *arg = argv[argi];
1045 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1046 if (class_filename == NULL)
1047 class_filename = find_classfile (arg, jcf, NULL);
1048 if (class_filename == NULL)
1050 perror ("Could not find class");
1051 return FATAL_EXIT_CODE;
1054 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1056 long compressed_size, member_size;
1057 int compression_method, filename_length, extra_length;
1058 int general_purpose_bits;
1059 const char *filename;
1061 if (flag_print_class_info)
1062 fprintf (out, "Reading classes from archive %s.\n",
1067 jcf_filbuf_t save_filbuf = jcf->filbuf;
1068 long magic = JCF_readu4_le (jcf);
1069 if (magic == 0x02014b50 || magic == 0x06054b50)
1070 break; /* got to central directory */
1071 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1073 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1074 return FATAL_EXIT_CODE;
1078 general_purpose_bits = JCF_readu2_le (jcf);
1079 compression_method = JCF_readu2_le (jcf);
1081 compressed_size = JCF_readu4_le (jcf);
1082 member_size = JCF_readu4_le (jcf);
1083 filename_length = JCF_readu2_le (jcf);
1084 extra_length = JCF_readu2_le (jcf);
1085 total_length = filename_length + extra_length
1087 if (jcf->read_end - jcf->read_ptr < total_length)
1088 jcf_trim_old_input (jcf);
1089 JCF_FILL (jcf, total_length);
1090 filename = (const char *) jcf->read_ptr;
1091 JCF_SKIP (jcf, filename_length);
1092 JCF_SKIP (jcf, extra_length);
1093 if (filename_length > 0
1094 && filename[filename_length-1] == '/')
1096 if (flag_print_class_info)
1097 fprintf (out, "[Skipping directory %.*s]\n",
1098 filename_length, filename);
1101 else if (compression_method != 0)
1103 if (flag_print_class_info)
1104 fprintf (out, "[Skipping compressed file %.*s]\n",
1105 filename_length, filename);
1108 else if (member_size < 4
1109 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1111 if (flag_print_class_info)
1112 fprintf (out, "[Skipping non-.class member %.*s]\n",
1113 filename_length, filename);
1118 if (flag_print_class_info)
1119 fprintf (out, "Reading class member: %.*s.\n",
1120 filename_length, filename);
1124 JCF_SKIP (jcf, compressed_size);
1128 unsigned char *save_end;
1129 jcf->filbuf = jcf_unexpected_eof;
1130 save_end = jcf->read_end;
1131 jcf->read_end = jcf->read_ptr + compressed_size;
1132 process_class (jcf);
1133 jcf->filbuf = save_filbuf;
1134 jcf->read_end = save_end;
1140 if (flag_print_class_info)
1141 fprintf (out, "Reading .class from %s.\n", class_filename);
1142 process_class (jcf);
1148 return SUCCESS_EXIT_CODE;
1154 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1160 if (flag_disassemble_methods == 0)
1162 #define BCODE byte_ops
1163 for (PC = 0; PC < len;)
1168 switch (byte_ops[PC++])
1171 /* This is the actual code emitted for each of opcodes in javaops.def.
1172 The actual opcode-specific stuff is handled by the OPKIND macro.
1173 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1174 Those macros are defined below. The OPKINDs that do not have any
1175 inline parameters (such as BINOP) and therefore do mot need anything
1176 else to me printed out just use an empty body. */
1178 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1180 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1181 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1182 fputc ('\n', out); \
1185 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1186 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1187 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1188 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1190 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1191 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1193 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1194 These all push a constant onto the opcode stack. */
1195 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1196 saw_index = 0, i = (OPERAND_VALUE); \
1197 if (oldpc+1 == PC) /* nothing */; \
1198 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1199 else fprintf (out, " %d", i);
1201 /* Print out operand (a local variable index) for LOAD opcodes.
1202 These all push local variable onto the opcode stack. */
1203 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1204 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1206 /* Handle STORE opcodes same as LOAD opcodes.
1207 These all store a value from the opcode stack in a local variable. */
1210 /* Handle more kind of opcodes. */
1211 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1212 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1213 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1214 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1215 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1216 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1217 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1219 /* Handle putfield and getfield opcodes, with static versions. */
1220 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1221 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1223 /* Print operand for invoke opcodes. */
1224 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1225 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1226 if (OPERAND_VALUE) /* for invokeinterface */ \
1227 { int nargs = IMMEDIATE_u1; PC++; \
1228 fprintf (out, " nargs:%d", nargs); }
1230 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1231 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1233 #define ARRAY(OPERAND_TYPE, SUBOP) \
1234 ARRAY_##SUBOP(OPERAND_TYPE)
1235 /* Handle sub-categories of ARRAY opcodes. */
1236 #define ARRAY_LOAD(TYPE) /* nothing */
1237 #define ARRAY_STORE(TYPE) /* nothing */
1238 #define ARRAY_LENGTH(TYPE) /* nothing */
1239 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1240 #define ARRAY_NEW_NUM \
1241 INT_temp = IMMEDIATE_u1; \
1242 { switch ((int) INT_temp) { \
1243 case 4: fputs (" boolean", out); break; \
1244 case 5: fputs (" char", out); break; \
1245 case 6: fputs (" float", out); break; \
1246 case 7: fputs (" double", out); break; \
1247 case 8: fputs (" byte", out); break; \
1248 case 9: fputs (" short", out); break; \
1249 case 10: fputs (" int", out); break; \
1250 case 11: fputs (" long", out); break; \
1251 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1254 #define ARRAY_NEW_PTR \
1255 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1257 #define ARRAY_NEW_MULTI \
1258 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1259 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1261 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1262 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1264 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1265 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1266 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1268 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1269 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1270 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1272 #undef RET /* Defined by config/i386/i386.h */
1273 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1274 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1276 fprintf (out, " %ld", (long) INT_temp);
1278 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1279 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1281 #define LOOKUP_SWITCH \
1282 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1283 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1284 while (--npairs >= 0) { \
1285 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1286 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1289 #define TABLE_SWITCH \
1290 { jint default_offset = IMMEDIATE_s4; \
1291 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1292 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1293 (long) low, (long) high, (long) default_offset+oldpc); \
1294 for (; low <= high; low++) { \
1295 jint offset = IMMEDIATE_s4; \
1296 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1299 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1300 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1302 #define SPECIAL_IINC(OPERAND_TYPE) \
1303 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1304 fprintf (out, " %d", i); \
1305 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1307 fprintf (out, " %d", i)
1309 #define SPECIAL_WIDE(OPERAND_TYPE) \
1312 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1313 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1314 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1315 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1317 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1318 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1320 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1321 TEST(OPERAND_TYPE, OPERAND_VALUE)
1323 #include "javaop.def"
1326 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1330 fprintf (out, " %ld", (long) INT_temp);
1336 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);