FSF GCC merge 02/23/03
[official-gcc.git] / gcc / java / jcf-dump.c
blob6d976e53450ec43e7806201801f8a6c24d96f141
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>
66 /* Outout file. */
67 FILE *out;
68 /* Name of output file, if NULL if stdout. */
69 char *output_file = NULL;
71 int verbose = 0;
73 int flag_disassemble_methods = 0;
74 int flag_print_class_info = 1;
75 int flag_print_constant_pool = 1;
76 int flag_print_fields = 1;
77 int flag_print_methods = 1;
78 int flag_print_attributes = 1;
80 /* When nonzero, warn when source file is newer than matching class
81 file. */
82 int flag_newer = 1;
84 /* Print names of classes that have a "main" method. */
85 int flag_print_main = 0;
87 /* Index in constant pool of this class. */
88 int this_class_index = 0;
90 int class_access_flags = 0;
92 /* Print in format similar to javap. VERY IMCOMPLETE. */
93 int flag_javap_compatible = 0;
95 static void print_access_flags (FILE *, uint16, char);
96 static void print_constant_terse (FILE*, JCF*, int, int);
97 static void print_constant (FILE *, JCF *, int, int);
98 static void print_constant_ref (FILE *, JCF *, int);
99 static void disassemble_method (JCF*, const unsigned char *, int);
100 static void print_name (FILE*, JCF*, int);
101 static void print_signature (FILE*, JCF*, int, int);
102 static int utf8_equal_string (struct JCF*, int, const char *);
103 static void usage (void) ATTRIBUTE_NORETURN;
104 static void help (void) ATTRIBUTE_NORETURN;
105 static void version (void) ATTRIBUTE_NORETURN;
106 static void process_class (struct JCF *);
107 static void print_constant_pool (struct JCF *);
108 static void print_exception_table (struct JCF *, const unsigned char *entries,
109 int);
111 #define PRINT_SIGNATURE_RESULT_ONLY 1
112 #define PRINT_SIGNATURE_ARGS_ONLY 2
114 static int
115 utf8_equal_string (JCF *jcf, int index, const char * value)
117 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
118 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
120 int len = strlen (value);
121 if (JPOOL_UTF_LENGTH (jcf, index) == len
122 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
123 return 1;
125 return 0;
128 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
129 this_class_index = 0; \
130 if (flag_print_class_info) \
131 fprintf (out, \
132 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
133 (long) MAGIC, (long) MINOR, (long) MAJOR)
135 #define HANDLE_START_CONSTANT_POOL(COUNT) \
136 if (flag_print_constant_pool) \
137 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
139 #define HANDLE_SOURCEFILE(INDEX) \
140 { fprintf (out, "Attribute "); \
141 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
142 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
143 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
145 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
146 this_class_index = THIS; \
147 class_access_flags = ACCESS_FLAGS; \
148 if (flag_print_class_info) \
149 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
150 print_access_flags (out, ACCESS_FLAGS, 'c'); \
151 fputc ('\n', out); \
152 fprintf (out, "This class: "); \
153 if (flag_print_constant_pool) \
154 fprintf (out, "%d=", THIS); \
155 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
156 if (flag_print_constant_pool || SUPER != 0) \
157 fprintf (out, ", super: "); \
158 if (flag_print_constant_pool) \
160 fprintf (out, "%d", SUPER); \
161 if (SUPER != 0) \
162 fputc ('=', out); \
164 if (SUPER != 0) \
165 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
166 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
169 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
170 (flag_print_attributes <= 0)
172 #define HANDLE_CLASS_INTERFACE(INDEX) \
173 if (flag_print_class_info) \
174 { fprintf (out, "- Implements: %d=", INDEX); \
175 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
176 fputc ('\n', out); }
178 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
179 if (flag_print_fields) \
180 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
182 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
183 if (flag_print_fields) \
184 { fprintf (out, "Field name:"); \
185 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
186 print_access_flags (out, ACCESS_FLAGS, 'f'); \
187 fprintf (out, " Signature: "); \
188 if (flag_print_constant_pool) \
189 fprintf (out, "%d=", SIGNATURE); \
190 print_signature (out, jcf, SIGNATURE, 0); \
191 fputc ('\n', out); } \
192 else \
193 flag_print_attributes--;
195 #define HANDLE_END_FIELD() \
196 if (! flag_print_fields) \
197 flag_print_attributes++;
199 #define HANDLE_START_METHODS(METHODS_COUNT) \
200 if (flag_print_methods) \
201 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
202 else \
203 flag_print_attributes--;
206 #define HANDLE_END_METHODS() \
207 if (! flag_print_methods) \
208 flag_print_attributes++;
210 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
212 if (flag_print_methods) \
214 if (flag_javap_compatible) \
216 fprintf (out, " "); \
217 print_access_flags (out, ACCESS_FLAGS, 'm'); \
218 fputc (' ', out); \
219 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
220 fputc (' ', out); \
221 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
222 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
223 fputc ('\n', out); \
225 else \
227 fprintf (out, "\nMethod name:"); \
228 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
229 print_access_flags (out, ACCESS_FLAGS, 'm'); \
230 fprintf (out, " Signature: "); \
231 if (flag_print_constant_pool) \
232 fprintf (out, "%d=", SIGNATURE); \
233 print_signature (out, jcf, SIGNATURE, 0); \
234 fputc ('\n', out); \
237 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
238 && utf8_equal_string (jcf, NAME, "main") \
239 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
240 && this_class_index > 0 \
241 && (class_access_flags & ACC_PUBLIC)) \
243 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
244 fputc ('\n', out); \
248 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
249 ( fprintf (out, "Attribute "), \
250 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
251 fprintf (out, ", length:%ld", (long) LENGTH) )
253 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
254 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
255 fprintf (out, ", value: "), \
256 print_constant_ref (out, jcf, VALUE_INDEX), \
257 fprintf (out, "\n") )
259 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
260 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
261 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
262 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
263 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
265 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
266 print_exception_table (jcf, ENTRIES, COUNT)
268 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
269 { int n = (COUNT); int i; \
270 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
271 fprintf (out, ", count: %d\n", n); \
272 for (i = 0; i < n; i++) {\
273 int ex_index = JCF_readu2 (jcf); \
274 fprintf (out, "%3d: ", i); \
275 print_constant_ref (out, jcf, ex_index); \
276 fputc ('\n', out); } }
278 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
279 { int n = (COUNT); int i; \
280 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
281 fprintf (out, ", count: %d\n", n); \
282 for (i = 0; i < n; i++) {\
283 int start_pc = JCF_readu2 (jcf); \
284 int length = JCF_readu2 (jcf); \
285 int name_index = JCF_readu2 (jcf); \
286 int signature_index = JCF_readu2 (jcf); \
287 int slot = JCF_readu2 (jcf); \
288 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
289 print_name (out, jcf, name_index); \
290 fprintf (out, ", type: %d=", signature_index); \
291 print_signature (out, jcf, signature_index, 0); \
292 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
294 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
295 { int n = (COUNT); int i; \
296 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
297 fprintf (out, ", count: %d\n", n); \
298 if (flag_disassemble_methods) \
299 for (i = 0; i < n; i++) {\
300 int start_pc = JCF_readu2 (jcf); \
301 int line_number = JCF_readu2 (jcf); \
302 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
303 else \
304 JCF_SKIP (jcf, 4 * n); }
306 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
307 { int n = (COUNT); \
308 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
309 while (n--) \
311 uint16 inner_class_info_index = JCF_readu2 (jcf); \
312 uint16 outer_class_info_index = JCF_readu2 (jcf); \
313 uint16 inner_name_index = JCF_readu2 (jcf); \
314 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
316 if (flag_print_class_info) \
318 fprintf (out, "\n class: "); \
319 if (flag_print_constant_pool) \
320 fprintf (out, "%d=", inner_class_info_index); \
321 print_constant_terse (out, jcf, \
322 inner_class_info_index, CONSTANT_Class); \
323 fprintf (out, " (%d=", inner_name_index); \
324 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
325 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
326 print_access_flags (out, inner_class_access_flags, 'c'); \
327 fprintf (out, ", outer class: "); \
328 if (flag_print_constant_pool) \
329 fprintf (out, "%d=", outer_class_info_index); \
330 print_constant_terse (out, jcf, \
331 outer_class_info_index, CONSTANT_Class); \
334 if (flag_print_class_info) \
335 fputc ('\n', out); \
338 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
339 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
340 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
342 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
343 if (flag_print_attributes > 0) \
344 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
346 #include "javaop.h"
348 static void
349 print_constant_ref (FILE *stream, JCF *jcf, int index)
351 fprintf (stream, "#%d=<", index);
352 if (index <= 0 || index >= JPOOL_SIZE(jcf))
353 fprintf (stream, "out of range");
354 else
355 print_constant (stream, jcf, index, 1);
356 fprintf (stream, ">");
359 /* Print the access flags given by FLAGS.
360 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
361 or 'm' (method flags). */
363 static void
364 print_access_flags (FILE *stream, uint16 flags, char context)
366 if (flags & ACC_PUBLIC) fprintf (stream, " public");
367 if (flags & ACC_PRIVATE) fprintf (stream, " private");
368 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
369 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
370 if (flags & ACC_STATIC) fprintf (stream, " static");
371 if (flags & ACC_FINAL) fprintf (stream, " final");
372 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
373 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
374 if (flags & ACC_NATIVE) fprintf (stream, " native");
375 if (flags & ACC_SYNCHRONIZED)
377 if (context == 'c')
378 fprintf (stream, " super");
379 else
380 fprintf (stream, " synchronized");
382 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
383 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
387 static void
388 print_name (FILE* stream, JCF* jcf, int name_index)
390 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
391 fprintf (stream, "<not a UTF8 constant>");
392 else
393 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
394 JPOOL_UTF_LENGTH (jcf, name_index));
397 /* If the type of the constant at INDEX matches EXPECTED,
398 print it tersely, otherwise more verbosely. */
400 static void
401 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
403 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
404 fprintf (out, "<constant pool index %d not in range>", index);
405 else if (JPOOL_TAG (jcf, index) != expected)
407 fprintf (out, "<Unexpected constant type ");
408 print_constant (out, jcf, index, 1);
409 fprintf (out, ">");
411 else
412 print_constant (out, jcf, index, 0);
415 /* Print the constant at INDEX in JCF's constant pool.
416 If verbosity==0, print very tersely (no extraneous text).
417 If verbosity==1, prefix the type of the constant.
418 If verbosity==2, add more descriptive text. */
420 static void
421 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
423 int j, n;
424 jlong num;
425 const char *str;
426 int kind = JPOOL_TAG (jcf, index);
427 switch (kind)
429 case CONSTANT_Class:
430 n = JPOOL_USHORT1 (jcf, index);
431 if (verbosity > 0)
433 if (verbosity > 1)
434 fprintf (out, "Class name: %d=", n);
435 else
436 fprintf (out, "Class ");
438 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
439 fprintf (out, "<out of range>");
440 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
442 int len = JPOOL_UTF_LENGTH (jcf, n);
443 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
445 else
446 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
447 break;
448 case CONSTANT_Fieldref:
449 str = "Field"; goto field_or_method;
450 case CONSTANT_Methodref:
451 str = "Method"; goto field_or_method;
452 case CONSTANT_InterfaceMethodref:
453 str = "InterfaceMethod"; goto field_or_method;
454 field_or_method:
456 uint16 tclass = JPOOL_USHORT1 (jcf, index);
457 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
458 if (verbosity == 2)
459 fprintf (out, "%sref class: %d=", str, tclass);
460 else if (verbosity > 0)
461 fprintf (out, "%s ", str);
462 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
463 if (verbosity < 2)
464 fprintf (out, ".");
465 else
466 fprintf (out, " name_and_type: %d=<", name_and_type);
467 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
468 if (verbosity == 2)
469 fputc ('>', out);
471 break;
472 case CONSTANT_String:
473 j = JPOOL_USHORT1 (jcf, index);
474 if (verbosity > 0)
476 if (verbosity > 1)
477 fprintf (out, "String %d=", j);
478 else
479 fprintf (out, "String ");
481 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
482 break;
483 case CONSTANT_Integer:
484 if (verbosity > 0)
485 fprintf (out, "Integer ");
486 num = JPOOL_INT (jcf, index);
487 goto integer;
488 case CONSTANT_Long:
489 if (verbosity > 0)
490 fprintf (out, "Long ");
491 num = JPOOL_LONG (jcf, index);
492 goto integer;
493 integer:
495 char buffer[25];
496 format_int (buffer, num, 10);
497 fprintf (out, "%s", buffer);
498 if (verbosity > 1)
500 format_uint (buffer, (uint64)num, 16);
501 fprintf (out, "=0x%s", buffer);
504 break;
505 case CONSTANT_Float:
507 union
509 jfloat f;
510 int32 i;
511 } pun;
513 pun.f = JPOOL_FLOAT (jcf, index);
514 fprintf (out, "%s%.10g",
515 verbosity > 0 ? "Float " : "", (double) pun.f);
516 if (verbosity > 1)
517 fprintf (out, ", bits = 0x%08lx", (long) pun.i);
519 break;
521 case CONSTANT_Double:
523 jdouble dnum = JPOOL_DOUBLE (jcf, index);
524 fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
525 if (verbosity > 1)
527 int32 hi, lo;
528 hi = JPOOL_UINT (jcf, index);
529 lo = JPOOL_UINT (jcf, index + 1);
530 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
532 break;
534 case CONSTANT_NameAndType:
536 uint16 name = JPOOL_USHORT1 (jcf, index);
537 uint16 sig = JPOOL_USHORT2 (jcf, index);
538 if (verbosity > 0)
540 if (verbosity > 1)
541 fprintf (out, "NameAndType name: %d=", name);
542 else
543 fprintf (out, "NameAndType ");
545 print_name (out, jcf, name);
546 if (verbosity <= 1)
547 fputc (' ', out);
548 else
549 fprintf (out, ", signature: %d=", sig);
550 print_signature (out, jcf, sig, 0);
552 break;
553 case CONSTANT_Utf8:
555 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
556 int length = JPOOL_UTF_LENGTH (jcf, index);
557 if (verbosity > 0)
558 { /* Print as 8-bit bytes. */
559 fputs ("Utf8: \"", out);
560 while (--length >= 0)
561 jcf_print_char (out, *str++);
563 else
564 { /* Print as Unicode. */
565 fputc ('\"', out);
566 jcf_print_utf8 (out, str, length);
568 fputc ('\"', out);
570 break;
571 default:
572 fprintf (out, "(Unknown constant type %d)", kind);
576 static void
577 print_constant_pool (JCF *jcf)
579 int i;
580 for (i = 1; i < JPOOL_SIZE(jcf); i++)
582 int kind = JPOOL_TAG (jcf, i);
583 fprintf (out, "#%d: ", i);
584 print_constant (out, jcf, i, 2);
585 fprintf (out, "\n");
586 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
587 i++; /* These take up two slots in the constant table */
591 static void
592 print_signature_type (FILE* stream, const unsigned char **ptr,
593 const unsigned char *limit)
595 int array_size;
596 if ((*ptr) >= limit)
597 return;
598 switch (*(*ptr))
600 case '[':
601 array_size = -1;
602 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
604 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
606 print_signature_type (stream, ptr, limit);
607 if (array_size == -1)
608 fprintf (stream, "[]");
609 else
610 fprintf (stream, "[%d]", array_size);
611 break;
612 case '(':
614 int nargs = 0;
615 fputc (*(*ptr)++, stream);
616 for (; **ptr != ')' && *ptr < limit; nargs++)
618 if (nargs > 0)
619 fputc (',', stream);
620 print_signature_type (stream, ptr, limit);
622 if (*ptr < limit)
624 fputc (*(*ptr)++, stream);
625 print_signature_type (stream, ptr, limit);
627 else
628 fprintf (stream, "???");
630 break;
632 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
633 case 'C': fprintf (stream, "char"); (*ptr)++; break;
634 case 'D': fprintf (stream, "double"); (*ptr)++; break;
635 case 'F': fprintf (stream, "float"); (*ptr)++; break;
636 case 'S': fprintf (stream, "short"); (*ptr)++; break;
637 case 'I': fprintf (stream, "int"); (*ptr)++; break;
638 case 'J': fprintf (stream, "long"); (*ptr)++; break;
639 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
640 case 'V': fprintf (stream, "void"); (*ptr)++; break;
642 case 'L':
643 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
644 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
645 if (*(*ptr) == ';')
646 (*ptr)++;
647 break;
648 default:
649 jcf_print_char (stream, *(*ptr)++);
653 static void
654 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
656 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
657 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
658 else
660 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
661 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
662 const unsigned char *limit;
663 limit = str + length;
664 if (str >= limit)
665 fprintf (stream, "<empty signature string>");
666 else
668 if (options & PRINT_SIGNATURE_RESULT_ONLY)
670 while (str < limit && *str++ != ')') ;
672 if (options & PRINT_SIGNATURE_ARGS_ONLY)
674 str++;
675 fputc ('(', stream);
676 while (str < limit && *str != ')')
678 print_signature_type (stream, &str, limit);
679 if (*str != ')')
680 fputs (", ", stream);
682 fputc (')', stream);
684 else
686 print_signature_type (stream, &str, limit);
687 if (str < limit)
689 fprintf (stream, "<junk:");
690 jcf_print_utf8 (stream, str, limit - str);
691 fputc ('>', stream);
699 static void
700 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
702 /* Print exception table. */
703 int i = count;
704 if (i > 0)
706 const unsigned char *ptr = entries;
707 fprintf (out, "Exceptions (count: %d):\n", i);
708 for (; --i >= 0; ptr+= 8)
710 int start_pc = GET_u2 (ptr);
711 int end_pc = GET_u2 (ptr+2);
712 int handler_pc = GET_u2 (ptr+4);
713 int catch_type = GET_u2 (ptr+6);
714 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
715 start_pc, end_pc, handler_pc, catch_type);
716 if (catch_type == 0)
717 fputs (" /* finally */", out);
718 else
720 fputc('=', out);
721 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
723 fputc ('\n', out);
728 #include "jcf-reader.c"
730 static void
731 process_class (JCF *jcf)
733 int code;
734 if (jcf_parse_preamble (jcf) != 0)
735 fprintf (stderr, "Not a valid Java .class file.\n");
737 /* Parse and possibly print constant pool */
738 code = jcf_parse_constant_pool (jcf);
739 if (code != 0)
741 fprintf (stderr, "error while parsing constant pool\n");
742 exit (FATAL_EXIT_CODE);
744 code = verify_constant_pool (jcf);
745 if (code > 0)
747 fprintf (stderr, "error in constant pool entry #%d\n", code);
748 exit (FATAL_EXIT_CODE);
750 if (flag_print_constant_pool)
751 print_constant_pool (jcf);
753 jcf_parse_class (jcf);
754 code = jcf_parse_fields (jcf);
755 if (code != 0)
757 fprintf (stderr, "error while parsing fields\n");
758 exit (FATAL_EXIT_CODE);
760 code = jcf_parse_methods (jcf);
761 if (code != 0)
763 fprintf (stderr, "error while parsing methods\n");
764 exit (FATAL_EXIT_CODE);
766 code = jcf_parse_final_attributes (jcf);
767 if (code != 0)
769 fprintf (stderr, "error while parsing final attributes\n");
770 exit (FATAL_EXIT_CODE);
772 jcf->filename = NULL;
777 /* This is used to mark options with no short value. */
778 #define LONG_OPT(Num) ((Num) + 128)
780 #define OPT_classpath LONG_OPT (0)
781 #define OPT_CLASSPATH OPT_classpath
782 #define OPT_bootclasspath LONG_OPT (1)
783 #define OPT_extdirs LONG_OPT (2)
784 #define OPT_HELP LONG_OPT (3)
785 #define OPT_VERSION LONG_OPT (4)
786 #define OPT_JAVAP LONG_OPT (5)
788 static const struct option options[] =
790 { "classpath", required_argument, NULL, OPT_classpath },
791 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
792 { "extdirs", required_argument, NULL, OPT_extdirs },
793 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
794 { "help", no_argument, NULL, OPT_HELP },
795 { "verbose", no_argument, NULL, 'v' },
796 { "version", no_argument, NULL, OPT_VERSION },
797 { "javap", no_argument, NULL, OPT_JAVAP },
798 { "print-main", no_argument, &flag_print_main, 1 },
799 { NULL, no_argument, NULL, 0 }
802 static void
803 usage (void)
805 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
806 exit (1);
809 static void
810 help (void)
812 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
813 printf ("Display contents of a class file in readable form.\n\n");
814 printf (" -c Disassemble method bodies\n");
815 printf (" --javap Generate output in `javap' format\n");
816 printf ("\n");
817 printf (" --classpath PATH Set path to find .class files\n");
818 printf (" -IDIR Append directory to class path\n");
819 printf (" --bootclasspath PATH Override built-in class path\n");
820 printf (" --extdirs PATH Set extensions directory path\n");
821 printf (" -o FILE Set output file name\n");
822 printf ("\n");
823 printf (" --help Print this help, then exit\n");
824 printf (" --version Print version number, then exit\n");
825 printf (" -v, --verbose Print extra information while running\n");
826 printf ("\n");
827 printf ("For bug reporting instructions, please see:\n");
828 printf ("%s.\n", bug_report_url);
829 exit (0);
832 static void
833 version (void)
835 printf ("jcf-dump (GCC) %s\n\n", version_string);
836 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
837 printf ("This is free software; see the source for copying conditions. There is NO\n");
838 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
839 exit (0);
843 main (int argc, char** argv)
845 JCF jcf[1];
846 int argi, opt;
848 if (argc <= 1)
850 fprintf (stderr, "jcf-dump: no classes specified\n");
851 usage ();
854 jcf_path_init ();
856 /* We use getopt_long_only to allow single `-' long options. For
857 some of our options this is more natural. */
858 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
860 switch (opt)
862 case 0:
863 /* Already handled. */
864 break;
866 case 'o':
867 output_file = optarg;
868 break;
870 case 'I':
871 jcf_path_include_arg (optarg);
872 break;
874 case 'v':
875 verbose++;
876 break;
878 case 'c':
879 flag_disassemble_methods = 1;
880 break;
882 case OPT_classpath:
883 jcf_path_classpath_arg (optarg);
884 break;
886 case OPT_bootclasspath:
887 jcf_path_bootclasspath_arg (optarg);
888 break;
890 case OPT_extdirs:
891 jcf_path_extdirs_arg (optarg);
892 break;
894 case OPT_HELP:
895 help ();
896 break;
898 case OPT_VERSION:
899 version ();
900 break;
902 case OPT_JAVAP:
903 flag_javap_compatible++;
904 flag_print_constant_pool = 0;
905 flag_print_attributes = 0;
906 break;
908 default:
909 usage ();
913 if (optind == argc)
915 fprintf (stderr, "jcf-dump: no classes specified\n");
916 usage ();
919 jcf_path_seal (verbose);
921 if (flag_print_main)
923 flag_print_fields = 0;
924 flag_print_methods = 0;
925 flag_print_constant_pool = 0;
926 flag_print_attributes = 0;
927 flag_print_class_info = 0;
930 if (output_file)
932 out = fopen (output_file, "w");
933 if (! out)
935 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
936 return FATAL_EXIT_CODE;
939 else
940 out = stdout;
942 if (optind >= argc)
944 fprintf (out, "Reading .class from <standard input>.\n");
945 open_class ("<stdio>", jcf, 0, NULL);
946 process_class (jcf);
948 else
950 for (argi = optind; argi < argc; argi++)
952 char *arg = argv[argi];
953 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
954 if (class_filename == NULL)
955 class_filename = find_classfile (arg, jcf, NULL);
956 if (class_filename == NULL)
958 perror ("Could not find class");
959 return FATAL_EXIT_CODE;
961 JCF_FILL (jcf, 4);
962 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
964 long compressed_size, member_size;
965 int compression_method, filename_length, extra_length;
966 int general_purpose_bits;
967 const char *filename;
968 int total_length;
969 if (flag_print_class_info)
970 fprintf (out, "Reading classes from archive %s.\n",
971 class_filename);
972 for (;;)
974 int skip = 0;
975 jcf_filbuf_t save_filbuf = jcf->filbuf;
976 long magic = JCF_readu4_le (jcf);
977 if (magic == 0x02014b50 || magic == 0x06054b50)
978 break; /* got to central directory */
979 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
981 fprintf (stderr, "bad format of .zip/.jar archive\n");
982 return FATAL_EXIT_CODE;
984 JCF_FILL (jcf, 26);
985 JCF_SKIP (jcf, 2);
986 general_purpose_bits = JCF_readu2_le (jcf);
987 compression_method = JCF_readu2_le (jcf);
988 JCF_SKIP (jcf, 8);
989 compressed_size = JCF_readu4_le (jcf);
990 member_size = JCF_readu4_le (jcf);
991 filename_length = JCF_readu2_le (jcf);
992 extra_length = JCF_readu2_le (jcf);
993 total_length = filename_length + extra_length
994 + compressed_size;
995 if (jcf->read_end - jcf->read_ptr < total_length)
996 jcf_trim_old_input (jcf);
997 JCF_FILL (jcf, total_length);
998 filename = jcf->read_ptr;
999 JCF_SKIP (jcf, filename_length);
1000 JCF_SKIP (jcf, extra_length);
1001 if (filename_length > 0
1002 && filename[filename_length-1] == '/')
1004 if (flag_print_class_info)
1005 fprintf (out, "[Skipping directory %.*s]\n",
1006 filename_length, filename);
1007 skip = 1;
1009 else if (compression_method != 0)
1011 if (flag_print_class_info)
1012 fprintf (out, "[Skipping compressed file %.*s]\n",
1013 filename_length, filename);
1014 skip = 1;
1016 else if (member_size < 4
1017 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1019 if (flag_print_class_info)
1020 fprintf (out, "[Skipping non-.class member %.*s]\n",
1021 filename_length, filename);
1022 skip = 1;
1024 else
1026 if (flag_print_class_info)
1027 fprintf (out, "Reading class member: %.*s.\n",
1028 filename_length, filename);
1030 if (skip)
1032 JCF_SKIP (jcf, compressed_size);
1034 else
1036 unsigned char *save_end;
1037 jcf->filbuf = jcf_unexpected_eof;
1038 save_end = jcf->read_end;
1039 jcf->read_end = jcf->read_ptr + compressed_size;
1040 process_class (jcf);
1041 jcf->filbuf = save_filbuf;
1042 jcf->read_end = save_end;
1046 else
1048 if (flag_print_class_info)
1049 fprintf (out, "Reading .class from %s.\n", class_filename);
1050 process_class (jcf);
1052 JCF_FINISH(jcf);
1056 return SUCCESS_EXIT_CODE;
1061 static void
1062 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1064 #undef PTR
1065 int PC;
1066 int i;
1067 int saw_wide = 0;
1068 if (flag_disassemble_methods == 0)
1069 return;
1070 #define BCODE byte_ops
1071 for (PC = 0; PC < len;)
1073 int oldpc = PC;
1074 int saw_index;
1075 jint INT_temp;
1076 switch (byte_ops[PC++])
1079 /* This is the actual code emitted for each of opcodes in javaops.def.
1080 The actual opcode-specific stuff is handled by the OPKIND macro.
1081 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1082 Those macros are defined below. The OPKINDs that do not have any
1083 inline parameters (such as BINOP) and therefore do mot need anything
1084 else to me printed out just use an empty body. */
1086 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1087 case OPCODE: \
1088 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1089 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1090 fputc ('\n', out); \
1091 break;
1093 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1094 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1095 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1096 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1098 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1099 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1101 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1102 These all push a constant onto the opcode stack. */
1103 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1104 saw_index = 0, i = (OPERAND_VALUE); \
1105 if (oldpc+1 == PC) /* nothing */; \
1106 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1107 else fprintf (out, " %d", i);
1109 /* Print out operand (a local variable index) for LOAD opcodes.
1110 These all push local variable onto the opcode stack. */
1111 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1112 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1114 /* Handle STORE opcodes same as LOAD opcodes.
1115 These all store a value from the opcode stack in a local variable. */
1116 #define STORE LOAD
1118 /* Handle more kind of opcodes. */
1119 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1120 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1121 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1122 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1123 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1124 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1125 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1127 /* Handle putfield and getfield opcodes, with static versions. */
1128 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1129 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1131 /* Print operand for invoke opcodes. */
1132 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1133 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1134 if (OPERAND_VALUE) /* for invokeinterface */ \
1135 { int nargs = IMMEDIATE_u1; PC++; \
1136 fprintf (out, " nargs:%d", nargs); }
1138 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1139 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1141 #define ARRAY(OPERAND_TYPE, SUBOP) \
1142 ARRAY_##SUBOP(OPERAND_TYPE)
1143 /* Handle sub-categories of ARRAY opcodes. */
1144 #define ARRAY_LOAD(TYPE) /* nothing */
1145 #define ARRAY_STORE(TYPE) /* nothing */
1146 #define ARRAY_LENGTH(TYPE) /* nothing */
1147 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1148 #define ARRAY_NEW_NUM \
1149 INT_temp = IMMEDIATE_u1; \
1150 { switch ((int) INT_temp) { \
1151 case 4: fputs (" boolean", out); break; \
1152 case 5: fputs (" char", out); break; \
1153 case 6: fputs (" float", out); break; \
1154 case 7: fputs (" double", out); break; \
1155 case 8: fputs (" byte", out); break; \
1156 case 9: fputs (" short", out); break; \
1157 case 10: fputs (" int", out); break; \
1158 case 11: fputs (" long", out); break; \
1159 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1162 #define ARRAY_NEW_PTR \
1163 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1165 #define ARRAY_NEW_MULTI \
1166 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1167 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1169 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1170 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1172 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1173 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1174 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1176 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1177 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1178 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1180 #undef RET /* Defined by config/i386/i386.h */
1181 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1182 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1183 saw_wide = 0; \
1184 fprintf (out, " %ld", (long) INT_temp);
1186 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1187 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1189 #define LOOKUP_SWITCH \
1190 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1191 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1192 while (--npairs >= 0) { \
1193 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1194 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1197 #define TABLE_SWITCH \
1198 { jint default_offset = IMMEDIATE_s4; \
1199 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1200 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1201 (long) low, (long) high, (long) default_offset+oldpc); \
1202 for (; low <= high; low++) { \
1203 jint offset = IMMEDIATE_s4; \
1204 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1207 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1208 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1210 #define SPECIAL_IINC(OPERAND_TYPE) \
1211 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1212 fprintf (out, " %d", i); \
1213 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1214 saw_wide = 0; \
1215 fprintf (out, " %d", i)
1217 #define SPECIAL_WIDE(OPERAND_TYPE) \
1218 saw_wide = 1;
1220 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1221 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1222 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1223 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1225 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1226 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1228 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1229 TEST(OPERAND_TYPE, OPERAND_VALUE)
1231 #include "javaop.def"
1233 load_store:
1234 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1235 else
1237 saw_wide = 0;
1238 fprintf (out, " %ld", (long) INT_temp);
1240 fputc ('\n', out);
1241 break;
1243 default:
1244 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);