2001-02-14 Tom Tromey <tromey@redhat.com>
[official-gcc.git] / gcc / java / jcf-dump.c
blobde9758d4e169f563730e6b309a4ccbd46cc8820f
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)
9 any later version.
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
30 Each CLASS is either:
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
34 archive).
36 OPTIONS:
38 Dis-assemble each method.
39 -classpath PATH
40 Overrides $CLASSPATH.
41 --print-main
42 Print nothing if there is no valid "main" method;
43 otherwise, print only the class name.
44 --javap
45 Print output in the style of Sun's javap program. VERY UNFINISHED.
49 #include "config.h"
50 #include "system.h"
52 #include "jcf.h"
53 #include "tree.h"
54 #include "java-tree.h"
56 #include "version.h"
58 #include <getopt.h>
60 /* Outout file. */
61 FILE *out;
62 /* Name of output file, if NULL if stdout. */
63 char *output_file = NULL;
65 int verbose = 0;
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 /* When non zero, warn when source file is newer than matching class
75 file. */
76 int flag_newer = 1;
78 /* Print names of classes that have a "main" method. */
79 int flag_print_main = 0;
81 /* Index in constant pool of this class. */
82 int this_class_index = 0;
84 int class_access_flags = 0;
86 /* Print in format similar to javap. VERY IMCOMPLETE. */
87 int flag_javap_compatible = 0;
89 static void print_access_flags PARAMS ((FILE *, uint16, char));
90 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
91 static void print_constant PARAMS ((FILE *, JCF *, int, int));
92 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
93 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
94 static void print_name PARAMS ((FILE*, JCF*, int));
95 static void print_signature PARAMS ((FILE*, JCF*, int, int));
96 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
97 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
98 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
99 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
100 static void process_class PARAMS ((struct JCF *));
101 static void print_constant_pool PARAMS ((struct JCF *));
102 static void print_exception_table PARAMS ((struct JCF *,
103 const unsigned char *entries, int));
105 #define PRINT_SIGNATURE_RESULT_ONLY 1
106 #define PRINT_SIGNATURE_ARGS_ONLY 2
108 static int
109 DEFUN(utf8_equal_string, (jcf, index, value),
110 JCF *jcf AND int index AND const char * value)
112 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
113 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
115 int len = strlen (value);
116 if (JPOOL_UTF_LENGTH (jcf, index) == len
117 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
118 return 1;
120 return 0;
123 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
124 this_class_index = 0; \
125 if (flag_print_class_info) \
126 fprintf (out, \
127 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
128 (long) MAGIC, (long) MINOR, (long) MAJOR)
130 #define HANDLE_START_CONSTANT_POOL(COUNT) \
131 if (flag_print_constant_pool) \
132 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
134 #define HANDLE_SOURCEFILE(INDEX) \
135 { fprintf (out, "Attribute "); \
136 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
137 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
138 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
140 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
141 this_class_index = THIS; \
142 class_access_flags = ACCESS_FLAGS; \
143 if (flag_print_class_info) \
144 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
145 print_access_flags (out, ACCESS_FLAGS, 'c'); \
146 fputc ('\n', out); \
147 fprintf (out, "This class: "); \
148 if (flag_print_constant_pool) \
149 fprintf (out, "%d=", THIS); \
150 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
151 if (flag_print_constant_pool || SUPER != 0) \
152 fprintf (out, ", super: "); \
153 if (flag_print_constant_pool) \
155 fprintf (out, "%d", SUPER); \
156 if (SUPER != 0) \
157 fputc ('=', out); \
159 if (SUPER != 0) \
160 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
161 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
164 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
165 (flag_print_attributes <= 0)
167 #define HANDLE_CLASS_INTERFACE(INDEX) \
168 if (flag_print_class_info) \
169 { fprintf (out, "- Implements: %d=", INDEX); \
170 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
171 fputc ('\n', out); }
173 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
174 if (flag_print_fields) \
175 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
177 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
178 if (flag_print_fields) \
179 { fprintf (out, "Field name:"); \
180 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
181 print_access_flags (out, ACCESS_FLAGS, 'f'); \
182 fprintf (out, " Signature: "); \
183 if (flag_print_constant_pool) \
184 fprintf (out, "%d=", SIGNATURE); \
185 print_signature (out, jcf, SIGNATURE, 0); \
186 fputc ('\n', out); } \
187 else \
188 flag_print_attributes--;
190 #define HANDLE_END_FIELD() \
191 if (! flag_print_fields) \
192 flag_print_attributes++;
194 #define HANDLE_START_METHODS(METHODS_COUNT) \
195 if (flag_print_methods) \
196 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
197 else \
198 flag_print_attributes--;
201 #define HANDLE_END_METHODS() \
202 if (! flag_print_methods) \
203 flag_print_attributes++;
205 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
207 if (flag_print_methods) \
209 if (flag_javap_compatible) \
211 fprintf (out, " "); \
212 print_access_flags (out, ACCESS_FLAGS, 'm'); \
213 fputc (' ', out); \
214 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
215 fputc (' ', out); \
216 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
217 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
218 fputc ('\n', out); \
220 else \
222 fprintf (out, "\nMethod name:"); \
223 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
224 print_access_flags (out, ACCESS_FLAGS, 'm'); \
225 fprintf (out, " Signature: "); \
226 if (flag_print_constant_pool) \
227 fprintf (out, "%d=", SIGNATURE); \
228 print_signature (out, jcf, SIGNATURE, 0); \
229 fputc ('\n', out); \
232 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
233 && utf8_equal_string (jcf, NAME, "main") \
234 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
235 && this_class_index > 0 \
236 && (class_access_flags & ACC_PUBLIC)) \
238 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
239 fputc ('\n', out); \
243 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
244 ( fprintf (out, "Attribute "), \
245 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
246 fprintf (out, ", length:%ld", (long) LENGTH) )
248 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
249 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
250 fprintf (out, ", value: "), \
251 print_constant_ref (out, jcf, VALUE_INDEX), \
252 fprintf (out, "\n") )
254 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
255 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
256 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
257 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
258 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
260 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
261 print_exception_table (jcf, ENTRIES, COUNT)
263 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
264 { int n = (COUNT); int i; \
265 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
266 fprintf (out, ", count: %d\n", n); \
267 for (i = 0; i < n; i++) {\
268 int ex_index = JCF_readu2 (jcf); \
269 fprintf (out, "%3d: ", i); \
270 print_constant_ref (out, jcf, ex_index); \
271 fputc ('\n', out); } }
273 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
274 { int n = (COUNT); int i; \
275 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
276 fprintf (out, ", count: %d\n", n); \
277 for (i = 0; i < n; i++) {\
278 int start_pc = JCF_readu2 (jcf); \
279 int length = JCF_readu2 (jcf); \
280 int name_index = JCF_readu2 (jcf); \
281 int signature_index = JCF_readu2 (jcf); \
282 int slot = JCF_readu2 (jcf); \
283 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
284 print_name (out, jcf, name_index); \
285 fprintf (out, ", type: %d=", signature_index); \
286 print_signature (out, jcf, signature_index, 0); \
287 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
289 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
290 { int n = (COUNT); int i; \
291 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
292 fprintf (out, ", count: %d\n", n); \
293 if (flag_disassemble_methods) \
294 for (i = 0; i < n; i++) {\
295 int start_pc = JCF_readu2 (jcf); \
296 int line_number = JCF_readu2 (jcf); \
297 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
298 else \
299 JCF_SKIP (jcf, 4 * n); }
301 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
302 { int n = (COUNT); \
303 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
304 while (n--) \
306 uint16 inner_class_info_index = JCF_readu2 (jcf); \
307 uint16 outer_class_info_index = JCF_readu2 (jcf); \
308 uint16 inner_name_index = JCF_readu2 (jcf); \
309 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
311 if (flag_print_class_info) \
313 fprintf (out, "\n class: "); \
314 if (flag_print_constant_pool) \
315 fprintf (out, "%d=", inner_class_info_index); \
316 print_constant_terse (out, jcf, \
317 inner_class_info_index, CONSTANT_Class); \
318 fprintf (out, " (%d=", inner_name_index); \
319 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
320 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
321 print_access_flags (out, inner_class_access_flags, 'c'); \
322 fprintf (out, ", outer class: "); \
323 if (flag_print_constant_pool) \
324 fprintf (out, "%d=", outer_class_info_index); \
325 print_constant_terse (out, jcf, \
326 outer_class_info_index, CONSTANT_Class); \
329 if (flag_print_class_info) \
330 fputc ('\n', out); \
333 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
334 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
335 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
337 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
338 if (flag_print_attributes > 0) \
339 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
341 #include "javaop.h"
343 static void
344 DEFUN(print_constant_ref, (stream, jcf, index),
345 FILE *stream AND JCF *jcf AND int index)
347 fprintf (stream, "#%d=<", index);
348 if (index <= 0 || index >= JPOOL_SIZE(jcf))
349 fprintf (stream, "out of range");
350 else
351 print_constant (stream, jcf, index, 1);
352 fprintf (stream, ">");
355 /* Print the access flags given by FLAGS.
356 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
357 or 'm' (method flags). */
359 static void
360 DEFUN (print_access_flags, (stream, flags, context),
361 FILE *stream AND uint16 flags AND char context)
363 if (flags & ACC_PUBLIC) fprintf (stream, " public");
364 if (flags & ACC_PRIVATE) fprintf (stream, " private");
365 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
366 if (flags & ACC_STATIC) fprintf (stream, " static");
367 if (flags & ACC_FINAL) fprintf (stream, " final");
368 if (flags & ACC_SYNCHRONIZED)
370 if (context == 'c')
371 fprintf (stream, " super");
372 else
373 fprintf (stream, " synchronized");
375 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
376 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
377 if (flags & ACC_NATIVE) fprintf (stream, " native");
378 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
379 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
383 static void
384 DEFUN(print_name, (stream, jcf, name_index),
385 FILE* stream AND JCF* jcf AND int name_index)
387 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
388 fprintf (stream, "<not a UTF8 constant>");
389 else
390 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
391 JPOOL_UTF_LENGTH (jcf, name_index));
394 /* If the type of the constant at INDEX matches EXPECTED,
395 print it tersely, otherwise more verbosely. */
397 static void
398 DEFUN(print_constant_terse, (out, jcf, index, expected),
399 FILE *out AND JCF *jcf AND int index AND int expected)
401 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
402 fprintf (out, "<constant pool index %d not in range>", index);
403 else if (JPOOL_TAG (jcf, index) != expected)
405 fprintf (out, "<Unexpected constant type ");
406 print_constant (out, jcf, index, 1);
407 fprintf (out, ">");
409 else
410 print_constant (out, jcf, index, 0);
413 /* Print the constant at INDEX in JCF's constant pool.
414 If verbosity==0, print very tersely (no extraneous text).
415 If verbosity==1, prefix the type of the constant.
416 If verbosity==2, add more descriptive text. */
418 static void
419 DEFUN(print_constant, (out, jcf, index, verbosity),
420 FILE *out AND JCF *jcf AND int index AND int verbosity)
422 int j, n;
423 jlong num;
424 const char *str;
425 int kind = JPOOL_TAG (jcf, index);
426 switch (kind)
428 case CONSTANT_Class:
429 n = JPOOL_USHORT1 (jcf, index);
430 if (verbosity > 0)
432 if (verbosity > 1)
433 fprintf (out, "Class name: %d=", n);
434 else
435 fprintf (out, "Class ");
437 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
438 fprintf (out, "<out of range>");
439 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
441 int len = JPOOL_UTF_LENGTH (jcf, n);
442 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
444 else
445 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
446 break;
447 case CONSTANT_Fieldref:
448 str = "Field"; goto field_or_method;
449 case CONSTANT_Methodref:
450 str = "Method"; goto field_or_method;
451 case CONSTANT_InterfaceMethodref:
452 str = "InterfaceMethod"; goto field_or_method;
453 field_or_method:
455 uint16 tclass = JPOOL_USHORT1 (jcf, index);
456 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
457 if (verbosity == 2)
458 fprintf (out, "%sref class: %d=", str, tclass);
459 else if (verbosity > 0)
460 fprintf (out, "%s ", str);
461 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
462 if (verbosity < 2)
463 fprintf (out, ".");
464 else
465 fprintf (out, " name_and_type: %d=<", name_and_type);
466 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
467 if (verbosity == 2)
468 fputc ('>', out);
470 break;
471 case CONSTANT_String:
472 j = JPOOL_USHORT1 (jcf, index);
473 if (verbosity > 0)
475 if (verbosity > 1)
476 fprintf (out, "String %d=", j);
477 else
478 fprintf (out, "String ");
480 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
481 break;
482 case CONSTANT_Integer:
483 if (verbosity > 0)
484 fprintf (out, "Integer ");
485 num = JPOOL_INT (jcf, index);
486 goto integer;
487 case CONSTANT_Long:
488 if (verbosity > 0)
489 fprintf (out, "Long ");
490 num = JPOOL_LONG (jcf, index);
491 goto integer;
492 integer:
494 char buffer[25];
495 format_int (buffer, num, 10);
496 fprintf (out, "%s", buffer);
497 if (verbosity > 1)
499 format_uint (buffer, (uint64)num, 16);
500 fprintf (out, "=0x%s", buffer);
503 break;
504 case CONSTANT_Float:
506 jfloat fnum = JPOOL_FLOAT (jcf, index);
507 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
508 if (verbosity > 1)
509 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
510 break;
512 case CONSTANT_Double:
514 jdouble dnum = JPOOL_DOUBLE (jcf, index);
515 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
516 if (verbosity > 1)
518 int32 hi, lo;
519 hi = JPOOL_UINT (jcf, index);
520 lo = JPOOL_UINT (jcf, index + 1);
521 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
523 break;
525 case CONSTANT_NameAndType:
527 uint16 name = JPOOL_USHORT1 (jcf, index);
528 uint16 sig = JPOOL_USHORT2 (jcf, index);
529 if (verbosity > 0)
531 if (verbosity > 1)
532 fprintf (out, "NameAndType name: %d=", name);
533 else
534 fprintf (out, "NameAndType ");
536 print_name (out, jcf, name);
537 if (verbosity <= 1)
538 fputc (' ', out);
539 else
540 fprintf (out, ", signature: %d=", sig);
541 print_signature (out, jcf, sig, 0);
543 break;
544 case CONSTANT_Utf8:
546 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
547 int length = JPOOL_UTF_LENGTH (jcf, index);
548 if (verbosity > 0)
549 { /* Print as 8-bit bytes. */
550 fputs ("Utf8: \"", out);
551 while (--length >= 0)
552 jcf_print_char (out, *str++);
554 else
555 { /* Print as Unicode. */
556 fputc ('\"', out);
557 jcf_print_utf8 (out, str, length);
559 fputc ('\"', out);
561 break;
562 default:
563 fprintf (out, "(Unknown constant type %d)", kind);
567 static void
568 DEFUN(print_constant_pool, (jcf),
569 JCF *jcf)
571 int i;
572 for (i = 1; i < JPOOL_SIZE(jcf); i++)
574 int kind = JPOOL_TAG (jcf, i);
575 fprintf (out, "#%d: ", i);
576 print_constant (out, jcf, i, 2);
577 fprintf (out, "\n");
578 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
579 i++; /* These take up two slots in the constant table */
583 static void
584 DEFUN(print_signature_type, (stream, ptr, limit),
585 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
587 int array_size;
588 if ((*ptr) >= limit)
589 return;
590 switch (*(*ptr))
592 case '[':
593 array_size = -1;
594 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
596 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
598 print_signature_type (stream, ptr, limit);
599 if (array_size == -1)
600 fprintf (stream, "[]");
601 else
602 fprintf (stream, "[%d]", array_size);
603 break;
604 case '(':
606 int nargs = 0;
607 fputc (*(*ptr)++, stream);
608 for (; **ptr != ')' && *ptr < limit; nargs++)
610 if (nargs > 0)
611 fputc (',', stream);
612 print_signature_type (stream, ptr, limit);
614 if (*ptr < limit)
616 fputc (*(*ptr)++, stream);
617 print_signature_type (stream, ptr, limit);
619 else
620 fprintf (stream, "???");
622 break;
624 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
625 case 'C': fprintf (stream, "char"); (*ptr)++; break;
626 case 'D': fprintf (stream, "double"); (*ptr)++; break;
627 case 'F': fprintf (stream, "float"); (*ptr)++; break;
628 case 'S': fprintf (stream, "short"); (*ptr)++; break;
629 case 'I': fprintf (stream, "int"); (*ptr)++; break;
630 case 'J': fprintf (stream, "long"); (*ptr)++; break;
631 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
632 case 'V': fprintf (stream, "void"); (*ptr)++; break;
634 case 'L':
635 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
636 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
637 if (*(*ptr) == ';')
638 (*ptr)++;
639 break;
640 default:
641 jcf_print_char (stream, *(*ptr)++);
645 static void
646 DEFUN(print_signature, (stream, jcf, signature_index, int options),
647 FILE* stream AND JCF *jcf AND int signature_index AND int options)
649 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
650 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
651 else
653 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
654 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
655 const unsigned char *limit;
656 limit = str + length;
657 if (str >= limit)
658 fprintf (stream, "<empty signature string>");
659 else
661 if (options & PRINT_SIGNATURE_RESULT_ONLY)
663 while (str < limit && *str++ != ')') ;
665 if (options & PRINT_SIGNATURE_ARGS_ONLY)
667 str++;
668 fputc ('(', stream);
669 while (str < limit && *str != ')')
671 print_signature_type (stream, &str, limit);
672 if (*str != ')')
673 fputs (", ", stream);
675 fputc (')', stream);
677 else
679 print_signature_type (stream, &str, limit);
680 if (str < limit)
682 fprintf (stream, "<junk:");
683 jcf_print_utf8 (stream, str, limit - str);
684 fputc ('>', stream);
692 static void
693 DEFUN(print_exception_table, (jcf, entries, count),
694 JCF *jcf AND const unsigned char *entries AND int count)
696 /* Print exception table. */
697 int i = count;
698 if (i > 0)
700 const unsigned char *ptr = entries;
701 fprintf (out, "Exceptions (count: %d):\n", i);
702 for (; --i >= 0; ptr+= 8)
704 int start_pc = GET_u2 (ptr);
705 int end_pc = GET_u2 (ptr+2);
706 int handler_pc = GET_u2 (ptr+4);
707 int catch_type = GET_u2 (ptr+6);
708 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
709 start_pc, end_pc, handler_pc, catch_type);
710 if (catch_type == 0)
711 fputs (" /* finally */", out);
712 else
714 fputc('=', out);
715 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
717 fputc ('\n', out);
722 #include "jcf-reader.c"
724 static void
725 DEFUN(process_class, (jcf),
726 JCF *jcf)
728 int code;
729 if (jcf_parse_preamble (jcf) != 0)
730 fprintf (stderr, "Not a valid Java .class file.\n");
732 /* Parse and possibly print constant pool */
733 code = jcf_parse_constant_pool (jcf);
734 if (code != 0)
736 fprintf (stderr, "error while parsing constant pool\n");
737 exit (FATAL_EXIT_CODE);
739 code = verify_constant_pool (jcf);
740 if (code > 0)
742 fprintf (stderr, "error in constant pool entry #%d\n", code);
743 exit (FATAL_EXIT_CODE);
745 if (flag_print_constant_pool)
746 print_constant_pool (jcf);
748 jcf_parse_class (jcf);
749 code = jcf_parse_fields (jcf);
750 if (code != 0)
752 fprintf (stderr, "error while parsing fields\n");
753 exit (FATAL_EXIT_CODE);
755 code = jcf_parse_methods (jcf);
756 if (code != 0)
758 fprintf (stderr, "error while parsing methods\n");
759 exit (FATAL_EXIT_CODE);
761 code = jcf_parse_final_attributes (jcf);
762 if (code != 0)
764 fprintf (stderr, "error while parsing final attributes\n");
765 exit (FATAL_EXIT_CODE);
767 jcf->filename = NULL;
772 /* This is used to mark options with no short value. */
773 #define LONG_OPT(Num) ((Num) + 128)
775 #define OPT_classpath LONG_OPT (0)
776 #define OPT_CLASSPATH LONG_OPT (1)
777 #define OPT_HELP LONG_OPT (2)
778 #define OPT_VERSION LONG_OPT (3)
779 #define OPT_JAVAP LONG_OPT (4)
781 static struct option options[] =
783 { "classpath", required_argument, NULL, OPT_classpath },
784 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
785 { "help", no_argument, NULL, OPT_HELP },
786 { "verbose", no_argument, NULL, 'v' },
787 { "version", no_argument, NULL, OPT_VERSION },
788 { "javap", no_argument, NULL, OPT_JAVAP },
789 { "print-main", no_argument, &flag_print_main, 1 },
790 { NULL, no_argument, NULL, 0 }
793 static void
794 usage ()
796 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
797 exit (1);
800 static void
801 help ()
803 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
804 printf ("Display contents of a class file in readable form.\n\n");
805 printf (" -c Disassemble method bodies\n");
806 printf (" --javap Generate output in `javap' format\n");
807 printf ("\n");
808 printf (" --classpath PATH Set path to find .class files\n");
809 printf (" --CLASSPATH PATH Set path to find .class files\n");
810 printf (" -IDIR Append directory to class path\n");
811 printf (" -o FILE Set output file name\n");
812 printf ("\n");
813 printf (" --help Print this help, then exit\n");
814 printf (" --version Print version number, then exit\n");
815 printf (" -v, --verbose Print extra information while running\n");
816 printf ("\n");
817 printf ("For bug reporting instructions, please see:\n");
818 printf ("%s.\n", GCCBUGURL);
819 exit (0);
822 static void
823 version ()
825 printf ("jcf-dump (%s)\n\n", version_string);
826 printf ("Copyright (C) 2001 Free Software Foundation, Inc.\n");
827 printf ("This is free software; see the source for copying conditions. There is NO\n");
828 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
829 exit (0);
833 DEFUN(main, (argc, argv),
834 int argc AND char** argv)
836 JCF jcf[1];
837 int argi, opt;
839 if (argc <= 1)
841 fprintf (stderr, "jcf-dump: no classes specified\n");
842 usage ();
845 jcf_path_init ();
847 /* We use getopt_long_only to allow single `-' long options. For
848 some of our options this is more natural. */
849 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
851 switch (opt)
853 case 0:
854 /* Already handled. */
855 break;
857 case 'o':
858 output_file = optarg;
859 break;
861 case 'I':
862 jcf_path_include_arg (optarg);
863 break;
865 case 'v':
866 verbose++;
867 break;
869 case 'c':
870 flag_disassemble_methods = 1;
871 break;
873 case OPT_classpath:
874 jcf_path_classpath_arg (optarg);
875 break;
877 case OPT_CLASSPATH:
878 jcf_path_CLASSPATH_arg (optarg);
879 break;
881 case OPT_HELP:
882 help ();
883 break;
885 case OPT_VERSION:
886 version ();
887 break;
889 case OPT_JAVAP:
890 flag_javap_compatible++;
891 flag_print_constant_pool = 0;
892 break;
894 default:
895 usage ();
899 if (optind == argc)
901 fprintf (stderr, "jcf-dump: no classes specified\n");
902 usage ();
905 jcf_path_seal ();
907 if (flag_print_main)
909 flag_print_fields = 0;
910 flag_print_methods = 0;
911 flag_print_constant_pool = 0;
912 flag_print_attributes = 0;
913 flag_print_class_info = 0;
916 if (output_file)
918 out = fopen (output_file, "w");
919 if (! out)
921 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
922 return FATAL_EXIT_CODE;
925 else
926 out = stdout;
928 if (optind >= argc)
930 fprintf (out, "Reading .class from <standard input>.\n");
931 #if JCF_USE_STDIO
932 open_class ("<stdio>", jcf, stdin, NULL);
933 #else
934 open_class ("<stdio>", jcf, 0, NULL);
935 #endif
936 process_class (jcf);
938 else
940 for (argi = optind; argi < argc; argi++)
942 char *arg = argv[argi];
943 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
944 if (class_filename == NULL)
945 class_filename = find_classfile (arg, jcf, NULL);
946 if (class_filename == NULL)
948 perror ("Could not find class");
949 return FATAL_EXIT_CODE;
951 JCF_FILL (jcf, 4);
952 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
954 long compressed_size, member_size;
955 int compression_method, filename_length, extra_length;
956 int general_purpose_bits;
957 const char *filename;
958 int total_length;
959 if (flag_print_class_info)
960 fprintf (out, "Reading classes from archive %s.\n",
961 class_filename);
962 for (;;)
964 int skip = 0;
965 jcf_filbuf_t save_filbuf = jcf->filbuf;
966 long magic = JCF_readu4_le (jcf);
967 if (magic == 0x02014b50 || magic == 0x06054b50)
968 break; /* got to central directory */
969 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
971 fprintf (stderr, "bad format of .zip/.jar archive\n");
972 return FATAL_EXIT_CODE;
974 JCF_FILL (jcf, 26);
975 JCF_SKIP (jcf, 2);
976 general_purpose_bits = JCF_readu2_le (jcf);
977 compression_method = JCF_readu2_le (jcf);
978 JCF_SKIP (jcf, 8);
979 compressed_size = JCF_readu4_le (jcf);
980 member_size = JCF_readu4_le (jcf);
981 filename_length = JCF_readu2_le (jcf);
982 extra_length = JCF_readu2_le (jcf);
983 total_length = filename_length + extra_length
984 + compressed_size;
985 if (jcf->read_end - jcf->read_ptr < total_length)
986 jcf_trim_old_input (jcf);
987 JCF_FILL (jcf, total_length);
988 filename = jcf->read_ptr;
989 JCF_SKIP (jcf, filename_length);
990 JCF_SKIP (jcf, extra_length);
991 if (filename_length > 0
992 && filename[filename_length-1] == '/')
994 if (flag_print_class_info)
995 fprintf (out, "[Skipping directory %.*s]\n",
996 filename_length, filename);
997 skip = 1;
999 else if (compression_method != 0)
1001 if (flag_print_class_info)
1002 fprintf (out, "[Skipping compressed file %.*s]\n",
1003 filename_length, filename);
1004 skip = 1;
1006 else if (member_size < 4
1007 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1009 if (flag_print_class_info)
1010 fprintf (out, "[Skipping non-.class member %.*s]\n",
1011 filename_length, filename);
1012 skip = 1;
1014 else
1016 if (flag_print_class_info)
1017 fprintf (out, "Reading class member: %.*s.\n",
1018 filename_length, filename);
1020 if (skip)
1022 JCF_SKIP (jcf, compressed_size);
1024 else
1026 unsigned char *save_end;
1027 jcf->filbuf = jcf_unexpected_eof;
1028 save_end = jcf->read_end;
1029 jcf->read_end = jcf->read_ptr + compressed_size;
1030 process_class (jcf);
1031 jcf->filbuf = save_filbuf;
1032 jcf->read_end = save_end;
1036 else
1038 if (flag_print_class_info)
1039 fprintf (out, "Reading .class from %s.\n", class_filename);
1040 process_class (jcf);
1042 JCF_FINISH(jcf);
1046 return SUCCESS_EXIT_CODE;
1051 static void
1052 DEFUN(disassemble_method, (jcf, byte_ops, len),
1053 JCF* jcf AND const unsigned char *byte_ops AND int len)
1055 #undef AND /* Causes problems with opcodes for iand and land. */
1056 #undef PTR
1057 int PC;
1058 int i;
1059 int saw_wide = 0;
1060 if (flag_disassemble_methods == 0)
1061 return;
1062 #define BCODE byte_ops
1063 for (PC = 0; PC < len;)
1065 int oldpc = PC;
1066 int saw_index;
1067 jint INT_temp;
1068 switch (byte_ops[PC++])
1071 /* This is the actual code emitted for each of opcodes in javaops.def.
1072 The actual opcode-specific stuff is handled by the OPKIND macro.
1073 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1074 Those macros are defiend below. The OPKINDs that do not have any
1075 inline parameters (such as BINOP) and therefore do mot need anything
1076 else to me printed out just use an empty body. */
1078 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1079 case OPCODE: \
1080 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1081 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1082 fputc ('\n', out); \
1083 break;
1085 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1086 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1087 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1088 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1090 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1091 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1093 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1094 These all push a constant onto the opcode stack. */
1095 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1096 saw_index = 0, i = (OPERAND_VALUE); \
1097 if (oldpc+1 == PC) /* nothing */; \
1098 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1099 else fprintf (out, " %d", i);
1101 /* Print out operand (a local variable index) for LOAD opcodes.
1102 These all push local variable onto the opcode stack. */
1103 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1104 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1106 /* Handle STORE opcodes same as LOAD opcodes.
1107 These all store a value from the opcode stack in a local variable. */
1108 #define STORE LOAD
1110 /* Handle more kind of opcodes. */
1111 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1112 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1113 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1114 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1115 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1116 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1117 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1119 /* Handle putfield and getfield opcodes, with static versions. */
1120 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1121 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1123 /* Print operand for invoke opcodes. */
1124 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1125 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1126 if (OPERAND_VALUE) /* for invokeinterface */ \
1127 { int nargs = IMMEDIATE_u1; PC++; \
1128 fprintf (out, " nargs:%d", nargs); }
1130 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1131 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1133 #define ARRAY(OPERAND_TYPE, SUBOP) \
1134 ARRAY_##SUBOP(OPERAND_TYPE)
1135 /* Handle sub-categories of ARRAY opcodes. */
1136 #define ARRAY_LOAD(TYPE) /* nothing */
1137 #define ARRAY_STORE(TYPE) /* nothing */
1138 #define ARRAY_LENGTH(TYPE) /* nothing */
1139 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1140 #define ARRAY_NEW_NUM \
1141 INT_temp = IMMEDIATE_u1; \
1142 { switch ((int) INT_temp) { \
1143 case 4: fputs (" boolean", out); break; \
1144 case 5: fputs (" char", out); break; \
1145 case 6: fputs (" float", out); break; \
1146 case 7: fputs (" double", out); break; \
1147 case 8: fputs (" byte", out); break; \
1148 case 9: fputs (" short", out); break; \
1149 case 10: fputs (" int", out); break; \
1150 case 11: fputs (" long", out); break; \
1151 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1154 #define ARRAY_NEW_PTR \
1155 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1157 #define ARRAY_NEW_MULTI \
1158 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1159 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1161 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1162 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1164 #define BRANCH(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 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1169 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1170 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1172 #undef RET /* Defined by config/i386/i386.h */
1173 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1174 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1175 saw_wide = 0; \
1176 fprintf (out, " %ld", (long) INT_temp);
1178 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1179 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1181 #define LOOKUP_SWITCH \
1182 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1183 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1184 while (--npairs >= 0) { \
1185 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1186 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1189 #define TABLE_SWITCH \
1190 { jint default_offset = IMMEDIATE_s4; \
1191 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1192 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1193 (long) low, (long) high, (long) default_offset+oldpc); \
1194 for (; low <= high; low++) { \
1195 jint offset = IMMEDIATE_s4; \
1196 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1199 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1200 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1202 #define SPECIAL_IINC(OPERAND_TYPE) \
1203 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1204 fprintf (out, " %ld", (long) i); \
1205 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1206 saw_wide = 0; \
1207 fprintf (out, " %ld", (long) INT_temp)
1209 #define SPECIAL_WIDE(OPERAND_TYPE) \
1210 saw_wide = 1;
1212 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1213 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1214 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1215 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1217 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1218 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1220 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1221 TEST(OPERAND_TYPE, OPERAND_VALUE)
1223 #include "javaop.def"
1225 load_store:
1226 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1227 else
1229 saw_wide = 0;
1230 fprintf (out, " %ld", (long) INT_temp);
1232 fputc ('\n', out);
1233 break;
1235 default:
1236 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);