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, 2005,
5 2006 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 INCOMPLETE. */
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 2006 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
)
928 /* Unlock the stdio streams. */
929 unlock_std_streams ();
935 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
941 /* We use getopt_long_only to allow single `-' long options. For
942 some of our options this is more natural. */
943 while ((opt
= getopt_long_only (argc
, argv
, "o:I:vc", options
, NULL
)) != -1)
948 /* Already handled. */
952 output_file
= optarg
;
956 jcf_path_include_arg (optarg
);
964 flag_disassemble_methods
= 1;
968 jcf_path_classpath_arg (optarg
);
971 case OPT_bootclasspath
:
972 jcf_path_bootclasspath_arg (optarg
);
976 jcf_path_extdirs_arg (optarg
);
988 flag_javap_compatible
++;
989 flag_print_constant_pool
= 0;
990 flag_print_attributes
= 0;
998 if (verbose
&& ! flag_javap_compatible
)
999 flag_print_constant_pool
= 1;
1003 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
1007 jcf_path_seal (verbose
);
1009 if (flag_print_main
)
1011 flag_print_fields
= 0;
1012 flag_print_methods
= 0;
1013 flag_print_constant_pool
= 0;
1014 flag_print_attributes
= 0;
1015 flag_print_class_info
= 0;
1020 out
= fopen (output_file
, "w");
1023 fprintf (stderr
, _("Cannot open '%s' for output.\n"), output_file
);
1024 return FATAL_EXIT_CODE
;
1032 fprintf (out
, "Reading .class from <standard input>.\n");
1033 open_class ("<stdio>", jcf
, 0, NULL
);
1034 process_class (jcf
);
1038 for (argi
= optind
; argi
< argc
; argi
++)
1040 char *arg
= argv
[argi
];
1041 const char *class_filename
= find_class (arg
, strlen (arg
), jcf
, 0);
1042 if (class_filename
== NULL
)
1043 class_filename
= find_classfile (arg
, jcf
, NULL
);
1044 if (class_filename
== NULL
)
1046 perror ("Could not find class");
1047 return FATAL_EXIT_CODE
;
1050 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
1052 long compressed_size
, member_size
;
1053 int compression_method
, filename_length
, extra_length
;
1054 int general_purpose_bits
;
1055 const char *filename
;
1057 if (flag_print_class_info
)
1058 fprintf (out
, "Reading classes from archive %s.\n",
1063 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
1064 long magic
= JCF_readu4_le (jcf
);
1065 if (magic
== 0x02014b50 || magic
== 0x06054b50)
1066 break; /* got to central directory */
1067 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
1069 fprintf (stderr
, _("bad format of .zip/.jar archive\n"));
1070 return FATAL_EXIT_CODE
;
1074 general_purpose_bits
= JCF_readu2_le (jcf
);
1075 compression_method
= JCF_readu2_le (jcf
);
1077 compressed_size
= JCF_readu4_le (jcf
);
1078 member_size
= JCF_readu4_le (jcf
);
1079 filename_length
= JCF_readu2_le (jcf
);
1080 extra_length
= JCF_readu2_le (jcf
);
1081 total_length
= filename_length
+ extra_length
1083 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
1084 jcf_trim_old_input (jcf
);
1085 JCF_FILL (jcf
, total_length
);
1086 filename
= (const char *) jcf
->read_ptr
;
1087 JCF_SKIP (jcf
, filename_length
);
1088 JCF_SKIP (jcf
, extra_length
);
1089 if (filename_length
> 0
1090 && filename
[filename_length
-1] == '/')
1092 if (flag_print_class_info
)
1093 fprintf (out
, "[Skipping directory %.*s]\n",
1094 filename_length
, filename
);
1097 else if (compression_method
!= 0)
1099 if (flag_print_class_info
)
1100 fprintf (out
, "[Skipping compressed file %.*s]\n",
1101 filename_length
, filename
);
1104 else if (member_size
< 4
1105 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
1107 if (flag_print_class_info
)
1108 fprintf (out
, "[Skipping non-.class member %.*s]\n",
1109 filename_length
, filename
);
1114 if (flag_print_class_info
)
1115 fprintf (out
, "Reading class member: %.*s.\n",
1116 filename_length
, filename
);
1120 JCF_SKIP (jcf
, compressed_size
);
1124 unsigned char *save_end
;
1125 jcf
->filbuf
= jcf_unexpected_eof
;
1126 save_end
= jcf
->read_end
;
1127 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
1128 process_class (jcf
);
1129 jcf
->filbuf
= save_filbuf
;
1130 jcf
->read_end
= save_end
;
1136 if (flag_print_class_info
)
1137 fprintf (out
, "Reading .class from %s.\n", class_filename
);
1138 process_class (jcf
);
1144 return SUCCESS_EXIT_CODE
;
1150 disassemble_method (JCF
* jcf
, const unsigned char *byte_ops
, int len
)
1156 if (flag_disassemble_methods
== 0)
1158 #define BCODE byte_ops
1159 for (PC
= 0; PC
< len
;)
1164 switch (byte_ops
[PC
++])
1167 /* This is the actual code emitted for each of opcodes in javaops.def.
1168 The actual opcode-specific stuff is handled by the OPKIND macro.
1169 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1170 Those macros are defined below. The OPKINDs that do not have any
1171 inline parameters (such as BINOP) and therefore do mot need anything
1172 else to me printed out just use an empty body. */
1174 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1176 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1177 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1178 fputc ('\n', out); \
1181 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1182 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1183 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1184 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1186 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1187 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1189 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1190 These all push a constant onto the opcode stack. */
1191 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1192 saw_index = 0, i = (OPERAND_VALUE); \
1193 if (oldpc+1 == PC) /* nothing */; \
1194 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1195 else fprintf (out, " %d", i);
1197 /* Print out operand (a local variable index) for LOAD opcodes.
1198 These all push local variable onto the opcode stack. */
1199 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1200 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1202 /* Handle STORE opcodes same as LOAD opcodes.
1203 These all store a value from the opcode stack in a local variable. */
1206 /* Handle more kind of opcodes. */
1207 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1208 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1209 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1210 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1211 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1212 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1213 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1215 /* Handle putfield and getfield opcodes, with static versions. */
1216 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1217 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1219 /* Print operand for invoke opcodes. */
1220 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1221 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1222 if (OPERAND_VALUE) /* for invokeinterface */ \
1223 { int nargs = IMMEDIATE_u1; PC++; \
1224 fprintf (out, " nargs:%d", nargs); }
1226 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1227 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1229 #define ARRAY(OPERAND_TYPE, SUBOP) \
1230 ARRAY_##SUBOP(OPERAND_TYPE)
1231 /* Handle sub-categories of ARRAY opcodes. */
1232 #define ARRAY_LOAD(TYPE) /* nothing */
1233 #define ARRAY_STORE(TYPE) /* nothing */
1234 #define ARRAY_LENGTH(TYPE) /* nothing */
1235 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1236 #define ARRAY_NEW_NUM \
1237 INT_temp = IMMEDIATE_u1; \
1238 { switch ((int) INT_temp) { \
1239 case 4: fputs (" boolean", out); break; \
1240 case 5: fputs (" char", out); break; \
1241 case 6: fputs (" float", out); break; \
1242 case 7: fputs (" double", out); break; \
1243 case 8: fputs (" byte", out); break; \
1244 case 9: fputs (" short", out); break; \
1245 case 10: fputs (" int", out); break; \
1246 case 11: fputs (" long", out); break; \
1247 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1250 #define ARRAY_NEW_PTR \
1251 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1253 #define ARRAY_NEW_MULTI \
1254 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1255 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1257 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1258 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1260 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1261 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1262 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1264 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1265 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1266 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1268 #undef RET /* Defined by config/i386/i386.h */
1269 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1270 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1272 fprintf (out, " %ld", (long) INT_temp);
1274 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1275 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1277 #define LOOKUP_SWITCH \
1278 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1279 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1280 while (--npairs >= 0) { \
1281 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1282 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1285 #define TABLE_SWITCH \
1286 { jint default_offset = IMMEDIATE_s4; \
1287 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1288 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1289 (long) low, (long) high, (long) default_offset+oldpc); \
1290 for (; low <= high; low++) { \
1291 jint offset = IMMEDIATE_s4; \
1292 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1295 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1296 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1298 #define SPECIAL_IINC(OPERAND_TYPE) \
1299 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1300 fprintf (out, " %d", i); \
1301 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1303 fprintf (out, " %d", i)
1305 #define SPECIAL_WIDE(OPERAND_TYPE) \
1308 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1309 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1310 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1311 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1313 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1314 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1316 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1317 TEST(OPERAND_TYPE, OPERAND_VALUE)
1319 #include "javaop.def"
1322 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1326 fprintf (out
, " %ld", (long) INT_temp
);
1332 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);