2004-02-11 Eric Christopher <echristo@redhat.com>
[official-gcc.git] / gcc / java / jcf-dump.c
blob0776629a81e57eaf2d182e620eafbe68102c66de
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, 2004
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"
57 #include "intl.h"
59 #include "jcf.h"
60 #include "tree.h"
61 #include "java-tree.h"
63 #include "version.h"
65 #include <getopt.h>
66 #include <math.h>
68 /* Outout file. */
69 FILE *out;
70 /* Name of output file, if NULL if stdout. */
71 char *output_file = NULL;
73 int verbose = 0;
75 int flag_disassemble_methods = 0;
76 int flag_print_class_info = 1;
77 int flag_print_constant_pool = 1;
78 int flag_print_fields = 1;
79 int flag_print_methods = 1;
80 int flag_print_attributes = 1;
82 /* When nonzero, warn when source file is newer than matching class
83 file. */
84 int flag_newer = 1;
86 /* Print names of classes that have a "main" method. */
87 int flag_print_main = 0;
89 /* Index in constant pool of this class. */
90 int this_class_index = 0;
92 int class_access_flags = 0;
94 /* Print in format similar to javap. VERY IMCOMPLETE. */
95 int flag_javap_compatible = 0;
97 static void print_access_flags (FILE *, uint16, char);
98 static void print_constant_terse (FILE*, JCF*, int, int);
99 static void print_constant (FILE *, JCF *, int, int);
100 static void print_constant_ref (FILE *, JCF *, int);
101 static void disassemble_method (JCF*, const unsigned char *, int);
102 static void print_name (FILE*, JCF*, int);
103 static void print_signature (FILE*, JCF*, int, int);
104 static int utf8_equal_string (struct JCF*, int, const char *);
105 static void usage (void) ATTRIBUTE_NORETURN;
106 static void help (void) ATTRIBUTE_NORETURN;
107 static void version (void) ATTRIBUTE_NORETURN;
108 static void process_class (struct JCF *);
109 static void print_constant_pool (struct JCF *);
110 static void print_exception_table (struct JCF *, const unsigned char *entries,
111 int);
113 #define PRINT_SIGNATURE_RESULT_ONLY 1
114 #define PRINT_SIGNATURE_ARGS_ONLY 2
116 static int
117 utf8_equal_string (JCF *jcf, int index, const char * value)
119 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
120 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
122 int len = strlen (value);
123 if (JPOOL_UTF_LENGTH (jcf, index) == len
124 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
125 return 1;
127 return 0;
130 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
131 this_class_index = 0; \
132 if (flag_print_class_info) \
133 fprintf (out, \
134 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
135 (long) MAGIC, (long) MINOR, (long) MAJOR)
137 #define HANDLE_START_CONSTANT_POOL(COUNT) \
138 if (flag_print_constant_pool) \
139 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
141 #define HANDLE_SOURCEFILE(INDEX) \
142 { fprintf (out, "Attribute "); \
143 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
144 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
145 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
147 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
148 this_class_index = THIS; \
149 class_access_flags = ACCESS_FLAGS; \
150 if (flag_print_class_info) \
151 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
152 print_access_flags (out, ACCESS_FLAGS, 'c'); \
153 fputc ('\n', out); \
154 fprintf (out, "This class: "); \
155 if (flag_print_constant_pool) \
156 fprintf (out, "%d=", THIS); \
157 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
158 if (flag_print_constant_pool || SUPER != 0) \
159 fprintf (out, ", super: "); \
160 if (flag_print_constant_pool) \
162 fprintf (out, "%d", SUPER); \
163 if (SUPER != 0) \
164 fputc ('=', out); \
166 if (SUPER != 0) \
167 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
168 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
171 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
172 (flag_print_attributes <= 0)
174 #define HANDLE_CLASS_INTERFACE(INDEX) \
175 if (flag_print_class_info) \
176 { fprintf (out, "- Implements: %d=", INDEX); \
177 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
178 fputc ('\n', out); }
180 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
181 if (flag_print_fields) \
182 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
184 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
185 if (flag_print_fields) \
186 { fprintf (out, "Field name:"); \
187 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
188 print_access_flags (out, ACCESS_FLAGS, 'f'); \
189 fprintf (out, " Signature: "); \
190 if (flag_print_constant_pool) \
191 fprintf (out, "%d=", SIGNATURE); \
192 print_signature (out, jcf, SIGNATURE, 0); \
193 fputc ('\n', out); } \
194 else \
195 flag_print_attributes--;
197 #define HANDLE_END_FIELD() \
198 if (! flag_print_fields) \
199 flag_print_attributes++;
201 #define HANDLE_START_METHODS(METHODS_COUNT) \
202 if (flag_print_methods) \
203 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
204 else \
205 flag_print_attributes--;
208 #define HANDLE_END_METHODS() \
209 if (! flag_print_methods) \
210 flag_print_attributes++;
212 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
214 if (flag_print_methods) \
216 if (flag_javap_compatible) \
218 fprintf (out, " "); \
219 print_access_flags (out, ACCESS_FLAGS, 'm'); \
220 fputc (' ', out); \
221 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
222 fputc (' ', out); \
223 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
224 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
225 fputc ('\n', out); \
227 else \
229 fprintf (out, "\nMethod name:"); \
230 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
231 print_access_flags (out, ACCESS_FLAGS, 'm'); \
232 fprintf (out, " Signature: "); \
233 if (flag_print_constant_pool) \
234 fprintf (out, "%d=", SIGNATURE); \
235 print_signature (out, jcf, SIGNATURE, 0); \
236 fputc ('\n', out); \
239 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
240 && utf8_equal_string (jcf, NAME, "main") \
241 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
242 && this_class_index > 0 \
243 && (class_access_flags & ACC_PUBLIC)) \
245 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
246 fputc ('\n', out); \
250 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
251 ( fprintf (out, "Attribute "), \
252 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
253 fprintf (out, ", length:%ld", (long) LENGTH) )
255 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
256 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
257 fprintf (out, ", value: "), \
258 print_constant_ref (out, jcf, VALUE_INDEX), \
259 fprintf (out, "\n") )
261 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
262 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
263 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
264 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
265 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
267 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
268 print_exception_table (jcf, ENTRIES, COUNT)
270 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
271 { int n = (COUNT); int i; \
272 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
273 fprintf (out, ", count: %d\n", n); \
274 for (i = 0; i < n; i++) {\
275 int ex_index = JCF_readu2 (jcf); \
276 fprintf (out, "%3d: ", i); \
277 print_constant_ref (out, jcf, ex_index); \
278 fputc ('\n', out); } }
280 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
281 { int n = (COUNT); int i; \
282 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
283 fprintf (out, ", count: %d\n", n); \
284 for (i = 0; i < n; i++) {\
285 int start_pc = JCF_readu2 (jcf); \
286 int length = JCF_readu2 (jcf); \
287 int name_index = JCF_readu2 (jcf); \
288 int signature_index = JCF_readu2 (jcf); \
289 int slot = JCF_readu2 (jcf); \
290 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
291 print_name (out, jcf, name_index); \
292 fprintf (out, ", type: %d=", signature_index); \
293 print_signature (out, jcf, signature_index, 0); \
294 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
296 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
297 { int n = (COUNT); int i; \
298 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
299 fprintf (out, ", count: %d\n", n); \
300 if (flag_disassemble_methods) \
301 for (i = 0; i < n; i++) {\
302 int start_pc = JCF_readu2 (jcf); \
303 int line_number = JCF_readu2 (jcf); \
304 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
305 else \
306 JCF_SKIP (jcf, 4 * n); }
308 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
309 { int n = (COUNT); \
310 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
311 while (n--) \
313 uint16 inner_class_info_index = JCF_readu2 (jcf); \
314 uint16 outer_class_info_index = JCF_readu2 (jcf); \
315 uint16 inner_name_index = JCF_readu2 (jcf); \
316 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
318 if (flag_print_class_info) \
320 fprintf (out, "\n class: "); \
321 if (flag_print_constant_pool) \
322 fprintf (out, "%d=", inner_class_info_index); \
323 print_constant_terse (out, jcf, \
324 inner_class_info_index, CONSTANT_Class); \
325 fprintf (out, " (%d=", inner_name_index); \
326 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
327 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
328 print_access_flags (out, inner_class_access_flags, 'c'); \
329 fprintf (out, ", outer class: "); \
330 if (flag_print_constant_pool) \
331 fprintf (out, "%d=", outer_class_info_index); \
332 print_constant_terse (out, jcf, \
333 outer_class_info_index, CONSTANT_Class); \
336 if (flag_print_class_info) \
337 fputc ('\n', out); \
340 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
341 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
342 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
344 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
345 if (flag_print_attributes > 0) \
346 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
348 #include "javaop.h"
350 static void
351 print_constant_ref (FILE *stream, JCF *jcf, int index)
353 fprintf (stream, "#%d=<", index);
354 if (index <= 0 || index >= JPOOL_SIZE(jcf))
355 fprintf (stream, "out of range");
356 else
357 print_constant (stream, jcf, index, 1);
358 fprintf (stream, ">");
361 /* Print the access flags given by FLAGS.
362 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
363 or 'm' (method flags). */
365 static void
366 print_access_flags (FILE *stream, uint16 flags, char context)
368 if (flags & ACC_PUBLIC) fprintf (stream, " public");
369 if (flags & ACC_PRIVATE) fprintf (stream, " private");
370 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
371 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
372 if (flags & ACC_STATIC) fprintf (stream, " static");
373 if (flags & ACC_FINAL) fprintf (stream, " final");
374 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
375 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
376 if (flags & ACC_NATIVE) fprintf (stream, " native");
377 if (flags & ACC_SYNCHRONIZED)
379 if (context == 'c')
380 fprintf (stream, " super");
381 else
382 fprintf (stream, " synchronized");
384 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
385 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
389 static void
390 print_name (FILE* stream, JCF* jcf, int name_index)
392 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
393 fprintf (stream, "<not a UTF8 constant>");
394 else
395 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
396 JPOOL_UTF_LENGTH (jcf, name_index));
399 /* If the type of the constant at INDEX matches EXPECTED,
400 print it tersely, otherwise more verbosely. */
402 static void
403 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
405 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
406 fprintf (out, "<constant pool index %d not in range>", index);
407 else if (JPOOL_TAG (jcf, index) != expected)
409 fprintf (out, "<Unexpected constant type ");
410 print_constant (out, jcf, index, 1);
411 fprintf (out, ">");
413 else
414 print_constant (out, jcf, index, 0);
417 /* Print the constant at INDEX in JCF's constant pool.
418 If verbosity==0, print very tersely (no extraneous text).
419 If verbosity==1, prefix the type of the constant.
420 If verbosity==2, add more descriptive text. */
422 static void
423 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
425 int j, n;
426 jlong num;
427 const char *str;
428 int kind = JPOOL_TAG (jcf, index);
429 switch (kind)
431 case CONSTANT_Class:
432 n = JPOOL_USHORT1 (jcf, index);
433 if (verbosity > 0)
435 if (verbosity > 1)
436 fprintf (out, "Class name: %d=", n);
437 else
438 fprintf (out, "Class ");
440 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
441 fprintf (out, "<out of range>");
442 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
444 int len = JPOOL_UTF_LENGTH (jcf, n);
445 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
447 else
448 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
449 break;
450 case CONSTANT_Fieldref:
451 str = "Field"; goto field_or_method;
452 case CONSTANT_Methodref:
453 str = "Method"; goto field_or_method;
454 case CONSTANT_InterfaceMethodref:
455 str = "InterfaceMethod"; goto field_or_method;
456 field_or_method:
458 uint16 tclass = JPOOL_USHORT1 (jcf, index);
459 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
460 if (verbosity == 2)
461 fprintf (out, "%sref class: %d=", str, tclass);
462 else if (verbosity > 0)
463 fprintf (out, "%s ", str);
464 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
465 if (verbosity < 2)
466 fprintf (out, ".");
467 else
468 fprintf (out, " name_and_type: %d=<", name_and_type);
469 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
470 if (verbosity == 2)
471 fputc ('>', out);
473 break;
474 case CONSTANT_String:
475 j = JPOOL_USHORT1 (jcf, index);
476 if (verbosity > 0)
478 if (verbosity > 1)
479 fprintf (out, "String %d=", j);
480 else
481 fprintf (out, "String ");
483 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
484 break;
485 case CONSTANT_Integer:
486 if (verbosity > 0)
487 fprintf (out, "Integer ");
488 num = JPOOL_INT (jcf, index);
489 goto integer;
490 case CONSTANT_Long:
491 if (verbosity > 0)
492 fprintf (out, "Long ");
493 num = JPOOL_LONG (jcf, index);
494 goto integer;
495 integer:
497 char buffer[25];
498 format_int (buffer, num, 10);
499 fprintf (out, "%s", buffer);
500 if (verbosity > 1)
502 format_uint (buffer, (uint64)num, 16);
503 fprintf (out, "=0x%s", buffer);
506 break;
507 case CONSTANT_Float:
509 jfloat fnum = JPOOL_FLOAT (jcf, index);
511 if (verbosity > 0)
512 fputs ("Float ", out);
514 if (fnum.negative)
515 putc ('-', out);
517 if (JFLOAT_FINITE (fnum))
519 int dummy;
520 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
521 double f;
522 uint32 mantissa = fnum.mantissa;
523 if (fnum.exponent == 0)
524 /* Denormal. */
525 exponent++;
526 else
527 /* Normal; add the implicit bit. */
528 mantissa |= ((uint32)1 << 23);
530 f = frexp (mantissa, &dummy);
531 f = ldexp (f, exponent + 1);
532 fprintf (out, "%.10g", f);
534 else
536 if (fnum.mantissa == 0)
537 fputs ("Inf", out);
538 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
539 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
540 else
541 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
544 if (verbosity > 1)
545 fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
547 break;
549 case CONSTANT_Double:
551 jdouble dnum = JPOOL_DOUBLE (jcf, index);
553 if (verbosity > 0)
554 fputs ("Double ", out);
556 if (dnum.negative)
557 putc ('-', out);
559 if (JDOUBLE_FINITE (dnum))
561 int dummy;
562 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
563 double d;
564 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
565 + dnum.mantissa1);
566 if (dnum.exponent == 0)
567 /* Denormal. */
568 exponent++;
569 else
570 /* Normal; add the implicit bit. */
571 mantissa |= ((uint64)1 << 52);
573 d = frexp (mantissa, &dummy);
574 d = ldexp (d, exponent + 1);
575 fprintf (out, "%.20g", d);
577 else
579 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
580 mantissa = (mantissa << 32) + dnum.mantissa1;
582 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
583 fputs ("Inf", out);
584 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
585 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
586 else
587 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
589 if (verbosity > 1)
591 int32 hi, lo;
592 hi = JPOOL_UINT (jcf, index);
593 lo = JPOOL_UINT (jcf, index + 1);
594 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
596 break;
598 case CONSTANT_NameAndType:
600 uint16 name = JPOOL_USHORT1 (jcf, index);
601 uint16 sig = JPOOL_USHORT2 (jcf, index);
602 if (verbosity > 0)
604 if (verbosity > 1)
605 fprintf (out, "NameAndType name: %d=", name);
606 else
607 fprintf (out, "NameAndType ");
609 print_name (out, jcf, name);
610 if (verbosity <= 1)
611 fputc (' ', out);
612 else
613 fprintf (out, ", signature: %d=", sig);
614 print_signature (out, jcf, sig, 0);
616 break;
617 case CONSTANT_Utf8:
619 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
620 int length = JPOOL_UTF_LENGTH (jcf, index);
621 if (verbosity > 0)
622 { /* Print as 8-bit bytes. */
623 fputs ("Utf8: \"", out);
624 while (--length >= 0)
625 jcf_print_char (out, *str++);
627 else
628 { /* Print as Unicode. */
629 fputc ('\"', out);
630 jcf_print_utf8 (out, str, length);
632 fputc ('\"', out);
634 break;
635 default:
636 fprintf (out, "(Unknown constant type %d)", kind);
640 static void
641 print_constant_pool (JCF *jcf)
643 int i;
644 for (i = 1; i < JPOOL_SIZE(jcf); i++)
646 int kind = JPOOL_TAG (jcf, i);
647 fprintf (out, "#%d: ", i);
648 print_constant (out, jcf, i, 2);
649 fprintf (out, "\n");
650 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
651 i++; /* These take up two slots in the constant table */
655 static void
656 print_signature_type (FILE* stream, const unsigned char **ptr,
657 const unsigned char *limit)
659 int array_size;
660 if ((*ptr) >= limit)
661 return;
662 switch (*(*ptr))
664 case '[':
665 array_size = -1;
666 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
668 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
670 print_signature_type (stream, ptr, limit);
671 if (array_size == -1)
672 fprintf (stream, "[]");
673 else
674 fprintf (stream, "[%d]", array_size);
675 break;
676 case '(':
678 int nargs = 0;
679 fputc (*(*ptr)++, stream);
680 for (; **ptr != ')' && *ptr < limit; nargs++)
682 if (nargs > 0)
683 fputc (',', stream);
684 print_signature_type (stream, ptr, limit);
686 if (*ptr < limit)
688 fputc (*(*ptr)++, stream);
689 print_signature_type (stream, ptr, limit);
691 else
692 fprintf (stream, "???");
694 break;
696 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
697 case 'C': fprintf (stream, "char"); (*ptr)++; break;
698 case 'D': fprintf (stream, "double"); (*ptr)++; break;
699 case 'F': fprintf (stream, "float"); (*ptr)++; break;
700 case 'S': fprintf (stream, "short"); (*ptr)++; break;
701 case 'I': fprintf (stream, "int"); (*ptr)++; break;
702 case 'J': fprintf (stream, "long"); (*ptr)++; break;
703 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
704 case 'V': fprintf (stream, "void"); (*ptr)++; break;
706 case 'L':
707 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
708 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
709 if (*(*ptr) == ';')
710 (*ptr)++;
711 break;
712 default:
713 jcf_print_char (stream, *(*ptr)++);
717 static void
718 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
720 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
721 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
722 else
724 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
725 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
726 const unsigned char *limit;
727 limit = str + length;
728 if (str >= limit)
729 fprintf (stream, "<empty signature string>");
730 else
732 if (options & PRINT_SIGNATURE_RESULT_ONLY)
734 while (str < limit && *str++ != ')') ;
736 if (options & PRINT_SIGNATURE_ARGS_ONLY)
738 str++;
739 fputc ('(', stream);
740 while (str < limit && *str != ')')
742 print_signature_type (stream, &str, limit);
743 if (*str != ')')
744 fputs (", ", stream);
746 fputc (')', stream);
748 else
750 print_signature_type (stream, &str, limit);
751 if (str < limit)
753 fprintf (stream, "<junk:");
754 jcf_print_utf8 (stream, str, limit - str);
755 fputc ('>', stream);
763 static void
764 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
766 /* Print exception table. */
767 int i = count;
768 if (i > 0)
770 const unsigned char *ptr = entries;
771 fprintf (out, "Exceptions (count: %d):\n", i);
772 for (; --i >= 0; ptr+= 8)
774 int start_pc = GET_u2 (ptr);
775 int end_pc = GET_u2 (ptr+2);
776 int handler_pc = GET_u2 (ptr+4);
777 int catch_type = GET_u2 (ptr+6);
778 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
779 start_pc, end_pc, handler_pc, catch_type);
780 if (catch_type == 0)
781 fputs (" /* finally */", out);
782 else
784 fputc('=', out);
785 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
787 fputc ('\n', out);
792 #include "jcf-reader.c"
794 static void
795 process_class (JCF *jcf)
797 int code;
798 if (jcf_parse_preamble (jcf) != 0)
799 fprintf (stderr, _("Not a valid Java .class file.\n"));
801 /* Parse and possibly print constant pool */
802 code = jcf_parse_constant_pool (jcf);
803 if (code != 0)
805 fprintf (stderr, _("error while parsing constant pool\n"));
806 exit (FATAL_EXIT_CODE);
808 code = verify_constant_pool (jcf);
809 if (code > 0)
811 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
812 exit (FATAL_EXIT_CODE);
814 if (flag_print_constant_pool)
815 print_constant_pool (jcf);
817 jcf_parse_class (jcf);
818 code = jcf_parse_fields (jcf);
819 if (code != 0)
821 fprintf (stderr, _("error while parsing fields\n"));
822 exit (FATAL_EXIT_CODE);
824 code = jcf_parse_methods (jcf);
825 if (code != 0)
827 fprintf (stderr, _("error while parsing methods\n"));
828 exit (FATAL_EXIT_CODE);
830 code = jcf_parse_final_attributes (jcf);
831 if (code != 0)
833 fprintf (stderr, _("error while parsing final attributes\n"));
834 exit (FATAL_EXIT_CODE);
836 jcf->filename = NULL;
841 /* This is used to mark options with no short value. */
842 #define LONG_OPT(Num) ((Num) + 128)
844 #define OPT_classpath LONG_OPT (0)
845 #define OPT_CLASSPATH OPT_classpath
846 #define OPT_bootclasspath LONG_OPT (1)
847 #define OPT_extdirs LONG_OPT (2)
848 #define OPT_HELP LONG_OPT (3)
849 #define OPT_VERSION LONG_OPT (4)
850 #define OPT_JAVAP LONG_OPT (5)
852 static const struct option options[] =
854 { "classpath", required_argument, NULL, OPT_classpath },
855 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
856 { "extdirs", required_argument, NULL, OPT_extdirs },
857 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
858 { "help", no_argument, NULL, OPT_HELP },
859 { "verbose", no_argument, NULL, 'v' },
860 { "version", no_argument, NULL, OPT_VERSION },
861 { "javap", no_argument, NULL, OPT_JAVAP },
862 { "print-main", no_argument, &flag_print_main, 1 },
863 { NULL, no_argument, NULL, 0 }
866 static void
867 usage (void)
869 fprintf (stderr, _("Try `jcf-dump --help' for more information.\n"));
870 exit (1);
873 static void
874 help (void)
876 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
877 printf (_("Display contents of a class file in readable form.\n\n"));
878 printf (_(" -c Disassemble method bodies\n"));
879 printf (_(" --javap Generate output in `javap' format\n"));
880 printf ("\n");
881 printf (_(" --classpath PATH Set path to find .class files\n"));
882 printf (_(" -IDIR Append directory to class path\n"));
883 printf (_(" --bootclasspath PATH Override built-in class path\n"));
884 printf (_(" --extdirs PATH Set extensions directory path\n"));
885 printf (_(" -o FILE Set output file name\n"));
886 printf ("\n");
887 printf (_(" --help Print this help, then exit\n"));
888 printf (_(" --version Print version number, then exit\n"));
889 printf (_(" -v, --verbose Print extra information while running\n"));
890 printf ("\n");
891 printf (_("For bug reporting instructions, please see:\n"
892 "%s.\n"), bug_report_url);
893 exit (0);
896 static void
897 version (void)
899 printf ("jcf-dump (GCC) %s\n\n", version_string);
900 printf ("Copyright %s 2004 Free Software Foundation, Inc.\n", _("(C)"));
901 printf (_("This is free software; see the source for copying conditions. There is NO\n"
902 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
903 exit (0);
907 main (int argc, char** argv)
909 JCF jcf[1];
910 int argi, opt;
912 gcc_init_libintl ();
914 if (argc <= 1)
916 fprintf (stderr, _("jcf-dump: no classes specified\n"));
917 usage ();
920 jcf_path_init ();
922 /* We use getopt_long_only to allow single `-' long options. For
923 some of our options this is more natural. */
924 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
926 switch (opt)
928 case 0:
929 /* Already handled. */
930 break;
932 case 'o':
933 output_file = optarg;
934 break;
936 case 'I':
937 jcf_path_include_arg (optarg);
938 break;
940 case 'v':
941 verbose++;
942 break;
944 case 'c':
945 flag_disassemble_methods = 1;
946 break;
948 case OPT_classpath:
949 jcf_path_classpath_arg (optarg);
950 break;
952 case OPT_bootclasspath:
953 jcf_path_bootclasspath_arg (optarg);
954 break;
956 case OPT_extdirs:
957 jcf_path_extdirs_arg (optarg);
958 break;
960 case OPT_HELP:
961 help ();
962 break;
964 case OPT_VERSION:
965 version ();
966 break;
968 case OPT_JAVAP:
969 flag_javap_compatible++;
970 flag_print_constant_pool = 0;
971 flag_print_attributes = 0;
972 break;
974 default:
975 usage ();
979 if (optind == argc)
981 fprintf (stderr, _("jcf-dump: no classes specified\n"));
982 usage ();
985 jcf_path_seal (verbose);
987 if (flag_print_main)
989 flag_print_fields = 0;
990 flag_print_methods = 0;
991 flag_print_constant_pool = 0;
992 flag_print_attributes = 0;
993 flag_print_class_info = 0;
996 if (output_file)
998 out = fopen (output_file, "w");
999 if (! out)
1001 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1002 return FATAL_EXIT_CODE;
1005 else
1006 out = stdout;
1008 if (optind >= argc)
1010 fprintf (out, "Reading .class from <standard input>.\n");
1011 open_class ("<stdio>", jcf, 0, NULL);
1012 process_class (jcf);
1014 else
1016 for (argi = optind; argi < argc; argi++)
1018 char *arg = argv[argi];
1019 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1020 if (class_filename == NULL)
1021 class_filename = find_classfile (arg, jcf, NULL);
1022 if (class_filename == NULL)
1024 perror ("Could not find class");
1025 return FATAL_EXIT_CODE;
1027 JCF_FILL (jcf, 4);
1028 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1030 long compressed_size, member_size;
1031 int compression_method, filename_length, extra_length;
1032 int general_purpose_bits;
1033 const char *filename;
1034 int total_length;
1035 if (flag_print_class_info)
1036 fprintf (out, "Reading classes from archive %s.\n",
1037 class_filename);
1038 for (;;)
1040 int skip = 0;
1041 jcf_filbuf_t save_filbuf = jcf->filbuf;
1042 long magic = JCF_readu4_le (jcf);
1043 if (magic == 0x02014b50 || magic == 0x06054b50)
1044 break; /* got to central directory */
1045 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1047 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1048 return FATAL_EXIT_CODE;
1050 JCF_FILL (jcf, 26);
1051 JCF_SKIP (jcf, 2);
1052 general_purpose_bits = JCF_readu2_le (jcf);
1053 compression_method = JCF_readu2_le (jcf);
1054 JCF_SKIP (jcf, 8);
1055 compressed_size = JCF_readu4_le (jcf);
1056 member_size = JCF_readu4_le (jcf);
1057 filename_length = JCF_readu2_le (jcf);
1058 extra_length = JCF_readu2_le (jcf);
1059 total_length = filename_length + extra_length
1060 + compressed_size;
1061 if (jcf->read_end - jcf->read_ptr < total_length)
1062 jcf_trim_old_input (jcf);
1063 JCF_FILL (jcf, total_length);
1064 filename = jcf->read_ptr;
1065 JCF_SKIP (jcf, filename_length);
1066 JCF_SKIP (jcf, extra_length);
1067 if (filename_length > 0
1068 && filename[filename_length-1] == '/')
1070 if (flag_print_class_info)
1071 fprintf (out, "[Skipping directory %.*s]\n",
1072 filename_length, filename);
1073 skip = 1;
1075 else if (compression_method != 0)
1077 if (flag_print_class_info)
1078 fprintf (out, "[Skipping compressed file %.*s]\n",
1079 filename_length, filename);
1080 skip = 1;
1082 else if (member_size < 4
1083 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1085 if (flag_print_class_info)
1086 fprintf (out, "[Skipping non-.class member %.*s]\n",
1087 filename_length, filename);
1088 skip = 1;
1090 else
1092 if (flag_print_class_info)
1093 fprintf (out, "Reading class member: %.*s.\n",
1094 filename_length, filename);
1096 if (skip)
1098 JCF_SKIP (jcf, compressed_size);
1100 else
1102 unsigned char *save_end;
1103 jcf->filbuf = jcf_unexpected_eof;
1104 save_end = jcf->read_end;
1105 jcf->read_end = jcf->read_ptr + compressed_size;
1106 process_class (jcf);
1107 jcf->filbuf = save_filbuf;
1108 jcf->read_end = save_end;
1112 else
1114 if (flag_print_class_info)
1115 fprintf (out, "Reading .class from %s.\n", class_filename);
1116 process_class (jcf);
1118 JCF_FINISH(jcf);
1122 return SUCCESS_EXIT_CODE;
1127 static void
1128 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1130 #undef PTR
1131 int PC;
1132 int i;
1133 int saw_wide = 0;
1134 if (flag_disassemble_methods == 0)
1135 return;
1136 #define BCODE byte_ops
1137 for (PC = 0; PC < len;)
1139 int oldpc = PC;
1140 int saw_index;
1141 jint INT_temp;
1142 switch (byte_ops[PC++])
1145 /* This is the actual code emitted for each of opcodes in javaops.def.
1146 The actual opcode-specific stuff is handled by the OPKIND macro.
1147 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1148 Those macros are defined below. The OPKINDs that do not have any
1149 inline parameters (such as BINOP) and therefore do mot need anything
1150 else to me printed out just use an empty body. */
1152 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1153 case OPCODE: \
1154 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1155 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1156 fputc ('\n', out); \
1157 break;
1159 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1160 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1161 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1162 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1164 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1165 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1)) : 1)
1167 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1168 These all push a constant onto the opcode stack. */
1169 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1170 saw_index = 0, i = (OPERAND_VALUE); \
1171 if (oldpc+1 == PC) /* nothing */; \
1172 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1173 else fprintf (out, " %d", i);
1175 /* Print out operand (a local variable index) for LOAD opcodes.
1176 These all push local variable onto the opcode stack. */
1177 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1178 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1180 /* Handle STORE opcodes same as LOAD opcodes.
1181 These all store a value from the opcode stack in a local variable. */
1182 #define STORE LOAD
1184 /* Handle more kind of opcodes. */
1185 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1186 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1187 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1188 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1189 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1190 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1191 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1193 /* Handle putfield and getfield opcodes, with static versions. */
1194 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1195 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1197 /* Print operand for invoke opcodes. */
1198 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1199 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1200 if (OPERAND_VALUE) /* for invokeinterface */ \
1201 { int nargs = IMMEDIATE_u1; PC++; \
1202 fprintf (out, " nargs:%d", nargs); }
1204 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1205 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1207 #define ARRAY(OPERAND_TYPE, SUBOP) \
1208 ARRAY_##SUBOP(OPERAND_TYPE)
1209 /* Handle sub-categories of ARRAY opcodes. */
1210 #define ARRAY_LOAD(TYPE) /* nothing */
1211 #define ARRAY_STORE(TYPE) /* nothing */
1212 #define ARRAY_LENGTH(TYPE) /* nothing */
1213 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1214 #define ARRAY_NEW_NUM \
1215 INT_temp = IMMEDIATE_u1; \
1216 { switch ((int) INT_temp) { \
1217 case 4: fputs (" boolean", out); break; \
1218 case 5: fputs (" char", out); break; \
1219 case 6: fputs (" float", out); break; \
1220 case 7: fputs (" double", out); break; \
1221 case 8: fputs (" byte", out); break; \
1222 case 9: fputs (" short", out); break; \
1223 case 10: fputs (" int", out); break; \
1224 case 11: fputs (" long", out); break; \
1225 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1228 #define ARRAY_NEW_PTR \
1229 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1231 #define ARRAY_NEW_MULTI \
1232 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1233 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1235 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1236 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1238 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1239 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1240 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1242 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1243 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1244 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1246 #undef RET /* Defined by config/i386/i386.h */
1247 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1248 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1249 saw_wide = 0; \
1250 fprintf (out, " %ld", (long) INT_temp);
1252 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1253 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1255 #define LOOKUP_SWITCH \
1256 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1257 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1258 while (--npairs >= 0) { \
1259 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1260 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1263 #define TABLE_SWITCH \
1264 { jint default_offset = IMMEDIATE_s4; \
1265 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1266 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1267 (long) low, (long) high, (long) default_offset+oldpc); \
1268 for (; low <= high; low++) { \
1269 jint offset = IMMEDIATE_s4; \
1270 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1273 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1274 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1276 #define SPECIAL_IINC(OPERAND_TYPE) \
1277 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1278 fprintf (out, " %d", i); \
1279 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1280 saw_wide = 0; \
1281 fprintf (out, " %d", i)
1283 #define SPECIAL_WIDE(OPERAND_TYPE) \
1284 saw_wide = 1;
1286 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1287 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1288 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1289 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1291 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1292 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1294 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1295 TEST(OPERAND_TYPE, OPERAND_VALUE)
1297 #include "javaop.def"
1299 load_store:
1300 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1301 else
1303 saw_wide = 0;
1304 fprintf (out, " %ld", (long) INT_temp);
1306 fputc ('\n', out);
1307 break;
1309 default:
1310 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);