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