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