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 int 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
*, 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));
90 static void process_class
PROTO ((struct JCF
*));
92 #define PRINT_SIGNATURE_RESULT_ONLY 1
93 #define PRINT_SIGNATURE_ARGS_ONLY 2
96 DEFUN(utf8_equal_string
, (jcf
, index
, value
),
97 JCF
*jcf AND
int index AND
const char * value
)
99 if (CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
)
100 && JPOOL_TAG (jcf
, index
) == CONSTANT_Utf8
)
102 int len
= strlen (value
);
103 if (JPOOL_UTF_LENGTH (jcf
, index
) == len
104 && memcmp (JPOOL_UTF_DATA (jcf
, index
), value
, len
) == 0)
110 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
111 this_class_index = 0; \
112 if (flag_print_class_info) \
114 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
115 (long) MAGIC, (long) MINOR, (long) MAJOR)
117 #define HANDLE_START_CONSTANT_POOL(COUNT) \
118 if (flag_print_constant_pool) \
119 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
121 #define HANDLE_SOURCEFILE(INDEX) \
122 { fprintf (out, "Attribute "); \
123 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
124 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
125 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
127 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
128 this_class_index = THIS; \
129 class_access_flags = ACCESS_FLAGS; \
130 if (flag_print_class_info) \
131 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
132 print_access_flags (out, ACCESS_FLAGS, 'c'); \
134 fprintf (out, "This class: "); \
135 if (flag_print_constant_pool) \
136 fprintf (out, "%d=", THIS); \
137 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
138 if (flag_print_constant_pool || SUPER != 0) \
139 fprintf (out, ", super: "); \
140 if (flag_print_constant_pool) \
142 fprintf (out, "%d", SUPER); \
147 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
148 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
151 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
152 (flag_print_attributes <= 0)
154 #define HANDLE_CLASS_INTERFACE(INDEX) \
155 if (flag_print_class_info) \
156 { fprintf (out, "- Implements: %d=", INDEX); \
157 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
160 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
161 if (flag_print_fields) \
162 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
164 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
165 if (flag_print_fields) \
166 { fprintf (out, "Field name:"); \
167 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
168 print_access_flags (out, ACCESS_FLAGS, 'f'); \
169 fprintf (out, " Signature: "); \
170 if (flag_print_constant_pool) \
171 fprintf (out, "%d=", SIGNATURE); \
172 print_signature (out, jcf, SIGNATURE, 0); \
173 fputc ('\n', out); } \
175 flag_print_attributes--;
177 #define HANDLE_END_FIELD() \
178 if (! flag_print_fields) \
179 flag_print_attributes++;
181 #define HANDLE_START_METHODS(METHODS_COUNT) \
182 if (flag_print_methods) \
183 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
185 flag_print_attributes--;
188 #define HANDLE_END_METHODS() \
189 if (! flag_print_methods) \
190 flag_print_attributes++;
192 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
194 if (flag_print_methods) \
196 if (flag_javap_compatible) \
198 fprintf (out, " "); \
199 print_access_flags (out, ACCESS_FLAGS, 'm'); \
201 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
203 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
204 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
209 fprintf (out, "\nMethod name:"); \
210 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
211 print_access_flags (out, ACCESS_FLAGS, 'm'); \
212 fprintf (out, " Signature: "); \
213 if (flag_print_constant_pool) \
214 fprintf (out, "%d=", SIGNATURE); \
215 print_signature (out, jcf, SIGNATURE, 0); \
219 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
220 && utf8_equal_string (jcf, NAME, "main") \
221 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
222 && this_class_index > 0 \
223 && (class_access_flags & ACC_PUBLIC)) \
225 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
230 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
231 ( fprintf (out, "Attribute "), \
232 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
233 fprintf (out, ", length:%ld", (long) LENGTH) )
235 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
236 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
237 fprintf (out, ", value: "), \
238 print_constant_ref (out, jcf, VALUE_INDEX), \
239 fprintf (out, "\n") )
241 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
242 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
243 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
244 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
245 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
247 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
248 print_exception_table (jcf, ENTRIES, COUNT)
250 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
251 { int n = (COUNT); int i; \
252 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
253 fprintf (out, ", count: %d\n", n); \
254 for (i = 0; i < n; i++) {\
255 int ex_index = JCF_readu2 (jcf); \
256 fprintf (out, "%3d: ", i); \
257 print_constant_ref (out, jcf, ex_index); \
258 fputc ('\n', out); } }
260 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
261 { int n = (COUNT); int i; \
262 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
263 fprintf (out, ", count: %d\n", n); \
264 for (i = 0; i < n; i++) {\
265 int start_pc = JCF_readu2 (jcf); \
266 int length = JCF_readu2 (jcf); \
267 int name_index = JCF_readu2 (jcf); \
268 int signature_index = JCF_readu2 (jcf); \
269 int slot = JCF_readu2 (jcf); \
270 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
271 print_name (out, jcf, name_index); \
272 fprintf (out, ", type: %d=", signature_index); \
273 print_signature (out, jcf, signature_index, 0); \
274 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
276 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
277 { int n = (COUNT); int i; \
278 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
279 fprintf (out, ", count: %d\n", n); \
280 if (flag_disassemble_methods) \
281 for (i = 0; i < n; i++) {\
282 int start_pc = JCF_readu2 (jcf); \
283 int line_number = JCF_readu2 (jcf); \
284 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
286 JCF_SKIP (jcf, 4 * n); }
288 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
289 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
290 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
292 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
293 if (flag_print_attributes > 0) \
294 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
299 DEFUN(print_constant_ref
, (stream
, jcf
, index
),
300 FILE *stream AND JCF
*jcf AND
int index
)
302 fprintf (stream
, "#%d=<", index
);
303 if (index
<= 0 || index
>= JPOOL_SIZE(jcf
))
304 fprintf (stream
, "out of range");
306 print_constant (stream
, jcf
, index
, 1);
307 fprintf (stream
, ">");
310 /* Print the access flags given by FLAGS.
311 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
312 or 'm' (method flags). */
315 DEFUN (print_access_flags
, (stream
, flags
, context
),
316 FILE *stream AND uint16 flags AND
char context
)
318 if (flags
& ACC_PUBLIC
) fprintf (stream
, " public");
319 if (flags
& ACC_PRIVATE
) fprintf (stream
, " private");
320 if (flags
& ACC_PROTECTED
) fprintf (stream
, " protected");
321 if (flags
& ACC_STATIC
) fprintf (stream
, " static");
322 if (flags
& ACC_FINAL
) fprintf (stream
, " final");
323 if (flags
& ACC_SYNCHRONIZED
)
326 fprintf (stream
, " super");
328 fprintf (stream
, " synchronized");
330 if (flags
& ACC_VOLATILE
) fprintf (stream
, " volatile");
331 if (flags
& ACC_TRANSIENT
) fprintf (stream
, " transient");
332 if (flags
& ACC_NATIVE
) fprintf (stream
, " native");
333 if (flags
& ACC_INTERFACE
) fprintf (stream
, " interface");
334 if (flags
& ACC_ABSTRACT
) fprintf (stream
, " abstract");
339 DEFUN(print_name
, (stream
, jcf
, name_index
),
340 FILE* stream AND JCF
* jcf AND
int name_index
)
342 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
343 fprintf (stream
, "<not a UTF8 constant>");
345 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
,name_index
),
346 JPOOL_UTF_LENGTH (jcf
, name_index
));
349 /* If the type of the constant at INDEX matches EXPECTED,
350 print it tersely, otherwise more verbosely. */
353 DEFUN(print_constant_terse
, (out
, jcf
, index
, expected
),
354 FILE *out AND JCF
*jcf AND
int index AND
int expected
)
356 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
))
357 fprintf (out
, "<constant pool index %d not in range>", index
);
358 else if (JPOOL_TAG (jcf
, index
) != expected
)
360 fprintf (out
, "<Unexpected constant type ");
361 print_constant (out
, jcf
, index
, 1);
365 print_constant (out
, jcf
, index
, 0);
368 /* Print the constant at INDEX in JCF's constant pool.
369 If verbosity==0, print very tersely (no extraneous text).
370 If verbosity==1, prefix the type of the constant.
371 If verbosity==2, add more descriptive text. */
374 DEFUN(print_constant
, (out
, jcf
, index
, verbosity
),
375 FILE *out AND JCF
*jcf AND
int index AND
int verbosity
)
380 int kind
= JPOOL_TAG (jcf
, index
);
384 n
= JPOOL_USHORT1 (jcf
, index
);
386 fprintf (out
, verbosity
> 1 ? "Class name: %d=" : "Class ", n
);
387 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, n
))
388 fprintf (out
, "<out of range>");
389 else if (verbosity
< 2 && JPOOL_TAG (jcf
, n
) == CONSTANT_Utf8
)
391 int len
= JPOOL_UTF_LENGTH (jcf
, n
);
392 jcf_print_utf8_replace (out
, JPOOL_UTF_DATA(jcf
,n
), len
, '/', '.');
395 print_constant_terse (out
, jcf
, n
, CONSTANT_Utf8
);
397 case CONSTANT_Fieldref
:
398 str
= "Field"; goto field_or_method
;
399 case CONSTANT_Methodref
:
400 str
= "Method"; goto field_or_method
;
401 case CONSTANT_InterfaceMethodref
:
402 str
= "InterfaceMethod"; goto field_or_method
;
405 uint16 tclass
= JPOOL_USHORT1 (jcf
, index
);
406 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
408 fprintf (out
, "%sref class: %d=", str
, tclass
);
409 else if (verbosity
> 0)
410 fprintf (out
, "%s ", str
);
411 print_constant_terse (out
, jcf
, tclass
, CONSTANT_Class
);
412 fprintf (out
, verbosity
< 2 ? "." : " name_and_type: %d=<",
414 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
419 case CONSTANT_String
:
420 j
= JPOOL_USHORT1 (jcf
, index
);
422 fprintf (out
, verbosity
> 1 ? "String %d=" : "String ", j
);
423 print_constant_terse (out
, jcf
, j
, CONSTANT_Utf8
);
425 case CONSTANT_Integer
:
427 fprintf (out
, "Integer ");
428 num
= JPOOL_INT (jcf
, index
);
432 fprintf (out
, "Long ");
433 num
= JPOOL_LONG (jcf
, index
);
438 format_int (buffer
, num
, 10);
439 fprintf (out
, "%s", buffer
);
442 format_uint (buffer
, (uint64
)num
, 16);
443 fprintf (out
, "=0x%s", buffer
);
449 jfloat fnum
= JPOOL_FLOAT (jcf
, index
);
450 fprintf (out
, "%s%.10g", verbosity
> 1 ? "Float " : "", (double) fnum
);
452 fprintf (out
, ", bits = 0x%08lx", (long) (* (int32
*) &fnum
));
455 case CONSTANT_Double
:
457 jdouble dnum
= JPOOL_DOUBLE (jcf
, index
);
458 fprintf (out
, "%s%.20g", verbosity
> 1 ? "Double " : "", dnum
);
462 hi
= JPOOL_UINT (jcf
, index
);
463 lo
= JPOOL_UINT (jcf
, index
+ 1);
464 fprintf (out
, ", bits = 0x%08lx%08lx", (long) hi
, (long) lo
);
468 case CONSTANT_NameAndType
:
470 uint16 name
= JPOOL_USHORT1 (jcf
, index
);
471 uint16 sig
= JPOOL_USHORT2 (jcf
, index
);
473 fprintf (out
, verbosity
> 1 ? "%s name: %d=" : "%s ",
474 "NameAndType", name
);
475 print_name (out
, jcf
, name
);
479 fprintf (out
, ", signature: %d=", sig
);
480 print_signature (out
, jcf
, sig
, 0);
485 register unsigned char *str
= JPOOL_UTF_DATA (jcf
, index
);
486 int length
= JPOOL_UTF_LENGTH (jcf
, index
);
488 { /* Print as 8-bit bytes. */
489 fputs ("Utf8: \"", out
);
490 while (--length
>= 0)
491 jcf_print_char (out
, *str
++);
494 { /* Print as Unicode. */
496 jcf_print_utf8 (out
, str
, length
);
502 fprintf (out
, "(Unknown constant type %d)", kind
);
507 DEFUN(print_constant_pool
, (jcf
),
511 for (i
= 1; i
< JPOOL_SIZE(jcf
); i
++)
513 int kind
= JPOOL_TAG (jcf
, i
);
514 fprintf (out
, "#%d: ", i
);
515 print_constant (out
, jcf
, i
, 2);
517 if (kind
== CONSTANT_Double
|| kind
== CONSTANT_Long
)
518 i
++; /* These take up two slots in the constant table */
523 DEFUN(print_signature_type
, (stream
, ptr
, limit
),
524 FILE* stream AND
const unsigned char **ptr AND
const unsigned char *limit
)
533 for ((*ptr
)++; (*ptr
) < limit
&& ISDIGIT (**ptr
); (*ptr
)++)
535 array_size
= (array_size
< 0 ? 0 : 10 * array_size
) + *(*ptr
) - '0';
537 print_signature_type (stream
, ptr
, limit
);
538 if (array_size
== -1)
539 fprintf (stream
, "[]");
541 fprintf (stream
, "[%d]", array_size
);
546 fputc (*(*ptr
)++, stream
);
547 for (; **ptr
!= ')' && *ptr
< limit
; nargs
++)
551 print_signature_type (stream
, ptr
, limit
);
555 fputc (*(*ptr
)++, stream
);
556 print_signature_type (stream
, ptr
, limit
);
559 fprintf (stream
, "???");
563 case 'B': fprintf (stream
, "byte"); (*ptr
)++; break;
564 case 'C': fprintf (stream
, "char"); (*ptr
)++; break;
565 case 'D': fprintf (stream
, "double"); (*ptr
)++; break;
566 case 'F': fprintf (stream
, "float"); (*ptr
)++; break;
567 case 'S': fprintf (stream
, "short"); (*ptr
)++; break;
568 case 'I': fprintf (stream
, "int"); (*ptr
)++; break;
569 case 'J': fprintf (stream
, "long"); (*ptr
)++; break;
570 case 'Z': fprintf (stream
, "boolean"); (*ptr
)++; break;
571 case 'V': fprintf (stream
, "void"); (*ptr
)++; break;
574 for ((*ptr
)++; (*ptr
)<limit
&& *(*ptr
) != ';'; (*ptr
)++)
575 jcf_print_char (stream
, *(*ptr
) == '/' ? '.' : *(*ptr
));
580 jcf_print_char (stream
, *(*ptr
)++);
585 DEFUN(print_signature
, (stream
, jcf
, signature_index
, int options
),
586 FILE* stream AND JCF
*jcf AND
int signature_index AND
int options
)
588 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
589 print_constant_terse (out
, jcf
, signature_index
, CONSTANT_Utf8
);
592 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, signature_index
);
593 int length
= JPOOL_UTF_LENGTH (jcf
, signature_index
);
594 const unsigned char *limit
;
595 limit
= str
+ length
;
597 fprintf (stream
, "<empty signature string>");
600 if (options
& PRINT_SIGNATURE_RESULT_ONLY
)
602 while (str
< limit
&& *str
++ != ')') ;
604 if (options
& PRINT_SIGNATURE_ARGS_ONLY
)
608 while (str
< limit
&& *str
!= ')')
610 print_signature_type (stream
, &str
, limit
);
612 fputs (", ", stream
);
618 print_signature_type (stream
, &str
, limit
);
621 fprintf (stream
, "<junk:");
622 jcf_print_utf8 (stream
, str
, limit
- str
);
632 DEFUN(print_exception_table
, (jcf
, entries
, count
),
633 JCF
*jcf AND
unsigned char *entries AND
int count
)
635 /* Print exception table. */
639 unsigned char *ptr
= entries
;
640 fprintf (out
, "Exceptions (count: %d):\n", i
);
641 for (; --i
>= 0; ptr
+= 8)
643 int start_pc
= GET_u2 (ptr
);
644 int end_pc
= GET_u2 (ptr
+2);
645 int handler_pc
= GET_u2 (ptr
+4);
646 int catch_type
= GET_u2 (ptr
+6);
647 fprintf (out
, " start: %d, end: %d, handler: %d, type: %d",
648 start_pc
, end_pc
, handler_pc
, catch_type
);
650 fputs (" /* finally */", out
);
654 print_constant_terse (out
, jcf
, catch_type
, CONSTANT_Class
);
661 #include "jcf-reader.c"
666 fprintf (stderr
, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
671 DEFUN(process_class
, (jcf
),
675 if (jcf_parse_preamble (jcf
) != 0)
676 fprintf (stderr
, "Not a valid Java .class file.\n");
678 /* Parse and possibly print constant pool */
679 code
= jcf_parse_constant_pool (jcf
);
682 fprintf (stderr
, "error while parsing constant pool\n");
683 exit (FATAL_EXIT_CODE
);
685 code
= verify_constant_pool (jcf
);
688 fprintf (stderr
, "error in constant pool entry #%d\n", code
);
689 exit (FATAL_EXIT_CODE
);
691 if (flag_print_constant_pool
)
692 print_constant_pool (jcf
);
694 jcf_parse_class (jcf
);
695 code
= jcf_parse_fields (jcf
);
698 fprintf (stderr
, "error while parsing fields\n");
699 exit (FATAL_EXIT_CODE
);
701 code
= jcf_parse_methods (jcf
);
704 fprintf (stderr
, "error while parsing methods\n");
705 exit (FATAL_EXIT_CODE
);
707 code
= jcf_parse_final_attributes (jcf
);
710 fprintf (stderr
, "error while parsing final attributes\n");
711 exit (FATAL_EXIT_CODE
);
713 jcf
->filename
= NULL
;
717 DEFUN(main
, (argc
, argv
),
718 int argc AND
char** argv
)
727 for (argi
= 1; argi
< argc
; argi
++)
729 char *arg
= argv
[argi
];
731 if (arg
[0] != '-' || ! strcmp (arg
, "--"))
734 /* Just let all arguments be given in either "-" or "--" form. */
738 if (strcmp (arg
, "-o") == 0 && argi
+ 1 < argc
)
739 output_file
= argv
[++argi
];
740 else if (strcmp (arg
, "-classpath") == 0 && argi
+ 1 < argc
)
741 jcf_path_classpath_arg (argv
[++argi
]);
742 else if (strcmp (arg
, "-CLASSPATH") == 0 && argi
+ 1 < argc
)
743 jcf_path_CLASSPATH_arg (argv
[++argi
]);
744 else if (strncmp (arg
, "-I", 2) == 0)
745 jcf_path_include_arg (arg
+ 2);
746 else if (strcmp (arg
, "-verbose") == 0)
748 else if (strcmp (arg
, "-print-main") == 0)
750 else if (strcmp (arg
, "-c") == 0)
751 flag_disassemble_methods
++;
752 else if (strcmp (arg
, "-javap") == 0)
754 flag_javap_compatible
++;
755 flag_print_constant_pool
= 0;
759 fprintf (stderr
, "%s: illegal argument\n", argv
[argi
]);
760 exit (FATAL_EXIT_CODE
);
771 flag_print_fields
= 0;
772 flag_print_methods
= 0;
773 flag_print_constant_pool
= 0;
774 flag_print_attributes
= 0;
775 flag_print_class_info
= 0;
780 out
= fopen (output_file
, "w");
783 fprintf (stderr
, "Cannot open '%s' for output.\n", output_file
);
784 exit (FATAL_EXIT_CODE
);
792 fprintf (out
, "Reading .class from <standard input>.\n");
794 open_class ("<stdio>", jcf
, stdin
, NULL
);
796 open_class ("<stdio>", jcf
, 0, NULL
);
802 for (; argi
< argc
; argi
++)
804 char *arg
= argv
[argi
];
805 char* class_filename
= find_class (arg
, strlen (arg
), jcf
, 0);
806 if (class_filename
== NULL
)
807 class_filename
= find_classfile (arg
, jcf
, NULL
);
808 if (class_filename
== NULL
)
810 perror ("Could not find class");
811 exit (FATAL_EXIT_CODE
);
814 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
816 long compressed_size
, member_size
;
817 int compression_method
, filename_length
, extra_length
;
818 int general_purpose_bits
;
821 if (flag_print_class_info
)
822 fprintf (out
, "Reading classes from archive %s.\n",
827 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
828 long magic
= JCF_readu4_le (jcf
);
829 if (magic
== 0x02014b50 || magic
== 0x06054b50)
830 break; /* got to central directory */
831 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
833 fprintf (stderr
, "bad format of .zip/.jar archive\n");
834 exit (FATAL_EXIT_CODE
);
838 general_purpose_bits
= JCF_readu2_le (jcf
);
839 compression_method
= JCF_readu2_le (jcf
);
841 compressed_size
= JCF_readu4_le (jcf
);
842 member_size
= JCF_readu4_le (jcf
);
843 filename_length
= JCF_readu2_le (jcf
);
844 extra_length
= JCF_readu2_le (jcf
);
845 total_length
= filename_length
+ extra_length
847 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
848 jcf_trim_old_input (jcf
);
849 JCF_FILL (jcf
, total_length
);
850 filename
= jcf
->read_ptr
;
851 JCF_SKIP (jcf
, filename_length
);
852 JCF_SKIP (jcf
, extra_length
);
853 if (filename_length
> 0
854 && filename
[filename_length
-1] == '/')
856 if (flag_print_class_info
)
857 fprintf (out
, "[Skipping directory %.*s]\n",
858 filename_length
, filename
);
861 else if (compression_method
!= 0)
863 if (flag_print_class_info
)
864 fprintf (out
, "[Skipping compressed file %.*s]\n",
865 filename_length
, filename
);
868 else if (member_size
< 4
869 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
871 if (flag_print_class_info
)
872 fprintf (out
, "[Skipping non-.class member %.*s]\n",
873 filename_length
, filename
);
878 if (flag_print_class_info
)
879 fprintf (out
, "Reading class member: %.*s.\n",
880 filename_length
, filename
);
884 JCF_SKIP (jcf
, compressed_size
);
888 unsigned char *save_end
;
889 jcf
->filbuf
= jcf_unexpected_eof
;
890 save_end
= jcf
->read_end
;
891 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
893 jcf
->filbuf
= save_filbuf
;
894 jcf
->read_end
= save_end
;
900 if (flag_print_class_info
)
901 fprintf (out
, "Reading .class from %s.\n", class_filename
);
908 exit (SUCCESS_EXIT_CODE
);
912 DEFUN(disassemble_method
, (jcf
, byte_ops
, len
),
913 JCF
* jcf AND
unsigned char *byte_ops AND
int len
)
915 #undef AND /* Causes problems with opcodes for iand and land. */
920 if (flag_disassemble_methods
== 0)
922 #define BCODE byte_ops
923 for (PC
= 0; PC
< len
;)
928 switch (byte_ops
[PC
++])
931 /* This is the actual code emitted for each of opcodes in javaops.def.
932 The actual opcode-specific stuff is handled by the OPKIND macro.
933 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
934 Those macros are defiend below. The OPKINDs that do not have any
935 inline parameters (such as BINOP) and therefore do mot need anything
936 else to me printed out just use an empty body. */
938 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
940 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
941 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
945 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
946 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
947 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
948 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
950 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
951 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
953 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
954 These all push a constant onto the opcode stack. */
955 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
956 saw_index = 0, i = (OPERAND_VALUE); \
957 if (oldpc+1 == PC) /* nothing */; \
958 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
959 else fprintf (out, " %d", i);
961 /* Print out operand (a local variable index) for LOAD opcodes.
962 These all push local variable onto the opcode stack. */
963 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
964 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
966 /* Handle STORE opcodes same as LOAD opcodes.
967 These all store a value from the opcode stack in a local variable. */
970 /* Handle more kind of opcodes. */
971 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
972 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
973 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
974 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
975 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
976 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
977 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
979 /* Handle putfield and getfield opcodes, with static versions. */
980 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
981 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
983 /* Print operand for invoke opcodes. */
984 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
985 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
986 if (OPERAND_VALUE) /* for invokeinterface */ \
987 { int nargs = IMMEDIATE_u1; PC++; \
988 fprintf (out, " nargs:%d", nargs); }
990 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
991 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
993 #define ARRAY(OPERAND_TYPE, SUBOP) \
994 ARRAY_##SUBOP(OPERAND_TYPE)
995 /* Handle sub-categories of ARRAY opcodes. */
996 #define ARRAY_LOAD(TYPE) /* nothing */
997 #define ARRAY_STORE(TYPE) /* nothing */
998 #define ARRAY_LENGTH(TYPE) /* nothing */
999 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1000 #define ARRAY_NEW_NUM \
1001 INT_temp = IMMEDIATE_u1; \
1003 switch (INT_temp) { \
1004 case 4: str = "boolean"; break; \
1005 case 5: str = "char"; break; \
1006 case 6: str = "float"; break; \
1007 case 7: str = "double"; break; \
1008 case 8: str = "byte"; break; \
1009 case 9: str = "short"; break; \
1010 case 10: str = "int"; break; \
1011 case 11: str = "long"; break; \
1012 default: str = "<unknown type code %d>"; break; \
1014 fputc (' ', out); fprintf (out, str, INT_temp); }
1016 #define ARRAY_NEW_PTR \
1017 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1019 #define ARRAY_NEW_MULTI \
1020 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1021 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1023 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1024 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1026 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1027 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1028 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1030 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1031 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1032 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1034 #undef RET /* Defined by config/i386/i386.h */
1035 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1036 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1038 fprintf (out, " %ld", (long) INT_temp);
1040 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1041 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1043 #define LOOKUP_SWITCH \
1044 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1045 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1046 while (--npairs >= 0) { \
1047 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1048 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1051 #define TABLE_SWITCH \
1052 { jint default_offset = IMMEDIATE_s4; \
1053 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1054 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1055 (long) low, (long) high, (long) default_offset+oldpc); \
1056 for (; low <= high; low++) { \
1057 jint offset = IMMEDIATE_s4; \
1058 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1061 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1062 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1064 #define SPECIAL_IINC(OPERAND_TYPE) \
1065 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1066 fprintf (out, " %d", i); \
1067 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1069 fprintf (out, " %d", i)
1071 #define SPECIAL_WIDE(OPERAND_TYPE) \
1074 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1075 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1076 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1077 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1079 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1080 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1082 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1083 TEST(OPERAND_TYPE, OPERAND_VALUE)
1085 #include "javaop.def"
1088 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1092 fprintf (out
, " %ld", (long) INT_temp
);
1098 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);