Fixed rare threading problem
[official-gcc.git] / gcc / java / jcf-dump.c
bloba87dd401e0fc6287bc2752ac3fd041e27f5fe95c
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
5 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
24 Java and all Java-based marks are trademarks or registered trademarks
25 of Sun Microsystems, Inc. in the United States and other countries.
26 The Free Software Foundation is independent of Sun Microsystems, Inc. */
28 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
31 jcf-dump is a program to print out the contents of class files.
32 Usage: jcf-dump [FLAGS] CLASS
33 Each CLASS is either:
34 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
35 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
36 + The name of a .zip or .jar file (which prints all the classes in the
37 archive).
39 OPTIONS:
41 Dis-assemble each method.
42 -classpath PATH
43 Overrides $CLASSPATH.
44 --print-main
45 Print nothing if there is no valid "main" method;
46 otherwise, print only the class name.
47 --javap
48 Print output in the style of Sun's javap program. VERY UNFINISHED.
52 #include "config.h"
53 #include "system.h"
54 #include "coretypes.h"
55 #include "tm.h"
56 #include "ggc.h"
58 #include "jcf.h"
59 #include "tree.h"
60 #include "java-tree.h"
62 #include "version.h"
64 #include <getopt.h>
65 #include <math.h>
67 /* Outout file. */
68 FILE *out;
69 /* Name of output file, if NULL if stdout. */
70 char *output_file = NULL;
72 int verbose = 0;
74 int flag_disassemble_methods = 0;
75 int flag_print_class_info = 1;
76 int flag_print_constant_pool = 1;
77 int flag_print_fields = 1;
78 int flag_print_methods = 1;
79 int flag_print_attributes = 1;
81 /* When nonzero, warn when source file is newer than matching class
82 file. */
83 int flag_newer = 1;
85 /* Print names of classes that have a "main" method. */
86 int flag_print_main = 0;
88 /* Index in constant pool of this class. */
89 int this_class_index = 0;
91 int class_access_flags = 0;
93 /* Print in format similar to javap. VERY IMCOMPLETE. */
94 int flag_javap_compatible = 0;
96 static void print_access_flags (FILE *, uint16, char);
97 static void print_constant_terse (FILE*, JCF*, int, int);
98 static void print_constant (FILE *, JCF *, int, int);
99 static void print_constant_ref (FILE *, JCF *, int);
100 static void disassemble_method (JCF*, const unsigned char *, int);
101 static void print_name (FILE*, JCF*, int);
102 static void print_signature (FILE*, JCF*, int, int);
103 static int utf8_equal_string (struct JCF*, int, const char *);
104 static void usage (void) ATTRIBUTE_NORETURN;
105 static void help (void) ATTRIBUTE_NORETURN;
106 static void version (void) ATTRIBUTE_NORETURN;
107 static void process_class (struct JCF *);
108 static void print_constant_pool (struct JCF *);
109 static void print_exception_table (struct JCF *, const unsigned char *entries,
110 int);
112 #define PRINT_SIGNATURE_RESULT_ONLY 1
113 #define PRINT_SIGNATURE_ARGS_ONLY 2
115 static int
116 utf8_equal_string (JCF *jcf, int index, const char * value)
118 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
119 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
121 int len = strlen (value);
122 if (JPOOL_UTF_LENGTH (jcf, index) == len
123 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
124 return 1;
126 return 0;
129 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
130 this_class_index = 0; \
131 if (flag_print_class_info) \
132 fprintf (out, \
133 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
134 (long) MAGIC, (long) MINOR, (long) MAJOR)
136 #define HANDLE_START_CONSTANT_POOL(COUNT) \
137 if (flag_print_constant_pool) \
138 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
140 #define HANDLE_SOURCEFILE(INDEX) \
141 { fprintf (out, "Attribute "); \
142 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
143 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
144 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
146 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
147 this_class_index = THIS; \
148 class_access_flags = ACCESS_FLAGS; \
149 if (flag_print_class_info) \
150 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
151 print_access_flags (out, ACCESS_FLAGS, 'c'); \
152 fputc ('\n', out); \
153 fprintf (out, "This class: "); \
154 if (flag_print_constant_pool) \
155 fprintf (out, "%d=", THIS); \
156 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
157 if (flag_print_constant_pool || SUPER != 0) \
158 fprintf (out, ", super: "); \
159 if (flag_print_constant_pool) \
161 fprintf (out, "%d", SUPER); \
162 if (SUPER != 0) \
163 fputc ('=', out); \
165 if (SUPER != 0) \
166 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
167 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
170 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
171 (flag_print_attributes <= 0)
173 #define HANDLE_CLASS_INTERFACE(INDEX) \
174 if (flag_print_class_info) \
175 { fprintf (out, "- Implements: %d=", INDEX); \
176 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
177 fputc ('\n', out); }
179 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
180 if (flag_print_fields) \
181 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
183 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
184 if (flag_print_fields) \
185 { fprintf (out, "Field name:"); \
186 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
187 print_access_flags (out, ACCESS_FLAGS, 'f'); \
188 fprintf (out, " Signature: "); \
189 if (flag_print_constant_pool) \
190 fprintf (out, "%d=", SIGNATURE); \
191 print_signature (out, jcf, SIGNATURE, 0); \
192 fputc ('\n', out); } \
193 else \
194 flag_print_attributes--;
196 #define HANDLE_END_FIELD() \
197 if (! flag_print_fields) \
198 flag_print_attributes++;
200 #define HANDLE_START_METHODS(METHODS_COUNT) \
201 if (flag_print_methods) \
202 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
203 else \
204 flag_print_attributes--;
207 #define HANDLE_END_METHODS() \
208 if (! flag_print_methods) \
209 flag_print_attributes++;
211 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
213 if (flag_print_methods) \
215 if (flag_javap_compatible) \
217 fprintf (out, " "); \
218 print_access_flags (out, ACCESS_FLAGS, 'm'); \
219 fputc (' ', out); \
220 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
221 fputc (' ', out); \
222 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
223 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
224 fputc ('\n', out); \
226 else \
228 fprintf (out, "\nMethod name:"); \
229 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
230 print_access_flags (out, ACCESS_FLAGS, 'm'); \
231 fprintf (out, " Signature: "); \
232 if (flag_print_constant_pool) \
233 fprintf (out, "%d=", SIGNATURE); \
234 print_signature (out, jcf, SIGNATURE, 0); \
235 fputc ('\n', out); \
238 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
239 && utf8_equal_string (jcf, NAME, "main") \
240 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
241 && this_class_index > 0 \
242 && (class_access_flags & ACC_PUBLIC)) \
244 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
245 fputc ('\n', out); \
249 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
250 ( fprintf (out, "Attribute "), \
251 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
252 fprintf (out, ", length:%ld", (long) LENGTH) )
254 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
255 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
256 fprintf (out, ", value: "), \
257 print_constant_ref (out, jcf, VALUE_INDEX), \
258 fprintf (out, "\n") )
260 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
261 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
262 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
263 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
264 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
266 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
267 print_exception_table (jcf, ENTRIES, COUNT)
269 #define HANDLE_EXCEPTIONS_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 ex_index = JCF_readu2 (jcf); \
275 fprintf (out, "%3d: ", i); \
276 print_constant_ref (out, jcf, ex_index); \
277 fputc ('\n', out); } }
279 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
280 { int n = (COUNT); int i; \
281 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
282 fprintf (out, ", count: %d\n", n); \
283 for (i = 0; i < n; i++) {\
284 int start_pc = JCF_readu2 (jcf); \
285 int length = JCF_readu2 (jcf); \
286 int name_index = JCF_readu2 (jcf); \
287 int signature_index = JCF_readu2 (jcf); \
288 int slot = JCF_readu2 (jcf); \
289 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
290 print_name (out, jcf, name_index); \
291 fprintf (out, ", type: %d=", signature_index); \
292 print_signature (out, jcf, signature_index, 0); \
293 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
295 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
296 { int n = (COUNT); int i; \
297 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
298 fprintf (out, ", count: %d\n", n); \
299 if (flag_disassemble_methods) \
300 for (i = 0; i < n; i++) {\
301 int start_pc = JCF_readu2 (jcf); \
302 int line_number = JCF_readu2 (jcf); \
303 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
304 else \
305 JCF_SKIP (jcf, 4 * n); }
307 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
308 { int n = (COUNT); \
309 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
310 while (n--) \
312 uint16 inner_class_info_index = JCF_readu2 (jcf); \
313 uint16 outer_class_info_index = JCF_readu2 (jcf); \
314 uint16 inner_name_index = JCF_readu2 (jcf); \
315 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
317 if (flag_print_class_info) \
319 fprintf (out, "\n class: "); \
320 if (flag_print_constant_pool) \
321 fprintf (out, "%d=", inner_class_info_index); \
322 print_constant_terse (out, jcf, \
323 inner_class_info_index, CONSTANT_Class); \
324 fprintf (out, " (%d=", inner_name_index); \
325 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
326 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
327 print_access_flags (out, inner_class_access_flags, 'c'); \
328 fprintf (out, ", outer class: "); \
329 if (flag_print_constant_pool) \
330 fprintf (out, "%d=", outer_class_info_index); \
331 print_constant_terse (out, jcf, \
332 outer_class_info_index, CONSTANT_Class); \
335 if (flag_print_class_info) \
336 fputc ('\n', out); \
339 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
340 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
341 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
343 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
344 if (flag_print_attributes > 0) \
345 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
347 #include "javaop.h"
349 static void
350 print_constant_ref (FILE *stream, JCF *jcf, int index)
352 fprintf (stream, "#%d=<", index);
353 if (index <= 0 || index >= JPOOL_SIZE(jcf))
354 fprintf (stream, "out of range");
355 else
356 print_constant (stream, jcf, index, 1);
357 fprintf (stream, ">");
360 /* Print the access flags given by FLAGS.
361 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
362 or 'm' (method flags). */
364 static void
365 print_access_flags (FILE *stream, uint16 flags, char context)
367 if (flags & ACC_PUBLIC) fprintf (stream, " public");
368 if (flags & ACC_PRIVATE) fprintf (stream, " private");
369 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
370 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
371 if (flags & ACC_STATIC) fprintf (stream, " static");
372 if (flags & ACC_FINAL) fprintf (stream, " final");
373 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
374 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
375 if (flags & ACC_NATIVE) fprintf (stream, " native");
376 if (flags & ACC_SYNCHRONIZED)
378 if (context == 'c')
379 fprintf (stream, " super");
380 else
381 fprintf (stream, " synchronized");
383 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
384 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
388 static void
389 print_name (FILE* stream, JCF* jcf, int name_index)
391 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
392 fprintf (stream, "<not a UTF8 constant>");
393 else
394 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
395 JPOOL_UTF_LENGTH (jcf, name_index));
398 /* If the type of the constant at INDEX matches EXPECTED,
399 print it tersely, otherwise more verbosely. */
401 static void
402 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
404 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
405 fprintf (out, "<constant pool index %d not in range>", index);
406 else if (JPOOL_TAG (jcf, index) != expected)
408 fprintf (out, "<Unexpected constant type ");
409 print_constant (out, jcf, index, 1);
410 fprintf (out, ">");
412 else
413 print_constant (out, jcf, index, 0);
416 /* Print the constant at INDEX in JCF's constant pool.
417 If verbosity==0, print very tersely (no extraneous text).
418 If verbosity==1, prefix the type of the constant.
419 If verbosity==2, add more descriptive text. */
421 static void
422 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
424 int j, n;
425 jlong num;
426 const char *str;
427 int kind = JPOOL_TAG (jcf, index);
428 switch (kind)
430 case CONSTANT_Class:
431 n = JPOOL_USHORT1 (jcf, index);
432 if (verbosity > 0)
434 if (verbosity > 1)
435 fprintf (out, "Class name: %d=", n);
436 else
437 fprintf (out, "Class ");
439 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
440 fprintf (out, "<out of range>");
441 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
443 int len = JPOOL_UTF_LENGTH (jcf, n);
444 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
446 else
447 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
448 break;
449 case CONSTANT_Fieldref:
450 str = "Field"; goto field_or_method;
451 case CONSTANT_Methodref:
452 str = "Method"; goto field_or_method;
453 case CONSTANT_InterfaceMethodref:
454 str = "InterfaceMethod"; goto field_or_method;
455 field_or_method:
457 uint16 tclass = JPOOL_USHORT1 (jcf, index);
458 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
459 if (verbosity == 2)
460 fprintf (out, "%sref class: %d=", str, tclass);
461 else if (verbosity > 0)
462 fprintf (out, "%s ", str);
463 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
464 if (verbosity < 2)
465 fprintf (out, ".");
466 else
467 fprintf (out, " name_and_type: %d=<", name_and_type);
468 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
469 if (verbosity == 2)
470 fputc ('>', out);
472 break;
473 case CONSTANT_String:
474 j = JPOOL_USHORT1 (jcf, index);
475 if (verbosity > 0)
477 if (verbosity > 1)
478 fprintf (out, "String %d=", j);
479 else
480 fprintf (out, "String ");
482 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
483 break;
484 case CONSTANT_Integer:
485 if (verbosity > 0)
486 fprintf (out, "Integer ");
487 num = JPOOL_INT (jcf, index);
488 goto integer;
489 case CONSTANT_Long:
490 if (verbosity > 0)
491 fprintf (out, "Long ");
492 num = JPOOL_LONG (jcf, index);
493 goto integer;
494 integer:
496 char buffer[25];
497 format_int (buffer, num, 10);
498 fprintf (out, "%s", buffer);
499 if (verbosity > 1)
501 format_uint (buffer, (uint64)num, 16);
502 fprintf (out, "=0x%s", buffer);
505 break;
506 case CONSTANT_Float:
508 jfloat fnum = JPOOL_FLOAT (jcf, index);
510 if (verbosity > 0)
511 fputs ("Float ", out);
513 if (fnum.negative)
514 putc ('-', out);
516 if (JFLOAT_FINITE (fnum))
518 int dummy;
519 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
520 double f;
521 uint32 mantissa = fnum.mantissa;
522 if (fnum.exponent == 0)
523 /* Denormal. */
524 exponent++;
525 else
526 /* Normal; add the implicit bit. */
527 mantissa |= ((uint32)1 << 23);
529 f = frexp (mantissa, &dummy);
530 f = ldexp (f, exponent + 1);
531 fprintf (out, "%.10g", f);
533 else
535 if (fnum.mantissa == 0)
536 fputs ("Inf", out);
537 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
538 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
539 else
540 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
543 if (verbosity > 1)
544 fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
546 break;
548 case CONSTANT_Double:
550 jdouble dnum = JPOOL_DOUBLE (jcf, index);
552 if (verbosity > 0)
553 fputs ("Double ", out);
555 if (dnum.negative)
556 putc ('-', out);
558 if (JDOUBLE_FINITE (dnum))
560 int dummy;
561 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
562 double d;
563 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
564 + dnum.mantissa1);
565 if (dnum.exponent == 0)
566 /* Denormal. */
567 exponent++;
568 else
569 /* Normal; add the implicit bit. */
570 mantissa |= ((uint64)1 << 52);
572 d = frexp (mantissa, &dummy);
573 d = ldexp (d, exponent + 1);
574 fprintf (out, "%.20g", d);
576 else
578 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
579 mantissa = (mantissa << 32) + dnum.mantissa1;
581 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
582 fputs ("Inf", out);
583 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
584 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
585 else
586 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
588 if (verbosity > 1)
590 int32 hi, lo;
591 hi = JPOOL_UINT (jcf, index);
592 lo = JPOOL_UINT (jcf, index + 1);
593 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
595 break;
597 case CONSTANT_NameAndType:
599 uint16 name = JPOOL_USHORT1 (jcf, index);
600 uint16 sig = JPOOL_USHORT2 (jcf, index);
601 if (verbosity > 0)
603 if (verbosity > 1)
604 fprintf (out, "NameAndType name: %d=", name);
605 else
606 fprintf (out, "NameAndType ");
608 print_name (out, jcf, name);
609 if (verbosity <= 1)
610 fputc (' ', out);
611 else
612 fprintf (out, ", signature: %d=", sig);
613 print_signature (out, jcf, sig, 0);
615 break;
616 case CONSTANT_Utf8:
618 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
619 int length = JPOOL_UTF_LENGTH (jcf, index);
620 if (verbosity > 0)
621 { /* Print as 8-bit bytes. */
622 fputs ("Utf8: \"", out);
623 while (--length >= 0)
624 jcf_print_char (out, *str++);
626 else
627 { /* Print as Unicode. */
628 fputc ('\"', out);
629 jcf_print_utf8 (out, str, length);
631 fputc ('\"', out);
633 break;
634 default:
635 fprintf (out, "(Unknown constant type %d)", kind);
639 static void
640 print_constant_pool (JCF *jcf)
642 int i;
643 for (i = 1; i < JPOOL_SIZE(jcf); i++)
645 int kind = JPOOL_TAG (jcf, i);
646 fprintf (out, "#%d: ", i);
647 print_constant (out, jcf, i, 2);
648 fprintf (out, "\n");
649 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
650 i++; /* These take up two slots in the constant table */
654 static void
655 print_signature_type (FILE* stream, const unsigned char **ptr,
656 const unsigned char *limit)
658 int array_size;
659 if ((*ptr) >= limit)
660 return;
661 switch (*(*ptr))
663 case '[':
664 array_size = -1;
665 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
667 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
669 print_signature_type (stream, ptr, limit);
670 if (array_size == -1)
671 fprintf (stream, "[]");
672 else
673 fprintf (stream, "[%d]", array_size);
674 break;
675 case '(':
677 int nargs = 0;
678 fputc (*(*ptr)++, stream);
679 for (; **ptr != ')' && *ptr < limit; nargs++)
681 if (nargs > 0)
682 fputc (',', stream);
683 print_signature_type (stream, ptr, limit);
685 if (*ptr < limit)
687 fputc (*(*ptr)++, stream);
688 print_signature_type (stream, ptr, limit);
690 else
691 fprintf (stream, "???");
693 break;
695 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
696 case 'C': fprintf (stream, "char"); (*ptr)++; break;
697 case 'D': fprintf (stream, "double"); (*ptr)++; break;
698 case 'F': fprintf (stream, "float"); (*ptr)++; break;
699 case 'S': fprintf (stream, "short"); (*ptr)++; break;
700 case 'I': fprintf (stream, "int"); (*ptr)++; break;
701 case 'J': fprintf (stream, "long"); (*ptr)++; break;
702 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
703 case 'V': fprintf (stream, "void"); (*ptr)++; break;
705 case 'L':
706 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
707 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
708 if (*(*ptr) == ';')
709 (*ptr)++;
710 break;
711 default:
712 jcf_print_char (stream, *(*ptr)++);
716 static void
717 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
719 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
720 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
721 else
723 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
724 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
725 const unsigned char *limit;
726 limit = str + length;
727 if (str >= limit)
728 fprintf (stream, "<empty signature string>");
729 else
731 if (options & PRINT_SIGNATURE_RESULT_ONLY)
733 while (str < limit && *str++ != ')') ;
735 if (options & PRINT_SIGNATURE_ARGS_ONLY)
737 str++;
738 fputc ('(', stream);
739 while (str < limit && *str != ')')
741 print_signature_type (stream, &str, limit);
742 if (*str != ')')
743 fputs (", ", stream);
745 fputc (')', stream);
747 else
749 print_signature_type (stream, &str, limit);
750 if (str < limit)
752 fprintf (stream, "<junk:");
753 jcf_print_utf8 (stream, str, limit - str);
754 fputc ('>', stream);
762 static void
763 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
765 /* Print exception table. */
766 int i = count;
767 if (i > 0)
769 const unsigned char *ptr = entries;
770 fprintf (out, "Exceptions (count: %d):\n", i);
771 for (; --i >= 0; ptr+= 8)
773 int start_pc = GET_u2 (ptr);
774 int end_pc = GET_u2 (ptr+2);
775 int handler_pc = GET_u2 (ptr+4);
776 int catch_type = GET_u2 (ptr+6);
777 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
778 start_pc, end_pc, handler_pc, catch_type);
779 if (catch_type == 0)
780 fputs (" /* finally */", out);
781 else
783 fputc('=', out);
784 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
786 fputc ('\n', out);
791 #include "jcf-reader.c"
793 static void
794 process_class (JCF *jcf)
796 int code;
797 if (jcf_parse_preamble (jcf) != 0)
798 fprintf (stderr, "Not a valid Java .class file.\n");
800 /* Parse and possibly print constant pool */
801 code = jcf_parse_constant_pool (jcf);
802 if (code != 0)
804 fprintf (stderr, "error while parsing constant pool\n");
805 exit (FATAL_EXIT_CODE);
807 code = verify_constant_pool (jcf);
808 if (code > 0)
810 fprintf (stderr, "error in constant pool entry #%d\n", code);
811 exit (FATAL_EXIT_CODE);
813 if (flag_print_constant_pool)
814 print_constant_pool (jcf);
816 jcf_parse_class (jcf);
817 code = jcf_parse_fields (jcf);
818 if (code != 0)
820 fprintf (stderr, "error while parsing fields\n");
821 exit (FATAL_EXIT_CODE);
823 code = jcf_parse_methods (jcf);
824 if (code != 0)
826 fprintf (stderr, "error while parsing methods\n");
827 exit (FATAL_EXIT_CODE);
829 code = jcf_parse_final_attributes (jcf);
830 if (code != 0)
832 fprintf (stderr, "error while parsing final attributes\n");
833 exit (FATAL_EXIT_CODE);
835 jcf->filename = NULL;
840 /* This is used to mark options with no short value. */
841 #define LONG_OPT(Num) ((Num) + 128)
843 #define OPT_classpath LONG_OPT (0)
844 #define OPT_CLASSPATH OPT_classpath
845 #define OPT_bootclasspath LONG_OPT (1)
846 #define OPT_extdirs LONG_OPT (2)
847 #define OPT_HELP LONG_OPT (3)
848 #define OPT_VERSION LONG_OPT (4)
849 #define OPT_JAVAP LONG_OPT (5)
851 static const struct option options[] =
853 { "classpath", required_argument, NULL, OPT_classpath },
854 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
855 { "extdirs", required_argument, NULL, OPT_extdirs },
856 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
857 { "help", no_argument, NULL, OPT_HELP },
858 { "verbose", no_argument, NULL, 'v' },
859 { "version", no_argument, NULL, OPT_VERSION },
860 { "javap", no_argument, NULL, OPT_JAVAP },
861 { "print-main", no_argument, &flag_print_main, 1 },
862 { NULL, no_argument, NULL, 0 }
865 static void
866 usage (void)
868 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
869 exit (1);
872 static void
873 help (void)
875 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
876 printf ("Display contents of a class file in readable form.\n\n");
877 printf (" -c Disassemble method bodies\n");
878 printf (" --javap Generate output in `javap' format\n");
879 printf ("\n");
880 printf (" --classpath PATH Set path to find .class files\n");
881 printf (" -IDIR Append directory to class path\n");
882 printf (" --bootclasspath PATH Override built-in class path\n");
883 printf (" --extdirs PATH Set extensions directory path\n");
884 printf (" -o FILE Set output file name\n");
885 printf ("\n");
886 printf (" --help Print this help, then exit\n");
887 printf (" --version Print version number, then exit\n");
888 printf (" -v, --verbose Print extra information while running\n");
889 printf ("\n");
890 printf ("For bug reporting instructions, please see:\n");
891 printf ("%s.\n", bug_report_url);
892 exit (0);
895 static void
896 version (void)
898 printf ("jcf-dump (GCC) %s\n\n", version_string);
899 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
900 printf ("This is free software; see the source for copying conditions. There is NO\n");
901 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
902 exit (0);
906 main (int argc, char** argv)
908 JCF jcf[1];
909 int argi, opt;
911 if (argc <= 1)
913 fprintf (stderr, "jcf-dump: no classes specified\n");
914 usage ();
917 jcf_path_init ();
919 /* We use getopt_long_only to allow single `-' long options. For
920 some of our options this is more natural. */
921 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
923 switch (opt)
925 case 0:
926 /* Already handled. */
927 break;
929 case 'o':
930 output_file = optarg;
931 break;
933 case 'I':
934 jcf_path_include_arg (optarg);
935 break;
937 case 'v':
938 verbose++;
939 break;
941 case 'c':
942 flag_disassemble_methods = 1;
943 break;
945 case OPT_classpath:
946 jcf_path_classpath_arg (optarg);
947 break;
949 case OPT_bootclasspath:
950 jcf_path_bootclasspath_arg (optarg);
951 break;
953 case OPT_extdirs:
954 jcf_path_extdirs_arg (optarg);
955 break;
957 case OPT_HELP:
958 help ();
959 break;
961 case OPT_VERSION:
962 version ();
963 break;
965 case OPT_JAVAP:
966 flag_javap_compatible++;
967 flag_print_constant_pool = 0;
968 flag_print_attributes = 0;
969 break;
971 default:
972 usage ();
976 if (optind == argc)
978 fprintf (stderr, "jcf-dump: no classes specified\n");
979 usage ();
982 jcf_path_seal (verbose);
984 if (flag_print_main)
986 flag_print_fields = 0;
987 flag_print_methods = 0;
988 flag_print_constant_pool = 0;
989 flag_print_attributes = 0;
990 flag_print_class_info = 0;
993 if (output_file)
995 out = fopen (output_file, "w");
996 if (! out)
998 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
999 return FATAL_EXIT_CODE;
1002 else
1003 out = stdout;
1005 if (optind >= argc)
1007 fprintf (out, "Reading .class from <standard input>.\n");
1008 open_class ("<stdio>", jcf, 0, NULL);
1009 process_class (jcf);
1011 else
1013 for (argi = optind; argi < argc; argi++)
1015 char *arg = argv[argi];
1016 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1017 if (class_filename == NULL)
1018 class_filename = find_classfile (arg, jcf, NULL);
1019 if (class_filename == NULL)
1021 perror ("Could not find class");
1022 return FATAL_EXIT_CODE;
1024 JCF_FILL (jcf, 4);
1025 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1027 long compressed_size, member_size;
1028 int compression_method, filename_length, extra_length;
1029 int general_purpose_bits;
1030 const char *filename;
1031 int total_length;
1032 if (flag_print_class_info)
1033 fprintf (out, "Reading classes from archive %s.\n",
1034 class_filename);
1035 for (;;)
1037 int skip = 0;
1038 jcf_filbuf_t save_filbuf = jcf->filbuf;
1039 long magic = JCF_readu4_le (jcf);
1040 if (magic == 0x02014b50 || magic == 0x06054b50)
1041 break; /* got to central directory */
1042 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1044 fprintf (stderr, "bad format of .zip/.jar archive\n");
1045 return FATAL_EXIT_CODE;
1047 JCF_FILL (jcf, 26);
1048 JCF_SKIP (jcf, 2);
1049 general_purpose_bits = JCF_readu2_le (jcf);
1050 compression_method = JCF_readu2_le (jcf);
1051 JCF_SKIP (jcf, 8);
1052 compressed_size = JCF_readu4_le (jcf);
1053 member_size = JCF_readu4_le (jcf);
1054 filename_length = JCF_readu2_le (jcf);
1055 extra_length = JCF_readu2_le (jcf);
1056 total_length = filename_length + extra_length
1057 + compressed_size;
1058 if (jcf->read_end - jcf->read_ptr < total_length)
1059 jcf_trim_old_input (jcf);
1060 JCF_FILL (jcf, total_length);
1061 filename = jcf->read_ptr;
1062 JCF_SKIP (jcf, filename_length);
1063 JCF_SKIP (jcf, extra_length);
1064 if (filename_length > 0
1065 && filename[filename_length-1] == '/')
1067 if (flag_print_class_info)
1068 fprintf (out, "[Skipping directory %.*s]\n",
1069 filename_length, filename);
1070 skip = 1;
1072 else if (compression_method != 0)
1074 if (flag_print_class_info)
1075 fprintf (out, "[Skipping compressed file %.*s]\n",
1076 filename_length, filename);
1077 skip = 1;
1079 else if (member_size < 4
1080 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1082 if (flag_print_class_info)
1083 fprintf (out, "[Skipping non-.class member %.*s]\n",
1084 filename_length, filename);
1085 skip = 1;
1087 else
1089 if (flag_print_class_info)
1090 fprintf (out, "Reading class member: %.*s.\n",
1091 filename_length, filename);
1093 if (skip)
1095 JCF_SKIP (jcf, compressed_size);
1097 else
1099 unsigned char *save_end;
1100 jcf->filbuf = jcf_unexpected_eof;
1101 save_end = jcf->read_end;
1102 jcf->read_end = jcf->read_ptr + compressed_size;
1103 process_class (jcf);
1104 jcf->filbuf = save_filbuf;
1105 jcf->read_end = save_end;
1109 else
1111 if (flag_print_class_info)
1112 fprintf (out, "Reading .class from %s.\n", class_filename);
1113 process_class (jcf);
1115 JCF_FINISH(jcf);
1119 return SUCCESS_EXIT_CODE;
1124 static void
1125 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1127 #undef PTR
1128 int PC;
1129 int i;
1130 int saw_wide = 0;
1131 if (flag_disassemble_methods == 0)
1132 return;
1133 #define BCODE byte_ops
1134 for (PC = 0; PC < len;)
1136 int oldpc = PC;
1137 int saw_index;
1138 jint INT_temp;
1139 switch (byte_ops[PC++])
1142 /* This is the actual code emitted for each of opcodes in javaops.def.
1143 The actual opcode-specific stuff is handled by the OPKIND macro.
1144 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1145 Those macros are defined below. The OPKINDs that do not have any
1146 inline parameters (such as BINOP) and therefore do mot need anything
1147 else to me printed out just use an empty body. */
1149 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1150 case OPCODE: \
1151 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1152 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1153 fputc ('\n', out); \
1154 break;
1156 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1157 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1158 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1159 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1161 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1162 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1164 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1165 These all push a constant onto the opcode stack. */
1166 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1167 saw_index = 0, i = (OPERAND_VALUE); \
1168 if (oldpc+1 == PC) /* nothing */; \
1169 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1170 else fprintf (out, " %d", i);
1172 /* Print out operand (a local variable index) for LOAD opcodes.
1173 These all push local variable onto the opcode stack. */
1174 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1175 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1177 /* Handle STORE opcodes same as LOAD opcodes.
1178 These all store a value from the opcode stack in a local variable. */
1179 #define STORE LOAD
1181 /* Handle more kind of opcodes. */
1182 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1183 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1184 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1185 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1186 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1187 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1188 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1190 /* Handle putfield and getfield opcodes, with static versions. */
1191 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1192 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1194 /* Print operand for invoke opcodes. */
1195 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1196 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1197 if (OPERAND_VALUE) /* for invokeinterface */ \
1198 { int nargs = IMMEDIATE_u1; PC++; \
1199 fprintf (out, " nargs:%d", nargs); }
1201 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1202 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1204 #define ARRAY(OPERAND_TYPE, SUBOP) \
1205 ARRAY_##SUBOP(OPERAND_TYPE)
1206 /* Handle sub-categories of ARRAY opcodes. */
1207 #define ARRAY_LOAD(TYPE) /* nothing */
1208 #define ARRAY_STORE(TYPE) /* nothing */
1209 #define ARRAY_LENGTH(TYPE) /* nothing */
1210 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1211 #define ARRAY_NEW_NUM \
1212 INT_temp = IMMEDIATE_u1; \
1213 { switch ((int) INT_temp) { \
1214 case 4: fputs (" boolean", out); break; \
1215 case 5: fputs (" char", out); break; \
1216 case 6: fputs (" float", out); break; \
1217 case 7: fputs (" double", out); break; \
1218 case 8: fputs (" byte", out); break; \
1219 case 9: fputs (" short", out); break; \
1220 case 10: fputs (" int", out); break; \
1221 case 11: fputs (" long", out); break; \
1222 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1225 #define ARRAY_NEW_PTR \
1226 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1228 #define ARRAY_NEW_MULTI \
1229 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1230 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1232 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1233 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1235 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1236 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1237 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1239 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1240 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1241 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1243 #undef RET /* Defined by config/i386/i386.h */
1244 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1245 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1246 saw_wide = 0; \
1247 fprintf (out, " %ld", (long) INT_temp);
1249 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1250 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1252 #define LOOKUP_SWITCH \
1253 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1254 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1255 while (--npairs >= 0) { \
1256 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1257 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1260 #define TABLE_SWITCH \
1261 { jint default_offset = IMMEDIATE_s4; \
1262 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1263 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1264 (long) low, (long) high, (long) default_offset+oldpc); \
1265 for (; low <= high; low++) { \
1266 jint offset = IMMEDIATE_s4; \
1267 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1270 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1271 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1273 #define SPECIAL_IINC(OPERAND_TYPE) \
1274 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1275 fprintf (out, " %d", i); \
1276 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1277 saw_wide = 0; \
1278 fprintf (out, " %d", i)
1280 #define SPECIAL_WIDE(OPERAND_TYPE) \
1281 saw_wide = 1;
1283 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1284 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1285 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1286 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1288 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1289 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1291 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1292 TEST(OPERAND_TYPE, OPERAND_VALUE)
1294 #include "javaop.def"
1296 load_store:
1297 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1298 else
1300 saw_wide = 0;
1301 fprintf (out, " %ld", (long) INT_temp);
1303 fputc ('\n', out);
1304 break;
1306 default:
1307 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);