1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 97-99, 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 PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
298 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
299 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
301 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
302 if (flag_print_attributes > 0) \
303 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
308 DEFUN(print_constant_ref, (stream, jcf, index),
309 FILE *stream AND JCF *jcf AND int index)
311 fprintf (stream, "#%d=<", index);
312 if (index <= 0 || index >= JPOOL_SIZE(jcf))
313 fprintf (stream, "out of range");
315 print_constant (stream, jcf, index, 1);
316 fprintf (stream, ">");
319 /* Print the access flags given by FLAGS.
320 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
321 or 'm' (method flags). */
324 DEFUN (print_access_flags, (stream, flags, context),
325 FILE *stream AND uint16 flags AND char context)
327 if (flags & ACC_PUBLIC) fprintf (stream, " public");
328 if (flags & ACC_PRIVATE) fprintf (stream, " private");
329 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
330 if (flags & ACC_STATIC) fprintf (stream, " static");
331 if (flags & ACC_FINAL) fprintf (stream, " final");
332 if (flags & ACC_SYNCHRONIZED)
335 fprintf (stream, " super");
337 fprintf (stream, " synchronized");
339 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
340 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
341 if (flags & ACC_NATIVE) fprintf (stream, " native");
342 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
343 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
348 DEFUN(print_name, (stream, jcf, name_index),
349 FILE* stream AND JCF* jcf AND int name_index)
351 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
352 fprintf (stream, "<not a UTF8 constant>");
354 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
355 JPOOL_UTF_LENGTH (jcf, name_index));
358 /* If the type of the constant at INDEX matches EXPECTED,
359 print it tersely, otherwise more verbosely. */
362 DEFUN(print_constant_terse, (out, jcf, index, expected),
363 FILE *out AND JCF *jcf AND int index AND int expected)
365 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
366 fprintf (out, "<constant pool index %d not in range>", index);
367 else if (JPOOL_TAG (jcf, index) != expected)
369 fprintf (out, "<Unexpected constant type ");
370 print_constant (out, jcf, index, 1);
374 print_constant (out, jcf, index, 0);
377 /* Print the constant at INDEX in JCF's constant pool.
378 If verbosity==0, print very tersely (no extraneous text).
379 If verbosity==1, prefix the type of the constant.
380 If verbosity==2, add more descriptive text. */
383 DEFUN(print_constant, (out, jcf, index, verbosity),
384 FILE *out AND JCF *jcf AND int index AND int verbosity)
389 int kind = JPOOL_TAG (jcf, index);
393 n = JPOOL_USHORT1 (jcf, index);
397 fprintf (out, "Class name: %d=", n);
399 fprintf (out, "Class ");
401 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
402 fprintf (out, "<out of range>");
403 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
405 int len = JPOOL_UTF_LENGTH (jcf, n);
406 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
409 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
411 case CONSTANT_Fieldref:
412 str = "Field"; goto field_or_method;
413 case CONSTANT_Methodref:
414 str = "Method"; goto field_or_method;
415 case CONSTANT_InterfaceMethodref:
416 str = "InterfaceMethod"; goto field_or_method;
419 uint16 tclass = JPOOL_USHORT1 (jcf, index);
420 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
422 fprintf (out, "%sref class: %d=", str, tclass);
423 else if (verbosity > 0)
424 fprintf (out, "%s ", str);
425 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
429 fprintf (out, " name_and_type: %d=<", name_and_type);
430 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
435 case CONSTANT_String:
436 j = JPOOL_USHORT1 (jcf, index);
440 fprintf (out, "String %d=", j);
442 fprintf (out, "String ");
444 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
446 case CONSTANT_Integer:
448 fprintf (out, "Integer ");
449 num = JPOOL_INT (jcf, index);
453 fprintf (out, "Long ");
454 num = JPOOL_LONG (jcf, index);
459 format_int (buffer, num, 10);
460 fprintf (out, "%s", buffer);
463 format_uint (buffer, (uint64)num, 16);
464 fprintf (out, "=0x%s", buffer);
470 jfloat fnum = JPOOL_FLOAT (jcf, index);
471 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
473 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
476 case CONSTANT_Double:
478 jdouble dnum = JPOOL_DOUBLE (jcf, index);
479 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
483 hi = JPOOL_UINT (jcf, index);
484 lo = JPOOL_UINT (jcf, index + 1);
485 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
489 case CONSTANT_NameAndType:
491 uint16 name = JPOOL_USHORT1 (jcf, index);
492 uint16 sig = JPOOL_USHORT2 (jcf, index);
496 fprintf (out, "NameAndType name: %d=", name);
498 fprintf (out, "NameAndType ");
500 print_name (out, jcf, name);
504 fprintf (out, ", signature: %d=", sig);
505 print_signature (out, jcf, sig, 0);
510 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
511 int length = JPOOL_UTF_LENGTH (jcf, index);
513 { /* Print as 8-bit bytes. */
514 fputs ("Utf8: \"", out);
515 while (--length >= 0)
516 jcf_print_char (out, *str++);
519 { /* Print as Unicode. */
521 jcf_print_utf8 (out, str, length);
527 fprintf (out, "(Unknown constant type %d)", kind);
532 DEFUN(print_constant_pool, (jcf),
536 for (i = 1; i < JPOOL_SIZE(jcf); i++)
538 int kind = JPOOL_TAG (jcf, i);
539 fprintf (out, "#%d: ", i);
540 print_constant (out, jcf, i, 2);
542 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
543 i++; /* These take up two slots in the constant table */
548 DEFUN(print_signature_type, (stream, ptr, limit),
549 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
558 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
560 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
562 print_signature_type (stream, ptr, limit);
563 if (array_size == -1)
564 fprintf (stream, "[]");
566 fprintf (stream, "[%d]", array_size);
571 fputc (*(*ptr)++, stream);
572 for (; **ptr != ')' && *ptr < limit; nargs++)
576 print_signature_type (stream, ptr, limit);
580 fputc (*(*ptr)++, stream);
581 print_signature_type (stream, ptr, limit);
584 fprintf (stream, "???");
588 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
589 case 'C': fprintf (stream, "char"); (*ptr)++; break;
590 case 'D': fprintf (stream, "double"); (*ptr)++; break;
591 case 'F': fprintf (stream, "float"); (*ptr)++; break;
592 case 'S': fprintf (stream, "short"); (*ptr)++; break;
593 case 'I': fprintf (stream, "int"); (*ptr)++; break;
594 case 'J': fprintf (stream, "long"); (*ptr)++; break;
595 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
596 case 'V': fprintf (stream, "void"); (*ptr)++; break;
599 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
600 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
605 jcf_print_char (stream, *(*ptr)++);
610 DEFUN(print_signature, (stream, jcf, signature_index, int options),
611 FILE* stream AND JCF *jcf AND int signature_index AND int options)
613 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
614 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
617 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
618 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
619 const unsigned char *limit;
620 limit = str + length;
622 fprintf (stream, "<empty signature string>");
625 if (options & PRINT_SIGNATURE_RESULT_ONLY)
627 while (str < limit && *str++ != ')') ;
629 if (options & PRINT_SIGNATURE_ARGS_ONLY)
633 while (str < limit && *str != ')')
635 print_signature_type (stream, &str, limit);
637 fputs (", ", stream);
643 print_signature_type (stream, &str, limit);
646 fprintf (stream, "<junk:");
647 jcf_print_utf8 (stream, str, limit - str);
657 DEFUN(print_exception_table, (jcf, entries, count),
658 JCF *jcf AND const unsigned char *entries AND int count)
660 /* Print exception table. */
664 const unsigned char *ptr = entries;
665 fprintf (out, "Exceptions (count: %d):\n", i);
666 for (; --i >= 0; ptr+= 8)
668 int start_pc = GET_u2 (ptr);
669 int end_pc = GET_u2 (ptr+2);
670 int handler_pc = GET_u2 (ptr+4);
671 int catch_type = GET_u2 (ptr+6);
672 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
673 start_pc, end_pc, handler_pc, catch_type);
675 fputs (" /* finally */", out);
679 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
686 #include "jcf-reader.c"
689 DEFUN(process_class, (jcf),
693 if (jcf_parse_preamble (jcf) != 0)
694 fprintf (stderr, "Not a valid Java .class file.\n");
696 /* Parse and possibly print constant pool */
697 code = jcf_parse_constant_pool (jcf);
700 fprintf (stderr, "error while parsing constant pool\n");
701 exit (FATAL_EXIT_CODE);
703 code = verify_constant_pool (jcf);
706 fprintf (stderr, "error in constant pool entry #%d\n", code);
707 exit (FATAL_EXIT_CODE);
709 if (flag_print_constant_pool)
710 print_constant_pool (jcf);
712 jcf_parse_class (jcf);
713 code = jcf_parse_fields (jcf);
716 fprintf (stderr, "error while parsing fields\n");
717 exit (FATAL_EXIT_CODE);
719 code = jcf_parse_methods (jcf);
722 fprintf (stderr, "error while parsing methods\n");
723 exit (FATAL_EXIT_CODE);
725 code = jcf_parse_final_attributes (jcf);
728 fprintf (stderr, "error while parsing final attributes\n");
729 exit (FATAL_EXIT_CODE);
731 jcf->filename = NULL;
736 /* This is used to mark options with no short value. */
737 #define LONG_OPT(Num) ((Num) + 128)
739 #define OPT_classpath LONG_OPT (0)
740 #define OPT_CLASSPATH LONG_OPT (1)
741 #define OPT_HELP LONG_OPT (2)
742 #define OPT_VERSION LONG_OPT (3)
743 #define OPT_JAVAP LONG_OPT (4)
745 static struct option options[] =
747 { "classpath", required_argument, NULL, OPT_classpath },
748 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
749 { "help", no_argument, NULL, OPT_HELP },
750 { "verbose", no_argument, NULL, 'v' },
751 { "version", no_argument, NULL, OPT_VERSION },
752 { "javap", no_argument, NULL, OPT_JAVAP },
753 { "print-main", no_argument, &flag_print_main, 1 },
754 { NULL, no_argument, NULL, 0 }
760 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
767 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
768 printf ("Display contents of a class file in readable form.\n\n");
769 printf (" -c Disassemble method bodies\n");
770 printf (" --javap Generate output in `javap' format\n");
772 printf (" --classpath PATH Set path to find .class files\n");
773 printf (" --CLASSPATH PATH Set path to find .class files\n");
774 printf (" -IDIR Append directory to class path\n");
775 printf (" -o FILE Set output file name\n");
777 printf (" --help Print this help, then exit\n");
778 printf (" --version Print version number, then exit\n");
779 printf (" -v, --verbose Print extra information while running\n");
781 printf ("For bug reporting instructions, please see:\n");
782 printf ("<URL:http://www.gnu.org/software/gcc/faq.html#bugreport>.\n");
789 printf ("jcf-dump (%s)\n\n", version_string);
790 printf ("Copyright (C) 1998, 1999 Free Software Foundation, Inc.\n");
791 printf ("This is free software; see the source for copying conditions. There is NO\n");
792 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
797 DEFUN(main, (argc, argv),
798 int argc AND char** argv)
805 fprintf (stderr, "jcf-dump: no classes specified\n");
811 /* We use getopt_long_only to allow single `-' long options. For
812 some of our options this is more natural. */
813 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
818 /* Already handled. */
822 output_file = optarg;
826 jcf_path_include_arg (optarg);
834 flag_disassemble_methods = 1;
838 jcf_path_classpath_arg (optarg);
842 jcf_path_CLASSPATH_arg (optarg);
854 flag_javap_compatible++;
855 flag_print_constant_pool = 0;
865 fprintf (stderr, "jcf-dump: no classes specified\n");
873 flag_print_fields = 0;
874 flag_print_methods = 0;
875 flag_print_constant_pool = 0;
876 flag_print_attributes = 0;
877 flag_print_class_info = 0;
882 out = fopen (output_file, "w");
885 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
886 return FATAL_EXIT_CODE;
894 fprintf (out, "Reading .class from <standard input>.\n");
896 open_class ("<stdio>", jcf, stdin, NULL);
898 open_class ("<stdio>", jcf, 0, NULL);
904 for (argi = optind; argi < argc; argi++)
906 char *arg = argv[argi];
907 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
908 if (class_filename == NULL)
909 class_filename = find_classfile (arg, jcf, NULL);
910 if (class_filename == NULL)
912 perror ("Could not find class");
913 return FATAL_EXIT_CODE;
916 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
918 long compressed_size, member_size;
919 int compression_method, filename_length, extra_length;
920 int general_purpose_bits;
921 const char *filename;
923 if (flag_print_class_info)
924 fprintf (out, "Reading classes from archive %s.\n",
929 jcf_filbuf_t save_filbuf = jcf->filbuf;
930 long magic = JCF_readu4_le (jcf);
931 if (magic == 0x02014b50 || magic == 0x06054b50)
932 break; /* got to central directory */
933 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
935 fprintf (stderr, "bad format of .zip/.jar archive\n");
936 return FATAL_EXIT_CODE;
940 general_purpose_bits = JCF_readu2_le (jcf);
941 compression_method = JCF_readu2_le (jcf);
943 compressed_size = JCF_readu4_le (jcf);
944 member_size = JCF_readu4_le (jcf);
945 filename_length = JCF_readu2_le (jcf);
946 extra_length = JCF_readu2_le (jcf);
947 total_length = filename_length + extra_length
949 if (jcf->read_end - jcf->read_ptr < total_length)
950 jcf_trim_old_input (jcf);
951 JCF_FILL (jcf, total_length);
952 filename = jcf->read_ptr;
953 JCF_SKIP (jcf, filename_length);
954 JCF_SKIP (jcf, extra_length);
955 if (filename_length > 0
956 && filename[filename_length-1] == '/')
958 if (flag_print_class_info)
959 fprintf (out, "[Skipping directory %.*s]\n",
960 filename_length, filename);
963 else if (compression_method != 0)
965 if (flag_print_class_info)
966 fprintf (out, "[Skipping compressed file %.*s]\n",
967 filename_length, filename);
970 else if (member_size < 4
971 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
973 if (flag_print_class_info)
974 fprintf (out, "[Skipping non-.class member %.*s]\n",
975 filename_length, filename);
980 if (flag_print_class_info)
981 fprintf (out, "Reading class member: %.*s.\n",
982 filename_length, filename);
986 JCF_SKIP (jcf, compressed_size);
990 unsigned char *save_end;
991 jcf->filbuf = jcf_unexpected_eof;
992 save_end = jcf->read_end;
993 jcf->read_end = jcf->read_ptr + compressed_size;
995 jcf->filbuf = save_filbuf;
996 jcf->read_end = save_end;
1002 if (flag_print_class_info)
1003 fprintf (out, "Reading .class from %s.\n", class_filename);
1004 process_class (jcf);
1010 return SUCCESS_EXIT_CODE;
1016 DEFUN(disassemble_method, (jcf, byte_ops, len),
1017 JCF* jcf AND const unsigned char *byte_ops AND int len)
1019 #undef AND /* Causes problems with opcodes for iand and land. */
1024 if (flag_disassemble_methods == 0)
1026 #define BCODE byte_ops
1027 for (PC = 0; PC < len;)
1032 switch (byte_ops[PC++])
1035 /* This is the actual code emitted for each of opcodes in javaops.def.
1036 The actual opcode-specific stuff is handled by the OPKIND macro.
1037 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1038 Those macros are defiend below. The OPKINDs that do not have any
1039 inline parameters (such as BINOP) and therefore do mot need anything
1040 else to me printed out just use an empty body. */
1042 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1044 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1045 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1046 fputc ('\n', out); \
1049 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1050 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1051 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1052 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1054 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1055 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1057 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1058 These all push a constant onto the opcode stack. */
1059 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1060 saw_index = 0, i = (OPERAND_VALUE); \
1061 if (oldpc+1 == PC) /* nothing */; \
1062 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1063 else fprintf (out, " %d", i);
1065 /* Print out operand (a local variable index) for LOAD opcodes.
1066 These all push local variable onto the opcode stack. */
1067 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1068 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1070 /* Handle STORE opcodes same as LOAD opcodes.
1071 These all store a value from the opcode stack in a local variable. */
1074 /* Handle more kind of opcodes. */
1075 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1076 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1077 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1078 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1079 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1080 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1081 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1083 /* Handle putfield and getfield opcodes, with static versions. */
1084 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1085 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1087 /* Print operand for invoke opcodes. */
1088 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1089 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1090 if (OPERAND_VALUE) /* for invokeinterface */ \
1091 { int nargs = IMMEDIATE_u1; PC++; \
1092 fprintf (out, " nargs:%d", nargs); }
1094 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1095 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1097 #define ARRAY(OPERAND_TYPE, SUBOP) \
1098 ARRAY_##SUBOP(OPERAND_TYPE)
1099 /* Handle sub-categories of ARRAY opcodes. */
1100 #define ARRAY_LOAD(TYPE) /* nothing */
1101 #define ARRAY_STORE(TYPE) /* nothing */
1102 #define ARRAY_LENGTH(TYPE) /* nothing */
1103 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1104 #define ARRAY_NEW_NUM \
1105 INT_temp = IMMEDIATE_u1; \
1106 { switch ((int) INT_temp) { \
1107 case 4: fputs (" boolean", out); break; \
1108 case 5: fputs (" char", out); break; \
1109 case 6: fputs (" float", out); break; \
1110 case 7: fputs (" double", out); break; \
1111 case 8: fputs (" byte", out); break; \
1112 case 9: fputs (" short", out); break; \
1113 case 10: fputs (" int", out); break; \
1114 case 11: fputs (" long", out); break; \
1115 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1118 #define ARRAY_NEW_PTR \
1119 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1121 #define ARRAY_NEW_MULTI \
1122 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1123 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1125 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1126 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1128 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1129 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1130 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1132 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1133 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1134 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1136 #undef RET /* Defined by config/i386/i386.h */
1137 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1138 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1140 fprintf (out, " %ld", (long) INT_temp);
1142 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1143 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1145 #define LOOKUP_SWITCH \
1146 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1147 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1148 while (--npairs >= 0) { \
1149 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1150 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1153 #define TABLE_SWITCH \
1154 { jint default_offset = IMMEDIATE_s4; \
1155 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1156 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1157 (long) low, (long) high, (long) default_offset+oldpc); \
1158 for (; low <= high; low++) { \
1159 jint offset = IMMEDIATE_s4; \
1160 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1163 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1164 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1166 #define SPECIAL_IINC(OPERAND_TYPE) \
1167 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1168 fprintf (out, " %d", i); \
1169 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1171 fprintf (out, " %d", i)
1173 #define SPECIAL_WIDE(OPERAND_TYPE) \
1176 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1177 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1178 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1179 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1181 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1182 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1184 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1185 TEST(OPERAND_TYPE, OPERAND_VALUE)
1187 #include "javaop.def"
1190 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1194 fprintf (out, " %ld", (long) INT_temp);
1200 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);