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 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
28 jcf-dump is a program to print out the contents of class files.
29 Usage: jcf-dump [FLAGS] CLASS
31 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
32 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
33 + The name of a .zip or .jar file (which prints all the classes in the
38 Dis-assemble each method.
42 Print nothing if there is no valid "main" method;
43 otherwise, print only the class name.
45 Print output in the style of Sun's javap program. VERY UNFINISHED.
54 #include "java-tree.h"
62 /* Name of output file, if NULL if stdout. */
63 char *output_file = NULL;
67 int flag_disassemble_methods = 0;
68 int flag_print_class_info = 1;
69 int flag_print_constant_pool = 1;
70 int flag_print_fields = 1;
71 int flag_print_methods = 1;
72 int flag_print_attributes = 1;
74 /* Print names of classes that have a "main" method. */
75 int flag_print_main = 0;
77 /* Index in constant pool of this class. */
78 int this_class_index = 0;
80 int class_access_flags = 0;
82 /* Print in format similar to javap. VERY IMCOMPLETE. */
83 int flag_javap_compatible = 0;
85 static void print_access_flags PARAMS ((FILE *, uint16, char));
86 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
87 static void print_constant PARAMS ((FILE *, JCF *, int, int));
88 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
89 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
90 static void print_name PARAMS ((FILE*, JCF*, int));
91 static void print_signature PARAMS ((FILE*, JCF*, int, int));
92 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
93 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
94 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
95 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
96 static void process_class PARAMS ((struct JCF *));
97 static void print_constant_pool PARAMS ((struct JCF *));
98 static void print_exception_table PARAMS ((struct JCF *,
99 const unsigned char *entries, int));
101 #define PRINT_SIGNATURE_RESULT_ONLY 1
102 #define PRINT_SIGNATURE_ARGS_ONLY 2
105 DEFUN(utf8_equal_string, (jcf, index, value),
106 JCF *jcf AND int index AND const char * value)
108 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
109 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
111 int len = strlen (value);
112 if (JPOOL_UTF_LENGTH (jcf, index) == len
113 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
119 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
120 this_class_index = 0; \
121 if (flag_print_class_info) \
123 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
124 (long) MAGIC, (long) MINOR, (long) MAJOR)
126 #define HANDLE_START_CONSTANT_POOL(COUNT) \
127 if (flag_print_constant_pool) \
128 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
130 #define HANDLE_SOURCEFILE(INDEX) \
131 { fprintf (out, "Attribute "); \
132 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
133 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
134 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
136 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
137 this_class_index = THIS; \
138 class_access_flags = ACCESS_FLAGS; \
139 if (flag_print_class_info) \
140 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
141 print_access_flags (out, ACCESS_FLAGS, 'c'); \
143 fprintf (out, "This class: "); \
144 if (flag_print_constant_pool) \
145 fprintf (out, "%d=", THIS); \
146 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
147 if (flag_print_constant_pool || SUPER != 0) \
148 fprintf (out, ", super: "); \
149 if (flag_print_constant_pool) \
151 fprintf (out, "%d", SUPER); \
156 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
157 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
160 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
161 (flag_print_attributes <= 0)
163 #define HANDLE_CLASS_INTERFACE(INDEX) \
164 if (flag_print_class_info) \
165 { fprintf (out, "- Implements: %d=", INDEX); \
166 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
169 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
170 if (flag_print_fields) \
171 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
173 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
174 if (flag_print_fields) \
175 { fprintf (out, "Field name:"); \
176 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
177 print_access_flags (out, ACCESS_FLAGS, 'f'); \
178 fprintf (out, " Signature: "); \
179 if (flag_print_constant_pool) \
180 fprintf (out, "%d=", SIGNATURE); \
181 print_signature (out, jcf, SIGNATURE, 0); \
182 fputc ('\n', out); } \
184 flag_print_attributes--;
186 #define HANDLE_END_FIELD() \
187 if (! flag_print_fields) \
188 flag_print_attributes++;
190 #define HANDLE_START_METHODS(METHODS_COUNT) \
191 if (flag_print_methods) \
192 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
194 flag_print_attributes--;
197 #define HANDLE_END_METHODS() \
198 if (! flag_print_methods) \
199 flag_print_attributes++;
201 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
203 if (flag_print_methods) \
205 if (flag_javap_compatible) \
207 fprintf (out, " "); \
208 print_access_flags (out, ACCESS_FLAGS, 'm'); \
210 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
212 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
213 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
218 fprintf (out, "\nMethod name:"); \
219 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
220 print_access_flags (out, ACCESS_FLAGS, 'm'); \
221 fprintf (out, " Signature: "); \
222 if (flag_print_constant_pool) \
223 fprintf (out, "%d=", SIGNATURE); \
224 print_signature (out, jcf, SIGNATURE, 0); \
228 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
229 && utf8_equal_string (jcf, NAME, "main") \
230 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
231 && this_class_index > 0 \
232 && (class_access_flags & ACC_PUBLIC)) \
234 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
239 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
240 ( fprintf (out, "Attribute "), \
241 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
242 fprintf (out, ", length:%ld", (long) LENGTH) )
244 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
245 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
246 fprintf (out, ", value: "), \
247 print_constant_ref (out, jcf, VALUE_INDEX), \
248 fprintf (out, "\n") )
250 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
251 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
252 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
253 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
254 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
256 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
257 print_exception_table (jcf, ENTRIES, COUNT)
259 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
260 { int n = (COUNT); int i; \
261 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
262 fprintf (out, ", count: %d\n", n); \
263 for (i = 0; i < n; i++) {\
264 int ex_index = JCF_readu2 (jcf); \
265 fprintf (out, "%3d: ", i); \
266 print_constant_ref (out, jcf, ex_index); \
267 fputc ('\n', out); } }
269 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
270 { int n = (COUNT); int i; \
271 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
272 fprintf (out, ", count: %d\n", n); \
273 for (i = 0; i < n; i++) {\
274 int start_pc = JCF_readu2 (jcf); \
275 int length = JCF_readu2 (jcf); \
276 int name_index = JCF_readu2 (jcf); \
277 int signature_index = JCF_readu2 (jcf); \
278 int slot = JCF_readu2 (jcf); \
279 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
280 print_name (out, jcf, name_index); \
281 fprintf (out, ", type: %d=", signature_index); \
282 print_signature (out, jcf, signature_index, 0); \
283 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
285 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
286 { int n = (COUNT); int i; \
287 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
288 fprintf (out, ", count: %d\n", n); \
289 if (flag_disassemble_methods) \
290 for (i = 0; i < n; i++) {\
291 int start_pc = JCF_readu2 (jcf); \
292 int line_number = JCF_readu2 (jcf); \
293 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
295 JCF_SKIP (jcf, 4 * n); }
297 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
299 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
302 uint16 inner_class_info_index = JCF_readu2 (jcf); \
303 uint16 outer_class_info_index = JCF_readu2 (jcf); \
304 uint16 inner_name_index = JCF_readu2 (jcf); \
305 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
307 if (flag_print_class_info) \
309 fprintf (out, "\n class: "); \
310 if (flag_print_constant_pool) \
311 fprintf (out, "%d=", inner_class_info_index); \
312 print_constant_terse (out, jcf, \
313 inner_class_info_index, CONSTANT_Class); \
314 fprintf (out, " (%d=", inner_name_index); \
315 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
316 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
317 print_access_flags (out, inner_class_access_flags, 'c'); \
318 fprintf (out, ", outer class: "); \
319 if (flag_print_constant_pool) \
320 fprintf (out, "%d=", outer_class_info_index); \
321 print_constant_terse (out, jcf, \
322 outer_class_info_index, CONSTANT_Class); \
325 if (flag_print_class_info) \
329 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
330 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
331 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
333 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
334 if (flag_print_attributes > 0) \
335 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
340 DEFUN(print_constant_ref, (stream, jcf, index),
341 FILE *stream AND JCF *jcf AND int index)
343 fprintf (stream, "#%d=<", index);
344 if (index <= 0 || index >= JPOOL_SIZE(jcf))
345 fprintf (stream, "out of range");
347 print_constant (stream, jcf, index, 1);
348 fprintf (stream, ">");
351 /* Print the access flags given by FLAGS.
352 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
353 or 'm' (method flags). */
356 DEFUN (print_access_flags, (stream, flags, context),
357 FILE *stream AND uint16 flags AND char context)
359 if (flags & ACC_PUBLIC) fprintf (stream, " public");
360 if (flags & ACC_PRIVATE) fprintf (stream, " private");
361 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
362 if (flags & ACC_STATIC) fprintf (stream, " static");
363 if (flags & ACC_FINAL) fprintf (stream, " final");
364 if (flags & ACC_SYNCHRONIZED)
367 fprintf (stream, " super");
369 fprintf (stream, " synchronized");
371 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
372 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
373 if (flags & ACC_NATIVE) fprintf (stream, " native");
374 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
375 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
380 DEFUN(print_name, (stream, jcf, name_index),
381 FILE* stream AND JCF* jcf AND int name_index)
383 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
384 fprintf (stream, "<not a UTF8 constant>");
386 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
387 JPOOL_UTF_LENGTH (jcf, name_index));
390 /* If the type of the constant at INDEX matches EXPECTED,
391 print it tersely, otherwise more verbosely. */
394 DEFUN(print_constant_terse, (out, jcf, index, expected),
395 FILE *out AND JCF *jcf AND int index AND int expected)
397 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
398 fprintf (out, "<constant pool index %d not in range>", index);
399 else if (JPOOL_TAG (jcf, index) != expected)
401 fprintf (out, "<Unexpected constant type ");
402 print_constant (out, jcf, index, 1);
406 print_constant (out, jcf, index, 0);
409 /* Print the constant at INDEX in JCF's constant pool.
410 If verbosity==0, print very tersely (no extraneous text).
411 If verbosity==1, prefix the type of the constant.
412 If verbosity==2, add more descriptive text. */
415 DEFUN(print_constant, (out, jcf, index, verbosity),
416 FILE *out AND JCF *jcf AND int index AND int verbosity)
421 int kind = JPOOL_TAG (jcf, index);
425 n = JPOOL_USHORT1 (jcf, index);
429 fprintf (out, "Class name: %d=", n);
431 fprintf (out, "Class ");
433 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
434 fprintf (out, "<out of range>");
435 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
437 int len = JPOOL_UTF_LENGTH (jcf, n);
438 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
441 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
443 case CONSTANT_Fieldref:
444 str = "Field"; goto field_or_method;
445 case CONSTANT_Methodref:
446 str = "Method"; goto field_or_method;
447 case CONSTANT_InterfaceMethodref:
448 str = "InterfaceMethod"; goto field_or_method;
451 uint16 tclass = JPOOL_USHORT1 (jcf, index);
452 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
454 fprintf (out, "%sref class: %d=", str, tclass);
455 else if (verbosity > 0)
456 fprintf (out, "%s ", str);
457 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
461 fprintf (out, " name_and_type: %d=<", name_and_type);
462 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
467 case CONSTANT_String:
468 j = JPOOL_USHORT1 (jcf, index);
472 fprintf (out, "String %d=", j);
474 fprintf (out, "String ");
476 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
478 case CONSTANT_Integer:
480 fprintf (out, "Integer ");
481 num = JPOOL_INT (jcf, index);
485 fprintf (out, "Long ");
486 num = JPOOL_LONG (jcf, index);
491 format_int (buffer, num, 10);
492 fprintf (out, "%s", buffer);
495 format_uint (buffer, (uint64)num, 16);
496 fprintf (out, "=0x%s", buffer);
502 jfloat fnum = JPOOL_FLOAT (jcf, index);
503 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
505 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
508 case CONSTANT_Double:
510 jdouble dnum = JPOOL_DOUBLE (jcf, index);
511 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
515 hi = JPOOL_UINT (jcf, index);
516 lo = JPOOL_UINT (jcf, index + 1);
517 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
521 case CONSTANT_NameAndType:
523 uint16 name = JPOOL_USHORT1 (jcf, index);
524 uint16 sig = JPOOL_USHORT2 (jcf, index);
528 fprintf (out, "NameAndType name: %d=", name);
530 fprintf (out, "NameAndType ");
532 print_name (out, jcf, name);
536 fprintf (out, ", signature: %d=", sig);
537 print_signature (out, jcf, sig, 0);
542 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
543 int length = JPOOL_UTF_LENGTH (jcf, index);
545 { /* Print as 8-bit bytes. */
546 fputs ("Utf8: \"", out);
547 while (--length >= 0)
548 jcf_print_char (out, *str++);
551 { /* Print as Unicode. */
553 jcf_print_utf8 (out, str, length);
559 fprintf (out, "(Unknown constant type %d)", kind);
564 DEFUN(print_constant_pool, (jcf),
568 for (i = 1; i < JPOOL_SIZE(jcf); i++)
570 int kind = JPOOL_TAG (jcf, i);
571 fprintf (out, "#%d: ", i);
572 print_constant (out, jcf, i, 2);
574 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
575 i++; /* These take up two slots in the constant table */
580 DEFUN(print_signature_type, (stream, ptr, limit),
581 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
590 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
592 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
594 print_signature_type (stream, ptr, limit);
595 if (array_size == -1)
596 fprintf (stream, "[]");
598 fprintf (stream, "[%d]", array_size);
603 fputc (*(*ptr)++, stream);
604 for (; **ptr != ')' && *ptr < limit; nargs++)
608 print_signature_type (stream, ptr, limit);
612 fputc (*(*ptr)++, stream);
613 print_signature_type (stream, ptr, limit);
616 fprintf (stream, "???");
620 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
621 case 'C': fprintf (stream, "char"); (*ptr)++; break;
622 case 'D': fprintf (stream, "double"); (*ptr)++; break;
623 case 'F': fprintf (stream, "float"); (*ptr)++; break;
624 case 'S': fprintf (stream, "short"); (*ptr)++; break;
625 case 'I': fprintf (stream, "int"); (*ptr)++; break;
626 case 'J': fprintf (stream, "long"); (*ptr)++; break;
627 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
628 case 'V': fprintf (stream, "void"); (*ptr)++; break;
631 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
632 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
637 jcf_print_char (stream, *(*ptr)++);
642 DEFUN(print_signature, (stream, jcf, signature_index, int options),
643 FILE* stream AND JCF *jcf AND int signature_index AND int options)
645 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
646 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
649 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
650 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
651 const unsigned char *limit;
652 limit = str + length;
654 fprintf (stream, "<empty signature string>");
657 if (options & PRINT_SIGNATURE_RESULT_ONLY)
659 while (str < limit && *str++ != ')') ;
661 if (options & PRINT_SIGNATURE_ARGS_ONLY)
665 while (str < limit && *str != ')')
667 print_signature_type (stream, &str, limit);
669 fputs (", ", stream);
675 print_signature_type (stream, &str, limit);
678 fprintf (stream, "<junk:");
679 jcf_print_utf8 (stream, str, limit - str);
689 DEFUN(print_exception_table, (jcf, entries, count),
690 JCF *jcf AND const unsigned char *entries AND int count)
692 /* Print exception table. */
696 const unsigned char *ptr = entries;
697 fprintf (out, "Exceptions (count: %d):\n", i);
698 for (; --i >= 0; ptr+= 8)
700 int start_pc = GET_u2 (ptr);
701 int end_pc = GET_u2 (ptr+2);
702 int handler_pc = GET_u2 (ptr+4);
703 int catch_type = GET_u2 (ptr+6);
704 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
705 start_pc, end_pc, handler_pc, catch_type);
707 fputs (" /* finally */", out);
711 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
718 #include "jcf-reader.c"
721 DEFUN(process_class, (jcf),
725 if (jcf_parse_preamble (jcf) != 0)
726 fprintf (stderr, "Not a valid Java .class file.\n");
728 /* Parse and possibly print constant pool */
729 code = jcf_parse_constant_pool (jcf);
732 fprintf (stderr, "error while parsing constant pool\n");
733 exit (FATAL_EXIT_CODE);
735 code = verify_constant_pool (jcf);
738 fprintf (stderr, "error in constant pool entry #%d\n", code);
739 exit (FATAL_EXIT_CODE);
741 if (flag_print_constant_pool)
742 print_constant_pool (jcf);
744 jcf_parse_class (jcf);
745 code = jcf_parse_fields (jcf);
748 fprintf (stderr, "error while parsing fields\n");
749 exit (FATAL_EXIT_CODE);
751 code = jcf_parse_methods (jcf);
754 fprintf (stderr, "error while parsing methods\n");
755 exit (FATAL_EXIT_CODE);
757 code = jcf_parse_final_attributes (jcf);
760 fprintf (stderr, "error while parsing final attributes\n");
761 exit (FATAL_EXIT_CODE);
763 jcf->filename = NULL;
768 /* This is used to mark options with no short value. */
769 #define LONG_OPT(Num) ((Num) + 128)
771 #define OPT_classpath LONG_OPT (0)
772 #define OPT_CLASSPATH LONG_OPT (1)
773 #define OPT_HELP LONG_OPT (2)
774 #define OPT_VERSION LONG_OPT (3)
775 #define OPT_JAVAP LONG_OPT (4)
777 static struct option options[] =
779 { "classpath", required_argument, NULL, OPT_classpath },
780 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
781 { "help", no_argument, NULL, OPT_HELP },
782 { "verbose", no_argument, NULL, 'v' },
783 { "version", no_argument, NULL, OPT_VERSION },
784 { "javap", no_argument, NULL, OPT_JAVAP },
785 { "print-main", no_argument, &flag_print_main, 1 },
786 { NULL, no_argument, NULL, 0 }
792 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
799 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
800 printf ("Display contents of a class file in readable form.\n\n");
801 printf (" -c Disassemble method bodies\n");
802 printf (" --javap Generate output in `javap' format\n");
804 printf (" --classpath PATH Set path to find .class files\n");
805 printf (" --CLASSPATH PATH Set path to find .class files\n");
806 printf (" -IDIR Append directory to class path\n");
807 printf (" -o FILE Set output file name\n");
809 printf (" --help Print this help, then exit\n");
810 printf (" --version Print version number, then exit\n");
811 printf (" -v, --verbose Print extra information while running\n");
813 printf ("For bug reporting instructions, please see:\n");
814 printf ("%s.\n", GCCBUGURL);
821 printf ("jcf-dump (%s)\n\n", version_string);
822 printf ("Copyright (C) 1998, 1999 Free Software Foundation, Inc.\n");
823 printf ("This is free software; see the source for copying conditions. There is NO\n");
824 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
829 DEFUN(main, (argc, argv),
830 int argc AND char** argv)
837 fprintf (stderr, "jcf-dump: no classes specified\n");
843 /* We use getopt_long_only to allow single `-' long options. For
844 some of our options this is more natural. */
845 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
850 /* Already handled. */
854 output_file = optarg;
858 jcf_path_include_arg (optarg);
866 flag_disassemble_methods = 1;
870 jcf_path_classpath_arg (optarg);
874 jcf_path_CLASSPATH_arg (optarg);
886 flag_javap_compatible++;
887 flag_print_constant_pool = 0;
897 fprintf (stderr, "jcf-dump: no classes specified\n");
905 flag_print_fields = 0;
906 flag_print_methods = 0;
907 flag_print_constant_pool = 0;
908 flag_print_attributes = 0;
909 flag_print_class_info = 0;
914 out = fopen (output_file, "w");
917 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
918 return FATAL_EXIT_CODE;
926 fprintf (out, "Reading .class from <standard input>.\n");
928 open_class ("<stdio>", jcf, stdin, NULL);
930 open_class ("<stdio>", jcf, 0, NULL);
936 for (argi = optind; argi < argc; argi++)
938 char *arg = argv[argi];
939 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
940 if (class_filename == NULL)
941 class_filename = find_classfile (arg, jcf, NULL);
942 if (class_filename == NULL)
944 perror ("Could not find class");
945 return FATAL_EXIT_CODE;
948 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
950 long compressed_size, member_size;
951 int compression_method, filename_length, extra_length;
952 int general_purpose_bits;
953 const char *filename;
955 if (flag_print_class_info)
956 fprintf (out, "Reading classes from archive %s.\n",
961 jcf_filbuf_t save_filbuf = jcf->filbuf;
962 long magic = JCF_readu4_le (jcf);
963 if (magic == 0x02014b50 || magic == 0x06054b50)
964 break; /* got to central directory */
965 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
967 fprintf (stderr, "bad format of .zip/.jar archive\n");
968 return FATAL_EXIT_CODE;
972 general_purpose_bits = JCF_readu2_le (jcf);
973 compression_method = JCF_readu2_le (jcf);
975 compressed_size = JCF_readu4_le (jcf);
976 member_size = JCF_readu4_le (jcf);
977 filename_length = JCF_readu2_le (jcf);
978 extra_length = JCF_readu2_le (jcf);
979 total_length = filename_length + extra_length
981 if (jcf->read_end - jcf->read_ptr < total_length)
982 jcf_trim_old_input (jcf);
983 JCF_FILL (jcf, total_length);
984 filename = jcf->read_ptr;
985 JCF_SKIP (jcf, filename_length);
986 JCF_SKIP (jcf, extra_length);
987 if (filename_length > 0
988 && filename[filename_length-1] == '/')
990 if (flag_print_class_info)
991 fprintf (out, "[Skipping directory %.*s]\n",
992 filename_length, filename);
995 else if (compression_method != 0)
997 if (flag_print_class_info)
998 fprintf (out, "[Skipping compressed file %.*s]\n",
999 filename_length, filename);
1002 else if (member_size < 4
1003 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1005 if (flag_print_class_info)
1006 fprintf (out, "[Skipping non-.class member %.*s]\n",
1007 filename_length, filename);
1012 if (flag_print_class_info)
1013 fprintf (out, "Reading class member: %.*s.\n",
1014 filename_length, filename);
1018 JCF_SKIP (jcf, compressed_size);
1022 unsigned char *save_end;
1023 jcf->filbuf = jcf_unexpected_eof;
1024 save_end = jcf->read_end;
1025 jcf->read_end = jcf->read_ptr + compressed_size;
1026 process_class (jcf);
1027 jcf->filbuf = save_filbuf;
1028 jcf->read_end = save_end;
1034 if (flag_print_class_info)
1035 fprintf (out, "Reading .class from %s.\n", class_filename);
1036 process_class (jcf);
1042 return SUCCESS_EXIT_CODE;
1048 DEFUN(disassemble_method, (jcf, byte_ops, len),
1049 JCF* jcf AND const unsigned char *byte_ops AND int len)
1051 #undef AND /* Causes problems with opcodes for iand and land. */
1056 if (flag_disassemble_methods == 0)
1058 #define BCODE byte_ops
1059 for (PC = 0; PC < len;)
1064 switch (byte_ops[PC++])
1067 /* This is the actual code emitted for each of opcodes in javaops.def.
1068 The actual opcode-specific stuff is handled by the OPKIND macro.
1069 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1070 Those macros are defiend below. The OPKINDs that do not have any
1071 inline parameters (such as BINOP) and therefore do mot need anything
1072 else to me printed out just use an empty body. */
1074 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1076 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1077 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1078 fputc ('\n', out); \
1081 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1082 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1083 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1084 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1086 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1087 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1089 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1090 These all push a constant onto the opcode stack. */
1091 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1092 saw_index = 0, i = (OPERAND_VALUE); \
1093 if (oldpc+1 == PC) /* nothing */; \
1094 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1095 else fprintf (out, " %d", i);
1097 /* Print out operand (a local variable index) for LOAD opcodes.
1098 These all push local variable onto the opcode stack. */
1099 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1100 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1102 /* Handle STORE opcodes same as LOAD opcodes.
1103 These all store a value from the opcode stack in a local variable. */
1106 /* Handle more kind of opcodes. */
1107 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1108 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1109 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1110 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1111 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1112 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1113 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1115 /* Handle putfield and getfield opcodes, with static versions. */
1116 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1117 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1119 /* Print operand for invoke opcodes. */
1120 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1121 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1122 if (OPERAND_VALUE) /* for invokeinterface */ \
1123 { int nargs = IMMEDIATE_u1; PC++; \
1124 fprintf (out, " nargs:%d", nargs); }
1126 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1127 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1129 #define ARRAY(OPERAND_TYPE, SUBOP) \
1130 ARRAY_##SUBOP(OPERAND_TYPE)
1131 /* Handle sub-categories of ARRAY opcodes. */
1132 #define ARRAY_LOAD(TYPE) /* nothing */
1133 #define ARRAY_STORE(TYPE) /* nothing */
1134 #define ARRAY_LENGTH(TYPE) /* nothing */
1135 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1136 #define ARRAY_NEW_NUM \
1137 INT_temp = IMMEDIATE_u1; \
1138 { switch ((int) INT_temp) { \
1139 case 4: fputs (" boolean", out); break; \
1140 case 5: fputs (" char", out); break; \
1141 case 6: fputs (" float", out); break; \
1142 case 7: fputs (" double", out); break; \
1143 case 8: fputs (" byte", out); break; \
1144 case 9: fputs (" short", out); break; \
1145 case 10: fputs (" int", out); break; \
1146 case 11: fputs (" long", out); break; \
1147 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1150 #define ARRAY_NEW_PTR \
1151 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1153 #define ARRAY_NEW_MULTI \
1154 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1155 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1157 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1158 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1160 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1161 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1162 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1164 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1165 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1166 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1168 #undef RET /* Defined by config/i386/i386.h */
1169 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1170 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1172 fprintf (out, " %ld", (long) INT_temp);
1174 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1175 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1177 #define LOOKUP_SWITCH \
1178 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1179 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1180 while (--npairs >= 0) { \
1181 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1182 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1185 #define TABLE_SWITCH \
1186 { jint default_offset = IMMEDIATE_s4; \
1187 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1188 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1189 (long) low, (long) high, (long) default_offset+oldpc); \
1190 for (; low <= high; low++) { \
1191 jint offset = IMMEDIATE_s4; \
1192 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1195 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1196 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1198 #define SPECIAL_IINC(OPERAND_TYPE) \
1199 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1200 fprintf (out, " %d", i); \
1201 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1203 fprintf (out, " %d", i)
1205 #define SPECIAL_WIDE(OPERAND_TYPE) \
1208 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1209 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1210 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1211 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1213 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1214 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1216 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1217 TEST(OPERAND_TYPE, OPERAND_VALUE)
1219 #include "javaop.def"
1222 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1226 fprintf (out, " %ld", (long) INT_temp);
1232 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);