1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998 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 /* Name of output file, if NULL if stdout. */
55 char *output_file = NULL;
59 int flag_disassemble_methods = 0;
60 int flag_print_class_info = 1;
61 int flag_print_constant_pool = 1;
62 int flag_print_fields = 1;
63 int flag_print_methods = 1;
64 int flag_print_attributes = 1;
66 /* Print names of classes that have a "main" method. */
67 int flag_print_main = 0;
69 /* Index in constant pool of this class. */
70 int this_class_index = 0;
72 int class_access_flags = 0;
74 /* Print in format similar to javap. VERY IMCOMPLETE. */
75 int flag_javap_compatible = 0;
77 static int print_access_flags PROTO ((FILE *, uint16));
78 static void print_constant_terse PROTO ((FILE*, JCF*, int, int));
79 static void print_constant PROTO ((FILE *, JCF *, int, int));
80 static void print_constant_ref PROTO ((FILE *, JCF *, int));
81 static void disassemble_method PROTO ((JCF*, unsigned char *, int));
82 static void print_name PROTO ((FILE*, JCF*, int));
83 static void print_signature PROTO ((FILE*, JCF*, int, int));
85 #define PRINT_SIGNATURE_RESULT_ONLY 1
86 #define PRINT_SIGNATURE_ARGS_ONLY 2
88 extern char* open_class();
91 DEFUN(utf8_equal_string, (jcf, index, value),
92 JCF *jcf AND int index AND char * value)
94 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
95 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
97 int len = strlen (value);
98 if (JPOOL_UTF_LENGTH (jcf, index) == len
99 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
105 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
106 this_class_index = 0; \
107 if (flag_print_class_info) \
109 "Magic number: 0x%0x, minor_version: %d, major_version: %d.\n", \
112 #define HANDLE_START_CONSTANT_POOL(COUNT) \
113 if (flag_print_constant_pool) \
114 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
116 #define HANDLE_SOURCEFILE(INDEX) \
117 { fprintf (out, "Attribute "); \
118 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
119 fprintf (out, ", length:%d, #%d=", attribute_length, INDEX); \
120 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
122 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
123 this_class_index = THIS; \
124 class_access_flags = ACCESS_FLAGS; \
125 if (flag_print_class_info) \
126 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
127 print_access_flags (out, ACCESS_FLAGS); \
129 fprintf (out, "This class: "); \
130 if (flag_print_constant_pool) \
131 fprintf (out, "%d=", THIS); \
132 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
133 if (flag_print_constant_pool || SUPER != 0) \
134 fprintf (out, ", super: "); \
135 if (flag_print_constant_pool) \
137 fprintf (out, "%d", SUPER); \
142 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
143 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
146 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
147 (flag_print_attributes <= 0)
149 #define HANDLE_CLASS_INTERFACE(INDEX) \
150 if (flag_print_class_info) \
151 { fprintf (out, "- Implements: %d=", INDEX); \
152 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
155 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
156 if (flag_print_fields) \
157 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
159 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
160 if (flag_print_fields) \
161 { fprintf (out, "Field name:"); \
162 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
163 print_access_flags (out, ACCESS_FLAGS); \
164 fprintf (out, " Signature: "); \
165 if (flag_print_constant_pool) \
166 fprintf (out, "%d=", SIGNATURE); \
167 print_signature (out, jcf, SIGNATURE, 0); \
168 fputc ('\n', out); } \
170 flag_print_attributes--;
172 #define HANDLE_END_FIELD() \
173 if (! flag_print_fields) \
174 flag_print_attributes++;
176 #define HANDLE_START_METHODS(METHODS_COUNT) \
177 if (flag_print_methods) \
178 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
180 flag_print_attributes--;
183 #define HANDLE_END_METHODS() \
184 if (! flag_print_methods) \
185 flag_print_attributes++;
187 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
189 if (flag_print_methods) \
191 if (flag_javap_compatible) \
193 fprintf (out, " "); \
194 print_access_flags (out, ACCESS_FLAGS); \
196 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
198 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
199 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
204 fprintf (out, "\nMethod name:"); \
205 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
206 print_access_flags (out, ACCESS_FLAGS); \
207 fprintf (out, " Signature: "); \
208 if (flag_print_constant_pool) \
209 fprintf (out, "%d=", SIGNATURE); \
210 print_signature (out, jcf, SIGNATURE, 0); \
214 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
215 && utf8_equal_string (jcf, NAME, "main") \
216 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
217 && this_class_index > 0 \
218 && (class_access_flags & ACC_PUBLIC)) \
220 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
225 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
226 ( fprintf (out, "Attribute "), \
227 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
228 fprintf (out, ", length:%d", LENGTH) )
230 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
231 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
232 fprintf (out, ", value: "), \
233 print_constant_ref (out, jcf, VALUE_INDEX), \
234 fprintf (out, "\n") )
236 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
237 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
238 fprintf (out, ", max_stack:%d, max_locals:%d, code_length:%d\n", \
239 MAX_STACK, MAX_LOCALS, CODE_LENGTH); \
240 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
242 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
243 { int n = (COUNT); int i; \
244 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
245 fprintf (out, ", count: %d\n", n); \
246 for (i = 0; i < n; i++) {\
247 int ex_index = JCF_readu2 (jcf); \
248 fprintf (out, "%3d: ", i); \
249 print_constant_ref (out, jcf, ex_index); \
250 fputc ('\n', out); } }
252 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
253 { int n = (COUNT); int i; \
254 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
255 fprintf (out, ", count: %d\n", n); \
256 for (i = 0; i < n; i++) {\
257 int start_pc = JCF_readu2 (jcf); \
258 int length = JCF_readu2 (jcf); \
259 int name_index = JCF_readu2 (jcf); \
260 int signature_index = JCF_readu2 (jcf); \
261 int slot = JCF_readu2 (jcf); \
262 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
263 print_name (out, jcf, name_index); \
264 fprintf (out, ", type: %d=", signature_index); \
265 print_signature (out, jcf, signature_index, 0); \
266 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
268 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
269 { int n = (COUNT); int i; \
270 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
271 fprintf (out, ", count: %d\n", n); \
272 if (flag_disassemble_methods) \
273 for (i = 0; i < n; i++) {\
274 int start_pc = JCF_readu2 (jcf); \
275 int line_number = JCF_readu2 (jcf); \
276 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
278 JCF_SKIP (jcf, 4 * n); }
280 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
281 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
282 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
284 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
285 if (flag_print_attributes > 0) \
286 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
289 #include "jcf-reader.c"
292 DEFUN(print_constant_ref, (stream, jcf, index),
293 FILE *stream AND JCF *jcf AND int index)
295 fprintf (stream, "#%d=<", index);
296 if (index <= 0 || index >= JPOOL_SIZE(jcf))
297 fprintf (stream, "out of range");
299 print_constant (stream, jcf, index, 1);
300 fprintf (stream, ">", index);
304 DEFUN (print_access_flags, (stream, flags),
305 FILE *stream AND uint16 flags)
307 if (flags & ACC_PUBLIC) fprintf (stream, " public");
308 if (flags & ACC_PRIVATE) fprintf (stream, " private");
309 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
310 if (flags & ACC_STATIC) fprintf (stream, " static");
311 if (flags & ACC_FINAL) fprintf (stream, " final");
312 if (flags & ACC_SYNCHRONIZED) fprintf (stream, " synchronized");
313 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
314 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
315 if (flags & ACC_NATIVE) fprintf (stream, " native");
316 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
317 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
322 DEFUN(print_name, (stream, jcf, name_index),
323 FILE* stream AND JCF* jcf AND int name_index)
325 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
326 fprintf (stream, "<not a UTF8 constant>");
328 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
329 JPOOL_UTF_LENGTH (jcf, name_index));
332 /* If the type of the constant at INDEX matches EXPECTED,
333 print it tersely, otherwise more verbosely. */
336 DEFUN(print_constant_terse, (out, jcf, index, expected),
337 FILE *out AND JCF *jcf AND int index AND int expected)
339 if (JPOOL_TAG (jcf, index) != expected)
341 fprintf (out, "<Unexpected constant type ");
342 print_constant (out, jcf, index, 1);
346 print_constant (out, jcf, index, 0);
349 /* Print the constant at INDEX in JCF's constant pool.
350 If verbosity==0, print very tersely (no extraneous text).
351 If verbosity==1, prefix the type of the constant.
352 If verbosity==2, add more descriptive text. */
355 DEFUN(print_constant, (out, jcf, index, verbosity),
356 FILE *out AND JCF *jcf AND int index AND int verbosity)
361 int kind = JPOOL_TAG (jcf, index);
365 n = JPOOL_USHORT1 (jcf, index);
367 fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n);
368 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
369 fprintf (out, "<out of range>");
370 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
372 int len = JPOOL_UTF_LENGTH (jcf, n);
373 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
376 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
378 case CONSTANT_Fieldref:
379 str = "Field"; goto field_or_method;
380 case CONSTANT_Methodref:
381 str = "Method"; goto field_or_method;
382 case CONSTANT_InterfaceMethodref:
383 str = "InterfaceMethod"; goto field_or_method;
386 uint16 tclass = JPOOL_USHORT1 (jcf, index);
387 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
389 fprintf (out, "%sref class: %d=", str, tclass);
390 else if (verbosity > 0)
391 fprintf (out, "%s ", str);
392 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
393 fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<",
395 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
400 case CONSTANT_String:
401 j = JPOOL_USHORT1 (jcf, index);
403 fprintf (out, verbosity > 1 ? "String %d=" : "String ", j);
404 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
406 case CONSTANT_Integer:
408 fprintf (out, "Integer ");
409 num = JPOOL_INT (jcf, index);
413 fprintf (out, "Long ");
414 num = JPOOL_LONG (jcf, index);
419 format_int (buffer, num, 10);
420 fprintf (out, "%s", buffer);
423 format_uint (buffer, (uint64)num, 16);
424 fprintf (out, "=0x%s", buffer);
430 jfloat fnum = JPOOL_FLOAT (jcf, index);
431 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
433 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
436 case CONSTANT_Double:
438 jdouble dnum = JPOOL_DOUBLE (jcf, index);
439 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
443 hi = JPOOL_UINT (jcf, index);
444 lo = JPOOL_UINT (jcf, index + 1);
445 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
449 case CONSTANT_NameAndType:
451 uint16 name = JPOOL_USHORT1 (jcf, index);
452 uint16 sig = JPOOL_USHORT2 (jcf, index);
454 fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ",
455 "NameAndType", name);
456 print_name (out, jcf, name);
460 fprintf (out, ", signature: %d=", sig);
461 print_signature (out, jcf, sig, 0);
466 register unsigned char *str = JPOOL_UTF_DATA (jcf, index);
467 int length = JPOOL_UTF_LENGTH (jcf, index);
469 { /* Print as 8-bit bytes. */
470 fputs ("Utf8: \"", out);
471 while (--length >= 0)
472 jcf_print_char (out, *str++);
475 { /* Print as Unicode. */
477 jcf_print_utf8 (out, str, length);
483 fprintf (out, "(Unknown constant type %d)", kind);
488 DEFUN(print_constant_pool, (jcf),
492 for (i = 1; i < JPOOL_SIZE(jcf); i++)
494 int kind = JPOOL_TAG (jcf, i);
495 fprintf (out, "#%d: ", i);
496 print_constant (out, jcf, i, 2);
498 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
499 i++; /* These take up two slots in the constant table */
504 DEFUN(print_signature_type, (stream, ptr, limit),
505 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
514 for ((*ptr)++; (*ptr) < limit && isdigit (**ptr); (*ptr)++)
517 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
519 print_signature_type (stream, ptr, limit);
520 if (array_size == -1)
521 fprintf (stream, "[]");
523 fprintf (stream, "[%d]", array_size);
528 fputc (*(*ptr)++, stream);
529 for (; **ptr != ')' && *ptr < limit; nargs++)
533 print_signature_type (stream, ptr, limit);
537 fputc (*(*ptr)++, stream);
538 print_signature_type (stream, ptr, limit);
541 fprintf (stream, "???");
545 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
546 case 'C': fprintf (stream, "char"); (*ptr)++; break;
547 case 'D': fprintf (stream, "double"); (*ptr)++; break;
548 case 'F': fprintf (stream, "float"); (*ptr)++; break;
549 case 'S': fprintf (stream, "short"); (*ptr)++; break;
550 case 'I': fprintf (stream, "int"); (*ptr)++; break;
551 case 'J': fprintf (stream, "long"); (*ptr)++; break;
552 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
553 case 'V': fprintf (stream, "void"); (*ptr)++; break;
556 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
557 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
562 jcf_print_char (stream, *(*ptr)++);
567 DEFUN(print_signature, (stream, jcf, signature_index, int options),
568 FILE* stream AND JCF *jcf AND int signature_index AND int options)
570 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
571 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
575 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
576 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
577 const unsigned char *limit;
578 limit = str + length;
580 fprintf (stream, "<empty signature string>");
583 if (options & PRINT_SIGNATURE_RESULT_ONLY)
585 while (str < limit && *str++ != ')') ;
587 if (options & PRINT_SIGNATURE_ARGS_ONLY)
591 while (str < limit && *str != ')')
593 print_signature_type (stream, &str, limit);
595 fputs (", ", stream);
601 print_signature_type (stream, &str, limit);
604 fprintf (stream, "<junk:");
605 jcf_print_utf8 (stream, str, limit - str);
616 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
621 DEFUN(process_class, (jcf),
625 if (jcf_parse_preamble (jcf) != 0)
626 fprintf (stderr, "Not a valid Java .class file.\n");
628 /* Parse and possibly print constant pool */
629 code = jcf_parse_constant_pool (jcf);
632 fprintf (stderr, "error while parsing constant pool\n");
635 code = verify_constant_pool (jcf);
638 fprintf (stderr, "error in constant pool entry #%d\n", code);
641 if (flag_print_constant_pool)
642 print_constant_pool (jcf);
644 jcf_parse_class (jcf);
645 code = jcf_parse_fields (jcf);
648 fprintf (stderr, "error while parsing fields\n");
651 code = jcf_parse_methods (jcf);
654 fprintf (stderr, "error while parsing methods\n");
657 code = jcf_parse_final_attributes (jcf);
660 fprintf (stderr, "error while parsing final attributes\n");
663 jcf->filename = NULL;
667 DEFUN(main, (argc, argv),
668 int argc AND char** argv)
675 for (argi = 1; argi < argc; argi++)
677 char *arg = argv[argi];
680 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
681 output_file = argv[++argi];
682 else if (arg[1] == '-')
685 if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
686 classpath = argv[++argi];
687 else if (strcmp (arg, "-verbose") == 0)
689 else if (strcmp (arg, "-print-main") == 0)
691 else if (strcmp (arg, "-javap") == 0)
693 flag_javap_compatible++;
694 flag_print_constant_pool = 0;
696 else if (arg[2] == '\0')
700 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
705 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
706 classpath = argv[++argi];
707 else if (strcmp (arg, "-verbose") == 0)
709 else if (strcmp (arg, "-print-main") == 0)
711 else if (strcmp (arg, "-c") == 0)
712 flag_disassemble_methods++;
715 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
726 flag_print_fields = 0;
727 flag_print_methods = 0;
728 flag_print_constant_pool = 0;
729 flag_print_attributes = 0;
730 flag_print_class_info = 0;
733 if (classpath == NULL)
735 classpath = (char *) getenv ("CLASSPATH");
736 if (classpath == NULL)
742 out = fopen (output_file, "w");
745 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
754 fprintf (out, "Reading .class from <standard input>.\n");
756 open_class ("<stdio>", jcf, stdin);
758 open_class ("<stdio>", jcf, 0);
764 for (; argi < argc; argi++)
766 char *arg = argv[argi];
767 char* class_filename = find_class (arg, strlen (arg), jcf, 1);
768 if (class_filename == NULL)
769 class_filename = find_classfile (arg, jcf);
770 if (class_filename == NULL)
772 perror ("Could not find class");
776 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
778 long compressed_size, member_size;
779 int compression_method, filename_length, extra_length;
780 int general_purpose_bits;
783 if (flag_print_class_info)
784 fprintf (out, "Reading classes from archive %s.\n",
789 jcf_filbuf_t save_filbuf = jcf->filbuf;
790 long magic = JCF_readu4_le (jcf);
791 if (magic == 0x02014b50 || magic == 0x06054b50)
792 break; /* got to central directory */
793 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
795 fprintf (stderr, "bad format of .zip archine\n");
800 general_purpose_bits = JCF_readu2_le (jcf);
801 compression_method = JCF_readu2_le (jcf);
803 compressed_size = JCF_readu4_le (jcf);
804 member_size = JCF_readu4_le (jcf);
805 filename_length = JCF_readu2_le (jcf);
806 extra_length = JCF_readu2_le (jcf);
807 total_length = filename_length + extra_length
809 if (jcf->read_end - jcf->read_ptr < total_length)
810 jcf_trim_old_input (jcf);
811 JCF_FILL (jcf, total_length);
812 filename = jcf->read_ptr;
813 JCF_SKIP (jcf, filename_length);
814 JCF_SKIP (jcf, extra_length);
815 if (filename_length > 0
816 && filename[filename_length-1] == '/')
818 if (flag_print_class_info)
819 fprintf (out, "[Skipping directory %.*s]\n",
820 filename_length, filename);
823 else if (compression_method != 0)
825 if (flag_print_class_info)
826 fprintf (out, "[Skipping compressed file %.*s]\n",
827 filename_length, filename);
830 else if (member_size < 4
831 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
833 if (flag_print_class_info)
834 fprintf (out, "[Skipping non-.class member %.*s]\n",
835 filename_length, filename);
840 if (flag_print_class_info)
841 fprintf (out, "Reading class member: %.*s.\n",
842 filename_length, filename);
846 JCF_SKIP (jcf, compressed_size);
850 unsigned char *save_end;
851 jcf->filbuf = jcf_unexpected_eof;
852 save_end = jcf->read_end;
853 jcf->read_end = jcf->read_ptr + compressed_size;
855 jcf->filbuf = save_filbuf;
856 jcf->read_end = save_end;
862 if (flag_print_class_info)
863 fprintf (out, "Reading .class from %s.\n", class_filename);
872 DEFUN(disassemble_method, (jcf, byte_ops, len),
873 JCF* jcf AND unsigned char *byte_ops AND int len)
875 #undef AND /* Causes problems with opcodes for iand and land. */
879 if (flag_disassemble_methods == 0)
881 #define BCODE byte_ops
882 for (PC = 0; PC < len;)
890 switch (byte_ops[PC++])
893 /* This is the actual code emitted for each of opcodes in javaops.def.
894 The actual opcode-specific stuff is handled by the OPKIND macro.
895 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
896 Those macros are defiend below. The OPKINDs that do not have any
897 inline parameters (such as BINOP) and therefore do mot need anything
898 else to me printed out just use an empty body. */
900 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
902 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
903 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
907 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
908 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
909 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
910 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
912 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
913 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
915 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
916 These all push a constant onto the opcode stack. */
917 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
918 saw_index = 0, INT_temp = (OPERAND_VALUE); \
919 if (oldpc+1 == PC) /* nothing */; \
920 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, INT_temp); \
921 else fprintf (out, " %d", INT_temp);
923 /* Print out operand (a local variable index) for LOAD opcodes.
924 These all push local variable onto the opcode stack. */
925 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
926 INT_temp = (OPERAND_VALUE); \
927 if (oldpc+1 == PC) /* nothing - local index implied by opcode */; \
928 else fprintf (out, " %d", INT_temp);
930 /* Handle STORE opcodes same as LOAD opcodes.
931 These all store a value from the opcode stack in a local variable. */
934 /* Handle more kind of opcodes. */
935 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
936 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
937 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
938 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
939 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
940 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
941 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
943 /* Handle putfield and getfield opcodes, with static versions. */
944 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
945 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
947 /* Print operand for invoke opcodes. */
948 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
949 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
950 PC += 2 * OPERAND_VALUE /* for invokeinterface */;
952 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
953 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
955 #define ARRAY(OPERAND_TYPE, SUBOP) \
956 ARRAY_##SUBOP(OPERAND_TYPE)
957 /* Handle sub-categories of ARRAY opcodes. */
958 #define ARRAY_LOAD(TYPE) /* nothing */
959 #define ARRAY_STORE(TYPE) /* nothing */
960 #define ARRAY_LENGTH(TYPE) /* nothing */
961 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
962 #define ARRAY_NEW_NUM \
963 INT_temp = IMMEDIATE_u1; \
965 switch (INT_temp) { \
966 case 4: str = "boolean"; break; \
967 case 5: str = "char"; break; \
968 case 6: str = "float"; break; \
969 case 7: str = "double"; break; \
970 case 8: str = "byte"; break; \
971 case 9: str = "short"; break; \
972 case 10: str = "int"; break; \
973 case 11: str = "long"; break; \
974 default: str = "<unknown type code %d>"; break; \
976 fputc (' ', out); fprintf (out, str, INT_temp); }
978 #define ARRAY_NEW_PTR \
979 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
981 #define ARRAY_NEW_MULTI \
982 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
983 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
985 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
986 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
988 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
989 saw_index = 0, INT_temp = (OPERAND_VALUE); \
990 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
992 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
993 saw_index = 0, INT_temp = (OPERAND_VALUE); \
994 fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp)
996 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
997 INT_temp = (OPERAND_VALUE); \
998 fprintf (out, " %d", INT_temp);
1000 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1001 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1003 #define LOOKUP_SWITCH \
1004 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1005 fprintf (out, " npairs=%d, default=%d", npairs, default_offset+oldpc); \
1006 while (--npairs >= 0) { \
1007 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1008 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1011 #define TABLE_SWITCH \
1012 { jint default_offset = IMMEDIATE_s4; \
1013 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1014 fprintf (out, " low==%d, high=%ddefault=%d", \
1015 low, high, default_offset+oldpc); \
1016 for (; low <= high; low++) { \
1017 jint offset = IMMEDIATE_s4; \
1018 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1021 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1022 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1024 #define SPECIAL_IINC(OPERAND_TYPE) \
1025 INT_temp = IMMEDIATE_u1; \
1026 fprintf (out, "%d %d", INT_temp, IMMEDIATE_s1)
1028 #define SPECIAL_WIDE(OPERAND_TYPE) \
1029 INT_temp = IMMEDIATE_u1; fprintf (out, "%d", INT_temp)
1031 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1032 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1033 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1034 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1036 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1037 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1039 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1040 TEST(OPERAND_TYPE, OPERAND_VALUE)
1042 #include "javaop.def"
1044 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1048 /* Print exception table. */
1049 i = GET_u2(byte_ops+len);
1052 unsigned char *ptr = byte_ops+len+2;
1053 fprintf (out, "Exceptions (count: %d):\n", i);
1054 for (; --i >= 0; ptr+= 8)
1056 int start_pc = GET_u2 (ptr);
1057 int end_pc = GET_u2 (ptr+2);
1058 int handler_pc = GET_u2 (ptr+4);
1059 int catch_type = GET_u2 (ptr+6);
1060 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
1061 start_pc, end_pc, handler_pc, catch_type);
1062 if (catch_type == 0)
1063 fputs (" /* finally */", out);
1067 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);