1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999 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"
58 /* Name of output file, if NULL if stdout. */
59 char *output_file
= NULL
;
63 int flag_disassemble_methods
= 0;
64 int flag_print_class_info
= 1;
65 int flag_print_constant_pool
= 1;
66 int flag_print_fields
= 1;
67 int flag_print_methods
= 1;
68 int flag_print_attributes
= 1;
70 /* Print names of classes that have a "main" method. */
71 int flag_print_main
= 0;
73 /* Index in constant pool of this class. */
74 int this_class_index
= 0;
76 int class_access_flags
= 0;
78 /* Print in format similar to javap. VERY IMCOMPLETE. */
79 int flag_javap_compatible
= 0;
81 static void print_access_flags
PROTO ((FILE *, uint16
, char));
82 static void print_constant_terse
PROTO ((FILE*, JCF
*, int, int));
83 static void print_constant
PROTO ((FILE *, JCF
*, int, int));
84 static void print_constant_ref
PROTO ((FILE *, JCF
*, int));
85 static void disassemble_method
PROTO ((JCF
*, const unsigned char *, int));
86 static void print_name
PROTO ((FILE*, JCF
*, int));
87 static void print_signature
PROTO ((FILE*, JCF
*, int, int));
88 static int utf8_equal_string
PROTO ((struct JCF
*, int, const char *));
89 static int usage
PROTO ((void)) ATTRIBUTE_NORETURN
;
90 static void process_class
PROTO ((struct JCF
*));
91 static void print_constant_pool
PROTO ((struct JCF
*));
92 static void print_exception_table
PROTO ((struct JCF
*,
93 const unsigned char *entries
, int));
95 #define PRINT_SIGNATURE_RESULT_ONLY 1
96 #define PRINT_SIGNATURE_ARGS_ONLY 2
99 DEFUN(utf8_equal_string
, (jcf
, index
, value
),
100 JCF
*jcf AND
int index AND
const char * value
)
102 if (CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
)
103 && JPOOL_TAG (jcf
, index
) == CONSTANT_Utf8
)
105 int len
= strlen (value
);
106 if (JPOOL_UTF_LENGTH (jcf
, index
) == len
107 && memcmp (JPOOL_UTF_DATA (jcf
, index
), value
, len
) == 0)
113 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
114 this_class_index = 0; \
115 if (flag_print_class_info) \
117 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
118 (long) MAGIC, (long) MINOR, (long) MAJOR)
120 #define HANDLE_START_CONSTANT_POOL(COUNT) \
121 if (flag_print_constant_pool) \
122 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
124 #define HANDLE_SOURCEFILE(INDEX) \
125 { fprintf (out, "Attribute "); \
126 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
127 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
128 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
130 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
131 this_class_index = THIS; \
132 class_access_flags = ACCESS_FLAGS; \
133 if (flag_print_class_info) \
134 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
135 print_access_flags (out, ACCESS_FLAGS, 'c'); \
137 fprintf (out, "This class: "); \
138 if (flag_print_constant_pool) \
139 fprintf (out, "%d=", THIS); \
140 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
141 if (flag_print_constant_pool || SUPER != 0) \
142 fprintf (out, ", super: "); \
143 if (flag_print_constant_pool) \
145 fprintf (out, "%d", SUPER); \
150 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
151 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
154 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
155 (flag_print_attributes <= 0)
157 #define HANDLE_CLASS_INTERFACE(INDEX) \
158 if (flag_print_class_info) \
159 { fprintf (out, "- Implements: %d=", INDEX); \
160 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
163 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
164 if (flag_print_fields) \
165 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
167 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
168 if (flag_print_fields) \
169 { fprintf (out, "Field name:"); \
170 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
171 print_access_flags (out, ACCESS_FLAGS, 'f'); \
172 fprintf (out, " Signature: "); \
173 if (flag_print_constant_pool) \
174 fprintf (out, "%d=", SIGNATURE); \
175 print_signature (out, jcf, SIGNATURE, 0); \
176 fputc ('\n', out); } \
178 flag_print_attributes--;
180 #define HANDLE_END_FIELD() \
181 if (! flag_print_fields) \
182 flag_print_attributes++;
184 #define HANDLE_START_METHODS(METHODS_COUNT) \
185 if (flag_print_methods) \
186 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
188 flag_print_attributes--;
191 #define HANDLE_END_METHODS() \
192 if (! flag_print_methods) \
193 flag_print_attributes++;
195 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
197 if (flag_print_methods) \
199 if (flag_javap_compatible) \
201 fprintf (out, " "); \
202 print_access_flags (out, ACCESS_FLAGS, 'm'); \
204 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
206 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
207 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
212 fprintf (out, "\nMethod name:"); \
213 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
214 print_access_flags (out, ACCESS_FLAGS, 'm'); \
215 fprintf (out, " Signature: "); \
216 if (flag_print_constant_pool) \
217 fprintf (out, "%d=", SIGNATURE); \
218 print_signature (out, jcf, SIGNATURE, 0); \
222 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
223 && utf8_equal_string (jcf, NAME, "main") \
224 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
225 && this_class_index > 0 \
226 && (class_access_flags & ACC_PUBLIC)) \
228 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
233 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
234 ( fprintf (out, "Attribute "), \
235 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
236 fprintf (out, ", length:%ld", (long) LENGTH) )
238 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
239 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
240 fprintf (out, ", value: "), \
241 print_constant_ref (out, jcf, VALUE_INDEX), \
242 fprintf (out, "\n") )
244 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
245 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
246 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
247 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
248 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
250 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
251 print_exception_table (jcf, ENTRIES, COUNT)
253 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
254 { int n = (COUNT); int i; \
255 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
256 fprintf (out, ", count: %d\n", n); \
257 for (i = 0; i < n; i++) {\
258 int ex_index = JCF_readu2 (jcf); \
259 fprintf (out, "%3d: ", i); \
260 print_constant_ref (out, jcf, ex_index); \
261 fputc ('\n', out); } }
263 #define HANDLE_LOCALVARIABLETABLE_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 start_pc = JCF_readu2 (jcf); \
269 int length = JCF_readu2 (jcf); \
270 int name_index = JCF_readu2 (jcf); \
271 int signature_index = JCF_readu2 (jcf); \
272 int slot = JCF_readu2 (jcf); \
273 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
274 print_name (out, jcf, name_index); \
275 fprintf (out, ", type: %d=", signature_index); \
276 print_signature (out, jcf, signature_index, 0); \
277 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
279 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
280 { int n = (COUNT); int i; \
281 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
282 fprintf (out, ", count: %d\n", n); \
283 if (flag_disassemble_methods) \
284 for (i = 0; i < n; i++) {\
285 int start_pc = JCF_readu2 (jcf); \
286 int line_number = JCF_readu2 (jcf); \
287 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
289 JCF_SKIP (jcf, 4 * n); }
291 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
292 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
293 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
295 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
296 if (flag_print_attributes > 0) \
297 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
302 DEFUN(print_constant_ref
, (stream
, jcf
, index
),
303 FILE *stream AND JCF
*jcf AND
int index
)
305 fprintf (stream
, "#%d=<", index
);
306 if (index
<= 0 || index
>= JPOOL_SIZE(jcf
))
307 fprintf (stream
, "out of range");
309 print_constant (stream
, jcf
, index
, 1);
310 fprintf (stream
, ">");
313 /* Print the access flags given by FLAGS.
314 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
315 or 'm' (method flags). */
318 DEFUN (print_access_flags
, (stream
, flags
, context
),
319 FILE *stream AND uint16 flags AND
char context
)
321 if (flags
& ACC_PUBLIC
) fprintf (stream
, " public");
322 if (flags
& ACC_PRIVATE
) fprintf (stream
, " private");
323 if (flags
& ACC_PROTECTED
) fprintf (stream
, " protected");
324 if (flags
& ACC_STATIC
) fprintf (stream
, " static");
325 if (flags
& ACC_FINAL
) fprintf (stream
, " final");
326 if (flags
& ACC_SYNCHRONIZED
)
329 fprintf (stream
, " super");
331 fprintf (stream
, " synchronized");
333 if (flags
& ACC_VOLATILE
) fprintf (stream
, " volatile");
334 if (flags
& ACC_TRANSIENT
) fprintf (stream
, " transient");
335 if (flags
& ACC_NATIVE
) fprintf (stream
, " native");
336 if (flags
& ACC_INTERFACE
) fprintf (stream
, " interface");
337 if (flags
& ACC_ABSTRACT
) fprintf (stream
, " abstract");
342 DEFUN(print_name
, (stream
, jcf
, name_index
),
343 FILE* stream AND JCF
* jcf AND
int name_index
)
345 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
346 fprintf (stream
, "<not a UTF8 constant>");
348 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
,name_index
),
349 JPOOL_UTF_LENGTH (jcf
, name_index
));
352 /* If the type of the constant at INDEX matches EXPECTED,
353 print it tersely, otherwise more verbosely. */
356 DEFUN(print_constant_terse
, (out
, jcf
, index
, expected
),
357 FILE *out AND JCF
*jcf AND
int index AND
int expected
)
359 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
))
360 fprintf (out
, "<constant pool index %d not in range>", index
);
361 else if (JPOOL_TAG (jcf
, index
) != expected
)
363 fprintf (out
, "<Unexpected constant type ");
364 print_constant (out
, jcf
, index
, 1);
368 print_constant (out
, jcf
, index
, 0);
371 /* Print the constant at INDEX in JCF's constant pool.
372 If verbosity==0, print very tersely (no extraneous text).
373 If verbosity==1, prefix the type of the constant.
374 If verbosity==2, add more descriptive text. */
377 DEFUN(print_constant
, (out
, jcf
, index
, verbosity
),
378 FILE *out AND JCF
*jcf AND
int index AND
int verbosity
)
383 int kind
= JPOOL_TAG (jcf
, index
);
387 n
= JPOOL_USHORT1 (jcf
, index
);
389 fprintf (out
, verbosity
> 1 ? "Class name: %d=" : "Class ", n
);
390 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, n
))
391 fprintf (out
, "<out of range>");
392 else if (verbosity
< 2 && JPOOL_TAG (jcf
, n
) == CONSTANT_Utf8
)
394 int len
= JPOOL_UTF_LENGTH (jcf
, n
);
395 jcf_print_utf8_replace (out
, JPOOL_UTF_DATA(jcf
,n
), len
, '/', '.');
398 print_constant_terse (out
, jcf
, n
, CONSTANT_Utf8
);
400 case CONSTANT_Fieldref
:
401 str
= "Field"; goto field_or_method
;
402 case CONSTANT_Methodref
:
403 str
= "Method"; goto field_or_method
;
404 case CONSTANT_InterfaceMethodref
:
405 str
= "InterfaceMethod"; goto field_or_method
;
408 uint16 tclass
= JPOOL_USHORT1 (jcf
, index
);
409 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
411 fprintf (out
, "%sref class: %d=", str
, tclass
);
412 else if (verbosity
> 0)
413 fprintf (out
, "%s ", str
);
414 print_constant_terse (out
, jcf
, tclass
, CONSTANT_Class
);
415 fprintf (out
, verbosity
< 2 ? "." : " name_and_type: %d=<",
417 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
422 case CONSTANT_String
:
423 j
= JPOOL_USHORT1 (jcf
, index
);
425 fprintf (out
, verbosity
> 1 ? "String %d=" : "String ", j
);
426 print_constant_terse (out
, jcf
, j
, CONSTANT_Utf8
);
428 case CONSTANT_Integer
:
430 fprintf (out
, "Integer ");
431 num
= JPOOL_INT (jcf
, index
);
435 fprintf (out
, "Long ");
436 num
= JPOOL_LONG (jcf
, index
);
441 format_int (buffer
, num
, 10);
442 fprintf (out
, "%s", buffer
);
445 format_uint (buffer
, (uint64
)num
, 16);
446 fprintf (out
, "=0x%s", buffer
);
452 jfloat fnum
= JPOOL_FLOAT (jcf
, index
);
453 fprintf (out
, "%s%.10g", verbosity
> 1 ? "Float " : "", (double) fnum
);
455 fprintf (out
, ", bits = 0x%08lx", (long) (* (int32
*) &fnum
));
458 case CONSTANT_Double
:
460 jdouble dnum
= JPOOL_DOUBLE (jcf
, index
);
461 fprintf (out
, "%s%.20g", verbosity
> 1 ? "Double " : "", dnum
);
465 hi
= JPOOL_UINT (jcf
, index
);
466 lo
= JPOOL_UINT (jcf
, index
+ 1);
467 fprintf (out
, ", bits = 0x%08lx%08lx", (long) hi
, (long) lo
);
471 case CONSTANT_NameAndType
:
473 uint16 name
= JPOOL_USHORT1 (jcf
, index
);
474 uint16 sig
= JPOOL_USHORT2 (jcf
, index
);
476 fprintf (out
, verbosity
> 1 ? "%s name: %d=" : "%s ",
477 "NameAndType", name
);
478 print_name (out
, jcf
, name
);
482 fprintf (out
, ", signature: %d=", sig
);
483 print_signature (out
, jcf
, sig
, 0);
488 register const unsigned char *str
= JPOOL_UTF_DATA (jcf
, index
);
489 int length
= JPOOL_UTF_LENGTH (jcf
, index
);
491 { /* Print as 8-bit bytes. */
492 fputs ("Utf8: \"", out
);
493 while (--length
>= 0)
494 jcf_print_char (out
, *str
++);
497 { /* Print as Unicode. */
499 jcf_print_utf8 (out
, str
, length
);
505 fprintf (out
, "(Unknown constant type %d)", kind
);
510 DEFUN(print_constant_pool
, (jcf
),
514 for (i
= 1; i
< JPOOL_SIZE(jcf
); i
++)
516 int kind
= JPOOL_TAG (jcf
, i
);
517 fprintf (out
, "#%d: ", i
);
518 print_constant (out
, jcf
, i
, 2);
520 if (kind
== CONSTANT_Double
|| kind
== CONSTANT_Long
)
521 i
++; /* These take up two slots in the constant table */
526 DEFUN(print_signature_type
, (stream
, ptr
, limit
),
527 FILE* stream AND
const unsigned char **ptr AND
const unsigned char *limit
)
536 for ((*ptr
)++; (*ptr
) < limit
&& ISDIGIT (**ptr
); (*ptr
)++)
538 array_size
= (array_size
< 0 ? 0 : 10 * array_size
) + *(*ptr
) - '0';
540 print_signature_type (stream
, ptr
, limit
);
541 if (array_size
== -1)
542 fprintf (stream
, "[]");
544 fprintf (stream
, "[%d]", array_size
);
549 fputc (*(*ptr
)++, stream
);
550 for (; **ptr
!= ')' && *ptr
< limit
; nargs
++)
554 print_signature_type (stream
, ptr
, limit
);
558 fputc (*(*ptr
)++, stream
);
559 print_signature_type (stream
, ptr
, limit
);
562 fprintf (stream
, "???");
566 case 'B': fprintf (stream
, "byte"); (*ptr
)++; break;
567 case 'C': fprintf (stream
, "char"); (*ptr
)++; break;
568 case 'D': fprintf (stream
, "double"); (*ptr
)++; break;
569 case 'F': fprintf (stream
, "float"); (*ptr
)++; break;
570 case 'S': fprintf (stream
, "short"); (*ptr
)++; break;
571 case 'I': fprintf (stream
, "int"); (*ptr
)++; break;
572 case 'J': fprintf (stream
, "long"); (*ptr
)++; break;
573 case 'Z': fprintf (stream
, "boolean"); (*ptr
)++; break;
574 case 'V': fprintf (stream
, "void"); (*ptr
)++; break;
577 for ((*ptr
)++; (*ptr
)<limit
&& *(*ptr
) != ';'; (*ptr
)++)
578 jcf_print_char (stream
, *(*ptr
) == '/' ? '.' : *(*ptr
));
583 jcf_print_char (stream
, *(*ptr
)++);
588 DEFUN(print_signature
, (stream
, jcf
, signature_index
, int options
),
589 FILE* stream AND JCF
*jcf AND
int signature_index AND
int options
)
591 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
592 print_constant_terse (out
, jcf
, signature_index
, CONSTANT_Utf8
);
595 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, signature_index
);
596 int length
= JPOOL_UTF_LENGTH (jcf
, signature_index
);
597 const unsigned char *limit
;
598 limit
= str
+ length
;
600 fprintf (stream
, "<empty signature string>");
603 if (options
& PRINT_SIGNATURE_RESULT_ONLY
)
605 while (str
< limit
&& *str
++ != ')') ;
607 if (options
& PRINT_SIGNATURE_ARGS_ONLY
)
611 while (str
< limit
&& *str
!= ')')
613 print_signature_type (stream
, &str
, limit
);
615 fputs (", ", stream
);
621 print_signature_type (stream
, &str
, limit
);
624 fprintf (stream
, "<junk:");
625 jcf_print_utf8 (stream
, str
, limit
- str
);
635 DEFUN(print_exception_table
, (jcf
, entries
, count
),
636 JCF
*jcf AND
const unsigned char *entries AND
int count
)
638 /* Print exception table. */
642 const unsigned char *ptr
= entries
;
643 fprintf (out
, "Exceptions (count: %d):\n", i
);
644 for (; --i
>= 0; ptr
+= 8)
646 int start_pc
= GET_u2 (ptr
);
647 int end_pc
= GET_u2 (ptr
+2);
648 int handler_pc
= GET_u2 (ptr
+4);
649 int catch_type
= GET_u2 (ptr
+6);
650 fprintf (out
, " start: %d, end: %d, handler: %d, type: %d",
651 start_pc
, end_pc
, handler_pc
, catch_type
);
653 fputs (" /* finally */", out
);
657 print_constant_terse (out
, jcf
, catch_type
, CONSTANT_Class
);
664 #include "jcf-reader.c"
669 fprintf (stderr
, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
674 DEFUN(process_class
, (jcf
),
678 if (jcf_parse_preamble (jcf
) != 0)
679 fprintf (stderr
, "Not a valid Java .class file.\n");
681 /* Parse and possibly print constant pool */
682 code
= jcf_parse_constant_pool (jcf
);
685 fprintf (stderr
, "error while parsing constant pool\n");
686 exit (FATAL_EXIT_CODE
);
688 code
= verify_constant_pool (jcf
);
691 fprintf (stderr
, "error in constant pool entry #%d\n", code
);
692 exit (FATAL_EXIT_CODE
);
694 if (flag_print_constant_pool
)
695 print_constant_pool (jcf
);
697 jcf_parse_class (jcf
);
698 code
= jcf_parse_fields (jcf
);
701 fprintf (stderr
, "error while parsing fields\n");
702 exit (FATAL_EXIT_CODE
);
704 code
= jcf_parse_methods (jcf
);
707 fprintf (stderr
, "error while parsing methods\n");
708 exit (FATAL_EXIT_CODE
);
710 code
= jcf_parse_final_attributes (jcf
);
713 fprintf (stderr
, "error while parsing final attributes\n");
714 exit (FATAL_EXIT_CODE
);
716 jcf
->filename
= NULL
;
720 DEFUN(main
, (argc
, argv
),
721 int argc AND
char** argv
)
730 for (argi
= 1; argi
< argc
; argi
++)
732 const char *arg
= argv
[argi
];
734 if (arg
[0] != '-' || ! strcmp (arg
, "--"))
737 /* Just let all arguments be given in either "-" or "--" form. */
741 if (strcmp (arg
, "-o") == 0 && argi
+ 1 < argc
)
742 output_file
= argv
[++argi
];
743 else if (strcmp (arg
, "-classpath") == 0 && argi
+ 1 < argc
)
744 jcf_path_classpath_arg (argv
[++argi
]);
745 else if (strcmp (arg
, "-CLASSPATH") == 0 && argi
+ 1 < argc
)
746 jcf_path_CLASSPATH_arg (argv
[++argi
]);
747 else if (strncmp (arg
, "-I", 2) == 0)
748 jcf_path_include_arg (arg
+ 2);
749 else if (strcmp (arg
, "-verbose") == 0)
751 else if (strcmp (arg
, "-print-main") == 0)
753 else if (strcmp (arg
, "-c") == 0)
754 flag_disassemble_methods
++;
755 else if (strcmp (arg
, "-javap") == 0)
757 flag_javap_compatible
++;
758 flag_print_constant_pool
= 0;
762 fprintf (stderr
, "%s: illegal argument\n", argv
[argi
]);
763 return FATAL_EXIT_CODE
;
774 flag_print_fields
= 0;
775 flag_print_methods
= 0;
776 flag_print_constant_pool
= 0;
777 flag_print_attributes
= 0;
778 flag_print_class_info
= 0;
783 out
= fopen (output_file
, "w");
786 fprintf (stderr
, "Cannot open '%s' for output.\n", output_file
);
787 return FATAL_EXIT_CODE
;
795 fprintf (out
, "Reading .class from <standard input>.\n");
797 open_class ("<stdio>", jcf
, stdin
, NULL
);
799 open_class ("<stdio>", jcf
, 0, NULL
);
805 for (; argi
< argc
; argi
++)
807 char *arg
= argv
[argi
];
808 const char *class_filename
= find_class (arg
, strlen (arg
), jcf
, 0);
809 if (class_filename
== NULL
)
810 class_filename
= find_classfile (arg
, jcf
, NULL
);
811 if (class_filename
== NULL
)
813 perror ("Could not find class");
814 return FATAL_EXIT_CODE
;
817 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
819 long compressed_size
, member_size
;
820 int compression_method
, filename_length
, extra_length
;
821 int general_purpose_bits
;
822 const char *filename
;
824 if (flag_print_class_info
)
825 fprintf (out
, "Reading classes from archive %s.\n",
830 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
831 long magic
= JCF_readu4_le (jcf
);
832 if (magic
== 0x02014b50 || magic
== 0x06054b50)
833 break; /* got to central directory */
834 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
836 fprintf (stderr
, "bad format of .zip/.jar archive\n");
837 return FATAL_EXIT_CODE
;
841 general_purpose_bits
= JCF_readu2_le (jcf
);
842 compression_method
= JCF_readu2_le (jcf
);
844 compressed_size
= JCF_readu4_le (jcf
);
845 member_size
= JCF_readu4_le (jcf
);
846 filename_length
= JCF_readu2_le (jcf
);
847 extra_length
= JCF_readu2_le (jcf
);
848 total_length
= filename_length
+ extra_length
850 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
851 jcf_trim_old_input (jcf
);
852 JCF_FILL (jcf
, total_length
);
853 filename
= jcf
->read_ptr
;
854 JCF_SKIP (jcf
, filename_length
);
855 JCF_SKIP (jcf
, extra_length
);
856 if (filename_length
> 0
857 && filename
[filename_length
-1] == '/')
859 if (flag_print_class_info
)
860 fprintf (out
, "[Skipping directory %.*s]\n",
861 filename_length
, filename
);
864 else if (compression_method
!= 0)
866 if (flag_print_class_info
)
867 fprintf (out
, "[Skipping compressed file %.*s]\n",
868 filename_length
, filename
);
871 else if (member_size
< 4
872 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
874 if (flag_print_class_info
)
875 fprintf (out
, "[Skipping non-.class member %.*s]\n",
876 filename_length
, filename
);
881 if (flag_print_class_info
)
882 fprintf (out
, "Reading class member: %.*s.\n",
883 filename_length
, filename
);
887 JCF_SKIP (jcf
, compressed_size
);
891 unsigned char *save_end
;
892 jcf
->filbuf
= jcf_unexpected_eof
;
893 save_end
= jcf
->read_end
;
894 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
896 jcf
->filbuf
= save_filbuf
;
897 jcf
->read_end
= save_end
;
903 if (flag_print_class_info
)
904 fprintf (out
, "Reading .class from %s.\n", class_filename
);
911 return SUCCESS_EXIT_CODE
;
915 DEFUN(disassemble_method
, (jcf
, byte_ops
, len
),
916 JCF
* jcf AND
const unsigned char *byte_ops AND
int len
)
918 #undef AND /* Causes problems with opcodes for iand and land. */
923 if (flag_disassemble_methods
== 0)
925 #define BCODE byte_ops
926 for (PC
= 0; PC
< len
;)
931 switch (byte_ops
[PC
++])
934 /* This is the actual code emitted for each of opcodes in javaops.def.
935 The actual opcode-specific stuff is handled by the OPKIND macro.
936 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
937 Those macros are defiend below. The OPKINDs that do not have any
938 inline parameters (such as BINOP) and therefore do mot need anything
939 else to me printed out just use an empty body. */
941 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
943 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
944 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
948 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
949 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
950 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
951 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
953 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
954 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
956 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
957 These all push a constant onto the opcode stack. */
958 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
959 saw_index = 0, i = (OPERAND_VALUE); \
960 if (oldpc+1 == PC) /* nothing */; \
961 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
962 else fprintf (out, " %d", i);
964 /* Print out operand (a local variable index) for LOAD opcodes.
965 These all push local variable onto the opcode stack. */
966 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
967 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
969 /* Handle STORE opcodes same as LOAD opcodes.
970 These all store a value from the opcode stack in a local variable. */
973 /* Handle more kind of opcodes. */
974 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
975 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
976 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
977 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
978 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
979 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
980 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
982 /* Handle putfield and getfield opcodes, with static versions. */
983 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
984 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
986 /* Print operand for invoke opcodes. */
987 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
988 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
989 if (OPERAND_VALUE) /* for invokeinterface */ \
990 { int nargs = IMMEDIATE_u1; PC++; \
991 fprintf (out, " nargs:%d", nargs); }
993 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
994 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
996 #define ARRAY(OPERAND_TYPE, SUBOP) \
997 ARRAY_##SUBOP(OPERAND_TYPE)
998 /* Handle sub-categories of ARRAY opcodes. */
999 #define ARRAY_LOAD(TYPE) /* nothing */
1000 #define ARRAY_STORE(TYPE) /* nothing */
1001 #define ARRAY_LENGTH(TYPE) /* nothing */
1002 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1003 #define ARRAY_NEW_NUM \
1004 INT_temp = IMMEDIATE_u1; \
1005 { const char *str; \
1006 switch (INT_temp) { \
1007 case 4: str = "boolean"; break; \
1008 case 5: str = "char"; break; \
1009 case 6: str = "float"; break; \
1010 case 7: str = "double"; break; \
1011 case 8: str = "byte"; break; \
1012 case 9: str = "short"; break; \
1013 case 10: str = "int"; break; \
1014 case 11: str = "long"; break; \
1015 default: str = "<unknown type code %d>"; break; \
1017 fputc (' ', out); fprintf (out, str, INT_temp); }
1019 #define ARRAY_NEW_PTR \
1020 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1022 #define ARRAY_NEW_MULTI \
1023 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1024 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1026 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1027 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1029 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1030 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1031 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1033 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1034 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1035 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1037 #undef RET /* Defined by config/i386/i386.h */
1038 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1039 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1041 fprintf (out, " %ld", (long) INT_temp);
1043 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1044 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1046 #define LOOKUP_SWITCH \
1047 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1048 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1049 while (--npairs >= 0) { \
1050 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1051 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1054 #define TABLE_SWITCH \
1055 { jint default_offset = IMMEDIATE_s4; \
1056 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1057 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1058 (long) low, (long) high, (long) default_offset+oldpc); \
1059 for (; low <= high; low++) { \
1060 jint offset = IMMEDIATE_s4; \
1061 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1064 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1065 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1067 #define SPECIAL_IINC(OPERAND_TYPE) \
1068 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1069 fprintf (out, " %d", i); \
1070 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1072 fprintf (out, " %d", i)
1074 #define SPECIAL_WIDE(OPERAND_TYPE) \
1077 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1078 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1079 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1080 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1082 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1083 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1085 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1086 TEST(OPERAND_TYPE, OPERAND_VALUE)
1088 #include "javaop.def"
1091 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1095 fprintf (out
, " %ld", (long) INT_temp
);
1101 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);