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)
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
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
41 Dis-assemble each method.
45 Print nothing if there is no valid "main" method;
46 otherwise, print only the class name.
48 Print output in the style of Sun's javap program. VERY UNFINISHED.
54 #include "coretypes.h"
61 #include "java-tree.h"
70 /* Name of output file, if NULL if stdout. */
71 char *output_file
= NULL
;
75 int flag_disassemble_methods
= 0;
76 int flag_print_class_info
= 1;
77 int flag_print_constant_pool
= 0;
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
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
,
113 #define PRINT_SIGNATURE_RESULT_ONLY 1
114 #define PRINT_SIGNATURE_ARGS_ONLY 2
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)
130 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
131 this_class_index = 0; \
132 if (flag_print_class_info) \
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'); \
154 fprintf (out, "This class: "); \
155 print_constant_terse_with_index (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); \
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: "); \
175 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
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); } \
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); \
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'); \
219 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
221 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
222 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
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); \
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); \
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: ", slot); \
289 if (flag_print_constant_pool) \
290 fprintf (out, "%d=", name_index); \
291 print_name (out, jcf, name_index); \
292 fprintf (out, ", type: "); \
293 if (flag_print_constant_pool) \
294 fprintf (out, "%d=", signature_index); \
295 print_signature (out, jcf, signature_index, 0); \
296 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
298 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
299 { int n = (COUNT); int i; \
300 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
301 fprintf (out, ", count: %d\n", n); \
302 if (flag_disassemble_methods) \
303 for (i = 0; i < n; i++) {\
304 int start_pc = JCF_readu2 (jcf); \
305 int line_number = JCF_readu2 (jcf); \
306 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
308 JCF_SKIP (jcf, 4 * n); }
310 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
312 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
315 uint16 inner_class_info_index = JCF_readu2 (jcf); \
316 uint16 outer_class_info_index = JCF_readu2 (jcf); \
317 uint16 inner_name_index = JCF_readu2 (jcf); \
318 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
320 if (flag_print_class_info) \
322 fprintf (out, "\n inner: "); \
323 print_constant_terse_with_index (out, jcf, \
324 inner_class_info_index, CONSTANT_Class); \
325 if (inner_name_index == 0) \
326 fprintf (out, " (anonymous)"); \
327 else if (verbose || flag_print_constant_pool) \
329 fprintf (out, " ("); \
330 print_constant_terse_with_index (out, jcf, inner_name_index, \
334 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
335 print_access_flags (out, inner_class_access_flags, 'c'); \
336 fprintf (out, ", outer class: "); \
337 print_constant_terse_with_index (out, jcf, \
338 outer_class_info_index, CONSTANT_Class); \
341 if (flag_print_class_info) \
345 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
346 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
347 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
349 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
350 if (flag_print_attributes > 0) \
351 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
356 print_constant_ref (FILE *stream
, JCF
*jcf
, int index
)
358 if (index
<= 0 || index
>= JPOOL_SIZE(jcf
))
359 fprintf (stream
, "<out of range>");
362 if (flag_print_constant_pool
)
363 fprintf (stream
, "#%d=", index
);
365 print_constant (stream
, jcf
, index
, 1);
370 /* Print the access flags given by FLAGS.
371 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
372 or 'm' (method flags). */
375 print_access_flags (FILE *stream
, uint16 flags
, char context
)
377 if (flags
& ACC_PUBLIC
) fprintf (stream
, " public");
378 if (flags
& ACC_PRIVATE
) fprintf (stream
, " private");
379 if (flags
& ACC_PROTECTED
) fprintf (stream
, " protected");
380 if (flags
& ACC_ABSTRACT
) fprintf (stream
, " abstract");
381 if (flags
& ACC_STATIC
) fprintf (stream
, " static");
382 if (flags
& ACC_FINAL
) fprintf (stream
, " final");
383 if (flags
& ACC_TRANSIENT
) fprintf (stream
, " transient");
384 if (flags
& ACC_VOLATILE
) fprintf (stream
, " volatile");
385 if (flags
& ACC_NATIVE
) fprintf (stream
, " native");
386 if (flags
& ACC_SYNCHRONIZED
)
389 fprintf (stream
, " super");
391 fprintf (stream
, " synchronized");
393 if (flags
& ACC_INTERFACE
) fprintf (stream
, " interface");
394 if (flags
& ACC_STRICT
) fprintf (stream
, " strictfp");
399 print_name (FILE* stream
, JCF
* jcf
, int name_index
)
401 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
402 fprintf (stream
, "<not a UTF8 constant>");
404 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
,name_index
),
405 JPOOL_UTF_LENGTH (jcf
, name_index
));
408 /* If the type of the constant at INDEX matches EXPECTED,
409 print it tersely, otherwise more verbosely. */
412 print_constant_terse (FILE *out
, JCF
*jcf
, int index
, int expected
)
414 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
))
415 fprintf (out
, "<constant pool index %d not in range>", index
);
416 else if (JPOOL_TAG (jcf
, index
) != expected
)
418 fprintf (out
, "<Unexpected constant type ");
419 print_constant (out
, jcf
, index
, 1);
423 print_constant (out
, jcf
, index
, 0);
427 print_constant_terse_with_index (FILE *out
, JCF
*jcf
, int index
, int expected
)
429 if (flag_print_constant_pool
)
430 fprintf (out
, "%d=", index
);
431 print_constant_terse (out
, jcf
, index
, expected
);
434 /* Print the constant at INDEX in JCF's constant pool.
435 If verbosity==0, print very tersely (no extraneous text).
436 If verbosity==1, prefix the type of the constant.
437 If verbosity==2, add more descriptive text. */
440 print_constant (FILE *out
, JCF
*jcf
, int index
, int verbosity
)
445 int kind
= JPOOL_TAG (jcf
, index
);
449 n
= JPOOL_USHORT1 (jcf
, index
);
453 fprintf (out
, "Class name: %d=", n
);
455 fprintf (out
, "Class ");
457 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, n
))
458 fprintf (out
, "<out of range>");
459 else if (verbosity
< 2 && JPOOL_TAG (jcf
, n
) == CONSTANT_Utf8
)
461 int len
= JPOOL_UTF_LENGTH (jcf
, n
);
462 jcf_print_utf8_replace (out
, JPOOL_UTF_DATA(jcf
,n
), len
, '/', '.');
465 print_constant_terse (out
, jcf
, n
, CONSTANT_Utf8
);
467 case CONSTANT_Fieldref
:
468 str
= "Field"; goto field_or_method
;
469 case CONSTANT_Methodref
:
470 str
= "Method"; goto field_or_method
;
471 case CONSTANT_InterfaceMethodref
:
472 str
= "InterfaceMethod"; goto field_or_method
;
475 uint16 tclass
= JPOOL_USHORT1 (jcf
, index
);
476 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
478 fprintf (out
, "%sref class: %d=", str
, tclass
);
479 else if (verbosity
> 0)
480 fprintf (out
, "%s ", str
);
481 print_constant_terse (out
, jcf
, tclass
, CONSTANT_Class
);
485 fprintf (out
, " name_and_type: %d=<", name_and_type
);
486 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
491 case CONSTANT_String
:
492 j
= JPOOL_USHORT1 (jcf
, index
);
496 fprintf (out
, "String %d=", j
);
498 fprintf (out
, "String ");
500 print_constant_terse (out
, jcf
, j
, CONSTANT_Utf8
);
502 case CONSTANT_Integer
:
504 fprintf (out
, "Integer ");
505 num
= JPOOL_INT (jcf
, index
);
509 fprintf (out
, "Long ");
510 num
= JPOOL_LONG (jcf
, index
);
515 format_int (buffer
, num
, 10);
516 fprintf (out
, "%s", buffer
);
519 format_uint (buffer
, (uint64
)num
, 16);
520 fprintf (out
, "=0x%s", buffer
);
526 jfloat fnum
= JPOOL_FLOAT (jcf
, index
);
529 fputs ("Float ", out
);
534 if (JFLOAT_FINITE (fnum
))
537 int exponent
= fnum
.exponent
- JFLOAT_EXP_BIAS
;
539 uint32 mantissa
= fnum
.mantissa
;
540 if (fnum
.exponent
== 0)
544 /* Normal; add the implicit bit. */
545 mantissa
|= ((uint32
)1 << 23);
547 f
= frexp (mantissa
, &dummy
);
548 f
= ldexp (f
, exponent
+ 1);
549 fprintf (out
, "%.10g", f
);
553 if (fnum
.mantissa
== 0)
555 else if (fnum
.mantissa
& JFLOAT_QNAN_MASK
)
556 fprintf (out
, "QNaN(%u)", (fnum
.mantissa
& ~JFLOAT_QNAN_MASK
));
558 fprintf (out
, "SNaN(%u)", (fnum
.mantissa
& ~JFLOAT_QNAN_MASK
));
562 fprintf (out
, ", bits = 0x%08lx", JPOOL_UINT (jcf
, index
));
566 case CONSTANT_Double
:
568 jdouble dnum
= JPOOL_DOUBLE (jcf
, index
);
571 fputs ("Double ", out
);
576 if (JDOUBLE_FINITE (dnum
))
579 int exponent
= dnum
.exponent
- JDOUBLE_EXP_BIAS
;
581 uint64 mantissa
= ((((uint64
) dnum
.mantissa0
) << 32)
583 if (dnum
.exponent
== 0)
587 /* Normal; add the implicit bit. */
588 mantissa
|= ((uint64
)1 << 52);
590 d
= frexp (mantissa
, &dummy
);
591 d
= ldexp (d
, exponent
+ 1);
592 fprintf (out
, "%.20g", d
);
596 uint64 mantissa
= dnum
.mantissa0
& ~JDOUBLE_QNAN_MASK
;
597 mantissa
= (mantissa
<< 32) + dnum
.mantissa1
;
599 if (dnum
.mantissa0
== 0 && dnum
.mantissa1
== 0)
601 else if (dnum
.mantissa0
& JDOUBLE_QNAN_MASK
)
602 fprintf (out
, "QNaN(%llu)", (unsigned long long)mantissa
);
604 fprintf (out
, "SNaN(%llu)", (unsigned long long)mantissa
);
609 hi
= JPOOL_UINT (jcf
, index
);
610 lo
= JPOOL_UINT (jcf
, index
+ 1);
611 fprintf (out
, ", bits = 0x%08lx%08lx", (long) hi
, (long) lo
);
615 case CONSTANT_NameAndType
:
617 uint16 name
= JPOOL_USHORT1 (jcf
, index
);
618 uint16 sig
= JPOOL_USHORT2 (jcf
, index
);
622 fprintf (out
, "NameAndType name: %d=", name
);
624 fprintf (out
, "NameAndType ");
626 print_name (out
, jcf
, name
);
630 fprintf (out
, ", signature: %d=", sig
);
631 print_signature (out
, jcf
, sig
, 0);
636 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, index
);
637 int length
= JPOOL_UTF_LENGTH (jcf
, index
);
639 { /* Print as 8-bit bytes. */
640 fputs ("Utf8: \"", out
);
641 while (--length
>= 0)
642 jcf_print_char (out
, *str
++);
645 { /* Print as Unicode. */
647 jcf_print_utf8 (out
, str
, length
);
653 fprintf (out
, "(Unknown constant type %d)", kind
);
658 print_constant_pool (JCF
*jcf
)
661 for (i
= 1; i
< JPOOL_SIZE(jcf
); i
++)
663 int kind
= JPOOL_TAG (jcf
, i
);
664 fprintf (out
, "#%d: ", i
);
665 print_constant (out
, jcf
, i
, 2);
667 if (kind
== CONSTANT_Double
|| kind
== CONSTANT_Long
)
668 i
++; /* These take up two slots in the constant table */
673 print_signature_type (FILE* stream
, const unsigned char **ptr
,
674 const unsigned char *limit
)
683 for ((*ptr
)++; (*ptr
) < limit
&& ISDIGIT (**ptr
); (*ptr
)++)
685 array_size
= (array_size
< 0 ? 0 : 10 * array_size
) + *(*ptr
) - '0';
687 print_signature_type (stream
, ptr
, limit
);
688 if (array_size
== -1)
689 fprintf (stream
, "[]");
691 fprintf (stream
, "[%d]", array_size
);
696 fputc (*(*ptr
)++, stream
);
697 for (; **ptr
!= ')' && *ptr
< limit
; nargs
++)
701 print_signature_type (stream
, ptr
, limit
);
705 fputc (*(*ptr
)++, stream
);
706 print_signature_type (stream
, ptr
, limit
);
709 fprintf (stream
, "???");
713 case 'B': fprintf (stream
, "byte"); (*ptr
)++; break;
714 case 'C': fprintf (stream
, "char"); (*ptr
)++; break;
715 case 'D': fprintf (stream
, "double"); (*ptr
)++; break;
716 case 'F': fprintf (stream
, "float"); (*ptr
)++; break;
717 case 'S': fprintf (stream
, "short"); (*ptr
)++; break;
718 case 'I': fprintf (stream
, "int"); (*ptr
)++; break;
719 case 'J': fprintf (stream
, "long"); (*ptr
)++; break;
720 case 'Z': fprintf (stream
, "boolean"); (*ptr
)++; break;
721 case 'V': fprintf (stream
, "void"); (*ptr
)++; break;
724 for ((*ptr
)++; (*ptr
)<limit
&& *(*ptr
) != ';'; (*ptr
)++)
725 jcf_print_char (stream
, *(*ptr
) == '/' ? '.' : *(*ptr
));
730 jcf_print_char (stream
, *(*ptr
)++);
735 print_signature (FILE* stream
, JCF
*jcf
, int signature_index
, int options
)
737 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
738 print_constant_terse (out
, jcf
, signature_index
, CONSTANT_Utf8
);
741 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, signature_index
);
742 int length
= JPOOL_UTF_LENGTH (jcf
, signature_index
);
743 const unsigned char *limit
;
744 limit
= str
+ length
;
746 fprintf (stream
, "<empty signature string>");
749 if (options
& PRINT_SIGNATURE_RESULT_ONLY
)
751 while (str
< limit
&& *str
++ != ')') ;
753 if (options
& PRINT_SIGNATURE_ARGS_ONLY
)
757 while (str
< limit
&& *str
!= ')')
759 print_signature_type (stream
, &str
, limit
);
761 fputs (", ", stream
);
767 print_signature_type (stream
, &str
, limit
);
770 fprintf (stream
, "<junk:");
771 jcf_print_utf8 (stream
, str
, limit
- str
);
781 print_exception_table (JCF
*jcf
, const unsigned char *entries
, int count
)
783 /* Print exception table. */
787 const unsigned char *ptr
= entries
;
788 fprintf (out
, "Exceptions (count: %d):\n", i
);
789 for (; --i
>= 0; ptr
+= 8)
791 int start_pc
= GET_u2 (ptr
);
792 int end_pc
= GET_u2 (ptr
+2);
793 int handler_pc
= GET_u2 (ptr
+4);
794 int catch_type
= GET_u2 (ptr
+6);
795 fprintf (out
, " start: %d, end: %d, handler: %d, type: ",
796 start_pc
, end_pc
, handler_pc
);
798 fputs ("0 /* finally */", out
);
800 print_constant_terse_with_index (out
, jcf
,
801 catch_type
, CONSTANT_Class
);
807 #include "jcf-reader.c"
810 process_class (JCF
*jcf
)
813 if (jcf_parse_preamble (jcf
) != 0)
814 fprintf (stderr
, _("Not a valid Java .class file.\n"));
816 /* Parse and possibly print constant pool */
817 code
= jcf_parse_constant_pool (jcf
);
820 fprintf (stderr
, _("error while parsing constant pool\n"));
821 exit (FATAL_EXIT_CODE
);
823 code
= verify_constant_pool (jcf
);
826 fprintf (stderr
, _("error in constant pool entry #%d\n"), code
);
827 exit (FATAL_EXIT_CODE
);
829 if (flag_print_constant_pool
)
830 print_constant_pool (jcf
);
832 jcf_parse_class (jcf
);
833 code
= jcf_parse_fields (jcf
);
836 fprintf (stderr
, _("error while parsing fields\n"));
837 exit (FATAL_EXIT_CODE
);
839 code
= jcf_parse_methods (jcf
);
842 fprintf (stderr
, _("error while parsing methods\n"));
843 exit (FATAL_EXIT_CODE
);
845 code
= jcf_parse_final_attributes (jcf
);
848 fprintf (stderr
, _("error while parsing final attributes\n"));
849 exit (FATAL_EXIT_CODE
);
851 jcf
->filename
= NULL
;
856 /* This is used to mark options with no short value. */
857 #define LONG_OPT(Num) ((Num) + 128)
859 #define OPT_classpath LONG_OPT (0)
860 #define OPT_CLASSPATH OPT_classpath
861 #define OPT_bootclasspath LONG_OPT (1)
862 #define OPT_extdirs LONG_OPT (2)
863 #define OPT_HELP LONG_OPT (3)
864 #define OPT_VERSION LONG_OPT (4)
865 #define OPT_JAVAP LONG_OPT (5)
867 static const struct option options
[] =
869 { "classpath", required_argument
, NULL
, OPT_classpath
},
870 { "bootclasspath", required_argument
, NULL
, OPT_bootclasspath
},
871 { "extdirs", required_argument
, NULL
, OPT_extdirs
},
872 { "CLASSPATH", required_argument
, NULL
, OPT_CLASSPATH
},
873 { "help", no_argument
, NULL
, OPT_HELP
},
874 { "verbose", no_argument
, NULL
, 'v' },
875 { "version", no_argument
, NULL
, OPT_VERSION
},
876 { "javap", no_argument
, NULL
, OPT_JAVAP
},
877 { "print-main", no_argument
, &flag_print_main
, 1 },
878 { "print-constants", no_argument
, &flag_print_constant_pool
, 1 },
879 { NULL
, no_argument
, NULL
, 0 }
885 fprintf (stderr
, _("Try `jcf-dump --help' for more information.\n"));
892 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
893 printf (_("Display contents of a class file in readable form.\n\n"));
894 printf (_(" -c Disassemble method bodies\n"));
895 printf (_(" --javap Generate output in `javap' format\n"));
897 printf (_(" --classpath PATH Set path to find .class files\n"));
898 printf (_(" -IDIR Append directory to class path\n"));
899 printf (_(" --bootclasspath PATH Override built-in class path\n"));
900 printf (_(" --extdirs PATH Set extensions directory path\n"));
901 printf (_(" -o FILE Set output file name\n"));
903 printf (_(" --help Print this help, then exit\n"));
904 printf (_(" --version Print version number, then exit\n"));
905 printf (_(" -v, --verbose Print extra information while running\n"));
907 printf (_("For bug reporting instructions, please see:\n"
908 "%s.\n"), bug_report_url
);
915 printf ("jcf-dump (GCC) %s\n\n", version_string
);
916 printf ("Copyright %s 2004 Free Software Foundation, Inc.\n", _("(C)"));
917 printf (_("This is free software; see the source for copying conditions. There is NO\n"
918 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
923 main (int argc
, char** argv
)
932 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
938 /* We use getopt_long_only to allow single `-' long options. For
939 some of our options this is more natural. */
940 while ((opt
= getopt_long_only (argc
, argv
, "o:I:vc", options
, NULL
)) != -1)
945 /* Already handled. */
949 output_file
= optarg
;
953 jcf_path_include_arg (optarg
);
961 flag_disassemble_methods
= 1;
965 jcf_path_classpath_arg (optarg
);
968 case OPT_bootclasspath
:
969 jcf_path_bootclasspath_arg (optarg
);
973 jcf_path_extdirs_arg (optarg
);
985 flag_javap_compatible
++;
986 flag_print_constant_pool
= 0;
987 flag_print_attributes
= 0;
995 if (verbose
&& ! flag_javap_compatible
)
996 flag_print_constant_pool
= 1;
1000 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
1004 jcf_path_seal (verbose
);
1006 if (flag_print_main
)
1008 flag_print_fields
= 0;
1009 flag_print_methods
= 0;
1010 flag_print_constant_pool
= 0;
1011 flag_print_attributes
= 0;
1012 flag_print_class_info
= 0;
1017 out
= fopen (output_file
, "w");
1020 fprintf (stderr
, _("Cannot open '%s' for output.\n"), output_file
);
1021 return FATAL_EXIT_CODE
;
1029 fprintf (out
, "Reading .class from <standard input>.\n");
1030 open_class ("<stdio>", jcf
, 0, NULL
);
1031 process_class (jcf
);
1035 for (argi
= optind
; argi
< argc
; argi
++)
1037 char *arg
= argv
[argi
];
1038 const char *class_filename
= find_class (arg
, strlen (arg
), jcf
, 0);
1039 if (class_filename
== NULL
)
1040 class_filename
= find_classfile (arg
, jcf
, NULL
);
1041 if (class_filename
== NULL
)
1043 perror ("Could not find class");
1044 return FATAL_EXIT_CODE
;
1047 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
1049 long compressed_size
, member_size
;
1050 int compression_method
, filename_length
, extra_length
;
1051 int general_purpose_bits
;
1052 const char *filename
;
1054 if (flag_print_class_info
)
1055 fprintf (out
, "Reading classes from archive %s.\n",
1060 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
1061 long magic
= JCF_readu4_le (jcf
);
1062 if (magic
== 0x02014b50 || magic
== 0x06054b50)
1063 break; /* got to central directory */
1064 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
1066 fprintf (stderr
, _("bad format of .zip/.jar archive\n"));
1067 return FATAL_EXIT_CODE
;
1071 general_purpose_bits
= JCF_readu2_le (jcf
);
1072 compression_method
= JCF_readu2_le (jcf
);
1074 compressed_size
= JCF_readu4_le (jcf
);
1075 member_size
= JCF_readu4_le (jcf
);
1076 filename_length
= JCF_readu2_le (jcf
);
1077 extra_length
= JCF_readu2_le (jcf
);
1078 total_length
= filename_length
+ extra_length
1080 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
1081 jcf_trim_old_input (jcf
);
1082 JCF_FILL (jcf
, total_length
);
1083 filename
= (const char *) jcf
->read_ptr
;
1084 JCF_SKIP (jcf
, filename_length
);
1085 JCF_SKIP (jcf
, extra_length
);
1086 if (filename_length
> 0
1087 && filename
[filename_length
-1] == '/')
1089 if (flag_print_class_info
)
1090 fprintf (out
, "[Skipping directory %.*s]\n",
1091 filename_length
, filename
);
1094 else if (compression_method
!= 0)
1096 if (flag_print_class_info
)
1097 fprintf (out
, "[Skipping compressed file %.*s]\n",
1098 filename_length
, filename
);
1101 else if (member_size
< 4
1102 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
1104 if (flag_print_class_info
)
1105 fprintf (out
, "[Skipping non-.class member %.*s]\n",
1106 filename_length
, filename
);
1111 if (flag_print_class_info
)
1112 fprintf (out
, "Reading class member: %.*s.\n",
1113 filename_length
, filename
);
1117 JCF_SKIP (jcf
, compressed_size
);
1121 unsigned char *save_end
;
1122 jcf
->filbuf
= jcf_unexpected_eof
;
1123 save_end
= jcf
->read_end
;
1124 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
1125 process_class (jcf
);
1126 jcf
->filbuf
= save_filbuf
;
1127 jcf
->read_end
= save_end
;
1133 if (flag_print_class_info
)
1134 fprintf (out
, "Reading .class from %s.\n", class_filename
);
1135 process_class (jcf
);
1141 return SUCCESS_EXIT_CODE
;
1147 disassemble_method (JCF
* jcf
, const unsigned char *byte_ops
, int len
)
1153 if (flag_disassemble_methods
== 0)
1155 #define BCODE byte_ops
1156 for (PC
= 0; PC
< len
;)
1161 switch (byte_ops
[PC
++])
1164 /* This is the actual code emitted for each of opcodes in javaops.def.
1165 The actual opcode-specific stuff is handled by the OPKIND macro.
1166 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1167 Those macros are defined below. The OPKINDs that do not have any
1168 inline parameters (such as BINOP) and therefore do mot need anything
1169 else to me printed out just use an empty body. */
1171 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1173 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1174 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1175 fputc ('\n', out); \
1178 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1179 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1180 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1181 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1183 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1184 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1)) : 1)
1186 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1187 These all push a constant onto the opcode stack. */
1188 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1189 saw_index = 0, i = (OPERAND_VALUE); \
1190 if (oldpc+1 == PC) /* nothing */; \
1191 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1192 else fprintf (out, " %d", i);
1194 /* Print out operand (a local variable index) for LOAD opcodes.
1195 These all push local variable onto the opcode stack. */
1196 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1197 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1199 /* Handle STORE opcodes same as LOAD opcodes.
1200 These all store a value from the opcode stack in a local variable. */
1203 /* Handle more kind of opcodes. */
1204 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1205 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1206 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1207 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1208 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1209 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1210 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1212 /* Handle putfield and getfield opcodes, with static versions. */
1213 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1214 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1216 /* Print operand for invoke opcodes. */
1217 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1218 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1219 if (OPERAND_VALUE) /* for invokeinterface */ \
1220 { int nargs = IMMEDIATE_u1; PC++; \
1221 fprintf (out, " nargs:%d", nargs); }
1223 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1224 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1226 #define ARRAY(OPERAND_TYPE, SUBOP) \
1227 ARRAY_##SUBOP(OPERAND_TYPE)
1228 /* Handle sub-categories of ARRAY opcodes. */
1229 #define ARRAY_LOAD(TYPE) /* nothing */
1230 #define ARRAY_STORE(TYPE) /* nothing */
1231 #define ARRAY_LENGTH(TYPE) /* nothing */
1232 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1233 #define ARRAY_NEW_NUM \
1234 INT_temp = IMMEDIATE_u1; \
1235 { switch ((int) INT_temp) { \
1236 case 4: fputs (" boolean", out); break; \
1237 case 5: fputs (" char", out); break; \
1238 case 6: fputs (" float", out); break; \
1239 case 7: fputs (" double", out); break; \
1240 case 8: fputs (" byte", out); break; \
1241 case 9: fputs (" short", out); break; \
1242 case 10: fputs (" int", out); break; \
1243 case 11: fputs (" long", out); break; \
1244 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1247 #define ARRAY_NEW_PTR \
1248 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1250 #define ARRAY_NEW_MULTI \
1251 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1252 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1254 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1255 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1257 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1258 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1259 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1261 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1262 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1263 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1265 #undef RET /* Defined by config/i386/i386.h */
1266 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1267 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1269 fprintf (out, " %ld", (long) INT_temp);
1271 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1272 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1274 #define LOOKUP_SWITCH \
1275 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1276 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1277 while (--npairs >= 0) { \
1278 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1279 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1282 #define TABLE_SWITCH \
1283 { jint default_offset = IMMEDIATE_s4; \
1284 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1285 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1286 (long) low, (long) high, (long) default_offset+oldpc); \
1287 for (; low <= high; low++) { \
1288 jint offset = IMMEDIATE_s4; \
1289 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1292 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1293 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1295 #define SPECIAL_IINC(OPERAND_TYPE) \
1296 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1297 fprintf (out, " %d", i); \
1298 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1300 fprintf (out, " %d", i)
1302 #define SPECIAL_WIDE(OPERAND_TYPE) \
1305 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1306 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1307 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1308 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1310 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1311 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1313 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1314 TEST(OPERAND_TYPE, OPERAND_VALUE)
1316 #include "javaop.def"
1319 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1323 fprintf (out
, " %ld", (long) INT_temp
);
1329 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);