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
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"
59 #include "java-tree.h"
67 /* Name of output file, if NULL if stdout. */
68 char *output_file = NULL;
72 int flag_disassemble_methods = 0;
73 int flag_print_class_info = 1;
74 int flag_print_constant_pool = 1;
75 int flag_print_fields = 1;
76 int flag_print_methods = 1;
77 int flag_print_attributes = 1;
79 /* When nonzero, warn when source file is newer than matching class
83 /* Print names of classes that have a "main" method. */
84 int flag_print_main = 0;
86 /* Index in constant pool of this class. */
87 int this_class_index = 0;
89 int class_access_flags = 0;
91 /* Print in format similar to javap. VERY IMCOMPLETE. */
92 int flag_javap_compatible = 0;
94 static void print_access_flags (FILE *, uint16, char);
95 static void print_constant_terse (FILE*, JCF*, int, int);
96 static void print_constant (FILE *, JCF *, int, int);
97 static void print_constant_ref (FILE *, JCF *, int);
98 static void disassemble_method (JCF*, const unsigned char *, int);
99 static void print_name (FILE*, JCF*, int);
100 static void print_signature (FILE*, JCF*, int, int);
101 static int utf8_equal_string (struct JCF*, int, const char *);
102 static void usage (void) ATTRIBUTE_NORETURN;
103 static void help (void) ATTRIBUTE_NORETURN;
104 static void version (void) ATTRIBUTE_NORETURN;
105 static void process_class (struct JCF *);
106 static void print_constant_pool (struct JCF *);
107 static void print_exception_table (struct JCF *, const unsigned char *entries,
110 #define PRINT_SIGNATURE_RESULT_ONLY 1
111 #define PRINT_SIGNATURE_ARGS_ONLY 2
114 utf8_equal_string (JCF *jcf, int index, const char * value)
116 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
117 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
119 int len = strlen (value);
120 if (JPOOL_UTF_LENGTH (jcf, index) == len
121 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
127 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
128 this_class_index = 0; \
129 if (flag_print_class_info) \
131 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
132 (long) MAGIC, (long) MINOR, (long) MAJOR)
134 #define HANDLE_START_CONSTANT_POOL(COUNT) \
135 if (flag_print_constant_pool) \
136 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
138 #define HANDLE_SOURCEFILE(INDEX) \
139 { fprintf (out, "Attribute "); \
140 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
141 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
142 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
144 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
145 this_class_index = THIS; \
146 class_access_flags = ACCESS_FLAGS; \
147 if (flag_print_class_info) \
148 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
149 print_access_flags (out, ACCESS_FLAGS, 'c'); \
151 fprintf (out, "This class: "); \
152 if (flag_print_constant_pool) \
153 fprintf (out, "%d=", THIS); \
154 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
155 if (flag_print_constant_pool || SUPER != 0) \
156 fprintf (out, ", super: "); \
157 if (flag_print_constant_pool) \
159 fprintf (out, "%d", SUPER); \
164 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
165 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
168 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
169 (flag_print_attributes <= 0)
171 #define HANDLE_CLASS_INTERFACE(INDEX) \
172 if (flag_print_class_info) \
173 { fprintf (out, "- Implements: %d=", INDEX); \
174 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
177 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
178 if (flag_print_fields) \
179 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
181 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
182 if (flag_print_fields) \
183 { fprintf (out, "Field name:"); \
184 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
185 print_access_flags (out, ACCESS_FLAGS, 'f'); \
186 fprintf (out, " Signature: "); \
187 if (flag_print_constant_pool) \
188 fprintf (out, "%d=", SIGNATURE); \
189 print_signature (out, jcf, SIGNATURE, 0); \
190 fputc ('\n', out); } \
192 flag_print_attributes--;
194 #define HANDLE_END_FIELD() \
195 if (! flag_print_fields) \
196 flag_print_attributes++;
198 #define HANDLE_START_METHODS(METHODS_COUNT) \
199 if (flag_print_methods) \
200 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
202 flag_print_attributes--;
205 #define HANDLE_END_METHODS() \
206 if (! flag_print_methods) \
207 flag_print_attributes++;
209 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
211 if (flag_print_methods) \
213 if (flag_javap_compatible) \
215 fprintf (out, " "); \
216 print_access_flags (out, ACCESS_FLAGS, 'm'); \
218 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
220 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
221 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
226 fprintf (out, "\nMethod name:"); \
227 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
228 print_access_flags (out, ACCESS_FLAGS, 'm'); \
229 fprintf (out, " Signature: "); \
230 if (flag_print_constant_pool) \
231 fprintf (out, "%d=", SIGNATURE); \
232 print_signature (out, jcf, SIGNATURE, 0); \
236 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
237 && utf8_equal_string (jcf, NAME, "main") \
238 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
239 && this_class_index > 0 \
240 && (class_access_flags & ACC_PUBLIC)) \
242 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
247 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
248 ( fprintf (out, "Attribute "), \
249 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
250 fprintf (out, ", length:%ld", (long) LENGTH) )
252 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
253 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
254 fprintf (out, ", value: "), \
255 print_constant_ref (out, jcf, VALUE_INDEX), \
256 fprintf (out, "\n") )
258 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
259 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
260 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
261 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
262 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
264 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
265 print_exception_table (jcf, ENTRIES, COUNT)
267 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
268 { int n = (COUNT); int i; \
269 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
270 fprintf (out, ", count: %d\n", n); \
271 for (i = 0; i < n; i++) {\
272 int ex_index = JCF_readu2 (jcf); \
273 fprintf (out, "%3d: ", i); \
274 print_constant_ref (out, jcf, ex_index); \
275 fputc ('\n', out); } }
277 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
278 { int n = (COUNT); int i; \
279 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
280 fprintf (out, ", count: %d\n", n); \
281 for (i = 0; i < n; i++) {\
282 int start_pc = JCF_readu2 (jcf); \
283 int length = JCF_readu2 (jcf); \
284 int name_index = JCF_readu2 (jcf); \
285 int signature_index = JCF_readu2 (jcf); \
286 int slot = JCF_readu2 (jcf); \
287 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
288 print_name (out, jcf, name_index); \
289 fprintf (out, ", type: %d=", signature_index); \
290 print_signature (out, jcf, signature_index, 0); \
291 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
293 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
294 { int n = (COUNT); int i; \
295 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
296 fprintf (out, ", count: %d\n", n); \
297 if (flag_disassemble_methods) \
298 for (i = 0; i < n; i++) {\
299 int start_pc = JCF_readu2 (jcf); \
300 int line_number = JCF_readu2 (jcf); \
301 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
303 JCF_SKIP (jcf, 4 * n); }
305 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
307 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
310 uint16 inner_class_info_index = JCF_readu2 (jcf); \
311 uint16 outer_class_info_index = JCF_readu2 (jcf); \
312 uint16 inner_name_index = JCF_readu2 (jcf); \
313 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
315 if (flag_print_class_info) \
317 fprintf (out, "\n class: "); \
318 if (flag_print_constant_pool) \
319 fprintf (out, "%d=", inner_class_info_index); \
320 print_constant_terse (out, jcf, \
321 inner_class_info_index, CONSTANT_Class); \
322 fprintf (out, " (%d=", inner_name_index); \
323 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
324 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
325 print_access_flags (out, inner_class_access_flags, 'c'); \
326 fprintf (out, ", outer class: "); \
327 if (flag_print_constant_pool) \
328 fprintf (out, "%d=", outer_class_info_index); \
329 print_constant_terse (out, jcf, \
330 outer_class_info_index, CONSTANT_Class); \
333 if (flag_print_class_info) \
337 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
338 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
339 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
341 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
342 if (flag_print_attributes > 0) \
343 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
348 print_constant_ref (FILE *stream, JCF *jcf, int index)
350 fprintf (stream, "#%d=<", index);
351 if (index <= 0 || index >= JPOOL_SIZE(jcf))
352 fprintf (stream, "out of range");
354 print_constant (stream, jcf, index, 1);
355 fprintf (stream, ">");
358 /* Print the access flags given by FLAGS.
359 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
360 or 'm' (method flags). */
363 print_access_flags (FILE *stream, uint16 flags, char context)
365 if (flags & ACC_PUBLIC) fprintf (stream, " public");
366 if (flags & ACC_PRIVATE) fprintf (stream, " private");
367 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
368 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
369 if (flags & ACC_STATIC) fprintf (stream, " static");
370 if (flags & ACC_FINAL) fprintf (stream, " final");
371 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
372 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
373 if (flags & ACC_NATIVE) fprintf (stream, " native");
374 if (flags & ACC_SYNCHRONIZED)
377 fprintf (stream, " super");
379 fprintf (stream, " synchronized");
381 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
382 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
387 print_name (FILE* stream, JCF* jcf, int name_index)
389 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
390 fprintf (stream, "<not a UTF8 constant>");
392 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
393 JPOOL_UTF_LENGTH (jcf, name_index));
396 /* If the type of the constant at INDEX matches EXPECTED,
397 print it tersely, otherwise more verbosely. */
400 print_constant_terse (FILE *out, JCF *jcf, int index, 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 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
425 int kind = JPOOL_TAG (jcf, index);
429 n = JPOOL_USHORT1 (jcf, index);
433 fprintf (out, "Class name: %d=", n);
435 fprintf (out, "Class ");
437 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
438 fprintf (out, "<out of range>");
439 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
441 int len = JPOOL_UTF_LENGTH (jcf, n);
442 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
445 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
447 case CONSTANT_Fieldref:
448 str = "Field"; goto field_or_method;
449 case CONSTANT_Methodref:
450 str = "Method"; goto field_or_method;
451 case CONSTANT_InterfaceMethodref:
452 str = "InterfaceMethod"; goto field_or_method;
455 uint16 tclass = JPOOL_USHORT1 (jcf, index);
456 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
458 fprintf (out, "%sref class: %d=", str, tclass);
459 else if (verbosity > 0)
460 fprintf (out, "%s ", str);
461 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
465 fprintf (out, " name_and_type: %d=<", name_and_type);
466 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
471 case CONSTANT_String:
472 j = JPOOL_USHORT1 (jcf, index);
476 fprintf (out, "String %d=", j);
478 fprintf (out, "String ");
480 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
482 case CONSTANT_Integer:
484 fprintf (out, "Integer ");
485 num = JPOOL_INT (jcf, index);
489 fprintf (out, "Long ");
490 num = JPOOL_LONG (jcf, index);
495 format_int (buffer, num, 10);
496 fprintf (out, "%s", buffer);
499 format_uint (buffer, (uint64)num, 16);
500 fprintf (out, "=0x%s", buffer);
512 pun.f = JPOOL_FLOAT (jcf, index);
513 fprintf (out, "%s%.10g",
514 verbosity > 0 ? "Float " : "", (double) pun.f);
516 fprintf (out, ", bits = 0x%08lx", (long) pun.i);
520 case CONSTANT_Double:
522 jdouble dnum = JPOOL_DOUBLE (jcf, index);
523 fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
527 hi = JPOOL_UINT (jcf, index);
528 lo = JPOOL_UINT (jcf, index + 1);
529 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
533 case CONSTANT_NameAndType:
535 uint16 name = JPOOL_USHORT1 (jcf, index);
536 uint16 sig = JPOOL_USHORT2 (jcf, index);
540 fprintf (out, "NameAndType name: %d=", name);
542 fprintf (out, "NameAndType ");
544 print_name (out, jcf, name);
548 fprintf (out, ", signature: %d=", sig);
549 print_signature (out, jcf, sig, 0);
554 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
555 int length = JPOOL_UTF_LENGTH (jcf, index);
557 { /* Print as 8-bit bytes. */
558 fputs ("Utf8: \"", out);
559 while (--length >= 0)
560 jcf_print_char (out, *str++);
563 { /* Print as Unicode. */
565 jcf_print_utf8 (out, str, length);
571 fprintf (out, "(Unknown constant type %d)", kind);
576 print_constant_pool (JCF *jcf)
579 for (i = 1; i < JPOOL_SIZE(jcf); i++)
581 int kind = JPOOL_TAG (jcf, i);
582 fprintf (out, "#%d: ", i);
583 print_constant (out, jcf, i, 2);
585 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
586 i++; /* These take up two slots in the constant table */
591 print_signature_type (FILE* stream, const unsigned char **ptr,
592 const unsigned char *limit)
601 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
603 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
605 print_signature_type (stream, ptr, limit);
606 if (array_size == -1)
607 fprintf (stream, "[]");
609 fprintf (stream, "[%d]", array_size);
614 fputc (*(*ptr)++, stream);
615 for (; **ptr != ')' && *ptr < limit; nargs++)
619 print_signature_type (stream, ptr, limit);
623 fputc (*(*ptr)++, stream);
624 print_signature_type (stream, ptr, limit);
627 fprintf (stream, "???");
631 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
632 case 'C': fprintf (stream, "char"); (*ptr)++; break;
633 case 'D': fprintf (stream, "double"); (*ptr)++; break;
634 case 'F': fprintf (stream, "float"); (*ptr)++; break;
635 case 'S': fprintf (stream, "short"); (*ptr)++; break;
636 case 'I': fprintf (stream, "int"); (*ptr)++; break;
637 case 'J': fprintf (stream, "long"); (*ptr)++; break;
638 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
639 case 'V': fprintf (stream, "void"); (*ptr)++; break;
642 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
643 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
648 jcf_print_char (stream, *(*ptr)++);
653 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
655 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
656 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
659 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
660 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
661 const unsigned char *limit;
662 limit = str + length;
664 fprintf (stream, "<empty signature string>");
667 if (options & PRINT_SIGNATURE_RESULT_ONLY)
669 while (str < limit && *str++ != ')') ;
671 if (options & PRINT_SIGNATURE_ARGS_ONLY)
675 while (str < limit && *str != ')')
677 print_signature_type (stream, &str, limit);
679 fputs (", ", stream);
685 print_signature_type (stream, &str, limit);
688 fprintf (stream, "<junk:");
689 jcf_print_utf8 (stream, str, limit - str);
699 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
701 /* Print exception table. */
705 const unsigned char *ptr = entries;
706 fprintf (out, "Exceptions (count: %d):\n", i);
707 for (; --i >= 0; ptr+= 8)
709 int start_pc = GET_u2 (ptr);
710 int end_pc = GET_u2 (ptr+2);
711 int handler_pc = GET_u2 (ptr+4);
712 int catch_type = GET_u2 (ptr+6);
713 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
714 start_pc, end_pc, handler_pc, catch_type);
716 fputs (" /* finally */", out);
720 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
727 #include "jcf-reader.c"
730 process_class (JCF *jcf)
733 if (jcf_parse_preamble (jcf) != 0)
734 fprintf (stderr, "Not a valid Java .class file.\n");
736 /* Parse and possibly print constant pool */
737 code = jcf_parse_constant_pool (jcf);
740 fprintf (stderr, "error while parsing constant pool\n");
741 exit (FATAL_EXIT_CODE);
743 code = verify_constant_pool (jcf);
746 fprintf (stderr, "error in constant pool entry #%d\n", code);
747 exit (FATAL_EXIT_CODE);
749 if (flag_print_constant_pool)
750 print_constant_pool (jcf);
752 jcf_parse_class (jcf);
753 code = jcf_parse_fields (jcf);
756 fprintf (stderr, "error while parsing fields\n");
757 exit (FATAL_EXIT_CODE);
759 code = jcf_parse_methods (jcf);
762 fprintf (stderr, "error while parsing methods\n");
763 exit (FATAL_EXIT_CODE);
765 code = jcf_parse_final_attributes (jcf);
768 fprintf (stderr, "error while parsing final attributes\n");
769 exit (FATAL_EXIT_CODE);
771 jcf->filename = NULL;
776 /* This is used to mark options with no short value. */
777 #define LONG_OPT(Num) ((Num) + 128)
779 #define OPT_classpath LONG_OPT (0)
780 #define OPT_CLASSPATH OPT_classpath
781 #define OPT_bootclasspath LONG_OPT (1)
782 #define OPT_extdirs LONG_OPT (2)
783 #define OPT_HELP LONG_OPT (3)
784 #define OPT_VERSION LONG_OPT (4)
785 #define OPT_JAVAP LONG_OPT (5)
787 static const struct option options[] =
789 { "classpath", required_argument, NULL, OPT_classpath },
790 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
791 { "extdirs", required_argument, NULL, OPT_extdirs },
792 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
793 { "help", no_argument, NULL, OPT_HELP },
794 { "verbose", no_argument, NULL, 'v' },
795 { "version", no_argument, NULL, OPT_VERSION },
796 { "javap", no_argument, NULL, OPT_JAVAP },
797 { "print-main", no_argument, &flag_print_main, 1 },
798 { NULL, no_argument, NULL, 0 }
804 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
811 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
812 printf ("Display contents of a class file in readable form.\n\n");
813 printf (" -c Disassemble method bodies\n");
814 printf (" --javap Generate output in `javap' format\n");
816 printf (" --classpath PATH Set path to find .class files\n");
817 printf (" -IDIR Append directory to class path\n");
818 printf (" --bootclasspath PATH Override built-in class path\n");
819 printf (" --extdirs PATH Set extensions directory path\n");
820 printf (" -o FILE Set output file name\n");
822 printf (" --help Print this help, then exit\n");
823 printf (" --version Print version number, then exit\n");
824 printf (" -v, --verbose Print extra information while running\n");
826 printf ("For bug reporting instructions, please see:\n");
827 printf ("%s.\n", bug_report_url);
834 printf ("jcf-dump (GCC) %s\n\n", version_string);
835 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
836 printf ("This is free software; see the source for copying conditions. There is NO\n");
837 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
842 main (int argc, char** argv)
849 fprintf (stderr, "jcf-dump: no classes specified\n");
855 /* We use getopt_long_only to allow single `-' long options. For
856 some of our options this is more natural. */
857 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
862 /* Already handled. */
866 output_file = optarg;
870 jcf_path_include_arg (optarg);
878 flag_disassemble_methods = 1;
882 jcf_path_classpath_arg (optarg);
885 case OPT_bootclasspath:
886 jcf_path_bootclasspath_arg (optarg);
890 jcf_path_extdirs_arg (optarg);
902 flag_javap_compatible++;
903 flag_print_constant_pool = 0;
904 flag_print_attributes = 0;
914 fprintf (stderr, "jcf-dump: no classes specified\n");
918 jcf_path_seal (verbose);
922 flag_print_fields = 0;
923 flag_print_methods = 0;
924 flag_print_constant_pool = 0;
925 flag_print_attributes = 0;
926 flag_print_class_info = 0;
931 out = fopen (output_file, "w");
934 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
935 return FATAL_EXIT_CODE;
943 fprintf (out, "Reading .class from <standard input>.\n");
944 open_class ("<stdio>", jcf, 0, NULL);
949 for (argi = optind; argi < argc; argi++)
951 char *arg = argv[argi];
952 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
953 if (class_filename == NULL)
954 class_filename = find_classfile (arg, jcf, NULL);
955 if (class_filename == NULL)
957 perror ("Could not find class");
958 return FATAL_EXIT_CODE;
961 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
963 long compressed_size, member_size;
964 int compression_method, filename_length, extra_length;
965 int general_purpose_bits;
966 const char *filename;
968 if (flag_print_class_info)
969 fprintf (out, "Reading classes from archive %s.\n",
974 jcf_filbuf_t save_filbuf = jcf->filbuf;
975 long magic = JCF_readu4_le (jcf);
976 if (magic == 0x02014b50 || magic == 0x06054b50)
977 break; /* got to central directory */
978 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
980 fprintf (stderr, "bad format of .zip/.jar archive\n");
981 return FATAL_EXIT_CODE;
985 general_purpose_bits = JCF_readu2_le (jcf);
986 compression_method = JCF_readu2_le (jcf);
988 compressed_size = JCF_readu4_le (jcf);
989 member_size = JCF_readu4_le (jcf);
990 filename_length = JCF_readu2_le (jcf);
991 extra_length = JCF_readu2_le (jcf);
992 total_length = filename_length + extra_length
994 if (jcf->read_end - jcf->read_ptr < total_length)
995 jcf_trim_old_input (jcf);
996 JCF_FILL (jcf, total_length);
997 filename = jcf->read_ptr;
998 JCF_SKIP (jcf, filename_length);
999 JCF_SKIP (jcf, extra_length);
1000 if (filename_length > 0
1001 && filename[filename_length-1] == '/')
1003 if (flag_print_class_info)
1004 fprintf (out, "[Skipping directory %.*s]\n",
1005 filename_length, filename);
1008 else if (compression_method != 0)
1010 if (flag_print_class_info)
1011 fprintf (out, "[Skipping compressed file %.*s]\n",
1012 filename_length, filename);
1015 else if (member_size < 4
1016 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1018 if (flag_print_class_info)
1019 fprintf (out, "[Skipping non-.class member %.*s]\n",
1020 filename_length, filename);
1025 if (flag_print_class_info)
1026 fprintf (out, "Reading class member: %.*s.\n",
1027 filename_length, filename);
1031 JCF_SKIP (jcf, compressed_size);
1035 unsigned char *save_end;
1036 jcf->filbuf = jcf_unexpected_eof;
1037 save_end = jcf->read_end;
1038 jcf->read_end = jcf->read_ptr + compressed_size;
1039 process_class (jcf);
1040 jcf->filbuf = save_filbuf;
1041 jcf->read_end = save_end;
1047 if (flag_print_class_info)
1048 fprintf (out, "Reading .class from %s.\n", class_filename);
1049 process_class (jcf);
1055 return SUCCESS_EXIT_CODE;
1061 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
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]);