1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
5 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
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"
59 #include "java-tree.h"
67 /* Name of output file, if NULL if stdout. */
68 char *output_file
= NULL
;
72 int flag_disassemble_methods
= 0;
73 int flag_print_class_info
= 1;
74 int flag_print_constant_pool
= 1;
75 int flag_print_fields
= 1;
76 int flag_print_methods
= 1;
77 int flag_print_attributes
= 1;
79 /* When nonzero, warn when source file is newer than matching class
83 /* Print names of classes that have a "main" method. */
84 int flag_print_main
= 0;
86 /* Index in constant pool of this class. */
87 int this_class_index
= 0;
89 int class_access_flags
= 0;
91 /* Print in format similar to javap. VERY IMCOMPLETE. */
92 int flag_javap_compatible
= 0;
94 static void print_access_flags
PARAMS ((FILE *, uint16
, char));
95 static void print_constant_terse
PARAMS ((FILE*, JCF
*, int, int));
96 static void print_constant
PARAMS ((FILE *, JCF
*, int, int));
97 static void print_constant_ref
PARAMS ((FILE *, JCF
*, int));
98 static void disassemble_method
PARAMS ((JCF
*, const unsigned char *, int));
99 static void print_name
PARAMS ((FILE*, JCF
*, int));
100 static void print_signature
PARAMS ((FILE*, JCF
*, int, int));
101 static int utf8_equal_string
PARAMS ((struct JCF
*, int, const char *));
102 static void usage
PARAMS ((void)) ATTRIBUTE_NORETURN
;
103 static void help
PARAMS ((void)) ATTRIBUTE_NORETURN
;
104 static void version
PARAMS ((void)) ATTRIBUTE_NORETURN
;
105 static void process_class
PARAMS ((struct JCF
*));
106 static void print_constant_pool
PARAMS ((struct JCF
*));
107 static void print_exception_table
PARAMS ((struct JCF
*,
108 const unsigned char *entries
, int));
110 #define PRINT_SIGNATURE_RESULT_ONLY 1
111 #define PRINT_SIGNATURE_ARGS_ONLY 2
114 DEFUN(utf8_equal_string
, (jcf
, index
, value
),
115 JCF
*jcf AND
int index AND
const char * value
)
117 if (CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
)
118 && JPOOL_TAG (jcf
, index
) == CONSTANT_Utf8
)
120 int len
= strlen (value
);
121 if (JPOOL_UTF_LENGTH (jcf
, index
) == len
122 && memcmp (JPOOL_UTF_DATA (jcf
, index
), value
, len
) == 0)
128 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
129 this_class_index = 0; \
130 if (flag_print_class_info) \
132 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
133 (long) MAGIC, (long) MINOR, (long) MAJOR)
135 #define HANDLE_START_CONSTANT_POOL(COUNT) \
136 if (flag_print_constant_pool) \
137 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
139 #define HANDLE_SOURCEFILE(INDEX) \
140 { fprintf (out, "Attribute "); \
141 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
142 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
143 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
145 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
146 this_class_index = THIS; \
147 class_access_flags = ACCESS_FLAGS; \
148 if (flag_print_class_info) \
149 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
150 print_access_flags (out, ACCESS_FLAGS, 'c'); \
152 fprintf (out, "This class: "); \
153 if (flag_print_constant_pool) \
154 fprintf (out, "%d=", THIS); \
155 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
156 if (flag_print_constant_pool || SUPER != 0) \
157 fprintf (out, ", super: "); \
158 if (flag_print_constant_pool) \
160 fprintf (out, "%d", SUPER); \
165 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
166 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
169 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
170 (flag_print_attributes <= 0)
172 #define HANDLE_CLASS_INTERFACE(INDEX) \
173 if (flag_print_class_info) \
174 { fprintf (out, "- Implements: %d=", INDEX); \
175 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
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: %d=", slot, name_index); \
289 print_name (out, jcf, name_index); \
290 fprintf (out, ", type: %d=", signature_index); \
291 print_signature (out, jcf, signature_index, 0); \
292 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
294 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
295 { int n = (COUNT); int i; \
296 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
297 fprintf (out, ", count: %d\n", n); \
298 if (flag_disassemble_methods) \
299 for (i = 0; i < n; i++) {\
300 int start_pc = JCF_readu2 (jcf); \
301 int line_number = JCF_readu2 (jcf); \
302 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
304 JCF_SKIP (jcf, 4 * n); }
306 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
308 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
311 uint16 inner_class_info_index = JCF_readu2 (jcf); \
312 uint16 outer_class_info_index = JCF_readu2 (jcf); \
313 uint16 inner_name_index = JCF_readu2 (jcf); \
314 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
316 if (flag_print_class_info) \
318 fprintf (out, "\n class: "); \
319 if (flag_print_constant_pool) \
320 fprintf (out, "%d=", inner_class_info_index); \
321 print_constant_terse (out, jcf, \
322 inner_class_info_index, CONSTANT_Class); \
323 fprintf (out, " (%d=", inner_name_index); \
324 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
325 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
326 print_access_flags (out, inner_class_access_flags, 'c'); \
327 fprintf (out, ", outer class: "); \
328 if (flag_print_constant_pool) \
329 fprintf (out, "%d=", outer_class_info_index); \
330 print_constant_terse (out, jcf, \
331 outer_class_info_index, CONSTANT_Class); \
334 if (flag_print_class_info) \
338 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
339 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
340 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
342 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
343 if (flag_print_attributes > 0) \
344 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
349 DEFUN(print_constant_ref
, (stream
, jcf
, index
),
350 FILE *stream AND JCF
*jcf AND
int index
)
352 fprintf (stream
, "#%d=<", index
);
353 if (index
<= 0 || index
>= JPOOL_SIZE(jcf
))
354 fprintf (stream
, "out of range");
356 print_constant (stream
, jcf
, index
, 1);
357 fprintf (stream
, ">");
360 /* Print the access flags given by FLAGS.
361 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
362 or 'm' (method flags). */
365 DEFUN (print_access_flags
, (stream
, flags
, context
),
366 FILE *stream AND uint16 flags AND
char context
)
368 if (flags
& ACC_PUBLIC
) fprintf (stream
, " public");
369 if (flags
& ACC_PRIVATE
) fprintf (stream
, " private");
370 if (flags
& ACC_PROTECTED
) fprintf (stream
, " protected");
371 if (flags
& ACC_ABSTRACT
) fprintf (stream
, " abstract");
372 if (flags
& ACC_STATIC
) fprintf (stream
, " static");
373 if (flags
& ACC_FINAL
) fprintf (stream
, " final");
374 if (flags
& ACC_TRANSIENT
) fprintf (stream
, " transient");
375 if (flags
& ACC_VOLATILE
) fprintf (stream
, " volatile");
376 if (flags
& ACC_NATIVE
) fprintf (stream
, " native");
377 if (flags
& ACC_SYNCHRONIZED
)
380 fprintf (stream
, " super");
382 fprintf (stream
, " synchronized");
384 if (flags
& ACC_INTERFACE
) fprintf (stream
, " interface");
385 if (flags
& ACC_STRICT
) fprintf (stream
, " strictfp");
390 DEFUN(print_name
, (stream
, jcf
, name_index
),
391 FILE* stream AND JCF
* jcf AND
int name_index
)
393 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
394 fprintf (stream
, "<not a UTF8 constant>");
396 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
,name_index
),
397 JPOOL_UTF_LENGTH (jcf
, name_index
));
400 /* If the type of the constant at INDEX matches EXPECTED,
401 print it tersely, otherwise more verbosely. */
404 DEFUN(print_constant_terse
, (out
, jcf
, index
, expected
),
405 FILE *out AND JCF
*jcf AND
int index AND
int expected
)
407 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
))
408 fprintf (out
, "<constant pool index %d not in range>", index
);
409 else if (JPOOL_TAG (jcf
, index
) != expected
)
411 fprintf (out
, "<Unexpected constant type ");
412 print_constant (out
, jcf
, index
, 1);
416 print_constant (out
, jcf
, index
, 0);
419 /* Print the constant at INDEX in JCF's constant pool.
420 If verbosity==0, print very tersely (no extraneous text).
421 If verbosity==1, prefix the type of the constant.
422 If verbosity==2, add more descriptive text. */
425 DEFUN(print_constant
, (out
, jcf
, index
, verbosity
),
426 FILE *out AND JCF
*jcf AND
int index AND
int verbosity
)
431 int kind
= JPOOL_TAG (jcf
, index
);
435 n
= JPOOL_USHORT1 (jcf
, index
);
439 fprintf (out
, "Class name: %d=", n
);
441 fprintf (out
, "Class ");
443 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, n
))
444 fprintf (out
, "<out of range>");
445 else if (verbosity
< 2 && JPOOL_TAG (jcf
, n
) == CONSTANT_Utf8
)
447 int len
= JPOOL_UTF_LENGTH (jcf
, n
);
448 jcf_print_utf8_replace (out
, JPOOL_UTF_DATA(jcf
,n
), len
, '/', '.');
451 print_constant_terse (out
, jcf
, n
, CONSTANT_Utf8
);
453 case CONSTANT_Fieldref
:
454 str
= "Field"; goto field_or_method
;
455 case CONSTANT_Methodref
:
456 str
= "Method"; goto field_or_method
;
457 case CONSTANT_InterfaceMethodref
:
458 str
= "InterfaceMethod"; goto field_or_method
;
461 uint16 tclass
= JPOOL_USHORT1 (jcf
, index
);
462 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
464 fprintf (out
, "%sref class: %d=", str
, tclass
);
465 else if (verbosity
> 0)
466 fprintf (out
, "%s ", str
);
467 print_constant_terse (out
, jcf
, tclass
, CONSTANT_Class
);
471 fprintf (out
, " name_and_type: %d=<", name_and_type
);
472 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
477 case CONSTANT_String
:
478 j
= JPOOL_USHORT1 (jcf
, index
);
482 fprintf (out
, "String %d=", j
);
484 fprintf (out
, "String ");
486 print_constant_terse (out
, jcf
, j
, CONSTANT_Utf8
);
488 case CONSTANT_Integer
:
490 fprintf (out
, "Integer ");
491 num
= JPOOL_INT (jcf
, index
);
495 fprintf (out
, "Long ");
496 num
= JPOOL_LONG (jcf
, index
);
501 format_int (buffer
, num
, 10);
502 fprintf (out
, "%s", buffer
);
505 format_uint (buffer
, (uint64
)num
, 16);
506 fprintf (out
, "=0x%s", buffer
);
518 pun
.f
= JPOOL_FLOAT (jcf
, index
);
519 fprintf (out
, "%s%.10g",
520 verbosity
> 0 ? "Float " : "", (double) pun
.f
);
522 fprintf (out
, ", bits = 0x%08lx", (long) pun
.i
);
526 case CONSTANT_Double
:
528 jdouble dnum
= JPOOL_DOUBLE (jcf
, index
);
529 fprintf (out
, "%s%.20g", verbosity
> 0 ? "Double " : "", dnum
);
533 hi
= JPOOL_UINT (jcf
, index
);
534 lo
= JPOOL_UINT (jcf
, index
+ 1);
535 fprintf (out
, ", bits = 0x%08lx%08lx", (long) hi
, (long) lo
);
539 case CONSTANT_NameAndType
:
541 uint16 name
= JPOOL_USHORT1 (jcf
, index
);
542 uint16 sig
= JPOOL_USHORT2 (jcf
, index
);
546 fprintf (out
, "NameAndType name: %d=", name
);
548 fprintf (out
, "NameAndType ");
550 print_name (out
, jcf
, name
);
554 fprintf (out
, ", signature: %d=", sig
);
555 print_signature (out
, jcf
, sig
, 0);
560 register const unsigned char *str
= JPOOL_UTF_DATA (jcf
, index
);
561 int length
= JPOOL_UTF_LENGTH (jcf
, index
);
563 { /* Print as 8-bit bytes. */
564 fputs ("Utf8: \"", out
);
565 while (--length
>= 0)
566 jcf_print_char (out
, *str
++);
569 { /* Print as Unicode. */
571 jcf_print_utf8 (out
, str
, length
);
577 fprintf (out
, "(Unknown constant type %d)", kind
);
582 DEFUN(print_constant_pool
, (jcf
),
586 for (i
= 1; i
< JPOOL_SIZE(jcf
); i
++)
588 int kind
= JPOOL_TAG (jcf
, i
);
589 fprintf (out
, "#%d: ", i
);
590 print_constant (out
, jcf
, i
, 2);
592 if (kind
== CONSTANT_Double
|| kind
== CONSTANT_Long
)
593 i
++; /* These take up two slots in the constant table */
598 DEFUN(print_signature_type
, (stream
, ptr
, limit
),
599 FILE* stream AND
const unsigned char **ptr AND
const unsigned char *limit
)
608 for ((*ptr
)++; (*ptr
) < limit
&& ISDIGIT (**ptr
); (*ptr
)++)
610 array_size
= (array_size
< 0 ? 0 : 10 * array_size
) + *(*ptr
) - '0';
612 print_signature_type (stream
, ptr
, limit
);
613 if (array_size
== -1)
614 fprintf (stream
, "[]");
616 fprintf (stream
, "[%d]", array_size
);
621 fputc (*(*ptr
)++, stream
);
622 for (; **ptr
!= ')' && *ptr
< limit
; nargs
++)
626 print_signature_type (stream
, ptr
, limit
);
630 fputc (*(*ptr
)++, stream
);
631 print_signature_type (stream
, ptr
, limit
);
634 fprintf (stream
, "???");
638 case 'B': fprintf (stream
, "byte"); (*ptr
)++; break;
639 case 'C': fprintf (stream
, "char"); (*ptr
)++; break;
640 case 'D': fprintf (stream
, "double"); (*ptr
)++; break;
641 case 'F': fprintf (stream
, "float"); (*ptr
)++; break;
642 case 'S': fprintf (stream
, "short"); (*ptr
)++; break;
643 case 'I': fprintf (stream
, "int"); (*ptr
)++; break;
644 case 'J': fprintf (stream
, "long"); (*ptr
)++; break;
645 case 'Z': fprintf (stream
, "boolean"); (*ptr
)++; break;
646 case 'V': fprintf (stream
, "void"); (*ptr
)++; break;
649 for ((*ptr
)++; (*ptr
)<limit
&& *(*ptr
) != ';'; (*ptr
)++)
650 jcf_print_char (stream
, *(*ptr
) == '/' ? '.' : *(*ptr
));
655 jcf_print_char (stream
, *(*ptr
)++);
660 DEFUN(print_signature
, (stream
, jcf
, signature_index
, int options
),
661 FILE* stream AND JCF
*jcf AND
int signature_index AND
int options
)
663 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
664 print_constant_terse (out
, jcf
, signature_index
, CONSTANT_Utf8
);
667 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, signature_index
);
668 int length
= JPOOL_UTF_LENGTH (jcf
, signature_index
);
669 const unsigned char *limit
;
670 limit
= str
+ length
;
672 fprintf (stream
, "<empty signature string>");
675 if (options
& PRINT_SIGNATURE_RESULT_ONLY
)
677 while (str
< limit
&& *str
++ != ')') ;
679 if (options
& PRINT_SIGNATURE_ARGS_ONLY
)
683 while (str
< limit
&& *str
!= ')')
685 print_signature_type (stream
, &str
, limit
);
687 fputs (", ", stream
);
693 print_signature_type (stream
, &str
, limit
);
696 fprintf (stream
, "<junk:");
697 jcf_print_utf8 (stream
, str
, limit
- str
);
707 DEFUN(print_exception_table
, (jcf
, entries
, count
),
708 JCF
*jcf AND
const unsigned char *entries AND
int count
)
710 /* Print exception table. */
714 const unsigned char *ptr
= entries
;
715 fprintf (out
, "Exceptions (count: %d):\n", i
);
716 for (; --i
>= 0; ptr
+= 8)
718 int start_pc
= GET_u2 (ptr
);
719 int end_pc
= GET_u2 (ptr
+2);
720 int handler_pc
= GET_u2 (ptr
+4);
721 int catch_type
= GET_u2 (ptr
+6);
722 fprintf (out
, " start: %d, end: %d, handler: %d, type: %d",
723 start_pc
, end_pc
, handler_pc
, catch_type
);
725 fputs (" /* finally */", out
);
729 print_constant_terse (out
, jcf
, catch_type
, CONSTANT_Class
);
736 #include "jcf-reader.c"
739 DEFUN(process_class
, (jcf
),
743 if (jcf_parse_preamble (jcf
) != 0)
744 fprintf (stderr
, "Not a valid Java .class file.\n");
746 /* Parse and possibly print constant pool */
747 code
= jcf_parse_constant_pool (jcf
);
750 fprintf (stderr
, "error while parsing constant pool\n");
751 exit (FATAL_EXIT_CODE
);
753 code
= verify_constant_pool (jcf
);
756 fprintf (stderr
, "error in constant pool entry #%d\n", code
);
757 exit (FATAL_EXIT_CODE
);
759 if (flag_print_constant_pool
)
760 print_constant_pool (jcf
);
762 jcf_parse_class (jcf
);
763 code
= jcf_parse_fields (jcf
);
766 fprintf (stderr
, "error while parsing fields\n");
767 exit (FATAL_EXIT_CODE
);
769 code
= jcf_parse_methods (jcf
);
772 fprintf (stderr
, "error while parsing methods\n");
773 exit (FATAL_EXIT_CODE
);
775 code
= jcf_parse_final_attributes (jcf
);
778 fprintf (stderr
, "error while parsing final attributes\n");
779 exit (FATAL_EXIT_CODE
);
781 jcf
->filename
= NULL
;
786 /* This is used to mark options with no short value. */
787 #define LONG_OPT(Num) ((Num) + 128)
789 #define OPT_classpath LONG_OPT (0)
790 #define OPT_CLASSPATH OPT_classpath
791 #define OPT_bootclasspath LONG_OPT (1)
792 #define OPT_extdirs LONG_OPT (2)
793 #define OPT_HELP LONG_OPT (3)
794 #define OPT_VERSION LONG_OPT (4)
795 #define OPT_JAVAP LONG_OPT (5)
797 static const struct option options
[] =
799 { "classpath", required_argument
, NULL
, OPT_classpath
},
800 { "bootclasspath", required_argument
, NULL
, OPT_bootclasspath
},
801 { "extdirs", required_argument
, NULL
, OPT_extdirs
},
802 { "CLASSPATH", required_argument
, NULL
, OPT_CLASSPATH
},
803 { "help", no_argument
, NULL
, OPT_HELP
},
804 { "verbose", no_argument
, NULL
, 'v' },
805 { "version", no_argument
, NULL
, OPT_VERSION
},
806 { "javap", no_argument
, NULL
, OPT_JAVAP
},
807 { "print-main", no_argument
, &flag_print_main
, 1 },
808 { NULL
, no_argument
, NULL
, 0 }
814 fprintf (stderr
, "Try `jcf-dump --help' for more information.\n");
821 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
822 printf ("Display contents of a class file in readable form.\n\n");
823 printf (" -c Disassemble method bodies\n");
824 printf (" --javap Generate output in `javap' format\n");
826 printf (" --classpath PATH Set path to find .class files\n");
827 printf (" -IDIR Append directory to class path\n");
828 printf (" --bootclasspath PATH Override built-in class path\n");
829 printf (" --extdirs PATH Set extensions directory path\n");
830 printf (" -o FILE Set output file name\n");
832 printf (" --help Print this help, then exit\n");
833 printf (" --version Print version number, then exit\n");
834 printf (" -v, --verbose Print extra information while running\n");
836 printf ("For bug reporting instructions, please see:\n");
837 printf ("%s.\n", bug_report_url
);
844 printf ("jcf-dump (GCC) %s\n\n", version_string
);
845 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
846 printf ("This is free software; see the source for copying conditions. There is NO\n");
847 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
852 DEFUN(main
, (argc
, argv
),
853 int argc AND
char** argv
)
860 fprintf (stderr
, "jcf-dump: no classes specified\n");
866 /* We use getopt_long_only to allow single `-' long options. For
867 some of our options this is more natural. */
868 while ((opt
= getopt_long_only (argc
, argv
, "o:I:vc", options
, NULL
)) != -1)
873 /* Already handled. */
877 output_file
= optarg
;
881 jcf_path_include_arg (optarg
);
889 flag_disassemble_methods
= 1;
893 jcf_path_classpath_arg (optarg
);
896 case OPT_bootclasspath
:
897 jcf_path_bootclasspath_arg (optarg
);
901 jcf_path_extdirs_arg (optarg
);
913 flag_javap_compatible
++;
914 flag_print_constant_pool
= 0;
915 flag_print_attributes
= 0;
925 fprintf (stderr
, "jcf-dump: no classes specified\n");
929 jcf_path_seal (verbose
);
933 flag_print_fields
= 0;
934 flag_print_methods
= 0;
935 flag_print_constant_pool
= 0;
936 flag_print_attributes
= 0;
937 flag_print_class_info
= 0;
942 out
= fopen (output_file
, "w");
945 fprintf (stderr
, "Cannot open '%s' for output.\n", output_file
);
946 return FATAL_EXIT_CODE
;
954 fprintf (out
, "Reading .class from <standard input>.\n");
955 open_class ("<stdio>", jcf
, 0, NULL
);
960 for (argi
= optind
; argi
< argc
; argi
++)
962 char *arg
= argv
[argi
];
963 const char *class_filename
= find_class (arg
, strlen (arg
), jcf
, 0);
964 if (class_filename
== NULL
)
965 class_filename
= find_classfile (arg
, jcf
, NULL
);
966 if (class_filename
== NULL
)
968 perror ("Could not find class");
969 return FATAL_EXIT_CODE
;
972 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
974 long compressed_size
, member_size
;
975 int compression_method
, filename_length
, extra_length
;
976 int general_purpose_bits
;
977 const char *filename
;
979 if (flag_print_class_info
)
980 fprintf (out
, "Reading classes from archive %s.\n",
985 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
986 long magic
= JCF_readu4_le (jcf
);
987 if (magic
== 0x02014b50 || magic
== 0x06054b50)
988 break; /* got to central directory */
989 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
991 fprintf (stderr
, "bad format of .zip/.jar archive\n");
992 return FATAL_EXIT_CODE
;
996 general_purpose_bits
= JCF_readu2_le (jcf
);
997 compression_method
= JCF_readu2_le (jcf
);
999 compressed_size
= JCF_readu4_le (jcf
);
1000 member_size
= JCF_readu4_le (jcf
);
1001 filename_length
= JCF_readu2_le (jcf
);
1002 extra_length
= JCF_readu2_le (jcf
);
1003 total_length
= filename_length
+ extra_length
1005 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
1006 jcf_trim_old_input (jcf
);
1007 JCF_FILL (jcf
, total_length
);
1008 filename
= jcf
->read_ptr
;
1009 JCF_SKIP (jcf
, filename_length
);
1010 JCF_SKIP (jcf
, extra_length
);
1011 if (filename_length
> 0
1012 && filename
[filename_length
-1] == '/')
1014 if (flag_print_class_info
)
1015 fprintf (out
, "[Skipping directory %.*s]\n",
1016 filename_length
, filename
);
1019 else if (compression_method
!= 0)
1021 if (flag_print_class_info
)
1022 fprintf (out
, "[Skipping compressed file %.*s]\n",
1023 filename_length
, filename
);
1026 else if (member_size
< 4
1027 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
1029 if (flag_print_class_info
)
1030 fprintf (out
, "[Skipping non-.class member %.*s]\n",
1031 filename_length
, filename
);
1036 if (flag_print_class_info
)
1037 fprintf (out
, "Reading class member: %.*s.\n",
1038 filename_length
, filename
);
1042 JCF_SKIP (jcf
, compressed_size
);
1046 unsigned char *save_end
;
1047 jcf
->filbuf
= jcf_unexpected_eof
;
1048 save_end
= jcf
->read_end
;
1049 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
1050 process_class (jcf
);
1051 jcf
->filbuf
= save_filbuf
;
1052 jcf
->read_end
= save_end
;
1058 if (flag_print_class_info
)
1059 fprintf (out
, "Reading .class from %s.\n", class_filename
);
1060 process_class (jcf
);
1066 return SUCCESS_EXIT_CODE
;
1072 DEFUN(disassemble_method
, (jcf
, byte_ops
, len
),
1073 JCF
* jcf AND
const unsigned char *byte_ops AND
int len
)
1075 #undef AND /* Causes problems with opcodes for iand and land. */
1080 if (flag_disassemble_methods
== 0)
1082 #define BCODE byte_ops
1083 for (PC
= 0; PC
< len
;)
1088 switch (byte_ops
[PC
++])
1091 /* This is the actual code emitted for each of opcodes in javaops.def.
1092 The actual opcode-specific stuff is handled by the OPKIND macro.
1093 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1094 Those macros are defiend below. The OPKINDs that do not have any
1095 inline parameters (such as BINOP) and therefore do mot need anything
1096 else to me printed out just use an empty body. */
1098 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1100 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1101 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1102 fputc ('\n', out); \
1105 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1106 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1107 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1108 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1110 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1111 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1113 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1114 These all push a constant onto the opcode stack. */
1115 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1116 saw_index = 0, i = (OPERAND_VALUE); \
1117 if (oldpc+1 == PC) /* nothing */; \
1118 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1119 else fprintf (out, " %d", i);
1121 /* Print out operand (a local variable index) for LOAD opcodes.
1122 These all push local variable onto the opcode stack. */
1123 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1124 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1126 /* Handle STORE opcodes same as LOAD opcodes.
1127 These all store a value from the opcode stack in a local variable. */
1130 /* Handle more kind of opcodes. */
1131 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1132 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1133 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1134 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1135 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1136 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1137 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1139 /* Handle putfield and getfield opcodes, with static versions. */
1140 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1141 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1143 /* Print operand for invoke opcodes. */
1144 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1145 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1146 if (OPERAND_VALUE) /* for invokeinterface */ \
1147 { int nargs = IMMEDIATE_u1; PC++; \
1148 fprintf (out, " nargs:%d", nargs); }
1150 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1151 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1153 #define ARRAY(OPERAND_TYPE, SUBOP) \
1154 ARRAY_##SUBOP(OPERAND_TYPE)
1155 /* Handle sub-categories of ARRAY opcodes. */
1156 #define ARRAY_LOAD(TYPE) /* nothing */
1157 #define ARRAY_STORE(TYPE) /* nothing */
1158 #define ARRAY_LENGTH(TYPE) /* nothing */
1159 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1160 #define ARRAY_NEW_NUM \
1161 INT_temp = IMMEDIATE_u1; \
1162 { switch ((int) INT_temp) { \
1163 case 4: fputs (" boolean", out); break; \
1164 case 5: fputs (" char", out); break; \
1165 case 6: fputs (" float", out); break; \
1166 case 7: fputs (" double", out); break; \
1167 case 8: fputs (" byte", out); break; \
1168 case 9: fputs (" short", out); break; \
1169 case 10: fputs (" int", out); break; \
1170 case 11: fputs (" long", out); break; \
1171 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1174 #define ARRAY_NEW_PTR \
1175 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1177 #define ARRAY_NEW_MULTI \
1178 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1179 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1181 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1182 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1184 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1185 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1186 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1188 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1189 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1190 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1192 #undef RET /* Defined by config/i386/i386.h */
1193 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1194 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1196 fprintf (out, " %ld", (long) INT_temp);
1198 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1199 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1201 #define LOOKUP_SWITCH \
1202 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1203 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1204 while (--npairs >= 0) { \
1205 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1206 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1209 #define TABLE_SWITCH \
1210 { jint default_offset = IMMEDIATE_s4; \
1211 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1212 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1213 (long) low, (long) high, (long) default_offset+oldpc); \
1214 for (; low <= high; low++) { \
1215 jint offset = IMMEDIATE_s4; \
1216 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1219 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1220 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1222 #define SPECIAL_IINC(OPERAND_TYPE) \
1223 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1224 fprintf (out, " %d", i); \
1225 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1227 fprintf (out, " %d", i)
1229 #define SPECIAL_WIDE(OPERAND_TYPE) \
1232 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1233 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1234 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1235 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1237 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1238 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1240 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1241 TEST(OPERAND_TYPE, OPERAND_VALUE)
1243 #include "javaop.def"
1246 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1250 fprintf (out
, " %ld", (long) INT_temp
);
1256 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);