2010-07-27 Paolo Carlini <paolo.carlini@oracle.com>
[official-gcc/alias-decl.git] / gcc / java / jcf-dump.c
blob2012f7b0eacca80d08049eea9a974ff00b441bd2
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, 2007, 2008, 2009, 2010 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 3, 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 COPYING3. If not see
21 <http://www.gnu.org/licenses/>.
23 Java and all Java-based marks are trademarks or registered trademarks
24 of Sun Microsystems, Inc. in the United States and other countries.
25 The Free Software Foundation is independent of Sun Microsystems, Inc. */
27 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
30 jcf-dump is a program to print out the contents of class files.
31 Usage: jcf-dump [FLAGS] CLASS
32 Each CLASS is either:
33 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
34 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
35 + The name of a .zip or .jar file (which prints all the classes in the
36 archive).
38 OPTIONS:
40 Dis-assemble each method.
41 -classpath PATH
42 Overrides $CLASSPATH.
43 --print-main
44 Print nothing if there is no valid "main" method;
45 otherwise, print only the class name.
46 --javap
47 Print output in the style of Sun's javap program. VERY UNFINISHED.
51 #include "config.h"
52 #include "system.h"
53 #include "coretypes.h"
54 #include "intl.h"
56 #include "jcf.h"
57 #include "tree.h"
58 #include "java-tree.h"
60 #include "version.h"
62 #include <getopt.h>
63 #include <math.h>
65 /* Output file. */
66 FILE *out;
67 /* Name of output file, if NULL if stdout. */
68 char *output_file = NULL;
70 int verbose = 0;
72 int flag_disassemble_methods = 0;
73 int flag_print_class_info = 1;
74 int flag_print_constant_pool = 0;
75 int flag_print_fields = 1;
76 int flag_print_methods = 1;
77 int flag_print_attributes = 1;
79 /* When nonzero, warn when source file is newer than matching class
80 file. */
81 int flag_newer = 1;
83 /* Print names of classes that have a "main" method. */
84 int flag_print_main = 0;
86 /* Index in constant pool of this class. */
87 int this_class_index = 0;
89 int class_access_flags = 0;
91 /* Print in format similar to javap. VERY INCOMPLETE. */
92 int flag_javap_compatible = 0;
94 static void print_access_flags (FILE *, uint16, char);
95 static void print_constant_terse (FILE*, JCF*, int, int);
96 static void print_constant_terse_with_index (FILE *, JCF *, int, int);
97 static void print_constant (FILE *, JCF *, int, int);
98 static void print_constant_ref (FILE *, JCF *, int);
99 static void disassemble_method (JCF*, const unsigned char *, int);
100 static void print_name (FILE*, JCF*, int);
101 static void print_signature (FILE*, JCF*, int, int);
102 static int utf8_equal_string (struct JCF*, int, const char *);
103 static void usage (void) ATTRIBUTE_NORETURN;
104 static void help (void) ATTRIBUTE_NORETURN;
105 static void version (void) ATTRIBUTE_NORETURN;
106 static void process_class (struct JCF *);
107 static void print_constant_pool (struct JCF *);
108 static void print_exception_table (struct JCF *, const unsigned char *entries,
109 int);
110 static void indent (FILE *, int);
111 static void print_element_value (FILE *, JCF *, int);
112 static void print_annotation (FILE *, JCF *, int);
113 static void print_annotations (FILE *, JCF *, int);
114 static void print_parameter_annotations (FILE *, JCF *, int);
116 #define PRINT_SIGNATURE_RESULT_ONLY 1
117 #define PRINT_SIGNATURE_ARGS_ONLY 2
119 static int
120 utf8_equal_string (JCF *jcf, int index, const char * value)
122 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
123 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
125 int len = strlen (value);
126 if (JPOOL_UTF_LENGTH (jcf, index) == len
127 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
128 return 1;
130 return 0;
133 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
134 this_class_index = 0; \
135 if (flag_print_class_info) \
136 fprintf (out, \
137 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
138 (unsigned long) MAGIC, (long) MINOR, (long) MAJOR)
140 #define HANDLE_START_CONSTANT_POOL(COUNT) \
141 if (flag_print_constant_pool) \
142 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
144 #define HANDLE_SOURCEFILE(INDEX) \
145 { fprintf (out, "Attribute "); \
146 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
147 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
148 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
150 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
151 this_class_index = THIS; \
152 class_access_flags = ACCESS_FLAGS; \
153 if (flag_print_class_info) \
154 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
155 print_access_flags (out, ACCESS_FLAGS, 'c'); \
156 fputc ('\n', out); \
157 fprintf (out, "This class: "); \
158 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
159 if (flag_print_constant_pool || SUPER != 0) \
160 fprintf (out, ", super: "); \
161 if (flag_print_constant_pool) \
163 fprintf (out, "%d", SUPER); \
164 if (SUPER != 0) \
165 fputc ('=', out); \
167 if (SUPER != 0) \
168 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
169 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
172 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
173 (flag_print_attributes <= 0)
175 #define HANDLE_CLASS_INTERFACE(INDEX) \
176 if (flag_print_class_info) \
177 { fprintf (out, "- Implements: "); \
178 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
179 fputc ('\n', out); }
181 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
182 if (flag_print_fields) \
183 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
185 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
186 if (flag_print_fields) \
187 { fprintf (out, "Field name:"); \
188 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
189 print_access_flags (out, ACCESS_FLAGS, 'f'); \
190 fprintf (out, " Descriptor: "); \
191 if (flag_print_constant_pool) \
192 fprintf (out, "%d=", SIGNATURE); \
193 print_signature (out, jcf, SIGNATURE, 0); \
194 fputc ('\n', out); } \
195 else \
196 flag_print_attributes--;
198 #define HANDLE_END_FIELD() \
199 if (! flag_print_fields) \
200 flag_print_attributes++;
202 #define HANDLE_START_METHODS(METHODS_COUNT) \
203 if (flag_print_methods) \
204 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
205 else \
206 flag_print_attributes--;
209 #define HANDLE_END_METHODS() \
210 if (! flag_print_methods) \
211 flag_print_attributes++;
213 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
215 if (flag_print_methods) \
217 if (flag_javap_compatible) \
219 fprintf (out, " "); \
220 print_access_flags (out, ACCESS_FLAGS, 'm'); \
221 fputc (' ', out); \
222 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
223 fputc (' ', out); \
224 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
225 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
226 fputc ('\n', out); \
228 else \
230 fprintf (out, "\nMethod name:"); \
231 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
232 print_access_flags (out, ACCESS_FLAGS, 'm'); \
233 fprintf (out, " Descriptor: "); \
234 if (flag_print_constant_pool) \
235 fprintf (out, "%d=", SIGNATURE); \
236 print_signature (out, jcf, SIGNATURE, 0); \
237 fputc ('\n', out); \
240 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
241 && utf8_equal_string (jcf, NAME, "main") \
242 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
243 && this_class_index > 0 \
244 && (class_access_flags & ACC_PUBLIC)) \
246 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
247 fputc ('\n', out); \
251 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
252 ( fprintf (out, "Attribute "), \
253 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
254 fprintf (out, ", length:%ld", (long) LENGTH) )
256 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
257 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
258 fprintf (out, ", value: "), \
259 print_constant_ref (out, jcf, VALUE_INDEX), \
260 fprintf (out, "\n") )
262 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
263 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
264 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
265 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
266 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
268 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
269 print_exception_table (jcf, ENTRIES, COUNT)
271 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
272 { int n = (COUNT); int i; \
273 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
274 fprintf (out, ", count: %d\n", n); \
275 for (i = 0; i < n; i++) {\
276 int ex_index = JCF_readu2 (jcf); \
277 fprintf (out, "%3d: ", i); \
278 print_constant_ref (out, jcf, ex_index); \
279 fputc ('\n', out); } }
281 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
282 { int n = (COUNT); int i; \
283 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
284 fprintf (out, ", count: %d\n", n); \
285 for (i = 0; i < n; i++) {\
286 int start_pc = JCF_readu2 (jcf); \
287 int length = JCF_readu2 (jcf); \
288 int name_index = JCF_readu2 (jcf); \
289 int signature_index = JCF_readu2 (jcf); \
290 int slot = JCF_readu2 (jcf); \
291 fprintf (out, " slot#%d: name: ", slot); \
292 if (flag_print_constant_pool) \
293 fprintf (out, "%d=", name_index); \
294 print_name (out, jcf, name_index); \
295 fprintf (out, ", type: "); \
296 if (flag_print_constant_pool) \
297 fprintf (out, "%d=", signature_index); \
298 print_signature (out, jcf, signature_index, 0); \
299 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
301 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \
302 { int n = (COUNT); int i; \
303 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
304 fprintf (out, ", count: %d\n", n); \
305 for (i = 0; i < n; i++) { \
306 int start_pc = JCF_readu2 (jcf); \
307 int length = JCF_readu2 (jcf); \
308 int name_index = JCF_readu2 (jcf); \
309 int signature_index = JCF_readu2 (jcf); \
310 int slot = JCF_readu2 (jcf); \
311 fprintf (out, " slot#%d: name: ", slot); \
312 if (flag_print_constant_pool) \
313 fprintf (out, "%d=", name_index); \
314 print_name (out, jcf, name_index); \
315 fprintf (out, ", type: "); \
316 if (flag_print_constant_pool) \
317 fprintf (out, "%d=", signature_index); \
318 print_signature (out, jcf, signature_index, 0); \
319 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
321 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
322 { int n = (COUNT); int i; \
323 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
324 fprintf (out, ", count: %d\n", n); \
325 if (flag_disassemble_methods) \
326 for (i = 0; i < n; i++) {\
327 int start_pc = JCF_readu2 (jcf); \
328 int line_number = JCF_readu2 (jcf); \
329 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
330 else \
331 JCF_SKIP (jcf, 4 * n); }
333 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
334 { int n = (COUNT); \
335 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
336 while (n--) \
338 uint16 inner_class_info_index = JCF_readu2 (jcf); \
339 uint16 outer_class_info_index = JCF_readu2 (jcf); \
340 uint16 inner_name_index = JCF_readu2 (jcf); \
341 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
343 if (flag_print_class_info) \
345 fprintf (out, "\n inner: "); \
346 if (inner_class_info_index == 0) \
347 fprintf (out, " (no inner info index)"); \
348 else \
349 print_constant_terse_with_index (out, jcf, \
350 inner_class_info_index, \
351 CONSTANT_Class); \
352 if (inner_name_index == 0) \
353 fprintf (out, " (anonymous)"); \
354 else if (verbose || flag_print_constant_pool) \
356 fprintf (out, " ("); \
357 print_constant_terse_with_index (out, jcf, inner_name_index, \
358 CONSTANT_Utf8); \
359 fputc (')', out); \
361 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
362 print_access_flags (out, inner_class_access_flags, 'c'); \
363 fprintf (out, ", outer class: "); \
364 if (outer_class_info_index == 0) \
365 fprintf (out, "(not a member)"); \
366 else \
367 print_constant_terse_with_index (out, jcf, \
368 outer_class_info_index, \
369 CONSTANT_Class); \
372 if (flag_print_class_info) \
373 fputc ('\n', out); \
376 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
377 { int i, n = (LENGTH), c = 0; \
378 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
379 fputc ('\n', out); \
380 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
381 if (c != '\r' && c != '\n') fputc('\n', out); }
383 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \
384 { uint16 class_index, method_index; \
385 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
386 class_index = JCF_readu2 (jcf); \
387 method_index = JCF_readu2 (jcf); \
388 fprintf (out, "\n Class: "); \
389 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
390 fprintf (out, "\n Method: "); \
391 print_constant_terse_with_index (out, jcf, method_index, \
392 CONSTANT_NameAndType); \
393 fputc ('\n', out); \
396 #define HANDLE_SIGNATURE_ATTRIBUTE() \
398 uint16 signature; \
399 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
400 signature = JCF_readu2 (jcf); \
401 fprintf (out, "\n Value: "); \
402 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
403 fputc ('\n', out); \
406 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
408 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
409 print_annotations (out, jcf, 1); \
412 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
414 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
415 print_annotations (out, jcf, 1); \
418 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
420 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
421 print_parameter_annotations (out, jcf, 1); \
424 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
426 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
427 print_parameter_annotations (out, jcf, 1); \
430 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
432 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
433 print_element_value (out, jcf, 1); \
437 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
438 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
439 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
441 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
442 if (flag_print_attributes > 0) \
443 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
445 #include "javaop.h"
449 static void
450 indent (FILE *stream, int level)
452 int i;
453 for (i = 0; i < level; ++i)
454 fprintf (stream, " ");
457 static void
458 print_element_value (FILE *stream, JCF *jcf, int level)
460 uint8 tag = JCF_readu (jcf);
461 indent (stream, level);
462 switch (tag)
464 case 'B':
465 case 'C':
466 case 'S':
467 case 'Z':
468 case 'I':
470 uint16 cindex = JCF_readu2 (jcf);
471 print_constant_terse_with_index (stream, jcf, cindex,
472 CONSTANT_Integer);
474 break;
475 case 'D':
477 uint16 cindex = JCF_readu2 (jcf);
478 print_constant_terse_with_index (stream, jcf, cindex,
479 CONSTANT_Double);
481 break;
482 case 'F':
484 uint16 cindex = JCF_readu2 (jcf);
485 print_constant_terse_with_index (stream, jcf, cindex,
486 CONSTANT_Float);
488 break;
489 case 'J':
491 uint16 cindex = JCF_readu2 (jcf);
492 print_constant_terse_with_index (stream, jcf, cindex,
493 CONSTANT_Long);
495 break;
496 case 's':
498 uint16 cindex = JCF_readu2 (jcf);
499 /* Despite what the JVM spec says, compilers generate a Utf8
500 constant here, not a String. */
501 print_constant_terse_with_index (stream, jcf, cindex,
502 CONSTANT_Utf8);
504 break;
506 case 'e':
508 uint16 type_name_index = JCF_readu2 (jcf);
509 uint16 const_name_index = JCF_readu2 (jcf);
510 fprintf (stream, "enum class: ");
511 print_constant_terse_with_index (stream, jcf, type_name_index,
512 CONSTANT_Utf8);
513 fprintf (stream, "\n");
514 indent (stream, level);
515 fprintf (stream, "Field: ");
516 print_constant_terse_with_index (stream, jcf, const_name_index,
517 CONSTANT_Utf8);
519 break;
520 case 'c':
522 uint16 class_info_index = JCF_readu2 (jcf);
523 print_constant_terse_with_index (stream, jcf, class_info_index,
524 CONSTANT_Utf8);
526 break;
527 case '@':
529 fprintf (stream, "Annotation:\n");
530 print_annotation (stream, jcf, level + 1);
532 break;
533 case '[':
535 uint16 n_array_elts = JCF_readu2 (jcf);
536 fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
537 while (n_array_elts--)
538 print_element_value (stream, jcf, level + 1);
539 indent (stream, level);
540 fprintf (stream, "]");
542 break;
543 default:
544 fprintf (stream, "Unexpected tag value: %d", (int) tag);
545 break;
547 fputc ('\n', stream);
550 static void
551 print_annotation (FILE *stream, JCF *jcf, int level)
553 uint16 type_index = JCF_readu2 (jcf);
554 uint16 npairs = JCF_readu2 (jcf);
555 fprintf (stream, "\n");
556 indent (stream, level);
557 fprintf (stream, "Annotation name: ");
558 print_constant_terse_with_index (stream, jcf, type_index,
559 CONSTANT_Utf8);
560 if (npairs)
562 fprintf (stream, "\n");
563 while (npairs--)
565 uint16 name_index = JCF_readu2 (jcf);
566 indent (stream, level + 1);
567 fprintf (stream, "Name: ");
568 print_constant_terse_with_index (stream, jcf, name_index,
569 CONSTANT_Utf8);
570 fprintf (stream, "\n");
571 print_element_value (stream, jcf, level + 2);
576 static void
577 print_annotations (FILE *stream, JCF *jcf, int level)
579 uint16 num = JCF_readu2 (jcf);
580 while (num--)
581 print_annotation (stream, jcf, level);
584 static void
585 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
587 uint8 nparams = JCF_readu (jcf);
588 uint8 i;
589 for (i = 0; i < nparams; ++i)
591 indent (stream, level);
592 fprintf (stream, "Parameter annotations (%d):\n", (int) i);
593 print_annotations (stream, jcf, level + 1);
599 static void
600 print_constant_ref (FILE *stream, JCF *jcf, int index)
602 if (index <= 0 || index >= JPOOL_SIZE(jcf))
603 fprintf (stream, "<out of range>");
604 else
606 if (flag_print_constant_pool)
607 fprintf (stream, "#%d=", index);
608 fputc ('<', stream);
609 print_constant (stream, jcf, index, 1);
610 fputc ('>', stream);
614 /* Print the access flags given by FLAGS.
615 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
616 or 'm' (method flags). */
618 static void
619 print_access_flags (FILE *stream, uint16 flags, char context)
621 if (flags & ACC_PUBLIC) fprintf (stream, " public");
622 if (flags & ACC_PRIVATE) fprintf (stream, " private");
623 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
624 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
625 if (flags & ACC_STATIC) fprintf (stream, " static");
626 if (flags & ACC_FINAL) fprintf (stream, " final");
627 if (flags & ACC_TRANSIENT)
628 fprintf (stream, context == 'm' ? " varargs" : " transient");
629 if (flags & ACC_VOLATILE)
630 fprintf (stream, context == 'm' ? " bridge" : " volatile");
631 if (flags & ACC_NATIVE) fprintf (stream, " native");
632 if (flags & ACC_SYNCHRONIZED)
634 if (context == 'c')
635 fprintf (stream, " super");
636 else
637 fprintf (stream, " synchronized");
639 if (flags & ACC_INTERFACE)
640 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
641 if (flags & ACC_ENUM) fprintf (stream, " enum");
642 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
643 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
647 static void
648 print_name (FILE* stream, JCF* jcf, int name_index)
650 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
651 fprintf (stream, "<not a UTF8 constant>");
652 else
653 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
654 JPOOL_UTF_LENGTH (jcf, name_index));
657 /* If the type of the constant at INDEX matches EXPECTED,
658 print it tersely, otherwise more verbosely. */
660 static void
661 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
663 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
664 fprintf (out, "<constant pool index %d not in range>", index);
665 else if (JPOOL_TAG (jcf, index) != expected)
667 fprintf (out, "<Unexpected constant type ");
668 print_constant (out, jcf, index, 1);
669 fprintf (out, ">");
671 else
672 print_constant (out, jcf, index, 0);
675 static void
676 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
678 if (flag_print_constant_pool)
679 fprintf (out, "%d=", index);
680 print_constant_terse (out, jcf, index, expected);
683 /* Print the constant at INDEX in JCF's constant pool.
684 If verbosity==0, print very tersely (no extraneous text).
685 If verbosity==1, prefix the type of the constant.
686 If verbosity==2, add more descriptive text. */
688 static void
689 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
691 int j, n;
692 jlong num;
693 const char *str;
694 int kind = JPOOL_TAG (jcf, index);
695 switch (kind)
697 case CONSTANT_Class:
698 n = JPOOL_USHORT1 (jcf, index);
699 if (verbosity > 0)
701 if (verbosity > 1)
702 fprintf (out, "Class name: %d=", n);
703 else
704 fprintf (out, "Class ");
706 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
707 fprintf (out, "<out of range>");
708 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
710 int len = JPOOL_UTF_LENGTH (jcf, n);
711 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
713 else
714 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
715 break;
716 case CONSTANT_Fieldref:
717 str = "Field"; goto field_or_method;
718 case CONSTANT_Methodref:
719 str = "Method"; goto field_or_method;
720 case CONSTANT_InterfaceMethodref:
721 str = "InterfaceMethod"; goto field_or_method;
722 field_or_method:
724 uint16 tclass = JPOOL_USHORT1 (jcf, index);
725 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
726 if (verbosity == 2)
727 fprintf (out, "%sref class: %d=", str, tclass);
728 else if (verbosity > 0)
729 fprintf (out, "%s ", str);
730 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
731 if (verbosity < 2)
732 fprintf (out, ".");
733 else
734 fprintf (out, " name_and_type: %d=<", name_and_type);
735 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
736 if (verbosity == 2)
737 fputc ('>', out);
739 break;
740 case CONSTANT_String:
741 j = JPOOL_USHORT1 (jcf, index);
742 if (verbosity > 0)
744 if (verbosity > 1)
745 fprintf (out, "String %d=", j);
746 else
747 fprintf (out, "String ");
749 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
750 break;
751 case CONSTANT_Integer:
752 if (verbosity > 0)
753 fprintf (out, "Integer ");
754 num = JPOOL_INT (jcf, index);
755 goto integer;
756 case CONSTANT_Long:
757 if (verbosity > 0)
758 fprintf (out, "Long ");
759 num = JPOOL_LONG (jcf, index);
760 goto integer;
761 integer:
763 char buffer[25];
764 format_int (buffer, num, 10);
765 fprintf (out, "%s", buffer);
766 if (verbosity > 1)
768 format_uint (buffer, (uint64)num, 16);
769 fprintf (out, "=0x%s", buffer);
772 break;
773 case CONSTANT_Float:
775 jfloat fnum = JPOOL_FLOAT (jcf, index);
777 if (verbosity > 0)
778 fputs ("Float ", out);
780 if (fnum.negative)
781 putc ('-', out);
783 if (JFLOAT_FINITE (fnum))
785 int dummy;
786 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
787 double f;
788 uint32 mantissa = fnum.mantissa;
789 if (fnum.exponent == 0)
790 /* Denormal. */
791 exponent++;
792 else
793 /* Normal; add the implicit bit. */
794 mantissa |= ((uint32)1 << 23);
796 f = frexp (mantissa, &dummy);
797 f = ldexp (f, exponent + 1);
798 fprintf (out, "%.10g", f);
800 else
802 if (fnum.mantissa == 0)
803 fputs ("Inf", out);
804 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
805 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
806 else
807 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
810 if (verbosity > 1)
811 fprintf (out, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf, index));
813 break;
815 case CONSTANT_Double:
817 jdouble dnum = JPOOL_DOUBLE (jcf, index);
819 if (verbosity > 0)
820 fputs ("Double ", out);
822 if (dnum.negative)
823 putc ('-', out);
825 if (JDOUBLE_FINITE (dnum))
827 int dummy;
828 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
829 double d;
830 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
831 + dnum.mantissa1);
832 if (dnum.exponent == 0)
833 /* Denormal. */
834 exponent++;
835 else
836 /* Normal; add the implicit bit. */
837 mantissa |= ((uint64)1 << 52);
839 d = frexp (mantissa, &dummy);
840 d = ldexp (d, exponent + 1);
841 fprintf (out, "%.20g", d);
843 else
845 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
846 mantissa = (mantissa << 32) + dnum.mantissa1;
848 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
849 fputs ("Inf", out);
850 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
851 fprintf (out, "QNaN(%" HOST_LONG_LONG_FORMAT "u)",
852 (unsigned long long)mantissa);
853 else
854 fprintf (out, "SNaN(%" HOST_LONG_LONG_FORMAT "u)",
855 (unsigned long long)mantissa);
857 if (verbosity > 1)
859 int32 hi, lo;
860 hi = JPOOL_UINT (jcf, index);
861 lo = JPOOL_UINT (jcf, index + 1);
862 fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi,
863 (unsigned long) lo);
865 break;
867 case CONSTANT_NameAndType:
869 uint16 name = JPOOL_USHORT1 (jcf, index);
870 uint16 sig = JPOOL_USHORT2 (jcf, index);
871 if (verbosity > 0)
873 if (verbosity > 1)
874 fprintf (out, "NameAndType name: %d=", name);
875 else
876 fprintf (out, "NameAndType ");
878 print_name (out, jcf, name);
879 if (verbosity <= 1)
880 fputc (' ', out);
881 else
882 fprintf (out, ", signature: %d=", sig);
883 print_signature (out, jcf, sig, 0);
885 break;
886 case CONSTANT_Utf8:
888 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
889 int length = JPOOL_UTF_LENGTH (jcf, index);
890 if (verbosity > 0)
891 { /* Print as 8-bit bytes. */
892 fputs ("Utf8: \"", out);
893 while (--length >= 0)
894 jcf_print_char (out, *str++);
896 else
897 { /* Print as Unicode. */
898 fputc ('\"', out);
899 jcf_print_utf8 (out, str, length);
901 fputc ('\"', out);
903 break;
904 default:
905 fprintf (out, "(Unknown constant type %d)", kind);
909 static void
910 print_constant_pool (JCF *jcf)
912 int i;
913 for (i = 1; i < JPOOL_SIZE(jcf); i++)
915 int kind = JPOOL_TAG (jcf, i);
916 fprintf (out, "#%d: ", i);
917 print_constant (out, jcf, i, 2);
918 fprintf (out, "\n");
919 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
920 i++; /* These take up two slots in the constant table */
924 static void
925 print_signature_type (FILE* stream, const unsigned char **ptr,
926 const unsigned char *limit)
928 int array_size;
929 if ((*ptr) >= limit)
930 return;
931 switch (*(*ptr))
933 case '[':
934 array_size = -1;
935 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
937 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
939 print_signature_type (stream, ptr, limit);
940 if (array_size == -1)
941 fprintf (stream, "[]");
942 else
943 fprintf (stream, "[%d]", array_size);
944 break;
945 case '(':
947 int nargs = 0;
948 fputc (*(*ptr)++, stream);
949 for (; **ptr != ')' && *ptr < limit; nargs++)
951 if (nargs > 0)
952 fputc (',', stream);
953 print_signature_type (stream, ptr, limit);
955 if (*ptr < limit)
957 fputc (*(*ptr)++, stream);
958 print_signature_type (stream, ptr, limit);
960 else
961 fprintf (stream, "???");
963 break;
965 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
966 case 'C': fprintf (stream, "char"); (*ptr)++; break;
967 case 'D': fprintf (stream, "double"); (*ptr)++; break;
968 case 'F': fprintf (stream, "float"); (*ptr)++; break;
969 case 'S': fprintf (stream, "short"); (*ptr)++; break;
970 case 'I': fprintf (stream, "int"); (*ptr)++; break;
971 case 'J': fprintf (stream, "long"); (*ptr)++; break;
972 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
973 case 'V': fprintf (stream, "void"); (*ptr)++; break;
975 case 'L':
976 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
977 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
978 if (*(*ptr) == ';')
979 (*ptr)++;
980 break;
981 default:
982 jcf_print_char (stream, *(*ptr)++);
986 static void
987 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
989 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
990 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
991 else
993 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
994 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
995 const unsigned char *limit;
996 limit = str + length;
997 if (str >= limit)
998 fprintf (stream, "<empty signature string>");
999 else
1001 if (options & PRINT_SIGNATURE_RESULT_ONLY)
1003 while (str < limit && *str++ != ')') ;
1005 if (options & PRINT_SIGNATURE_ARGS_ONLY)
1007 str++;
1008 fputc ('(', stream);
1009 while (str < limit && *str != ')')
1011 print_signature_type (stream, &str, limit);
1012 if (*str != ')')
1013 fputs (", ", stream);
1015 fputc (')', stream);
1017 else
1019 print_signature_type (stream, &str, limit);
1020 if (str < limit)
1022 fprintf (stream, "<junk:");
1023 jcf_print_utf8 (stream, str, limit - str);
1024 fputc ('>', stream);
1032 static void
1033 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1035 /* Print exception table. */
1036 int i = count;
1037 if (i > 0)
1039 const unsigned char *ptr = entries;
1040 fprintf (out, "Exceptions (count: %d):\n", i);
1041 for (; --i >= 0; ptr+= 8)
1043 int start_pc = GET_u2 (ptr);
1044 int end_pc = GET_u2 (ptr+2);
1045 int handler_pc = GET_u2 (ptr+4);
1046 int catch_type = GET_u2 (ptr+6);
1047 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
1048 start_pc, end_pc, handler_pc);
1049 if (catch_type == 0)
1050 fputs ("0 /* finally */", out);
1051 else
1052 print_constant_terse_with_index (out, jcf,
1053 catch_type, CONSTANT_Class);
1054 fputc ('\n', out);
1059 #include "jcf-reader.c"
1061 static void
1062 process_class (JCF *jcf)
1064 int code;
1065 if (jcf_parse_preamble (jcf) != 0)
1066 fprintf (stderr, _("Not a valid Java .class file.\n"));
1068 /* Parse and possibly print constant pool */
1069 code = jcf_parse_constant_pool (jcf);
1070 if (code != 0)
1072 fprintf (stderr, _("error while parsing constant pool\n"));
1073 exit (FATAL_EXIT_CODE);
1075 code = verify_constant_pool (jcf);
1076 if (code > 0)
1078 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1079 exit (FATAL_EXIT_CODE);
1081 if (flag_print_constant_pool)
1082 print_constant_pool (jcf);
1084 jcf_parse_class (jcf);
1085 code = jcf_parse_fields (jcf);
1086 if (code != 0)
1088 fprintf (stderr, _("error while parsing fields\n"));
1089 exit (FATAL_EXIT_CODE);
1091 code = jcf_parse_methods (jcf);
1092 if (code != 0)
1094 fprintf (stderr, _("error while parsing methods\n"));
1095 exit (FATAL_EXIT_CODE);
1097 code = jcf_parse_final_attributes (jcf);
1098 if (code != 0)
1100 fprintf (stderr, _("error while parsing final attributes\n"));
1101 exit (FATAL_EXIT_CODE);
1103 jcf->filename = NULL;
1108 /* This is used to mark options with no short value. */
1109 #define LONG_OPT(Num) ((Num) + 128)
1111 #define OPT_classpath LONG_OPT (0)
1112 #define OPT_CLASSPATH OPT_classpath
1113 #define OPT_bootclasspath LONG_OPT (1)
1114 #define OPT_extdirs LONG_OPT (2)
1115 #define OPT_HELP LONG_OPT (3)
1116 #define OPT_VERSION LONG_OPT (4)
1117 #define OPT_JAVAP LONG_OPT (5)
1119 static const struct option options[] =
1121 { "classpath", required_argument, NULL, OPT_classpath },
1122 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1123 { "extdirs", required_argument, NULL, OPT_extdirs },
1124 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
1125 { "help", no_argument, NULL, OPT_HELP },
1126 { "verbose", no_argument, NULL, 'v' },
1127 { "version", no_argument, NULL, OPT_VERSION },
1128 { "javap", no_argument, NULL, OPT_JAVAP },
1129 { "print-main", no_argument, &flag_print_main, 1 },
1130 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
1131 { NULL, no_argument, NULL, 0 }
1134 static void
1135 usage (void)
1137 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1138 exit (1);
1141 static void
1142 help (void)
1144 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1145 printf (_("Display contents of a class file in readable form.\n\n"));
1146 printf (_(" -c Disassemble method bodies\n"));
1147 printf (_(" --javap Generate output in 'javap' format\n"));
1148 printf ("\n");
1149 printf (_(" --classpath PATH Set path to find .class files\n"));
1150 printf (_(" -IDIR Append directory to class path\n"));
1151 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1152 printf (_(" --extdirs PATH Set extensions directory path\n"));
1153 printf (_(" -o FILE Set output file name\n"));
1154 printf ("\n");
1155 printf (_(" --help Print this help, then exit\n"));
1156 printf (_(" --version Print version number, then exit\n"));
1157 printf (_(" -v, --verbose Print extra information while running\n"));
1158 printf ("\n");
1159 printf (_("For bug reporting instructions, please see:\n"
1160 "%s.\n"), bug_report_url);
1161 exit (0);
1164 static void
1165 version (void)
1167 printf ("jcf-dump %s%s\n\n", pkgversion_string, version_string);
1168 printf ("Copyright %s 2010 Free Software Foundation, Inc.\n", _("(C)"));
1169 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1170 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1171 exit (0);
1175 main (int argc, char** argv)
1177 JCF jcf[1];
1178 int argi, opt;
1180 /* Unlock the stdio streams. */
1181 unlock_std_streams ();
1183 gcc_init_libintl ();
1185 if (argc <= 1)
1187 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1188 usage ();
1191 jcf_path_init ();
1193 /* We use getopt_long_only to allow single `-' long options. For
1194 some of our options this is more natural. */
1195 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1197 switch (opt)
1199 case 0:
1200 /* Already handled. */
1201 break;
1203 case 'o':
1204 output_file = optarg;
1205 break;
1207 case 'I':
1208 jcf_path_include_arg (optarg);
1209 break;
1211 case 'v':
1212 verbose++;
1213 break;
1215 case 'c':
1216 flag_disassemble_methods = 1;
1217 break;
1219 case OPT_classpath:
1220 jcf_path_classpath_arg (optarg);
1221 break;
1223 case OPT_bootclasspath:
1224 jcf_path_bootclasspath_arg (optarg);
1225 break;
1227 case OPT_extdirs:
1228 jcf_path_extdirs_arg (optarg);
1229 break;
1231 case OPT_HELP:
1232 help ();
1233 break;
1235 case OPT_VERSION:
1236 version ();
1237 break;
1239 case OPT_JAVAP:
1240 flag_javap_compatible++;
1241 flag_print_constant_pool = 0;
1242 flag_print_attributes = 0;
1243 break;
1245 default:
1246 usage ();
1250 if (verbose && ! flag_javap_compatible)
1251 flag_print_constant_pool = 1;
1253 if (optind == argc)
1255 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1256 usage ();
1259 jcf_path_seal (verbose);
1261 if (flag_print_main)
1263 flag_print_fields = 0;
1264 flag_print_methods = 0;
1265 flag_print_constant_pool = 0;
1266 flag_print_attributes = 0;
1267 flag_print_class_info = 0;
1270 if (output_file)
1272 out = fopen (output_file, "w");
1273 if (! out)
1275 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1276 return FATAL_EXIT_CODE;
1279 else
1280 out = stdout;
1282 if (optind >= argc)
1284 fprintf (out, "Reading .class from <standard input>.\n");
1285 open_class ("<stdio>", jcf, 0, NULL);
1286 process_class (jcf);
1288 else
1290 for (argi = optind; argi < argc; argi++)
1292 char *arg = argv[argi];
1293 const char *class_filename = find_class (arg, strlen (arg), jcf);
1294 if (class_filename == NULL)
1295 class_filename = find_classfile (arg, jcf, NULL);
1296 if (class_filename == NULL)
1298 perror ("Could not find class");
1299 return FATAL_EXIT_CODE;
1301 JCF_FILL (jcf, 4);
1302 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1304 long compressed_size, member_size;
1305 int compression_method, filename_length, extra_length;
1306 const char *filename;
1307 int total_length;
1308 if (flag_print_class_info)
1309 fprintf (out, "Reading classes from archive %s.\n",
1310 class_filename);
1311 for (;;)
1313 int skip = 0;
1314 jcf_filbuf_t save_filbuf = jcf->filbuf;
1315 long magic = JCF_readu4_le (jcf);
1316 if (magic == 0x02014b50 || magic == 0x06054b50)
1317 break; /* got to central directory */
1318 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1320 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1321 return FATAL_EXIT_CODE;
1323 JCF_FILL (jcf, 26);
1324 JCF_SKIP (jcf, 2);
1325 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf);
1326 compression_method = JCF_readu2_le (jcf);
1327 JCF_SKIP (jcf, 8);
1328 compressed_size = JCF_readu4_le (jcf);
1329 member_size = JCF_readu4_le (jcf);
1330 filename_length = JCF_readu2_le (jcf);
1331 extra_length = JCF_readu2_le (jcf);
1332 total_length = filename_length + extra_length
1333 + compressed_size;
1334 if (jcf->read_end - jcf->read_ptr < total_length)
1335 jcf_trim_old_input (jcf);
1336 JCF_FILL (jcf, total_length);
1337 filename = (const char *) jcf->read_ptr;
1338 JCF_SKIP (jcf, filename_length);
1339 JCF_SKIP (jcf, extra_length);
1340 if (filename_length > 0
1341 && filename[filename_length-1] == '/')
1343 if (flag_print_class_info)
1344 fprintf (out, "[Skipping directory %.*s]\n",
1345 filename_length, filename);
1346 skip = 1;
1348 else if (compression_method != 0)
1350 if (flag_print_class_info)
1351 fprintf (out, "[Skipping compressed file %.*s]\n",
1352 filename_length, filename);
1353 skip = 1;
1355 else if (member_size < 4
1356 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1358 if (flag_print_class_info)
1359 fprintf (out, "[Skipping non-.class member %.*s]\n",
1360 filename_length, filename);
1361 skip = 1;
1363 else
1365 if (flag_print_class_info)
1366 fprintf (out, "Reading class member: %.*s.\n",
1367 filename_length, filename);
1369 if (skip)
1371 JCF_SKIP (jcf, compressed_size);
1373 else
1375 unsigned char *save_end;
1376 jcf->filbuf = jcf_unexpected_eof;
1377 save_end = jcf->read_end;
1378 jcf->read_end = jcf->read_ptr + compressed_size;
1379 process_class (jcf);
1380 jcf->filbuf = save_filbuf;
1381 jcf->read_end = save_end;
1385 else
1387 if (flag_print_class_info)
1388 fprintf (out, "Reading .class from %s.\n", class_filename);
1389 process_class (jcf);
1391 JCF_FINISH(jcf);
1395 return SUCCESS_EXIT_CODE;
1400 static void
1401 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1403 #undef PTR
1404 int PC;
1405 int i;
1406 int saw_wide = 0;
1407 if (flag_disassemble_methods == 0)
1408 return;
1409 #define BCODE byte_ops
1410 for (PC = 0; PC < len;)
1412 int oldpc = PC;
1413 int saw_index;
1414 jint INT_temp;
1415 switch (byte_ops[PC++])
1418 /* This is the actual code emitted for each of opcodes in javaops.def.
1419 The actual opcode-specific stuff is handled by the OPKIND macro.
1420 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1421 Those macros are defined below. The OPKINDs that do not have any
1422 inline parameters (such as BINOP) and therefore do mot need anything
1423 else to me printed out just use an empty body. */
1425 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1426 case OPCODE: \
1427 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1428 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1429 fputc ('\n', out); \
1430 break;
1432 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1433 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1434 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1435 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1437 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1438 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1440 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1441 These all push a constant onto the opcode stack. */
1442 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1443 saw_index = 0, i = (OPERAND_VALUE); \
1444 if (oldpc+1 == PC) /* nothing */; \
1445 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1446 else fprintf (out, " %d", i);
1448 /* Print out operand (a local variable index) for LOAD opcodes.
1449 These all push local variable onto the opcode stack. */
1450 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1451 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1453 /* Handle STORE opcodes same as LOAD opcodes.
1454 These all store a value from the opcode stack in a local variable. */
1455 #define STORE LOAD
1457 /* Handle more kind of opcodes. */
1458 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1459 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1460 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1461 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1462 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1463 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1464 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1466 /* Handle putfield and getfield opcodes, with static versions. */
1467 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1468 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1470 /* Print operand for invoke opcodes. */
1471 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1472 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1473 if (OPERAND_VALUE) /* for invokeinterface */ \
1474 { int nargs = IMMEDIATE_u1; PC++; \
1475 fprintf (out, " nargs:%d", nargs); }
1477 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1478 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1480 #define ARRAY(OPERAND_TYPE, SUBOP) \
1481 ARRAY_##SUBOP(OPERAND_TYPE)
1482 /* Handle sub-categories of ARRAY opcodes. */
1483 #define ARRAY_LOAD(TYPE) /* nothing */
1484 #define ARRAY_STORE(TYPE) /* nothing */
1485 #define ARRAY_LENGTH(TYPE) /* nothing */
1486 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1487 #define ARRAY_NEW_NUM \
1488 INT_temp = IMMEDIATE_u1; \
1489 { switch ((int) INT_temp) { \
1490 case 4: fputs (" boolean", out); break; \
1491 case 5: fputs (" char", out); break; \
1492 case 6: fputs (" float", out); break; \
1493 case 7: fputs (" double", out); break; \
1494 case 8: fputs (" byte", out); break; \
1495 case 9: fputs (" short", out); break; \
1496 case 10: fputs (" int", out); break; \
1497 case 11: fputs (" long", out); break; \
1498 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1501 #define ARRAY_NEW_PTR \
1502 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1504 #define ARRAY_NEW_MULTI \
1505 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1506 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1508 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1509 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1511 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1512 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1513 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1515 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1516 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1517 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1519 #undef RET /* Defined by config/i386/i386.h */
1520 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1521 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1522 saw_wide = 0; \
1523 fprintf (out, " %ld", (long) INT_temp);
1525 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1526 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1528 #define LOOKUP_SWITCH \
1529 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1530 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1531 while (--npairs >= 0) { \
1532 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1533 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1536 #define TABLE_SWITCH \
1537 { jint default_offset = IMMEDIATE_s4; \
1538 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1539 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1540 (long) low, (long) high, (long) default_offset+oldpc); \
1541 for (; low <= high; low++) { \
1542 jint offset = IMMEDIATE_s4; \
1543 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1546 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1547 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1549 #define SPECIAL_IINC(OPERAND_TYPE) \
1550 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1551 fprintf (out, " %d", i); \
1552 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1553 saw_wide = 0; \
1554 fprintf (out, " %d", i)
1556 #define SPECIAL_WIDE(OPERAND_TYPE) \
1557 saw_wide = 1;
1559 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1560 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1561 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1562 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1564 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1565 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1567 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1568 TEST(OPERAND_TYPE, OPERAND_VALUE)
1570 #include "javaop.def"
1572 load_store:
1573 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1574 else
1576 saw_wide = 0;
1577 fprintf (out, " %ld", (long) INT_temp);
1579 fputc ('\n', out);
1580 break;
1582 default:
1583 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);