Merged gcj-eclipse to the gcj-eclipse-jmx branch:
[official-gcc.git] / gcc / java / jcf-dump.c
blob6162b175f37576099e0ded890b7823dba538d608
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
24 Java and all Java-based marks are trademarks or registered trademarks
25 of Sun Microsystems, Inc. in the United States and other countries.
26 The Free Software Foundation is independent of Sun Microsystems, Inc. */
28 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
31 jcf-dump is a program to print out the contents of class files.
32 Usage: jcf-dump [FLAGS] CLASS
33 Each CLASS is either:
34 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
35 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
36 + The name of a .zip or .jar file (which prints all the classes in the
37 archive).
39 OPTIONS:
41 Dis-assemble each method.
42 -classpath PATH
43 Overrides $CLASSPATH.
44 --print-main
45 Print nothing if there is no valid "main" method;
46 otherwise, print only the class name.
47 --javap
48 Print output in the style of Sun's javap program. VERY UNFINISHED.
52 #include "config.h"
53 #include "system.h"
54 #include "coretypes.h"
55 #include "tm.h"
56 #include "ggc.h"
57 #include "intl.h"
59 #include "jcf.h"
60 #include "tree.h"
61 #include "java-tree.h"
63 #include "version.h"
65 #include <getopt.h>
66 #include <math.h>
68 /* Output file. */
69 FILE *out;
70 /* Name of output file, if NULL if stdout. */
71 char *output_file = NULL;
73 int verbose = 0;
75 int flag_disassemble_methods = 0;
76 int flag_print_class_info = 1;
77 int flag_print_constant_pool = 0;
78 int flag_print_fields = 1;
79 int flag_print_methods = 1;
80 int flag_print_attributes = 1;
82 /* When nonzero, warn when source file is newer than matching class
83 file. */
84 int flag_newer = 1;
86 /* Print names of classes that have a "main" method. */
87 int flag_print_main = 0;
89 /* Index in constant pool of this class. */
90 int this_class_index = 0;
92 int class_access_flags = 0;
94 /* Print in format similar to javap. VERY INCOMPLETE. */
95 int flag_javap_compatible = 0;
97 static void print_access_flags (FILE *, uint16, char);
98 static void print_constant_terse (FILE*, JCF*, int, int);
99 static void print_constant_terse_with_index (FILE *, JCF *, int, int);
100 static void print_constant (FILE *, JCF *, int, int);
101 static void print_constant_ref (FILE *, JCF *, int);
102 static void disassemble_method (JCF*, const unsigned char *, int);
103 static void print_name (FILE*, JCF*, int);
104 static void print_signature (FILE*, JCF*, int, int);
105 static int utf8_equal_string (struct JCF*, int, const char *);
106 static void usage (void) ATTRIBUTE_NORETURN;
107 static void help (void) ATTRIBUTE_NORETURN;
108 static void version (void) ATTRIBUTE_NORETURN;
109 static void process_class (struct JCF *);
110 static void print_constant_pool (struct JCF *);
111 static void print_exception_table (struct JCF *, const unsigned char *entries,
112 int);
113 static void indent (FILE *, int);
114 static void print_element_value (FILE *, JCF *, int);
115 static void print_annotation (FILE *, JCF *, int);
116 static void print_annotations (FILE *, JCF *, int);
117 static void print_parameter_annotations (FILE *, JCF *, int);
119 #define PRINT_SIGNATURE_RESULT_ONLY 1
120 #define PRINT_SIGNATURE_ARGS_ONLY 2
122 static int
123 utf8_equal_string (JCF *jcf, int index, const char * value)
125 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
126 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
128 int len = strlen (value);
129 if (JPOOL_UTF_LENGTH (jcf, index) == len
130 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
131 return 1;
133 return 0;
136 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
137 this_class_index = 0; \
138 if (flag_print_class_info) \
139 fprintf (out, \
140 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
141 (long) MAGIC, (long) MINOR, (long) MAJOR)
143 #define HANDLE_START_CONSTANT_POOL(COUNT) \
144 if (flag_print_constant_pool) \
145 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
147 #define HANDLE_SOURCEFILE(INDEX) \
148 { fprintf (out, "Attribute "); \
149 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
150 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
151 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
153 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
154 this_class_index = THIS; \
155 class_access_flags = ACCESS_FLAGS; \
156 if (flag_print_class_info) \
157 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
158 print_access_flags (out, ACCESS_FLAGS, 'c'); \
159 fputc ('\n', out); \
160 fprintf (out, "This class: "); \
161 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
162 if (flag_print_constant_pool || SUPER != 0) \
163 fprintf (out, ", super: "); \
164 if (flag_print_constant_pool) \
166 fprintf (out, "%d", SUPER); \
167 if (SUPER != 0) \
168 fputc ('=', out); \
170 if (SUPER != 0) \
171 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
172 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
175 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
176 (flag_print_attributes <= 0)
178 #define HANDLE_CLASS_INTERFACE(INDEX) \
179 if (flag_print_class_info) \
180 { fprintf (out, "- Implements: "); \
181 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
182 fputc ('\n', out); }
184 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
185 if (flag_print_fields) \
186 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
188 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
189 if (flag_print_fields) \
190 { fprintf (out, "Field name:"); \
191 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
192 print_access_flags (out, ACCESS_FLAGS, 'f'); \
193 fprintf (out, " Descriptor: "); \
194 if (flag_print_constant_pool) \
195 fprintf (out, "%d=", SIGNATURE); \
196 print_signature (out, jcf, SIGNATURE, 0); \
197 fputc ('\n', out); } \
198 else \
199 flag_print_attributes--;
201 #define HANDLE_END_FIELD() \
202 if (! flag_print_fields) \
203 flag_print_attributes++;
205 #define HANDLE_START_METHODS(METHODS_COUNT) \
206 if (flag_print_methods) \
207 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
208 else \
209 flag_print_attributes--;
212 #define HANDLE_END_METHODS() \
213 if (! flag_print_methods) \
214 flag_print_attributes++;
216 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
218 if (flag_print_methods) \
220 if (flag_javap_compatible) \
222 fprintf (out, " "); \
223 print_access_flags (out, ACCESS_FLAGS, 'm'); \
224 fputc (' ', out); \
225 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
226 fputc (' ', out); \
227 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
228 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
229 fputc ('\n', out); \
231 else \
233 fprintf (out, "\nMethod name:"); \
234 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
235 print_access_flags (out, ACCESS_FLAGS, 'm'); \
236 fprintf (out, " Descriptor: "); \
237 if (flag_print_constant_pool) \
238 fprintf (out, "%d=", SIGNATURE); \
239 print_signature (out, jcf, SIGNATURE, 0); \
240 fputc ('\n', out); \
243 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
244 && utf8_equal_string (jcf, NAME, "main") \
245 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
246 && this_class_index > 0 \
247 && (class_access_flags & ACC_PUBLIC)) \
249 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
250 fputc ('\n', out); \
254 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
255 ( fprintf (out, "Attribute "), \
256 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
257 fprintf (out, ", length:%ld", (long) LENGTH) )
259 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
260 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
261 fprintf (out, ", value: "), \
262 print_constant_ref (out, jcf, VALUE_INDEX), \
263 fprintf (out, "\n") )
265 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
266 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
267 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
268 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
269 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
271 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
272 print_exception_table (jcf, ENTRIES, COUNT)
274 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
275 { int n = (COUNT); int i; \
276 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
277 fprintf (out, ", count: %d\n", n); \
278 for (i = 0; i < n; i++) {\
279 int ex_index = JCF_readu2 (jcf); \
280 fprintf (out, "%3d: ", i); \
281 print_constant_ref (out, jcf, ex_index); \
282 fputc ('\n', out); } }
284 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
285 { int n = (COUNT); int i; \
286 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
287 fprintf (out, ", count: %d\n", n); \
288 for (i = 0; i < n; i++) {\
289 int start_pc = JCF_readu2 (jcf); \
290 int length = JCF_readu2 (jcf); \
291 int name_index = JCF_readu2 (jcf); \
292 int signature_index = JCF_readu2 (jcf); \
293 int slot = JCF_readu2 (jcf); \
294 fprintf (out, " slot#%d: name: ", slot); \
295 if (flag_print_constant_pool) \
296 fprintf (out, "%d=", name_index); \
297 print_name (out, jcf, name_index); \
298 fprintf (out, ", type: "); \
299 if (flag_print_constant_pool) \
300 fprintf (out, "%d=", signature_index); \
301 print_signature (out, jcf, signature_index, 0); \
302 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
304 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \
305 { int n = (COUNT); int i; \
306 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
307 fprintf (out, ", count: %d\n", n); \
308 for (i = 0; i < n; i++) { \
309 int start_pc = JCF_readu2 (jcf); \
310 int length = JCF_readu2 (jcf); \
311 int name_index = JCF_readu2 (jcf); \
312 int signature_index = JCF_readu2 (jcf); \
313 int slot = JCF_readu2 (jcf); \
314 fprintf (out, " slot#%d: name: ", slot); \
315 if (flag_print_constant_pool) \
316 fprintf (out, "%d=", name_index); \
317 print_name (out, jcf, name_index); \
318 fprintf (out, ", type: "); \
319 if (flag_print_constant_pool) \
320 fprintf (out, "%d=", signature_index); \
321 print_signature (out, jcf, signature_index, 0); \
322 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
324 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
325 { int n = (COUNT); int i; \
326 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
327 fprintf (out, ", count: %d\n", n); \
328 if (flag_disassemble_methods) \
329 for (i = 0; i < n; i++) {\
330 int start_pc = JCF_readu2 (jcf); \
331 int line_number = JCF_readu2 (jcf); \
332 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
333 else \
334 JCF_SKIP (jcf, 4 * n); }
336 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
337 { int n = (COUNT); \
338 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
339 while (n--) \
341 uint16 inner_class_info_index = JCF_readu2 (jcf); \
342 uint16 outer_class_info_index = JCF_readu2 (jcf); \
343 uint16 inner_name_index = JCF_readu2 (jcf); \
344 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
346 if (flag_print_class_info) \
348 fprintf (out, "\n inner: "); \
349 if (inner_class_info_index == 0) \
350 fprintf (out, " (no inner info index)"); \
351 else \
352 print_constant_terse_with_index (out, jcf, \
353 inner_class_info_index, \
354 CONSTANT_Class); \
355 if (inner_name_index == 0) \
356 fprintf (out, " (anonymous)"); \
357 else if (verbose || flag_print_constant_pool) \
359 fprintf (out, " ("); \
360 print_constant_terse_with_index (out, jcf, inner_name_index, \
361 CONSTANT_Utf8); \
362 fputc (')', out); \
364 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
365 print_access_flags (out, inner_class_access_flags, 'c'); \
366 fprintf (out, ", outer class: "); \
367 if (outer_class_info_index == 0) \
368 fprintf (out, "(not a member)"); \
369 else \
370 print_constant_terse_with_index (out, jcf, \
371 outer_class_info_index, \
372 CONSTANT_Class); \
375 if (flag_print_class_info) \
376 fputc ('\n', out); \
379 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
380 { int i, n = (LENGTH), c = 0; \
381 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
382 fputc ('\n', out); \
383 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
384 if (c != '\r' && c != '\n') fputc('\n', out); }
386 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \
387 { uint16 class_index, method_index; \
388 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
389 class_index = JCF_readu2 (jcf); \
390 method_index = JCF_readu2 (jcf); \
391 fprintf (out, "\n Class: "); \
392 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
393 fprintf (out, "\n Method: "); \
394 print_constant_terse_with_index (out, jcf, method_index, \
395 CONSTANT_NameAndType); \
396 fputc ('\n', out); \
399 #define HANDLE_SIGNATURE_ATTRIBUTE() \
401 uint16 signature; \
402 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
403 signature = JCF_readu2 (jcf); \
404 fprintf (out, "\n Value: "); \
405 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
406 fputc ('\n', out); \
409 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
411 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
412 print_annotations (out, jcf, 1); \
415 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
417 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
418 print_annotations (out, jcf, 1); \
421 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
423 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
424 print_parameter_annotations (out, jcf, 1); \
427 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
429 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
430 print_parameter_annotations (out, jcf, 1); \
433 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
435 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
436 print_element_value (out, jcf, 1); \
440 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
441 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
442 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
444 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
445 if (flag_print_attributes > 0) \
446 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
448 #include "javaop.h"
452 static void
453 indent (FILE *stream, int level)
455 int i;
456 for (i = 0; i < level; ++i)
457 fprintf (stream, " ");
460 static void
461 print_element_value (FILE *stream, JCF *jcf, int level)
463 uint8 tag = JCF_readu (jcf);
464 indent (stream, level);
465 switch (tag)
467 case 'B':
468 case 'C':
469 case 'S':
470 case 'Z':
471 case 'I':
473 uint16 cindex = JCF_readu2 (jcf);
474 print_constant_terse_with_index (stream, jcf, cindex,
475 CONSTANT_Integer);
477 break;
478 case 'D':
480 uint16 cindex = JCF_readu2 (jcf);
481 print_constant_terse_with_index (stream, jcf, cindex,
482 CONSTANT_Double);
484 break;
485 case 'F':
487 uint16 cindex = JCF_readu2 (jcf);
488 print_constant_terse_with_index (stream, jcf, cindex,
489 CONSTANT_Float);
491 break;
492 case 'J':
494 uint16 cindex = JCF_readu2 (jcf);
495 print_constant_terse_with_index (stream, jcf, cindex,
496 CONSTANT_Long);
498 break;
499 case 's':
501 uint16 cindex = JCF_readu2 (jcf);
502 print_constant_terse_with_index (stream, jcf, cindex,
503 CONSTANT_String);
505 break;
507 case 'e':
509 uint16 type_name_index = JCF_readu2 (jcf);
510 uint16 const_name_index = JCF_readu2 (jcf);
511 fprintf (stream, "enum class: ");
512 print_constant_terse_with_index (stream, jcf, type_name_index,
513 CONSTANT_Utf8);
514 fprintf (stream, "\n");
515 indent (stream, level);
516 fprintf (stream, "Field: ");
517 print_constant_terse_with_index (stream, jcf, const_name_index,
518 CONSTANT_Utf8);
520 break;
521 case 'c':
523 uint16 class_info_index = JCF_readu2 (jcf);
524 print_constant_terse_with_index (stream, jcf, class_info_index,
525 CONSTANT_Utf8);
527 break;
528 case '@':
530 fprintf (stream, "Annotation:\n");
531 print_annotation (stream, jcf, level + 1);
533 break;
534 case '[':
536 uint16 n_array_elts = JCF_readu2 (jcf);
537 fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
538 while (n_array_elts--)
539 print_element_value (stream, jcf, level + 1);
540 indent (stream, level);
541 fprintf (stream, "]");
543 break;
544 default:
545 fprintf (stream, "Unexpected tag value: %d", (int) tag);
546 break;
548 fputc ('\n', stream);
551 static void
552 print_annotation (FILE *stream, JCF *jcf, int level)
554 uint16 type_index = JCF_readu2 (jcf);
555 uint16 npairs = JCF_readu2 (jcf);
556 fprintf (stream, "\n");
557 indent (stream, level);
558 fprintf (stream, "Annotation name: ");
559 print_constant_terse_with_index (stream, jcf, type_index,
560 CONSTANT_Utf8);
561 if (npairs)
563 fprintf (stream, "\n");
564 while (npairs--)
566 uint16 name_index = JCF_readu2 (jcf);
567 indent (stream, level + 1);
568 fprintf (stream, "Name: ");
569 print_constant_terse_with_index (stream, jcf, name_index,
570 CONSTANT_Utf8);
571 fprintf (stream, "\n");
572 print_element_value (stream, jcf, level + 2);
577 static void
578 print_annotations (FILE *stream, JCF *jcf, int level)
580 uint16 num = JCF_readu2 (jcf);
581 while (num--)
582 print_annotation (stream, jcf, level);
585 static void
586 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
588 uint8 nparams = JCF_readu (jcf);
589 uint8 i;
590 for (i = 0; i < nparams; ++i)
592 indent (stream, level);
593 fprintf (stream, "Parameter annotations (%d):\n", (int) i);
594 print_annotations (stream, jcf, level + 1);
600 static void
601 print_constant_ref (FILE *stream, JCF *jcf, int index)
603 if (index <= 0 || index >= JPOOL_SIZE(jcf))
604 fprintf (stream, "<out of range>");
605 else
607 if (flag_print_constant_pool)
608 fprintf (stream, "#%d=", index);
609 fputc ('<', stream);
610 print_constant (stream, jcf, index, 1);
611 fputc ('>', stream);
615 /* Print the access flags given by FLAGS.
616 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
617 or 'm' (method flags). */
619 static void
620 print_access_flags (FILE *stream, uint16 flags, char context)
622 if (flags & ACC_PUBLIC) fprintf (stream, " public");
623 if (flags & ACC_PRIVATE) fprintf (stream, " private");
624 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
625 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
626 if (flags & ACC_STATIC) fprintf (stream, " static");
627 if (flags & ACC_FINAL) fprintf (stream, " final");
628 if (flags & ACC_TRANSIENT)
629 fprintf (stream, context == 'm' ? " varargs" : " transient");
630 if (flags & ACC_VOLATILE)
631 fprintf (stream, context == 'm' ? " bridge" : " volatile");
632 if (flags & ACC_NATIVE) fprintf (stream, " native");
633 if (flags & ACC_SYNCHRONIZED)
635 if (context == 'c')
636 fprintf (stream, " super");
637 else
638 fprintf (stream, " synchronized");
640 if (flags & ACC_INTERFACE)
641 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
642 if (flags & ACC_ENUM) fprintf (stream, " enum");
643 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
644 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
648 static void
649 print_name (FILE* stream, JCF* jcf, int name_index)
651 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
652 fprintf (stream, "<not a UTF8 constant>");
653 else
654 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
655 JPOOL_UTF_LENGTH (jcf, name_index));
658 /* If the type of the constant at INDEX matches EXPECTED,
659 print it tersely, otherwise more verbosely. */
661 static void
662 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
664 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
665 fprintf (out, "<constant pool index %d not in range>", index);
666 else if (JPOOL_TAG (jcf, index) != expected)
668 fprintf (out, "<Unexpected constant type ");
669 print_constant (out, jcf, index, 1);
670 fprintf (out, ">");
672 else
673 print_constant (out, jcf, index, 0);
676 static void
677 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
679 if (flag_print_constant_pool)
680 fprintf (out, "%d=", index);
681 print_constant_terse (out, jcf, index, expected);
684 /* Print the constant at INDEX in JCF's constant pool.
685 If verbosity==0, print very tersely (no extraneous text).
686 If verbosity==1, prefix the type of the constant.
687 If verbosity==2, add more descriptive text. */
689 static void
690 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
692 int j, n;
693 jlong num;
694 const char *str;
695 int kind = JPOOL_TAG (jcf, index);
696 switch (kind)
698 case CONSTANT_Class:
699 n = JPOOL_USHORT1 (jcf, index);
700 if (verbosity > 0)
702 if (verbosity > 1)
703 fprintf (out, "Class name: %d=", n);
704 else
705 fprintf (out, "Class ");
707 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
708 fprintf (out, "<out of range>");
709 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
711 int len = JPOOL_UTF_LENGTH (jcf, n);
712 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
714 else
715 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
716 break;
717 case CONSTANT_Fieldref:
718 str = "Field"; goto field_or_method;
719 case CONSTANT_Methodref:
720 str = "Method"; goto field_or_method;
721 case CONSTANT_InterfaceMethodref:
722 str = "InterfaceMethod"; goto field_or_method;
723 field_or_method:
725 uint16 tclass = JPOOL_USHORT1 (jcf, index);
726 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
727 if (verbosity == 2)
728 fprintf (out, "%sref class: %d=", str, tclass);
729 else if (verbosity > 0)
730 fprintf (out, "%s ", str);
731 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
732 if (verbosity < 2)
733 fprintf (out, ".");
734 else
735 fprintf (out, " name_and_type: %d=<", name_and_type);
736 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
737 if (verbosity == 2)
738 fputc ('>', out);
740 break;
741 case CONSTANT_String:
742 j = JPOOL_USHORT1 (jcf, index);
743 if (verbosity > 0)
745 if (verbosity > 1)
746 fprintf (out, "String %d=", j);
747 else
748 fprintf (out, "String ");
750 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
751 break;
752 case CONSTANT_Integer:
753 if (verbosity > 0)
754 fprintf (out, "Integer ");
755 num = JPOOL_INT (jcf, index);
756 goto integer;
757 case CONSTANT_Long:
758 if (verbosity > 0)
759 fprintf (out, "Long ");
760 num = JPOOL_LONG (jcf, index);
761 goto integer;
762 integer:
764 char buffer[25];
765 format_int (buffer, num, 10);
766 fprintf (out, "%s", buffer);
767 if (verbosity > 1)
769 format_uint (buffer, (uint64)num, 16);
770 fprintf (out, "=0x%s", buffer);
773 break;
774 case CONSTANT_Float:
776 jfloat fnum = JPOOL_FLOAT (jcf, index);
778 if (verbosity > 0)
779 fputs ("Float ", out);
781 if (fnum.negative)
782 putc ('-', out);
784 if (JFLOAT_FINITE (fnum))
786 int dummy;
787 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
788 double f;
789 uint32 mantissa = fnum.mantissa;
790 if (fnum.exponent == 0)
791 /* Denormal. */
792 exponent++;
793 else
794 /* Normal; add the implicit bit. */
795 mantissa |= ((uint32)1 << 23);
797 f = frexp (mantissa, &dummy);
798 f = ldexp (f, exponent + 1);
799 fprintf (out, "%.10g", f);
801 else
803 if (fnum.mantissa == 0)
804 fputs ("Inf", out);
805 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
806 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
807 else
808 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
811 if (verbosity > 1)
812 fprintf (out, ", bits = 0x%08lx", (long) JPOOL_UINT (jcf, index));
814 break;
816 case CONSTANT_Double:
818 jdouble dnum = JPOOL_DOUBLE (jcf, index);
820 if (verbosity > 0)
821 fputs ("Double ", out);
823 if (dnum.negative)
824 putc ('-', out);
826 if (JDOUBLE_FINITE (dnum))
828 int dummy;
829 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
830 double d;
831 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
832 + dnum.mantissa1);
833 if (dnum.exponent == 0)
834 /* Denormal. */
835 exponent++;
836 else
837 /* Normal; add the implicit bit. */
838 mantissa |= ((uint64)1 << 52);
840 d = frexp (mantissa, &dummy);
841 d = ldexp (d, exponent + 1);
842 fprintf (out, "%.20g", d);
844 else
846 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
847 mantissa = (mantissa << 32) + dnum.mantissa1;
849 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
850 fputs ("Inf", out);
851 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
852 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
853 else
854 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
856 if (verbosity > 1)
858 int32 hi, lo;
859 hi = JPOOL_UINT (jcf, index);
860 lo = JPOOL_UINT (jcf, index + 1);
861 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
863 break;
865 case CONSTANT_NameAndType:
867 uint16 name = JPOOL_USHORT1 (jcf, index);
868 uint16 sig = JPOOL_USHORT2 (jcf, index);
869 if (verbosity > 0)
871 if (verbosity > 1)
872 fprintf (out, "NameAndType name: %d=", name);
873 else
874 fprintf (out, "NameAndType ");
876 print_name (out, jcf, name);
877 if (verbosity <= 1)
878 fputc (' ', out);
879 else
880 fprintf (out, ", signature: %d=", sig);
881 print_signature (out, jcf, sig, 0);
883 break;
884 case CONSTANT_Utf8:
886 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
887 int length = JPOOL_UTF_LENGTH (jcf, index);
888 if (verbosity > 0)
889 { /* Print as 8-bit bytes. */
890 fputs ("Utf8: \"", out);
891 while (--length >= 0)
892 jcf_print_char (out, *str++);
894 else
895 { /* Print as Unicode. */
896 fputc ('\"', out);
897 jcf_print_utf8 (out, str, length);
899 fputc ('\"', out);
901 break;
902 default:
903 fprintf (out, "(Unknown constant type %d)", kind);
907 static void
908 print_constant_pool (JCF *jcf)
910 int i;
911 for (i = 1; i < JPOOL_SIZE(jcf); i++)
913 int kind = JPOOL_TAG (jcf, i);
914 fprintf (out, "#%d: ", i);
915 print_constant (out, jcf, i, 2);
916 fprintf (out, "\n");
917 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
918 i++; /* These take up two slots in the constant table */
922 static void
923 print_signature_type (FILE* stream, const unsigned char **ptr,
924 const unsigned char *limit)
926 int array_size;
927 if ((*ptr) >= limit)
928 return;
929 switch (*(*ptr))
931 case '[':
932 array_size = -1;
933 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
935 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
937 print_signature_type (stream, ptr, limit);
938 if (array_size == -1)
939 fprintf (stream, "[]");
940 else
941 fprintf (stream, "[%d]", array_size);
942 break;
943 case '(':
945 int nargs = 0;
946 fputc (*(*ptr)++, stream);
947 for (; **ptr != ')' && *ptr < limit; nargs++)
949 if (nargs > 0)
950 fputc (',', stream);
951 print_signature_type (stream, ptr, limit);
953 if (*ptr < limit)
955 fputc (*(*ptr)++, stream);
956 print_signature_type (stream, ptr, limit);
958 else
959 fprintf (stream, "???");
961 break;
963 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
964 case 'C': fprintf (stream, "char"); (*ptr)++; break;
965 case 'D': fprintf (stream, "double"); (*ptr)++; break;
966 case 'F': fprintf (stream, "float"); (*ptr)++; break;
967 case 'S': fprintf (stream, "short"); (*ptr)++; break;
968 case 'I': fprintf (stream, "int"); (*ptr)++; break;
969 case 'J': fprintf (stream, "long"); (*ptr)++; break;
970 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
971 case 'V': fprintf (stream, "void"); (*ptr)++; break;
973 case 'L':
974 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
975 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
976 if (*(*ptr) == ';')
977 (*ptr)++;
978 break;
979 default:
980 jcf_print_char (stream, *(*ptr)++);
984 static void
985 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
987 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
988 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
989 else
991 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
992 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
993 const unsigned char *limit;
994 limit = str + length;
995 if (str >= limit)
996 fprintf (stream, "<empty signature string>");
997 else
999 if (options & PRINT_SIGNATURE_RESULT_ONLY)
1001 while (str < limit && *str++ != ')') ;
1003 if (options & PRINT_SIGNATURE_ARGS_ONLY)
1005 str++;
1006 fputc ('(', stream);
1007 while (str < limit && *str != ')')
1009 print_signature_type (stream, &str, limit);
1010 if (*str != ')')
1011 fputs (", ", stream);
1013 fputc (')', stream);
1015 else
1017 print_signature_type (stream, &str, limit);
1018 if (str < limit)
1020 fprintf (stream, "<junk:");
1021 jcf_print_utf8 (stream, str, limit - str);
1022 fputc ('>', stream);
1030 static void
1031 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1033 /* Print exception table. */
1034 int i = count;
1035 if (i > 0)
1037 const unsigned char *ptr = entries;
1038 fprintf (out, "Exceptions (count: %d):\n", i);
1039 for (; --i >= 0; ptr+= 8)
1041 int start_pc = GET_u2 (ptr);
1042 int end_pc = GET_u2 (ptr+2);
1043 int handler_pc = GET_u2 (ptr+4);
1044 int catch_type = GET_u2 (ptr+6);
1045 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
1046 start_pc, end_pc, handler_pc);
1047 if (catch_type == 0)
1048 fputs ("0 /* finally */", out);
1049 else
1050 print_constant_terse_with_index (out, jcf,
1051 catch_type, CONSTANT_Class);
1052 fputc ('\n', out);
1057 #include "jcf-reader.c"
1059 static void
1060 process_class (JCF *jcf)
1062 int code;
1063 if (jcf_parse_preamble (jcf) != 0)
1064 fprintf (stderr, _("Not a valid Java .class file.\n"));
1066 /* Parse and possibly print constant pool */
1067 code = jcf_parse_constant_pool (jcf);
1068 if (code != 0)
1070 fprintf (stderr, _("error while parsing constant pool\n"));
1071 exit (FATAL_EXIT_CODE);
1073 code = verify_constant_pool (jcf);
1074 if (code > 0)
1076 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1077 exit (FATAL_EXIT_CODE);
1079 if (flag_print_constant_pool)
1080 print_constant_pool (jcf);
1082 jcf_parse_class (jcf);
1083 code = jcf_parse_fields (jcf);
1084 if (code != 0)
1086 fprintf (stderr, _("error while parsing fields\n"));
1087 exit (FATAL_EXIT_CODE);
1089 code = jcf_parse_methods (jcf);
1090 if (code != 0)
1092 fprintf (stderr, _("error while parsing methods\n"));
1093 exit (FATAL_EXIT_CODE);
1095 code = jcf_parse_final_attributes (jcf);
1096 if (code != 0)
1098 fprintf (stderr, _("error while parsing final attributes\n"));
1099 exit (FATAL_EXIT_CODE);
1101 jcf->filename = NULL;
1106 /* This is used to mark options with no short value. */
1107 #define LONG_OPT(Num) ((Num) + 128)
1109 #define OPT_classpath LONG_OPT (0)
1110 #define OPT_CLASSPATH OPT_classpath
1111 #define OPT_bootclasspath LONG_OPT (1)
1112 #define OPT_extdirs LONG_OPT (2)
1113 #define OPT_HELP LONG_OPT (3)
1114 #define OPT_VERSION LONG_OPT (4)
1115 #define OPT_JAVAP LONG_OPT (5)
1117 static const struct option options[] =
1119 { "classpath", required_argument, NULL, OPT_classpath },
1120 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1121 { "extdirs", required_argument, NULL, OPT_extdirs },
1122 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
1123 { "help", no_argument, NULL, OPT_HELP },
1124 { "verbose", no_argument, NULL, 'v' },
1125 { "version", no_argument, NULL, OPT_VERSION },
1126 { "javap", no_argument, NULL, OPT_JAVAP },
1127 { "print-main", no_argument, &flag_print_main, 1 },
1128 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
1129 { NULL, no_argument, NULL, 0 }
1132 static void
1133 usage (void)
1135 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1136 exit (1);
1139 static void
1140 help (void)
1142 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1143 printf (_("Display contents of a class file in readable form.\n\n"));
1144 printf (_(" -c Disassemble method bodies\n"));
1145 printf (_(" --javap Generate output in 'javap' format\n"));
1146 printf ("\n");
1147 printf (_(" --classpath PATH Set path to find .class files\n"));
1148 printf (_(" -IDIR Append directory to class path\n"));
1149 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1150 printf (_(" --extdirs PATH Set extensions directory path\n"));
1151 printf (_(" -o FILE Set output file name\n"));
1152 printf ("\n");
1153 printf (_(" --help Print this help, then exit\n"));
1154 printf (_(" --version Print version number, then exit\n"));
1155 printf (_(" -v, --verbose Print extra information while running\n"));
1156 printf ("\n");
1157 printf (_("For bug reporting instructions, please see:\n"
1158 "%s.\n"), bug_report_url);
1159 exit (0);
1162 static void
1163 version (void)
1165 printf ("jcf-dump (GCC) %s\n\n", version_string);
1166 printf ("Copyright %s 2006 Free Software Foundation, Inc.\n", _("(C)"));
1167 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1168 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1169 exit (0);
1173 main (int argc, char** argv)
1175 JCF jcf[1];
1176 int argi, opt;
1178 /* Unlock the stdio streams. */
1179 unlock_std_streams ();
1181 gcc_init_libintl ();
1183 if (argc <= 1)
1185 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1186 usage ();
1189 jcf_path_init ();
1191 /* We use getopt_long_only to allow single `-' long options. For
1192 some of our options this is more natural. */
1193 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1195 switch (opt)
1197 case 0:
1198 /* Already handled. */
1199 break;
1201 case 'o':
1202 output_file = optarg;
1203 break;
1205 case 'I':
1206 jcf_path_include_arg (optarg);
1207 break;
1209 case 'v':
1210 verbose++;
1211 break;
1213 case 'c':
1214 flag_disassemble_methods = 1;
1215 break;
1217 case OPT_classpath:
1218 jcf_path_classpath_arg (optarg);
1219 break;
1221 case OPT_bootclasspath:
1222 jcf_path_bootclasspath_arg (optarg);
1223 break;
1225 case OPT_extdirs:
1226 jcf_path_extdirs_arg (optarg);
1227 break;
1229 case OPT_HELP:
1230 help ();
1231 break;
1233 case OPT_VERSION:
1234 version ();
1235 break;
1237 case OPT_JAVAP:
1238 flag_javap_compatible++;
1239 flag_print_constant_pool = 0;
1240 flag_print_attributes = 0;
1241 break;
1243 default:
1244 usage ();
1248 if (verbose && ! flag_javap_compatible)
1249 flag_print_constant_pool = 1;
1251 if (optind == argc)
1253 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1254 usage ();
1257 jcf_path_seal (verbose);
1259 if (flag_print_main)
1261 flag_print_fields = 0;
1262 flag_print_methods = 0;
1263 flag_print_constant_pool = 0;
1264 flag_print_attributes = 0;
1265 flag_print_class_info = 0;
1268 if (output_file)
1270 out = fopen (output_file, "w");
1271 if (! out)
1273 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1274 return FATAL_EXIT_CODE;
1277 else
1278 out = stdout;
1280 if (optind >= argc)
1282 fprintf (out, "Reading .class from <standard input>.\n");
1283 open_class ("<stdio>", jcf, 0, NULL);
1284 process_class (jcf);
1286 else
1288 for (argi = optind; argi < argc; argi++)
1290 char *arg = argv[argi];
1291 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1292 if (class_filename == NULL)
1293 class_filename = find_classfile (arg, jcf, NULL);
1294 if (class_filename == NULL)
1296 perror ("Could not find class");
1297 return FATAL_EXIT_CODE;
1299 JCF_FILL (jcf, 4);
1300 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1302 long compressed_size, member_size;
1303 int compression_method, filename_length, extra_length;
1304 int general_purpose_bits;
1305 const char *filename;
1306 int total_length;
1307 if (flag_print_class_info)
1308 fprintf (out, "Reading classes from archive %s.\n",
1309 class_filename);
1310 for (;;)
1312 int skip = 0;
1313 jcf_filbuf_t save_filbuf = jcf->filbuf;
1314 long magic = JCF_readu4_le (jcf);
1315 if (magic == 0x02014b50 || magic == 0x06054b50)
1316 break; /* got to central directory */
1317 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1319 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1320 return FATAL_EXIT_CODE;
1322 JCF_FILL (jcf, 26);
1323 JCF_SKIP (jcf, 2);
1324 general_purpose_bits = JCF_readu2_le (jcf);
1325 compression_method = JCF_readu2_le (jcf);
1326 JCF_SKIP (jcf, 8);
1327 compressed_size = JCF_readu4_le (jcf);
1328 member_size = JCF_readu4_le (jcf);
1329 filename_length = JCF_readu2_le (jcf);
1330 extra_length = JCF_readu2_le (jcf);
1331 total_length = filename_length + extra_length
1332 + compressed_size;
1333 if (jcf->read_end - jcf->read_ptr < total_length)
1334 jcf_trim_old_input (jcf);
1335 JCF_FILL (jcf, total_length);
1336 filename = (const char *) jcf->read_ptr;
1337 JCF_SKIP (jcf, filename_length);
1338 JCF_SKIP (jcf, extra_length);
1339 if (filename_length > 0
1340 && filename[filename_length-1] == '/')
1342 if (flag_print_class_info)
1343 fprintf (out, "[Skipping directory %.*s]\n",
1344 filename_length, filename);
1345 skip = 1;
1347 else if (compression_method != 0)
1349 if (flag_print_class_info)
1350 fprintf (out, "[Skipping compressed file %.*s]\n",
1351 filename_length, filename);
1352 skip = 1;
1354 else if (member_size < 4
1355 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1357 if (flag_print_class_info)
1358 fprintf (out, "[Skipping non-.class member %.*s]\n",
1359 filename_length, filename);
1360 skip = 1;
1362 else
1364 if (flag_print_class_info)
1365 fprintf (out, "Reading class member: %.*s.\n",
1366 filename_length, filename);
1368 if (skip)
1370 JCF_SKIP (jcf, compressed_size);
1372 else
1374 unsigned char *save_end;
1375 jcf->filbuf = jcf_unexpected_eof;
1376 save_end = jcf->read_end;
1377 jcf->read_end = jcf->read_ptr + compressed_size;
1378 process_class (jcf);
1379 jcf->filbuf = save_filbuf;
1380 jcf->read_end = save_end;
1384 else
1386 if (flag_print_class_info)
1387 fprintf (out, "Reading .class from %s.\n", class_filename);
1388 process_class (jcf);
1390 JCF_FINISH(jcf);
1394 return SUCCESS_EXIT_CODE;
1399 static void
1400 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1402 #undef PTR
1403 int PC;
1404 int i;
1405 int saw_wide = 0;
1406 if (flag_disassemble_methods == 0)
1407 return;
1408 #define BCODE byte_ops
1409 for (PC = 0; PC < len;)
1411 int oldpc = PC;
1412 int saw_index;
1413 jint INT_temp;
1414 switch (byte_ops[PC++])
1417 /* This is the actual code emitted for each of opcodes in javaops.def.
1418 The actual opcode-specific stuff is handled by the OPKIND macro.
1419 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1420 Those macros are defined below. The OPKINDs that do not have any
1421 inline parameters (such as BINOP) and therefore do mot need anything
1422 else to me printed out just use an empty body. */
1424 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1425 case OPCODE: \
1426 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1427 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1428 fputc ('\n', out); \
1429 break;
1431 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1432 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1433 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1434 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1436 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1437 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1439 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1440 These all push a constant onto the opcode stack. */
1441 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1442 saw_index = 0, i = (OPERAND_VALUE); \
1443 if (oldpc+1 == PC) /* nothing */; \
1444 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1445 else fprintf (out, " %d", i);
1447 /* Print out operand (a local variable index) for LOAD opcodes.
1448 These all push local variable onto the opcode stack. */
1449 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1450 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1452 /* Handle STORE opcodes same as LOAD opcodes.
1453 These all store a value from the opcode stack in a local variable. */
1454 #define STORE LOAD
1456 /* Handle more kind of opcodes. */
1457 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1458 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1459 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1460 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1461 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1462 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1463 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1465 /* Handle putfield and getfield opcodes, with static versions. */
1466 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1467 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1469 /* Print operand for invoke opcodes. */
1470 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1471 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1472 if (OPERAND_VALUE) /* for invokeinterface */ \
1473 { int nargs = IMMEDIATE_u1; PC++; \
1474 fprintf (out, " nargs:%d", nargs); }
1476 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1477 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1479 #define ARRAY(OPERAND_TYPE, SUBOP) \
1480 ARRAY_##SUBOP(OPERAND_TYPE)
1481 /* Handle sub-categories of ARRAY opcodes. */
1482 #define ARRAY_LOAD(TYPE) /* nothing */
1483 #define ARRAY_STORE(TYPE) /* nothing */
1484 #define ARRAY_LENGTH(TYPE) /* nothing */
1485 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1486 #define ARRAY_NEW_NUM \
1487 INT_temp = IMMEDIATE_u1; \
1488 { switch ((int) INT_temp) { \
1489 case 4: fputs (" boolean", out); break; \
1490 case 5: fputs (" char", out); break; \
1491 case 6: fputs (" float", out); break; \
1492 case 7: fputs (" double", out); break; \
1493 case 8: fputs (" byte", out); break; \
1494 case 9: fputs (" short", out); break; \
1495 case 10: fputs (" int", out); break; \
1496 case 11: fputs (" long", out); break; \
1497 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1500 #define ARRAY_NEW_PTR \
1501 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1503 #define ARRAY_NEW_MULTI \
1504 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1505 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1507 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1508 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1510 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1511 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1512 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1514 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1515 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1516 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1518 #undef RET /* Defined by config/i386/i386.h */
1519 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1520 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1521 saw_wide = 0; \
1522 fprintf (out, " %ld", (long) INT_temp);
1524 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1525 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1527 #define LOOKUP_SWITCH \
1528 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1529 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1530 while (--npairs >= 0) { \
1531 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1532 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1535 #define TABLE_SWITCH \
1536 { jint default_offset = IMMEDIATE_s4; \
1537 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1538 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1539 (long) low, (long) high, (long) default_offset+oldpc); \
1540 for (; low <= high; low++) { \
1541 jint offset = IMMEDIATE_s4; \
1542 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1545 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1546 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1548 #define SPECIAL_IINC(OPERAND_TYPE) \
1549 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1550 fprintf (out, " %d", i); \
1551 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1552 saw_wide = 0; \
1553 fprintf (out, " %d", i)
1555 #define SPECIAL_WIDE(OPERAND_TYPE) \
1556 saw_wide = 1;
1558 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1559 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1560 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1561 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1563 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1564 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1566 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1567 TEST(OPERAND_TYPE, OPERAND_VALUE)
1569 #include "javaop.def"
1571 load_store:
1572 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1573 else
1575 saw_wide = 0;
1576 fprintf (out, " %ld", (long) INT_temp);
1578 fputc ('\n', out);
1579 break;
1581 default:
1582 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);