1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
28 jcf-dump is a program to print out the contents of class files.
29 Usage: jcf-dump [FLAGS] CLASS
31 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
32 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
33 + The name of a .zip or .jar file (which prints all the classes in the
38 Dis-assemble each method.
42 Print nothing if there is no valid "main" method;
43 otherwise, print only the class name.
45 Print output in the style of Sun's javap program. VERY UNFINISHED.
51 #include "coretypes.h"
56 #include "java-tree.h"
64 /* Name of output file, if NULL if stdout. */
65 char *output_file = NULL;
69 int flag_disassemble_methods = 0;
70 int flag_print_class_info = 1;
71 int flag_print_constant_pool = 1;
72 int flag_print_fields = 1;
73 int flag_print_methods = 1;
74 int flag_print_attributes = 1;
76 /* When nonzero, warn when source file is newer than matching class
80 /* Print names of classes that have a "main" method. */
81 int flag_print_main = 0;
83 /* Index in constant pool of this class. */
84 int this_class_index = 0;
86 int class_access_flags = 0;
88 /* Print in format similar to javap. VERY IMCOMPLETE. */
89 int flag_javap_compatible = 0;
91 static void print_access_flags PARAMS ((FILE *, uint16, char));
92 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
93 static void print_constant PARAMS ((FILE *, JCF *, int, int));
94 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
95 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
96 static void print_name PARAMS ((FILE*, JCF*, int));
97 static void print_signature PARAMS ((FILE*, JCF*, int, int));
98 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
99 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
100 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
101 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
102 static void process_class PARAMS ((struct JCF *));
103 static void print_constant_pool PARAMS ((struct JCF *));
104 static void print_exception_table PARAMS ((struct JCF *,
105 const unsigned char *entries, int));
107 #define PRINT_SIGNATURE_RESULT_ONLY 1
108 #define PRINT_SIGNATURE_ARGS_ONLY 2
111 DEFUN(utf8_equal_string, (jcf, index, value),
112 JCF *jcf AND int index AND const char * value)
114 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
115 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
117 int len = strlen (value);
118 if (JPOOL_UTF_LENGTH (jcf, index) == len
119 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
125 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
126 this_class_index = 0; \
127 if (flag_print_class_info) \
129 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
130 (long) MAGIC, (long) MINOR, (long) MAJOR)
132 #define HANDLE_START_CONSTANT_POOL(COUNT) \
133 if (flag_print_constant_pool) \
134 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
136 #define HANDLE_SOURCEFILE(INDEX) \
137 { fprintf (out, "Attribute "); \
138 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
139 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
140 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
142 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
143 this_class_index = THIS; \
144 class_access_flags = ACCESS_FLAGS; \
145 if (flag_print_class_info) \
146 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
147 print_access_flags (out, ACCESS_FLAGS, 'c'); \
149 fprintf (out, "This class: "); \
150 if (flag_print_constant_pool) \
151 fprintf (out, "%d=", THIS); \
152 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
153 if (flag_print_constant_pool || SUPER != 0) \
154 fprintf (out, ", super: "); \
155 if (flag_print_constant_pool) \
157 fprintf (out, "%d", SUPER); \
162 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
163 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
166 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
167 (flag_print_attributes <= 0)
169 #define HANDLE_CLASS_INTERFACE(INDEX) \
170 if (flag_print_class_info) \
171 { fprintf (out, "- Implements: %d=", INDEX); \
172 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
175 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
176 if (flag_print_fields) \
177 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
179 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
180 if (flag_print_fields) \
181 { fprintf (out, "Field name:"); \
182 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
183 print_access_flags (out, ACCESS_FLAGS, 'f'); \
184 fprintf (out, " Signature: "); \
185 if (flag_print_constant_pool) \
186 fprintf (out, "%d=", SIGNATURE); \
187 print_signature (out, jcf, SIGNATURE, 0); \
188 fputc ('\n', out); } \
190 flag_print_attributes--;
192 #define HANDLE_END_FIELD() \
193 if (! flag_print_fields) \
194 flag_print_attributes++;
196 #define HANDLE_START_METHODS(METHODS_COUNT) \
197 if (flag_print_methods) \
198 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
200 flag_print_attributes--;
203 #define HANDLE_END_METHODS() \
204 if (! flag_print_methods) \
205 flag_print_attributes++;
207 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
209 if (flag_print_methods) \
211 if (flag_javap_compatible) \
213 fprintf (out, " "); \
214 print_access_flags (out, ACCESS_FLAGS, 'm'); \
216 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
218 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
219 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
224 fprintf (out, "\nMethod name:"); \
225 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
226 print_access_flags (out, ACCESS_FLAGS, 'm'); \
227 fprintf (out, " Signature: "); \
228 if (flag_print_constant_pool) \
229 fprintf (out, "%d=", SIGNATURE); \
230 print_signature (out, jcf, SIGNATURE, 0); \
234 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
235 && utf8_equal_string (jcf, NAME, "main") \
236 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
237 && this_class_index > 0 \
238 && (class_access_flags & ACC_PUBLIC)) \
240 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
245 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
246 ( fprintf (out, "Attribute "), \
247 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
248 fprintf (out, ", length:%ld", (long) LENGTH) )
250 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
251 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
252 fprintf (out, ", value: "), \
253 print_constant_ref (out, jcf, VALUE_INDEX), \
254 fprintf (out, "\n") )
256 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
257 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
258 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
259 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
260 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
262 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
263 print_exception_table (jcf, ENTRIES, COUNT)
265 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
266 { int n = (COUNT); int i; \
267 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
268 fprintf (out, ", count: %d\n", n); \
269 for (i = 0; i < n; i++) {\
270 int ex_index = JCF_readu2 (jcf); \
271 fprintf (out, "%3d: ", i); \
272 print_constant_ref (out, jcf, ex_index); \
273 fputc ('\n', out); } }
275 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
276 { int n = (COUNT); int i; \
277 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
278 fprintf (out, ", count: %d\n", n); \
279 for (i = 0; i < n; i++) {\
280 int start_pc = JCF_readu2 (jcf); \
281 int length = JCF_readu2 (jcf); \
282 int name_index = JCF_readu2 (jcf); \
283 int signature_index = JCF_readu2 (jcf); \
284 int slot = JCF_readu2 (jcf); \
285 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
286 print_name (out, jcf, name_index); \
287 fprintf (out, ", type: %d=", signature_index); \
288 print_signature (out, jcf, signature_index, 0); \
289 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
291 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
292 { int n = (COUNT); int i; \
293 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
294 fprintf (out, ", count: %d\n", n); \
295 if (flag_disassemble_methods) \
296 for (i = 0; i < n; i++) {\
297 int start_pc = JCF_readu2 (jcf); \
298 int line_number = JCF_readu2 (jcf); \
299 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
301 JCF_SKIP (jcf, 4 * n); }
303 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
305 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
308 uint16 inner_class_info_index = JCF_readu2 (jcf); \
309 uint16 outer_class_info_index = JCF_readu2 (jcf); \
310 uint16 inner_name_index = JCF_readu2 (jcf); \
311 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
313 if (flag_print_class_info) \
315 fprintf (out, "\n class: "); \
316 if (flag_print_constant_pool) \
317 fprintf (out, "%d=", inner_class_info_index); \
318 print_constant_terse (out, jcf, \
319 inner_class_info_index, CONSTANT_Class); \
320 fprintf (out, " (%d=", inner_name_index); \
321 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
322 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
323 print_access_flags (out, inner_class_access_flags, 'c'); \
324 fprintf (out, ", outer class: "); \
325 if (flag_print_constant_pool) \
326 fprintf (out, "%d=", outer_class_info_index); \
327 print_constant_terse (out, jcf, \
328 outer_class_info_index, CONSTANT_Class); \
331 if (flag_print_class_info) \
335 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
336 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
337 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
339 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
340 if (flag_print_attributes > 0) \
341 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
346 DEFUN(print_constant_ref, (stream, jcf, index),
347 FILE *stream AND JCF *jcf AND int index)
349 fprintf (stream, "#%d=<", index);
350 if (index <= 0 || index >= JPOOL_SIZE(jcf))
351 fprintf (stream, "out of range");
353 print_constant (stream, jcf, index, 1);
354 fprintf (stream, ">");
357 /* Print the access flags given by FLAGS.
358 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
359 or 'm' (method flags). */
362 DEFUN (print_access_flags, (stream, flags, context),
363 FILE *stream AND uint16 flags AND 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 DEFUN(print_name, (stream, jcf, name_index),
388 FILE* stream AND JCF* jcf AND int name_index)
390 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
391 fprintf (stream, "<not a UTF8 constant>");
393 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
394 JPOOL_UTF_LENGTH (jcf, name_index));
397 /* If the type of the constant at INDEX matches EXPECTED,
398 print it tersely, otherwise more verbosely. */
401 DEFUN(print_constant_terse, (out, jcf, index, expected),
402 FILE *out AND JCF *jcf AND int index AND int expected)
404 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
405 fprintf (out, "<constant pool index %d not in range>", index);
406 else if (JPOOL_TAG (jcf, index) != expected)
408 fprintf (out, "<Unexpected constant type ");
409 print_constant (out, jcf, index, 1);
413 print_constant (out, jcf, index, 0);
416 /* Print the constant at INDEX in JCF's constant pool.
417 If verbosity==0, print very tersely (no extraneous text).
418 If verbosity==1, prefix the type of the constant.
419 If verbosity==2, add more descriptive text. */
422 DEFUN(print_constant, (out, jcf, index, verbosity),
423 FILE *out AND JCF *jcf AND int index AND 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);
515 pun.f = JPOOL_FLOAT (jcf, index);
516 fprintf (out, "%s%.10g",
517 verbosity > 0 ? "Float " : "", (double) pun.f);
519 fprintf (out, ", bits = 0x%08lx", (long) pun.i);
523 case CONSTANT_Double:
525 jdouble dnum = JPOOL_DOUBLE (jcf, index);
526 fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
530 hi = JPOOL_UINT (jcf, index);
531 lo = JPOOL_UINT (jcf, index + 1);
532 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
536 case CONSTANT_NameAndType:
538 uint16 name = JPOOL_USHORT1 (jcf, index);
539 uint16 sig = JPOOL_USHORT2 (jcf, index);
543 fprintf (out, "NameAndType name: %d=", name);
545 fprintf (out, "NameAndType ");
547 print_name (out, jcf, name);
551 fprintf (out, ", signature: %d=", sig);
552 print_signature (out, jcf, sig, 0);
557 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
558 int length = JPOOL_UTF_LENGTH (jcf, index);
560 { /* Print as 8-bit bytes. */
561 fputs ("Utf8: \"", out);
562 while (--length >= 0)
563 jcf_print_char (out, *str++);
566 { /* Print as Unicode. */
568 jcf_print_utf8 (out, str, length);
574 fprintf (out, "(Unknown constant type %d)", kind);
579 DEFUN(print_constant_pool, (jcf),
583 for (i = 1; i < JPOOL_SIZE(jcf); i++)
585 int kind = JPOOL_TAG (jcf, i);
586 fprintf (out, "#%d: ", i);
587 print_constant (out, jcf, i, 2);
589 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
590 i++; /* These take up two slots in the constant table */
595 DEFUN(print_signature_type, (stream, ptr, limit),
596 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
605 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
607 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
609 print_signature_type (stream, ptr, limit);
610 if (array_size == -1)
611 fprintf (stream, "[]");
613 fprintf (stream, "[%d]", array_size);
618 fputc (*(*ptr)++, stream);
619 for (; **ptr != ')' && *ptr < limit; nargs++)
623 print_signature_type (stream, ptr, limit);
627 fputc (*(*ptr)++, stream);
628 print_signature_type (stream, ptr, limit);
631 fprintf (stream, "???");
635 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
636 case 'C': fprintf (stream, "char"); (*ptr)++; break;
637 case 'D': fprintf (stream, "double"); (*ptr)++; break;
638 case 'F': fprintf (stream, "float"); (*ptr)++; break;
639 case 'S': fprintf (stream, "short"); (*ptr)++; break;
640 case 'I': fprintf (stream, "int"); (*ptr)++; break;
641 case 'J': fprintf (stream, "long"); (*ptr)++; break;
642 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
643 case 'V': fprintf (stream, "void"); (*ptr)++; break;
646 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
647 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
652 jcf_print_char (stream, *(*ptr)++);
657 DEFUN(print_signature, (stream, jcf, signature_index, int options),
658 FILE* stream AND JCF *jcf AND int signature_index AND int options)
660 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
661 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
664 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
665 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
666 const unsigned char *limit;
667 limit = str + length;
669 fprintf (stream, "<empty signature string>");
672 if (options & PRINT_SIGNATURE_RESULT_ONLY)
674 while (str < limit && *str++ != ')') ;
676 if (options & PRINT_SIGNATURE_ARGS_ONLY)
680 while (str < limit && *str != ')')
682 print_signature_type (stream, &str, limit);
684 fputs (", ", stream);
690 print_signature_type (stream, &str, limit);
693 fprintf (stream, "<junk:");
694 jcf_print_utf8 (stream, str, limit - str);
704 DEFUN(print_exception_table, (jcf, entries, count),
705 JCF *jcf AND const unsigned char *entries AND int count)
707 /* Print exception table. */
711 const unsigned char *ptr = entries;
712 fprintf (out, "Exceptions (count: %d):\n", i);
713 for (; --i >= 0; ptr+= 8)
715 int start_pc = GET_u2 (ptr);
716 int end_pc = GET_u2 (ptr+2);
717 int handler_pc = GET_u2 (ptr+4);
718 int catch_type = GET_u2 (ptr+6);
719 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
720 start_pc, end_pc, handler_pc, catch_type);
722 fputs (" /* finally */", out);
726 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
733 #include "jcf-reader.c"
736 DEFUN(process_class, (jcf),
740 if (jcf_parse_preamble (jcf) != 0)
741 fprintf (stderr, "Not a valid Java .class file.\n");
743 /* Parse and possibly print constant pool */
744 code = jcf_parse_constant_pool (jcf);
747 fprintf (stderr, "error while parsing constant pool\n");
748 exit (FATAL_EXIT_CODE);
750 code = verify_constant_pool (jcf);
753 fprintf (stderr, "error in constant pool entry #%d\n", code);
754 exit (FATAL_EXIT_CODE);
756 if (flag_print_constant_pool)
757 print_constant_pool (jcf);
759 jcf_parse_class (jcf);
760 code = jcf_parse_fields (jcf);
763 fprintf (stderr, "error while parsing fields\n");
764 exit (FATAL_EXIT_CODE);
766 code = jcf_parse_methods (jcf);
769 fprintf (stderr, "error while parsing methods\n");
770 exit (FATAL_EXIT_CODE);
772 code = jcf_parse_final_attributes (jcf);
775 fprintf (stderr, "error while parsing final attributes\n");
776 exit (FATAL_EXIT_CODE);
778 jcf->filename = NULL;
783 /* This is used to mark options with no short value. */
784 #define LONG_OPT(Num) ((Num) + 128)
786 #define OPT_classpath LONG_OPT (0)
787 #define OPT_CLASSPATH OPT_classpath
788 #define OPT_bootclasspath LONG_OPT (1)
789 #define OPT_extdirs LONG_OPT (2)
790 #define OPT_HELP LONG_OPT (3)
791 #define OPT_VERSION LONG_OPT (4)
792 #define OPT_JAVAP LONG_OPT (5)
794 static const struct option options[] =
796 { "classpath", required_argument, NULL, OPT_classpath },
797 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
798 { "extdirs", required_argument, NULL, OPT_extdirs },
799 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
800 { "help", no_argument, NULL, OPT_HELP },
801 { "verbose", no_argument, NULL, 'v' },
802 { "version", no_argument, NULL, OPT_VERSION },
803 { "javap", no_argument, NULL, OPT_JAVAP },
804 { "print-main", no_argument, &flag_print_main, 1 },
805 { NULL, no_argument, NULL, 0 }
811 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
818 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
819 printf ("Display contents of a class file in readable form.\n\n");
820 printf (" -c Disassemble method bodies\n");
821 printf (" --javap Generate output in `javap' format\n");
823 printf (" --classpath PATH Set path to find .class files\n");
824 printf (" -IDIR Append directory to class path\n");
825 printf (" --bootclasspath PATH Override built-in class path\n");
826 printf (" --extdirs PATH Set extensions directory path\n");
827 printf (" -o FILE Set output file name\n");
829 printf (" --help Print this help, then exit\n");
830 printf (" --version Print version number, then exit\n");
831 printf (" -v, --verbose Print extra information while running\n");
833 printf ("For bug reporting instructions, please see:\n");
834 printf ("%s.\n", bug_report_url);
841 printf ("jcf-dump (GCC) %s\n\n", version_string);
842 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
843 printf ("This is free software; see the source for copying conditions. There is NO\n");
844 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
849 DEFUN(main, (argc, argv),
850 int argc AND char** argv)
857 fprintf (stderr, "jcf-dump: no classes specified\n");
863 /* We use getopt_long_only to allow single `-' long options. For
864 some of our options this is more natural. */
865 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
870 /* Already handled. */
874 output_file = optarg;
878 jcf_path_include_arg (optarg);
886 flag_disassemble_methods = 1;
890 jcf_path_classpath_arg (optarg);
893 case OPT_bootclasspath:
894 jcf_path_bootclasspath_arg (optarg);
898 jcf_path_extdirs_arg (optarg);
910 flag_javap_compatible++;
911 flag_print_constant_pool = 0;
912 flag_print_attributes = 0;
922 fprintf (stderr, "jcf-dump: no classes specified\n");
926 jcf_path_seal (verbose);
930 flag_print_fields = 0;
931 flag_print_methods = 0;
932 flag_print_constant_pool = 0;
933 flag_print_attributes = 0;
934 flag_print_class_info = 0;
939 out = fopen (output_file, "w");
942 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
943 return FATAL_EXIT_CODE;
951 fprintf (out, "Reading .class from <standard input>.\n");
952 open_class ("<stdio>", jcf, 0, NULL);
957 for (argi = optind; argi < argc; argi++)
959 char *arg = argv[argi];
960 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
961 if (class_filename == NULL)
962 class_filename = find_classfile (arg, jcf, NULL);
963 if (class_filename == NULL)
965 perror ("Could not find class");
966 return FATAL_EXIT_CODE;
969 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
971 long compressed_size, member_size;
972 int compression_method, filename_length, extra_length;
973 int general_purpose_bits;
974 const char *filename;
976 if (flag_print_class_info)
977 fprintf (out, "Reading classes from archive %s.\n",
982 jcf_filbuf_t save_filbuf = jcf->filbuf;
983 long magic = JCF_readu4_le (jcf);
984 if (magic == 0x02014b50 || magic == 0x06054b50)
985 break; /* got to central directory */
986 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
988 fprintf (stderr, "bad format of .zip/.jar archive\n");
989 return FATAL_EXIT_CODE;
993 general_purpose_bits = JCF_readu2_le (jcf);
994 compression_method = JCF_readu2_le (jcf);
996 compressed_size = JCF_readu4_le (jcf);
997 member_size = JCF_readu4_le (jcf);
998 filename_length = JCF_readu2_le (jcf);
999 extra_length = JCF_readu2_le (jcf);
1000 total_length = filename_length + extra_length
1002 if (jcf->read_end - jcf->read_ptr < total_length)
1003 jcf_trim_old_input (jcf);
1004 JCF_FILL (jcf, total_length);
1005 filename = jcf->read_ptr;
1006 JCF_SKIP (jcf, filename_length);
1007 JCF_SKIP (jcf, extra_length);
1008 if (filename_length > 0
1009 && filename[filename_length-1] == '/')
1011 if (flag_print_class_info)
1012 fprintf (out, "[Skipping directory %.*s]\n",
1013 filename_length, filename);
1016 else if (compression_method != 0)
1018 if (flag_print_class_info)
1019 fprintf (out, "[Skipping compressed file %.*s]\n",
1020 filename_length, filename);
1023 else if (member_size < 4
1024 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1026 if (flag_print_class_info)
1027 fprintf (out, "[Skipping non-.class member %.*s]\n",
1028 filename_length, filename);
1033 if (flag_print_class_info)
1034 fprintf (out, "Reading class member: %.*s.\n",
1035 filename_length, filename);
1039 JCF_SKIP (jcf, compressed_size);
1043 unsigned char *save_end;
1044 jcf->filbuf = jcf_unexpected_eof;
1045 save_end = jcf->read_end;
1046 jcf->read_end = jcf->read_ptr + compressed_size;
1047 process_class (jcf);
1048 jcf->filbuf = save_filbuf;
1049 jcf->read_end = save_end;
1055 if (flag_print_class_info)
1056 fprintf (out, "Reading .class from %s.\n", class_filename);
1057 process_class (jcf);
1063 return SUCCESS_EXIT_CODE;
1069 DEFUN(disassemble_method, (jcf, byte_ops, len),
1070 JCF* jcf AND const unsigned char *byte_ops AND int len)
1072 #undef AND /* Causes problems with opcodes for iand and land. */
1077 if (flag_disassemble_methods == 0)
1079 #define BCODE byte_ops
1080 for (PC = 0; PC < len;)
1085 switch (byte_ops[PC++])
1088 /* This is the actual code emitted for each of opcodes in javaops.def.
1089 The actual opcode-specific stuff is handled by the OPKIND macro.
1090 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1091 Those macros are defiend below. The OPKINDs that do not have any
1092 inline parameters (such as BINOP) and therefore do mot need anything
1093 else to me printed out just use an empty body. */
1095 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1097 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1098 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1099 fputc ('\n', out); \
1102 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1103 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1104 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1105 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1107 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1108 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1110 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1111 These all push a constant onto the opcode stack. */
1112 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1113 saw_index = 0, i = (OPERAND_VALUE); \
1114 if (oldpc+1 == PC) /* nothing */; \
1115 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1116 else fprintf (out, " %d", i);
1118 /* Print out operand (a local variable index) for LOAD opcodes.
1119 These all push local variable onto the opcode stack. */
1120 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1121 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1123 /* Handle STORE opcodes same as LOAD opcodes.
1124 These all store a value from the opcode stack in a local variable. */
1127 /* Handle more kind of opcodes. */
1128 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1129 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1130 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1131 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1132 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1133 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1134 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1136 /* Handle putfield and getfield opcodes, with static versions. */
1137 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1138 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1140 /* Print operand for invoke opcodes. */
1141 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1142 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1143 if (OPERAND_VALUE) /* for invokeinterface */ \
1144 { int nargs = IMMEDIATE_u1; PC++; \
1145 fprintf (out, " nargs:%d", nargs); }
1147 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1148 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1150 #define ARRAY(OPERAND_TYPE, SUBOP) \
1151 ARRAY_##SUBOP(OPERAND_TYPE)
1152 /* Handle sub-categories of ARRAY opcodes. */
1153 #define ARRAY_LOAD(TYPE) /* nothing */
1154 #define ARRAY_STORE(TYPE) /* nothing */
1155 #define ARRAY_LENGTH(TYPE) /* nothing */
1156 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1157 #define ARRAY_NEW_NUM \
1158 INT_temp = IMMEDIATE_u1; \
1159 { switch ((int) INT_temp) { \
1160 case 4: fputs (" boolean", out); break; \
1161 case 5: fputs (" char", out); break; \
1162 case 6: fputs (" float", out); break; \
1163 case 7: fputs (" double", out); break; \
1164 case 8: fputs (" byte", out); break; \
1165 case 9: fputs (" short", out); break; \
1166 case 10: fputs (" int", out); break; \
1167 case 11: fputs (" long", out); break; \
1168 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1171 #define ARRAY_NEW_PTR \
1172 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1174 #define ARRAY_NEW_MULTI \
1175 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1176 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1178 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1179 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1181 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1182 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1183 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1185 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1186 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1187 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1189 #undef RET /* Defined by config/i386/i386.h */
1190 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1191 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1193 fprintf (out, " %ld", (long) INT_temp);
1195 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1196 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1198 #define LOOKUP_SWITCH \
1199 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1200 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1201 while (--npairs >= 0) { \
1202 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1203 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1206 #define TABLE_SWITCH \
1207 { jint default_offset = IMMEDIATE_s4; \
1208 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1209 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1210 (long) low, (long) high, (long) default_offset+oldpc); \
1211 for (; low <= high; low++) { \
1212 jint offset = IMMEDIATE_s4; \
1213 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1216 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1217 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1219 #define SPECIAL_IINC(OPERAND_TYPE) \
1220 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1221 fprintf (out, " %d", i); \
1222 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1224 fprintf (out, " %d", i)
1226 #define SPECIAL_WIDE(OPERAND_TYPE) \
1229 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1230 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1231 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1232 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1234 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1235 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1237 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1238 TEST(OPERAND_TYPE, OPERAND_VALUE)
1240 #include "javaop.def"
1243 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1247 fprintf (out, " %ld", (long) INT_temp);
1253 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);