1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996-2015 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
29 jcf-dump is a program to print out the contents of class files.
30 Usage: jcf-dump [FLAGS] CLASS
32 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
33 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
34 + The name of a .zip or .jar file (which prints all the classes in the
39 Dis-assemble each method.
43 Print nothing if there is no valid "main" method;
44 otherwise, print only the class name.
46 Print output in the style of Sun's javap program. VERY UNFINISHED.
52 #include "coretypes.h"
54 #include "diagnostic.h"
60 #include "double-int.h"
68 #include "java-tree.h"
77 /* Name of output file, if NULL if stdout. */
78 char *output_file
= NULL
;
82 int flag_disassemble_methods
= 0;
83 int flag_print_class_info
= 1;
84 int flag_print_constant_pool
= 0;
85 int flag_print_fields
= 1;
86 int flag_print_methods
= 1;
87 int flag_print_attributes
= 1;
89 /* Print names of classes that have a "main" method. */
90 int flag_print_main
= 0;
92 /* Index in constant pool of this class. */
93 int this_class_index
= 0;
95 int class_access_flags
= 0;
97 /* Print in format similar to javap. VERY INCOMPLETE. */
98 int flag_javap_compatible
= 0;
100 static void print_access_flags (FILE *, uint16
, char);
101 static void print_constant_terse (FILE*, JCF
*, int, int);
102 static void print_constant_terse_with_index (FILE *, JCF
*, int, int);
103 static void print_constant (FILE *, JCF
*, int, int);
104 static void print_constant_ref (FILE *, JCF
*, int);
105 static void disassemble_method (JCF
*, const unsigned char *, int);
106 static void print_name (FILE*, JCF
*, int);
107 static void print_signature (FILE*, JCF
*, int, int);
108 static int utf8_equal_string (struct JCF
*, int, const char *);
109 static void usage (void) ATTRIBUTE_NORETURN
;
110 static void help (void) ATTRIBUTE_NORETURN
;
111 static void version (void) ATTRIBUTE_NORETURN
;
112 static void process_class (struct JCF
*);
113 static void print_constant_pool (struct JCF
*);
114 static void print_exception_table (struct JCF
*, const unsigned char *entries
,
116 static void indent (FILE *, int);
117 static void print_element_value (FILE *, JCF
*, int);
118 static void print_annotation (FILE *, JCF
*, int);
119 static void print_annotations (FILE *, JCF
*, int);
120 static void print_parameter_annotations (FILE *, JCF
*, int);
122 #define PRINT_SIGNATURE_RESULT_ONLY 1
123 #define PRINT_SIGNATURE_ARGS_ONLY 2
126 utf8_equal_string (JCF
*jcf
, int index
, const char * value
)
128 if (CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
)
129 && JPOOL_TAG (jcf
, index
) == CONSTANT_Utf8
)
131 int len
= strlen (value
);
132 if (JPOOL_UTF_LENGTH (jcf
, index
) == len
133 && memcmp (JPOOL_UTF_DATA (jcf
, index
), value
, len
) == 0)
139 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
140 this_class_index = 0; \
141 if (flag_print_class_info) \
143 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
144 (unsigned long) MAGIC, (long) MINOR, (long) MAJOR)
146 #define HANDLE_START_CONSTANT_POOL(COUNT) \
147 if (flag_print_constant_pool) \
148 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
150 #define HANDLE_SOURCEFILE(INDEX) \
151 { fprintf (out, "Attribute "); \
152 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
153 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
154 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
156 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
157 this_class_index = THIS; \
158 class_access_flags = ACCESS_FLAGS; \
159 if (flag_print_class_info) \
160 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
161 print_access_flags (out, ACCESS_FLAGS, 'c'); \
163 fprintf (out, "This class: "); \
164 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
165 if (flag_print_constant_pool || SUPER != 0) \
166 fprintf (out, ", super: "); \
167 if (flag_print_constant_pool) \
169 fprintf (out, "%d", SUPER); \
174 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
175 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
178 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
179 (flag_print_attributes <= 0)
181 #define HANDLE_CLASS_INTERFACE(INDEX) \
182 if (flag_print_class_info) \
183 { fprintf (out, "- Implements: "); \
184 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
187 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
188 if (flag_print_fields) \
189 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
191 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
192 if (flag_print_fields) \
193 { fprintf (out, "Field name:"); \
194 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
195 print_access_flags (out, ACCESS_FLAGS, 'f'); \
196 fprintf (out, " Descriptor: "); \
197 if (flag_print_constant_pool) \
198 fprintf (out, "%d=", SIGNATURE); \
199 print_signature (out, jcf, SIGNATURE, 0); \
200 fputc ('\n', out); } \
202 flag_print_attributes--;
204 #define HANDLE_END_FIELD() \
205 if (! flag_print_fields) \
206 flag_print_attributes++;
208 #define HANDLE_START_METHODS(METHODS_COUNT) \
209 if (flag_print_methods) \
210 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
212 flag_print_attributes--;
215 #define HANDLE_END_METHODS() \
216 if (! flag_print_methods) \
217 flag_print_attributes++;
219 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
221 if (flag_print_methods) \
223 if (flag_javap_compatible) \
225 fprintf (out, " "); \
226 print_access_flags (out, ACCESS_FLAGS, 'm'); \
228 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
230 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
231 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
236 fprintf (out, "\nMethod name:"); \
237 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
238 print_access_flags (out, ACCESS_FLAGS, 'm'); \
239 fprintf (out, " Descriptor: "); \
240 if (flag_print_constant_pool) \
241 fprintf (out, "%d=", SIGNATURE); \
242 print_signature (out, jcf, SIGNATURE, 0); \
246 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
247 && utf8_equal_string (jcf, NAME, "main") \
248 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
249 && this_class_index > 0 \
250 && (class_access_flags & ACC_PUBLIC)) \
252 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
257 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
258 ( fprintf (out, "Attribute "), \
259 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
260 fprintf (out, ", length:%ld", (long) LENGTH) )
262 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
263 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
264 fprintf (out, ", value: "), \
265 print_constant_ref (out, jcf, VALUE_INDEX), \
266 fprintf (out, "\n") )
268 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
269 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
270 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
271 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
272 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
274 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
275 print_exception_table (jcf, ENTRIES, COUNT)
277 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
278 { int n = (COUNT); int i; \
279 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
280 fprintf (out, ", count: %d\n", n); \
281 for (i = 0; i < n; i++) {\
282 int ex_index = JCF_readu2 (jcf); \
283 fprintf (out, "%3d: ", i); \
284 print_constant_ref (out, jcf, ex_index); \
285 fputc ('\n', out); } }
287 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
288 { int n = (COUNT); int i; \
289 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
290 fprintf (out, ", count: %d\n", n); \
291 for (i = 0; i < n; i++) {\
292 int start_pc = JCF_readu2 (jcf); \
293 int length = JCF_readu2 (jcf); \
294 int name_index = JCF_readu2 (jcf); \
295 int signature_index = JCF_readu2 (jcf); \
296 int slot = JCF_readu2 (jcf); \
297 fprintf (out, " slot#%d: name: ", slot); \
298 if (flag_print_constant_pool) \
299 fprintf (out, "%d=", name_index); \
300 print_name (out, jcf, name_index); \
301 fprintf (out, ", type: "); \
302 if (flag_print_constant_pool) \
303 fprintf (out, "%d=", signature_index); \
304 print_signature (out, jcf, signature_index, 0); \
305 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
307 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \
308 { int n = (COUNT); int i; \
309 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
310 fprintf (out, ", count: %d\n", n); \
311 for (i = 0; i < n; i++) { \
312 int start_pc = JCF_readu2 (jcf); \
313 int length = JCF_readu2 (jcf); \
314 int name_index = JCF_readu2 (jcf); \
315 int signature_index = JCF_readu2 (jcf); \
316 int slot = JCF_readu2 (jcf); \
317 fprintf (out, " slot#%d: name: ", slot); \
318 if (flag_print_constant_pool) \
319 fprintf (out, "%d=", name_index); \
320 print_name (out, jcf, name_index); \
321 fprintf (out, ", type: "); \
322 if (flag_print_constant_pool) \
323 fprintf (out, "%d=", signature_index); \
324 print_signature (out, jcf, signature_index, 0); \
325 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
327 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
328 { int n = (COUNT); int i; \
329 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
330 fprintf (out, ", count: %d\n", n); \
331 if (flag_disassemble_methods) \
332 for (i = 0; i < n; i++) {\
333 int start_pc = JCF_readu2 (jcf); \
334 int line_number = JCF_readu2 (jcf); \
335 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
337 JCF_SKIP (jcf, 4 * n); }
339 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
341 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
344 uint16 inner_class_info_index = JCF_readu2 (jcf); \
345 uint16 outer_class_info_index = JCF_readu2 (jcf); \
346 uint16 inner_name_index = JCF_readu2 (jcf); \
347 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
349 if (flag_print_class_info) \
351 fprintf (out, "\n inner: "); \
352 if (inner_class_info_index == 0) \
353 fprintf (out, " (no inner info index)"); \
355 print_constant_terse_with_index (out, jcf, \
356 inner_class_info_index, \
358 if (inner_name_index == 0) \
359 fprintf (out, " (anonymous)"); \
360 else if (verbose || flag_print_constant_pool) \
362 fprintf (out, " ("); \
363 print_constant_terse_with_index (out, jcf, inner_name_index, \
367 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
368 print_access_flags (out, inner_class_access_flags, 'c'); \
369 fprintf (out, ", outer class: "); \
370 if (outer_class_info_index == 0) \
371 fprintf (out, "(not a member)"); \
373 print_constant_terse_with_index (out, jcf, \
374 outer_class_info_index, \
378 if (flag_print_class_info) \
382 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
383 { int i, n = (LENGTH), c = 0; \
384 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
386 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
387 if (c != '\r' && c != '\n') fputc('\n', out); }
389 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \
390 { uint16 class_index, method_index; \
391 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
392 class_index = JCF_readu2 (jcf); \
393 method_index = JCF_readu2 (jcf); \
394 fprintf (out, "\n Class: "); \
395 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
396 fprintf (out, "\n Method: "); \
397 print_constant_terse_with_index (out, jcf, method_index, \
398 CONSTANT_NameAndType); \
402 #define HANDLE_SIGNATURE_ATTRIBUTE() \
405 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
406 signature = JCF_readu2 (jcf); \
407 fprintf (out, "\n Value: "); \
408 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
412 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
414 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
415 print_annotations (out, jcf, 1); \
418 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
420 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
421 print_annotations (out, jcf, 1); \
424 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
426 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
427 print_parameter_annotations (out, jcf, 1); \
430 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
432 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
433 print_parameter_annotations (out, jcf, 1); \
436 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
438 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
439 print_element_value (out, jcf, 1); \
442 #define HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE() \
444 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
445 fputc ('\n', out); jcf_parse_bootstrap_methods (jcf, attribute_length); \
448 #define HANDLE_END_BOOTSTRAP_METHODS(NUM_METHODS) \
451 for (i = 0; i < NUM_METHODS; i++) \
453 bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; \
454 fprintf (out, " %d: ", i); \
455 print_constant (out, jcf, m->method_ref, 1); \
456 fprintf (out, "\n"); \
460 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
461 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
462 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
464 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
465 if (flag_print_attributes > 0) \
466 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
473 indent (FILE *stream
, int level
)
476 for (i
= 0; i
< level
; ++i
)
477 fprintf (stream
, " ");
481 print_element_value (FILE *stream
, JCF
*jcf
, int level
)
483 uint8 tag
= JCF_readu (jcf
);
484 indent (stream
, level
);
493 uint16 cindex
= JCF_readu2 (jcf
);
494 print_constant_terse_with_index (stream
, jcf
, cindex
,
500 uint16 cindex
= JCF_readu2 (jcf
);
501 print_constant_terse_with_index (stream
, jcf
, cindex
,
507 uint16 cindex
= JCF_readu2 (jcf
);
508 print_constant_terse_with_index (stream
, jcf
, cindex
,
514 uint16 cindex
= JCF_readu2 (jcf
);
515 print_constant_terse_with_index (stream
, jcf
, cindex
,
521 uint16 cindex
= JCF_readu2 (jcf
);
522 /* Despite what the JVM spec says, compilers generate a Utf8
523 constant here, not a String. */
524 print_constant_terse_with_index (stream
, jcf
, cindex
,
531 uint16 type_name_index
= JCF_readu2 (jcf
);
532 uint16 const_name_index
= JCF_readu2 (jcf
);
533 fprintf (stream
, "enum class: ");
534 print_constant_terse_with_index (stream
, jcf
, type_name_index
,
536 fprintf (stream
, "\n");
537 indent (stream
, level
);
538 fprintf (stream
, "Field: ");
539 print_constant_terse_with_index (stream
, jcf
, const_name_index
,
545 uint16 class_info_index
= JCF_readu2 (jcf
);
546 print_constant_terse_with_index (stream
, jcf
, class_info_index
,
552 fprintf (stream
, "Annotation:\n");
553 print_annotation (stream
, jcf
, level
+ 1);
558 uint16 n_array_elts
= JCF_readu2 (jcf
);
559 fprintf (stream
, "array[%d]: [\n", (int) n_array_elts
);
560 while (n_array_elts
--)
561 print_element_value (stream
, jcf
, level
+ 1);
562 indent (stream
, level
);
563 fprintf (stream
, "]");
567 fprintf (stream
, "Unexpected tag value: %d", (int) tag
);
570 fputc ('\n', stream
);
574 print_annotation (FILE *stream
, JCF
*jcf
, int level
)
576 uint16 type_index
= JCF_readu2 (jcf
);
577 uint16 npairs
= JCF_readu2 (jcf
);
578 fprintf (stream
, "\n");
579 indent (stream
, level
);
580 fprintf (stream
, "Annotation name: ");
581 print_constant_terse_with_index (stream
, jcf
, type_index
,
585 fprintf (stream
, "\n");
588 uint16 name_index
= JCF_readu2 (jcf
);
589 indent (stream
, level
+ 1);
590 fprintf (stream
, "Name: ");
591 print_constant_terse_with_index (stream
, jcf
, name_index
,
593 fprintf (stream
, "\n");
594 print_element_value (stream
, jcf
, level
+ 2);
600 print_annotations (FILE *stream
, JCF
*jcf
, int level
)
602 uint16 num
= JCF_readu2 (jcf
);
604 print_annotation (stream
, jcf
, level
);
608 print_parameter_annotations (FILE *stream
, JCF
*jcf
, int level
)
610 uint8 nparams
= JCF_readu (jcf
);
612 for (i
= 0; i
< nparams
; ++i
)
614 indent (stream
, level
);
615 fprintf (stream
, "Parameter annotations (%d):\n", (int) i
);
616 print_annotations (stream
, jcf
, level
+ 1);
623 print_constant_ref (FILE *stream
, JCF
*jcf
, int index
)
625 if (index
<= 0 || index
>= JPOOL_SIZE(jcf
))
626 fprintf (stream
, "<out of range>");
629 if (flag_print_constant_pool
)
630 fprintf (stream
, "#%d=", index
);
632 print_constant (stream
, jcf
, index
, 1);
637 /* Print the access flags given by FLAGS.
638 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
639 or 'm' (method flags). */
642 print_access_flags (FILE *stream
, uint16 flags
, char context
)
644 if (flags
& ACC_PUBLIC
) fprintf (stream
, " public");
645 if (flags
& ACC_PRIVATE
) fprintf (stream
, " private");
646 if (flags
& ACC_PROTECTED
) fprintf (stream
, " protected");
647 if (flags
& ACC_ABSTRACT
) fprintf (stream
, " abstract");
648 if (flags
& ACC_STATIC
) fprintf (stream
, " static");
649 if (flags
& ACC_FINAL
) fprintf (stream
, " final");
650 if (flags
& ACC_TRANSIENT
)
651 fprintf (stream
, context
== 'm' ? " varargs" : " transient");
652 if (flags
& ACC_VOLATILE
)
653 fprintf (stream
, context
== 'm' ? " bridge" : " volatile");
654 if (flags
& ACC_NATIVE
) fprintf (stream
, " native");
655 if (flags
& ACC_SYNCHRONIZED
)
658 fprintf (stream
, " super");
660 fprintf (stream
, " synchronized");
662 if (flags
& ACC_INTERFACE
)
663 fprintf (stream
, (flags
& ACC_ANNOTATION
) ? " @interface" : " interface");
664 if (flags
& ACC_ENUM
) fprintf (stream
, " enum");
665 if (flags
& ACC_STRICT
) fprintf (stream
, " strictfp");
666 if (flags
& ACC_SYNTHETIC
) fprintf (stream
, " synthetic");
671 print_name (FILE* stream
, JCF
* jcf
, int name_index
)
673 if (JPOOL_TAG (jcf
, name_index
) != CONSTANT_Utf8
)
674 fprintf (stream
, "<not a UTF8 constant>");
676 jcf_print_utf8 (stream
, JPOOL_UTF_DATA (jcf
,name_index
),
677 JPOOL_UTF_LENGTH (jcf
, name_index
));
680 /* If the type of the constant at INDEX matches EXPECTED,
681 print it tersely, otherwise more verbosely. */
684 print_constant_terse (FILE *out
, JCF
*jcf
, int index
, int expected
)
686 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, index
))
687 fprintf (out
, "<constant pool index %d not in range>", index
);
688 else if (JPOOL_TAG (jcf
, index
) != expected
)
690 fprintf (out
, "<Unexpected constant type ");
691 print_constant (out
, jcf
, index
, 1);
695 print_constant (out
, jcf
, index
, 0);
699 print_constant_terse_with_index (FILE *out
, JCF
*jcf
, int index
, int expected
)
701 if (flag_print_constant_pool
)
702 fprintf (out
, "%d=", index
);
703 print_constant_terse (out
, jcf
, index
, expected
);
706 /* Print the constant at INDEX in JCF's constant pool.
707 If verbosity==0, print very tersely (no extraneous text).
708 If verbosity==1, prefix the type of the constant.
709 If verbosity==2, add more descriptive text. */
712 print_constant (FILE *out
, JCF
*jcf
, int index
, int verbosity
)
717 int kind
= JPOOL_TAG (jcf
, index
);
721 n
= JPOOL_USHORT1 (jcf
, index
);
725 fprintf (out
, "Class name: %d=", n
);
727 fprintf (out
, "Class ");
729 if (! CPOOL_INDEX_IN_RANGE (&jcf
->cpool
, n
))
730 fprintf (out
, "<out of range>");
731 else if (verbosity
< 2 && JPOOL_TAG (jcf
, n
) == CONSTANT_Utf8
)
733 int len
= JPOOL_UTF_LENGTH (jcf
, n
);
734 jcf_print_utf8_replace (out
, JPOOL_UTF_DATA(jcf
,n
), len
, '/', '.');
737 print_constant_terse (out
, jcf
, n
, CONSTANT_Utf8
);
739 case CONSTANT_Fieldref
:
740 str
= "Field"; goto field_or_method
;
741 case CONSTANT_Methodref
:
742 str
= "Method"; goto field_or_method
;
743 case CONSTANT_InterfaceMethodref
:
744 str
= "InterfaceMethod"; goto field_or_method
;
747 uint16 tclass
= JPOOL_USHORT1 (jcf
, index
);
748 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
750 fprintf (out
, "%sref class: %d=", str
, tclass
);
751 else if (verbosity
> 0)
752 fprintf (out
, "%s ", str
);
753 print_constant_terse (out
, jcf
, tclass
, CONSTANT_Class
);
757 fprintf (out
, " name_and_type: %d=<", name_and_type
);
758 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
763 case CONSTANT_String
:
764 j
= JPOOL_USHORT1 (jcf
, index
);
768 fprintf (out
, "String %d=", j
);
770 fprintf (out
, "String ");
772 print_constant_terse (out
, jcf
, j
, CONSTANT_Utf8
);
774 case CONSTANT_Integer
:
776 fprintf (out
, "Integer ");
777 num
= JPOOL_INT (jcf
, index
);
781 fprintf (out
, "Long ");
782 num
= JPOOL_LONG (jcf
, index
);
787 format_int (buffer
, num
, 10);
788 fprintf (out
, "%s", buffer
);
791 format_uint (buffer
, (uint64
)num
, 16);
792 fprintf (out
, "=0x%s", buffer
);
798 jfloat fnum
= JPOOL_FLOAT (jcf
, index
);
801 fputs ("Float ", out
);
806 if (JFLOAT_FINITE (fnum
))
809 int exponent
= fnum
.exponent
- JFLOAT_EXP_BIAS
;
811 uint32 mantissa
= fnum
.mantissa
;
812 if (fnum
.exponent
== 0)
816 /* Normal; add the implicit bit. */
817 mantissa
|= ((uint32
)1 << 23);
819 f
= frexp ((float) mantissa
, &dummy
);
820 f
= ldexp (f
, exponent
+ 1);
821 fprintf (out
, "%.10g", f
);
825 if (fnum
.mantissa
== 0)
827 else if (fnum
.mantissa
& JFLOAT_QNAN_MASK
)
828 fprintf (out
, "QNaN(%u)", (fnum
.mantissa
& ~JFLOAT_QNAN_MASK
));
830 fprintf (out
, "SNaN(%u)", (fnum
.mantissa
& ~JFLOAT_QNAN_MASK
));
834 fprintf (out
, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf
, index
));
838 case CONSTANT_Double
:
840 jdouble dnum
= JPOOL_DOUBLE (jcf
, index
);
843 fputs ("Double ", out
);
848 if (JDOUBLE_FINITE (dnum
))
851 int exponent
= dnum
.exponent
- JDOUBLE_EXP_BIAS
;
853 uint64 mantissa
= ((((uint64
) dnum
.mantissa0
) << 32)
855 if (dnum
.exponent
== 0)
859 /* Normal; add the implicit bit. */
860 mantissa
|= ((uint64
)1 << 52);
862 d
= frexp ((double) mantissa
, &dummy
);
863 d
= ldexp (d
, exponent
+ 1);
864 fprintf (out
, "%.20g", d
);
868 uint64 mantissa
= dnum
.mantissa0
& ~JDOUBLE_QNAN_MASK
;
869 mantissa
= (mantissa
<< 32) + dnum
.mantissa1
;
871 if (dnum
.mantissa0
== 0 && dnum
.mantissa1
== 0)
873 else if (dnum
.mantissa0
& JDOUBLE_QNAN_MASK
)
874 fprintf (out
, "QNaN(%" HOST_LONG_LONG_FORMAT
"u)",
875 (unsigned long long)mantissa
);
877 fprintf (out
, "SNaN(%" HOST_LONG_LONG_FORMAT
"u)",
878 (unsigned long long)mantissa
);
883 hi
= JPOOL_UINT (jcf
, index
);
884 lo
= JPOOL_UINT (jcf
, index
+ 1);
885 fprintf (out
, ", bits = 0x%08lx%08lx", (unsigned long) hi
,
890 case CONSTANT_NameAndType
:
892 uint16 name
= JPOOL_USHORT1 (jcf
, index
);
893 uint16 sig
= JPOOL_USHORT2 (jcf
, index
);
897 fprintf (out
, "NameAndType name: %d=", name
);
899 fprintf (out
, "NameAndType ");
901 print_name (out
, jcf
, name
);
905 fprintf (out
, ", signature: %d=", sig
);
906 print_signature (out
, jcf
, sig
, 0);
911 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, index
);
912 int length
= JPOOL_UTF_LENGTH (jcf
, index
);
914 { /* Print as 8-bit bytes. */
915 fputs ("Utf8: \"", out
);
916 while (--length
>= 0)
917 jcf_print_char (out
, *str
++);
920 { /* Print as Unicode. */
922 jcf_print_utf8 (out
, str
, length
);
927 case CONSTANT_MethodHandle
:
929 int kind
= JPOOL_USHORT1 (jcf
, index
);
931 fprintf (out
, "MethodHandle kind: %d=", kind
);
938 fprintf (out
, "Fieldref: %ld=", (long) JPOOL_USHORT2 (jcf
, index
));
939 print_constant (out
, jcf
, JPOOL_USHORT2 (jcf
, index
), 0);
945 fprintf (out
, "Methodref: %ld=", (long) JPOOL_USHORT2 (jcf
, index
));
946 print_constant (out
, jcf
, JPOOL_USHORT2 (jcf
, index
), 0);
950 fprintf (out
, "InterfaceMethodref: %ld=",
951 (long) JPOOL_USHORT2 (jcf
, index
));
952 print_constant (out
, jcf
, JPOOL_USHORT2 (jcf
, index
), 0);
957 case CONSTANT_MethodType
:
959 fprintf (out
, "MethodType %ld: ", (long) JPOOL_USHORT1 (jcf
, index
));
960 print_signature (out
, jcf
, JPOOL_USHORT1 (jcf
, index
), 0);
962 case CONSTANT_InvokeDynamic
:
964 uint16 name_and_type
= JPOOL_USHORT2 (jcf
, index
);
966 fprintf (out
, "InvokeDynamic: ");
967 fprintf (out
, "bootstrap_method: %ld ",
968 (long) JPOOL_USHORT1 (jcf
, index
));
970 fprintf (out
, " name_and_type: %d=<", name_and_type
);
971 print_constant_terse (out
, jcf
, name_and_type
, CONSTANT_NameAndType
);
977 fprintf (out
, "(Unknown constant type %d)", kind
);
982 print_constant_pool (JCF
*jcf
)
985 for (i
= 1; i
< JPOOL_SIZE(jcf
); i
++)
987 int kind
= JPOOL_TAG (jcf
, i
);
988 fprintf (out
, "#%d: ", i
);
989 print_constant (out
, jcf
, i
, 2);
991 if (kind
== CONSTANT_Double
|| kind
== CONSTANT_Long
)
992 i
++; /* These take up two slots in the constant table */
997 print_signature_type (FILE* stream
, const unsigned char **ptr
,
998 const unsigned char *limit
)
1001 if ((*ptr
) >= limit
)
1007 for ((*ptr
)++; (*ptr
) < limit
&& ISDIGIT (**ptr
); (*ptr
)++)
1009 array_size
= (array_size
< 0 ? 0 : 10 * array_size
) + *(*ptr
) - '0';
1011 print_signature_type (stream
, ptr
, limit
);
1012 if (array_size
== -1)
1013 fprintf (stream
, "[]");
1015 fprintf (stream
, "[%d]", array_size
);
1020 fputc (*(*ptr
)++, stream
);
1021 for (; **ptr
!= ')' && *ptr
< limit
; nargs
++)
1024 fputc (',', stream
);
1025 print_signature_type (stream
, ptr
, limit
);
1029 fputc (*(*ptr
)++, stream
);
1030 print_signature_type (stream
, ptr
, limit
);
1033 fprintf (stream
, "???");
1037 case 'B': fprintf (stream
, "byte"); (*ptr
)++; break;
1038 case 'C': fprintf (stream
, "char"); (*ptr
)++; break;
1039 case 'D': fprintf (stream
, "double"); (*ptr
)++; break;
1040 case 'F': fprintf (stream
, "float"); (*ptr
)++; break;
1041 case 'S': fprintf (stream
, "short"); (*ptr
)++; break;
1042 case 'I': fprintf (stream
, "int"); (*ptr
)++; break;
1043 case 'J': fprintf (stream
, "long"); (*ptr
)++; break;
1044 case 'Z': fprintf (stream
, "boolean"); (*ptr
)++; break;
1045 case 'V': fprintf (stream
, "void"); (*ptr
)++; break;
1048 for ((*ptr
)++; (*ptr
)<limit
&& *(*ptr
) != ';'; (*ptr
)++)
1049 jcf_print_char (stream
, *(*ptr
) == '/' ? '.' : *(*ptr
));
1054 jcf_print_char (stream
, *(*ptr
)++);
1059 print_signature (FILE* stream
, JCF
*jcf
, int signature_index
, int options
)
1061 if (JPOOL_TAG (jcf
, signature_index
) != CONSTANT_Utf8
)
1062 print_constant_terse (out
, jcf
, signature_index
, CONSTANT_Utf8
);
1065 const unsigned char *str
= JPOOL_UTF_DATA (jcf
, signature_index
);
1066 int length
= JPOOL_UTF_LENGTH (jcf
, signature_index
);
1067 const unsigned char *limit
;
1068 limit
= str
+ length
;
1070 fprintf (stream
, "<empty signature string>");
1073 if (options
& PRINT_SIGNATURE_RESULT_ONLY
)
1075 while (str
< limit
&& *str
++ != ')') ;
1077 if (options
& PRINT_SIGNATURE_ARGS_ONLY
)
1080 fputc ('(', stream
);
1081 while (str
< limit
&& *str
!= ')')
1083 print_signature_type (stream
, &str
, limit
);
1085 fputs (", ", stream
);
1087 fputc (')', stream
);
1091 print_signature_type (stream
, &str
, limit
);
1094 fprintf (stream
, "<junk:");
1095 jcf_print_utf8 (stream
, str
, limit
- str
);
1096 fputc ('>', stream
);
1105 print_exception_table (JCF
*jcf
, const unsigned char *entries
, int count
)
1107 /* Print exception table. */
1111 const unsigned char *ptr
= entries
;
1112 fprintf (out
, "Exceptions (count: %d):\n", i
);
1113 for (; --i
>= 0; ptr
+= 8)
1115 int start_pc
= GET_u2 (ptr
);
1116 int end_pc
= GET_u2 (ptr
+2);
1117 int handler_pc
= GET_u2 (ptr
+4);
1118 int catch_type
= GET_u2 (ptr
+6);
1119 fprintf (out
, " start: %d, end: %d, handler: %d, type: ",
1120 start_pc
, end_pc
, handler_pc
);
1121 if (catch_type
== 0)
1122 fputs ("0 /* finally */", out
);
1124 print_constant_terse_with_index (out
, jcf
,
1125 catch_type
, CONSTANT_Class
);
1131 #include "jcf-reader.c"
1134 process_class (JCF
*jcf
)
1137 if (jcf_parse_preamble (jcf
) != 0)
1138 fprintf (stderr
, _("Not a valid Java .class file.\n"));
1140 /* Parse and possibly print constant pool */
1141 code
= jcf_parse_constant_pool (jcf
);
1144 fprintf (stderr
, _("error while parsing constant pool\n"));
1145 exit (FATAL_EXIT_CODE
);
1147 code
= verify_constant_pool (jcf
);
1150 fprintf (stderr
, _("error in constant pool entry #%d\n"), code
);
1151 exit (FATAL_EXIT_CODE
);
1153 if (flag_print_constant_pool
)
1154 print_constant_pool (jcf
);
1156 jcf_parse_class (jcf
);
1157 code
= jcf_parse_fields (jcf
);
1160 fprintf (stderr
, _("error while parsing fields\n"));
1161 exit (FATAL_EXIT_CODE
);
1163 code
= jcf_parse_methods (jcf
);
1166 fprintf (stderr
, _("error while parsing methods\n"));
1167 exit (FATAL_EXIT_CODE
);
1169 code
= jcf_parse_final_attributes (jcf
);
1172 fprintf (stderr
, _("error while parsing final attributes\n"));
1173 exit (FATAL_EXIT_CODE
);
1175 jcf
->filename
= NULL
;
1180 /* This is used to mark options with no short value. */
1181 #define LONG_OPT(Num) ((Num) + 128)
1183 #define OPT_classpath LONG_OPT (0)
1184 #define OPT_CLASSPATH OPT_classpath
1185 #define OPT_bootclasspath LONG_OPT (1)
1186 #define OPT_extdirs LONG_OPT (2)
1187 #define OPT_HELP LONG_OPT (3)
1188 #define OPT_VERSION LONG_OPT (4)
1189 #define OPT_JAVAP LONG_OPT (5)
1191 static const struct option options
[] =
1193 { "classpath", required_argument
, NULL
, OPT_classpath
},
1194 { "bootclasspath", required_argument
, NULL
, OPT_bootclasspath
},
1195 { "extdirs", required_argument
, NULL
, OPT_extdirs
},
1196 { "CLASSPATH", required_argument
, NULL
, OPT_CLASSPATH
},
1197 { "help", no_argument
, NULL
, OPT_HELP
},
1198 { "verbose", no_argument
, NULL
, 'v' },
1199 { "version", no_argument
, NULL
, OPT_VERSION
},
1200 { "javap", no_argument
, NULL
, OPT_JAVAP
},
1201 { "print-main", no_argument
, &flag_print_main
, 1 },
1202 { "print-constants", no_argument
, &flag_print_constant_pool
, 1 },
1203 { NULL
, no_argument
, NULL
, 0 }
1209 fprintf (stderr
, _("Try 'jcf-dump --help' for more information.\n"));
1216 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1217 printf (_("Display contents of a class file in readable form.\n\n"));
1218 printf (_(" -c Disassemble method bodies\n"));
1219 printf (_(" --javap Generate output in 'javap' format\n"));
1221 printf (_(" --classpath PATH Set path to find .class files\n"));
1222 printf (_(" -IDIR Append directory to class path\n"));
1223 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1224 printf (_(" --extdirs PATH Set extensions directory path\n"));
1225 printf (_(" -o FILE Set output file name\n"));
1227 printf (_(" --help Print this help, then exit\n"));
1228 printf (_(" --version Print version number, then exit\n"));
1229 printf (_(" -v, --verbose Print extra information while running\n"));
1231 printf (_("For bug reporting instructions, please see:\n"
1232 "%s.\n"), bug_report_url
);
1239 printf ("jcf-dump %s%s\n\n", pkgversion_string
, version_string
);
1240 printf ("Copyright %s 2015 Free Software Foundation, Inc.\n", _("(C)"));
1241 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1242 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1247 main (int argc
, char** argv
)
1253 p
= argv
[0] + strlen (argv
[0]);
1254 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
1258 xmalloc_set_program_name (progname
);
1260 /* Unlock the stdio streams. */
1261 unlock_std_streams ();
1263 gcc_init_libintl ();
1265 diagnostic_initialize (global_dc
, 0);
1269 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
1275 /* We use getopt_long_only to allow single `-' long options. For
1276 some of our options this is more natural. */
1277 while ((opt
= getopt_long_only (argc
, argv
, "o:I:vc", options
, NULL
)) != -1)
1282 /* Already handled. */
1286 output_file
= optarg
;
1290 jcf_path_include_arg (optarg
);
1298 flag_disassemble_methods
= 1;
1302 jcf_path_classpath_arg (optarg
);
1305 case OPT_bootclasspath
:
1306 jcf_path_bootclasspath_arg (optarg
);
1310 jcf_path_extdirs_arg (optarg
);
1322 flag_javap_compatible
++;
1323 flag_print_constant_pool
= 0;
1324 flag_print_attributes
= 0;
1332 if (verbose
&& ! flag_javap_compatible
)
1333 flag_print_constant_pool
= 1;
1337 fprintf (stderr
, _("jcf-dump: no classes specified\n"));
1341 jcf_path_seal (verbose
);
1343 if (flag_print_main
)
1345 flag_print_fields
= 0;
1346 flag_print_methods
= 0;
1347 flag_print_constant_pool
= 0;
1348 flag_print_attributes
= 0;
1349 flag_print_class_info
= 0;
1354 out
= fopen (output_file
, "w");
1357 fprintf (stderr
, _("Cannot open '%s' for output.\n"), output_file
);
1358 return FATAL_EXIT_CODE
;
1366 fprintf (out
, "Reading .class from <standard input>.\n");
1367 open_class ("<stdio>", jcf
, 0, NULL
);
1368 process_class (jcf
);
1372 for (argi
= optind
; argi
< argc
; argi
++)
1374 char *arg
= argv
[argi
];
1375 const char *class_filename
= find_class (arg
, strlen (arg
), jcf
);
1376 if (class_filename
== NULL
)
1377 class_filename
= find_classfile (arg
, jcf
, NULL
);
1378 if (class_filename
== NULL
)
1380 perror ("Could not find class");
1381 return FATAL_EXIT_CODE
;
1384 if (GET_u4 (jcf
->read_ptr
) == ZIPMAGIC
)
1386 long compressed_size
, member_size
;
1387 int compression_method
, filename_length
, extra_length
;
1388 const char *filename
;
1390 if (flag_print_class_info
)
1391 fprintf (out
, "Reading classes from archive %s.\n",
1396 jcf_filbuf_t save_filbuf
= jcf
->filbuf
;
1397 long magic
= JCF_readu4_le (jcf
);
1398 if (magic
== 0x02014b50 || magic
== 0x06054b50)
1399 break; /* got to central directory */
1400 if (magic
!= 0x04034b50) /* ZIPMAGIC (little-endian) */
1402 fprintf (stderr
, _("bad format of .zip/.jar archive\n"));
1403 return FATAL_EXIT_CODE
;
1407 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf
);
1408 compression_method
= JCF_readu2_le (jcf
);
1410 compressed_size
= JCF_readu4_le (jcf
);
1411 member_size
= JCF_readu4_le (jcf
);
1412 filename_length
= JCF_readu2_le (jcf
);
1413 extra_length
= JCF_readu2_le (jcf
);
1414 total_length
= filename_length
+ extra_length
1416 if (jcf
->read_end
- jcf
->read_ptr
< total_length
)
1417 jcf_trim_old_input (jcf
);
1418 JCF_FILL (jcf
, total_length
);
1419 filename
= (const char *) jcf
->read_ptr
;
1420 JCF_SKIP (jcf
, filename_length
);
1421 JCF_SKIP (jcf
, extra_length
);
1422 if (filename_length
> 0
1423 && filename
[filename_length
-1] == '/')
1425 if (flag_print_class_info
)
1426 fprintf (out
, "[Skipping directory %.*s]\n",
1427 filename_length
, filename
);
1430 else if (compression_method
!= 0)
1432 if (flag_print_class_info
)
1433 fprintf (out
, "[Skipping compressed file %.*s]\n",
1434 filename_length
, filename
);
1437 else if (member_size
< 4
1438 || GET_u4 (jcf
->read_ptr
) != 0xcafebabe)
1440 if (flag_print_class_info
)
1441 fprintf (out
, "[Skipping non-.class member %.*s]\n",
1442 filename_length
, filename
);
1447 if (flag_print_class_info
)
1448 fprintf (out
, "Reading class member: %.*s.\n",
1449 filename_length
, filename
);
1453 JCF_SKIP (jcf
, compressed_size
);
1457 unsigned char *save_end
;
1458 jcf
->filbuf
= jcf_unexpected_eof
;
1459 save_end
= jcf
->read_end
;
1460 jcf
->read_end
= jcf
->read_ptr
+ compressed_size
;
1461 process_class (jcf
);
1462 jcf
->filbuf
= save_filbuf
;
1463 jcf
->read_end
= save_end
;
1469 if (flag_print_class_info
)
1470 fprintf (out
, "Reading .class from %s.\n", class_filename
);
1471 process_class (jcf
);
1477 return SUCCESS_EXIT_CODE
;
1483 disassemble_method (JCF
* jcf
, const unsigned char *byte_ops
, int len
)
1489 if (flag_disassemble_methods
== 0)
1491 #define BCODE byte_ops
1492 for (PC
= 0; PC
< len
;)
1497 switch (byte_ops
[PC
++])
1500 /* This is the actual code emitted for each of opcodes in javaops.def.
1501 The actual opcode-specific stuff is handled by the OPKIND macro.
1502 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1503 Those macros are defined below. The OPKINDs that do not have any
1504 inline parameters (such as BINOP) and therefore do mot need anything
1505 else to me printed out just use an empty body. */
1507 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1509 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1510 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1511 fputc ('\n', out); \
1514 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1515 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1516 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1517 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1519 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1520 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1522 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1523 These all push a constant onto the opcode stack. */
1524 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1525 saw_index = 0, i = (OPERAND_VALUE); \
1526 if (oldpc+1 == PC) /* nothing */; \
1527 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1528 else fprintf (out, " %d", i);
1530 /* Print out operand (a local variable index) for LOAD opcodes.
1531 These all push local variable onto the opcode stack. */
1532 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1533 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1535 /* Handle STORE opcodes same as LOAD opcodes.
1536 These all store a value from the opcode stack in a local variable. */
1539 /* Handle more kind of opcodes. */
1540 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1541 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1542 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1543 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1544 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1545 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1546 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1548 /* Handle putfield and getfield opcodes, with static versions. */
1549 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1550 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1552 /* Print operand for invoke opcodes. */
1553 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1554 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1555 if (OPERAND_VALUE) /* for invokeinterface */ \
1556 { int nargs = IMMEDIATE_u1; PC++; \
1557 fprintf (out, " nargs:%d", nargs); }
1559 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1560 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1562 #define ARRAY(OPERAND_TYPE, SUBOP) \
1563 ARRAY_##SUBOP(OPERAND_TYPE)
1564 /* Handle sub-categories of ARRAY opcodes. */
1565 #define ARRAY_LOAD(TYPE) /* nothing */
1566 #define ARRAY_STORE(TYPE) /* nothing */
1567 #define ARRAY_LENGTH(TYPE) /* nothing */
1568 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1569 #define ARRAY_NEW_NUM \
1570 INT_temp = IMMEDIATE_u1; \
1571 { switch ((int) INT_temp) { \
1572 case 4: fputs (" boolean", out); break; \
1573 case 5: fputs (" char", out); break; \
1574 case 6: fputs (" float", out); break; \
1575 case 7: fputs (" double", out); break; \
1576 case 8: fputs (" byte", out); break; \
1577 case 9: fputs (" short", out); break; \
1578 case 10: fputs (" int", out); break; \
1579 case 11: fputs (" long", out); break; \
1580 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1583 #define ARRAY_NEW_PTR \
1584 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1586 #define ARRAY_NEW_MULTI \
1587 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1588 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1590 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1591 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1593 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1594 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1595 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1597 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1598 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1599 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1601 #undef RET /* Defined by config/i386/i386.h */
1602 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1603 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1605 fprintf (out, " %ld", (long) INT_temp);
1607 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1608 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1610 #define LOOKUP_SWITCH \
1611 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1612 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1613 while (--npairs >= 0) { \
1614 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1615 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1618 #define TABLE_SWITCH \
1619 { jint default_offset = IMMEDIATE_s4; \
1620 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1621 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1622 (long) low, (long) high, (long) default_offset+oldpc); \
1623 for (; low <= high; low++) { \
1624 jint offset = IMMEDIATE_s4; \
1625 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1628 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1629 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1631 #define SPECIAL_IINC(OPERAND_TYPE) \
1632 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1633 fprintf (out, " %d", i); \
1634 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1636 fprintf (out, " %d", i)
1638 #define SPECIAL_WIDE(OPERAND_TYPE) \
1641 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1642 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1643 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1644 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1646 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1647 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1649 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1650 TEST(OPERAND_TYPE, OPERAND_VALUE)
1652 #include "javaop.def"
1655 if (oldpc
+1 == PC
) /* nothing - local index implied by opcode */;
1659 fprintf (out
, " %ld", (long) INT_temp
);
1665 fprintf (out
, "%3d: unknown(%3d)\n", oldpc
, byte_ops
[PC
]);