Pass name cleanups
[official-gcc.git] / gcc / java / jcf-dump.c
blob6a2714c12058ab57c5e1b4383f0a5ade4a611e3b
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, 2011 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"
55 #include "diagnostic.h"
57 #include "jcf.h"
58 #include "tree.h"
59 #include "java-tree.h"
61 #include "version.h"
63 #include <getopt.h>
64 #include <math.h>
66 /* Output file. */
67 FILE *out;
68 /* Name of output file, if NULL if stdout. */
69 char *output_file = NULL;
71 int verbose = 0;
73 int flag_disassemble_methods = 0;
74 int flag_print_class_info = 1;
75 int flag_print_constant_pool = 0;
76 int flag_print_fields = 1;
77 int flag_print_methods = 1;
78 int flag_print_attributes = 1;
80 /* Print names of classes that have a "main" method. */
81 int flag_print_main = 0;
83 /* Index in constant pool of this class. */
84 int this_class_index = 0;
86 int class_access_flags = 0;
88 /* Print in format similar to javap. VERY INCOMPLETE. */
89 int flag_javap_compatible = 0;
91 static void print_access_flags (FILE *, uint16, char);
92 static void print_constant_terse (FILE*, JCF*, int, int);
93 static void print_constant_terse_with_index (FILE *, JCF *, int, int);
94 static void print_constant (FILE *, JCF *, int, int);
95 static void print_constant_ref (FILE *, JCF *, int);
96 static void disassemble_method (JCF*, const unsigned char *, int);
97 static void print_name (FILE*, JCF*, int);
98 static void print_signature (FILE*, JCF*, int, int);
99 static int utf8_equal_string (struct JCF*, int, const char *);
100 static void usage (void) ATTRIBUTE_NORETURN;
101 static void help (void) ATTRIBUTE_NORETURN;
102 static void version (void) ATTRIBUTE_NORETURN;
103 static void process_class (struct JCF *);
104 static void print_constant_pool (struct JCF *);
105 static void print_exception_table (struct JCF *, const unsigned char *entries,
106 int);
107 static void indent (FILE *, int);
108 static void print_element_value (FILE *, JCF *, int);
109 static void print_annotation (FILE *, JCF *, int);
110 static void print_annotations (FILE *, JCF *, int);
111 static void print_parameter_annotations (FILE *, JCF *, int);
113 #define PRINT_SIGNATURE_RESULT_ONLY 1
114 #define PRINT_SIGNATURE_ARGS_ONLY 2
116 static int
117 utf8_equal_string (JCF *jcf, int index, const char * value)
119 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
120 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
122 int len = strlen (value);
123 if (JPOOL_UTF_LENGTH (jcf, index) == len
124 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
125 return 1;
127 return 0;
130 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
131 this_class_index = 0; \
132 if (flag_print_class_info) \
133 fprintf (out, \
134 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
135 (unsigned long) MAGIC, (long) MINOR, (long) MAJOR)
137 #define HANDLE_START_CONSTANT_POOL(COUNT) \
138 if (flag_print_constant_pool) \
139 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
141 #define HANDLE_SOURCEFILE(INDEX) \
142 { fprintf (out, "Attribute "); \
143 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
144 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
145 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
147 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
148 this_class_index = THIS; \
149 class_access_flags = ACCESS_FLAGS; \
150 if (flag_print_class_info) \
151 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
152 print_access_flags (out, ACCESS_FLAGS, 'c'); \
153 fputc ('\n', out); \
154 fprintf (out, "This class: "); \
155 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
156 if (flag_print_constant_pool || SUPER != 0) \
157 fprintf (out, ", super: "); \
158 if (flag_print_constant_pool) \
160 fprintf (out, "%d", SUPER); \
161 if (SUPER != 0) \
162 fputc ('=', out); \
164 if (SUPER != 0) \
165 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
166 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
169 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
170 (flag_print_attributes <= 0)
172 #define HANDLE_CLASS_INTERFACE(INDEX) \
173 if (flag_print_class_info) \
174 { fprintf (out, "- Implements: "); \
175 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
176 fputc ('\n', out); }
178 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
179 if (flag_print_fields) \
180 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
182 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
183 if (flag_print_fields) \
184 { fprintf (out, "Field name:"); \
185 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
186 print_access_flags (out, ACCESS_FLAGS, 'f'); \
187 fprintf (out, " Descriptor: "); \
188 if (flag_print_constant_pool) \
189 fprintf (out, "%d=", SIGNATURE); \
190 print_signature (out, jcf, SIGNATURE, 0); \
191 fputc ('\n', out); } \
192 else \
193 flag_print_attributes--;
195 #define HANDLE_END_FIELD() \
196 if (! flag_print_fields) \
197 flag_print_attributes++;
199 #define HANDLE_START_METHODS(METHODS_COUNT) \
200 if (flag_print_methods) \
201 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
202 else \
203 flag_print_attributes--;
206 #define HANDLE_END_METHODS() \
207 if (! flag_print_methods) \
208 flag_print_attributes++;
210 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
212 if (flag_print_methods) \
214 if (flag_javap_compatible) \
216 fprintf (out, " "); \
217 print_access_flags (out, ACCESS_FLAGS, 'm'); \
218 fputc (' ', out); \
219 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
220 fputc (' ', out); \
221 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
222 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
223 fputc ('\n', out); \
225 else \
227 fprintf (out, "\nMethod name:"); \
228 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
229 print_access_flags (out, ACCESS_FLAGS, 'm'); \
230 fprintf (out, " Descriptor: "); \
231 if (flag_print_constant_pool) \
232 fprintf (out, "%d=", SIGNATURE); \
233 print_signature (out, jcf, SIGNATURE, 0); \
234 fputc ('\n', out); \
237 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
238 && utf8_equal_string (jcf, NAME, "main") \
239 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
240 && this_class_index > 0 \
241 && (class_access_flags & ACC_PUBLIC)) \
243 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
244 fputc ('\n', out); \
248 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
249 ( fprintf (out, "Attribute "), \
250 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
251 fprintf (out, ", length:%ld", (long) LENGTH) )
253 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
254 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
255 fprintf (out, ", value: "), \
256 print_constant_ref (out, jcf, VALUE_INDEX), \
257 fprintf (out, "\n") )
259 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
260 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
261 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
262 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
263 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
265 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
266 print_exception_table (jcf, ENTRIES, COUNT)
268 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
269 { int n = (COUNT); int i; \
270 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
271 fprintf (out, ", count: %d\n", n); \
272 for (i = 0; i < n; i++) {\
273 int ex_index = JCF_readu2 (jcf); \
274 fprintf (out, "%3d: ", i); \
275 print_constant_ref (out, jcf, ex_index); \
276 fputc ('\n', out); } }
278 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
279 { int n = (COUNT); int i; \
280 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
281 fprintf (out, ", count: %d\n", n); \
282 for (i = 0; i < n; i++) {\
283 int start_pc = JCF_readu2 (jcf); \
284 int length = JCF_readu2 (jcf); \
285 int name_index = JCF_readu2 (jcf); \
286 int signature_index = JCF_readu2 (jcf); \
287 int slot = JCF_readu2 (jcf); \
288 fprintf (out, " slot#%d: name: ", slot); \
289 if (flag_print_constant_pool) \
290 fprintf (out, "%d=", name_index); \
291 print_name (out, jcf, name_index); \
292 fprintf (out, ", type: "); \
293 if (flag_print_constant_pool) \
294 fprintf (out, "%d=", signature_index); \
295 print_signature (out, jcf, signature_index, 0); \
296 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
298 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \
299 { int n = (COUNT); int i; \
300 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
301 fprintf (out, ", count: %d\n", n); \
302 for (i = 0; i < n; i++) { \
303 int start_pc = JCF_readu2 (jcf); \
304 int length = JCF_readu2 (jcf); \
305 int name_index = JCF_readu2 (jcf); \
306 int signature_index = JCF_readu2 (jcf); \
307 int slot = JCF_readu2 (jcf); \
308 fprintf (out, " slot#%d: name: ", slot); \
309 if (flag_print_constant_pool) \
310 fprintf (out, "%d=", name_index); \
311 print_name (out, jcf, name_index); \
312 fprintf (out, ", type: "); \
313 if (flag_print_constant_pool) \
314 fprintf (out, "%d=", signature_index); \
315 print_signature (out, jcf, signature_index, 0); \
316 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
318 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
319 { int n = (COUNT); int i; \
320 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
321 fprintf (out, ", count: %d\n", n); \
322 if (flag_disassemble_methods) \
323 for (i = 0; i < n; i++) {\
324 int start_pc = JCF_readu2 (jcf); \
325 int line_number = JCF_readu2 (jcf); \
326 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
327 else \
328 JCF_SKIP (jcf, 4 * n); }
330 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
331 { int n = (COUNT); \
332 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
333 while (n--) \
335 uint16 inner_class_info_index = JCF_readu2 (jcf); \
336 uint16 outer_class_info_index = JCF_readu2 (jcf); \
337 uint16 inner_name_index = JCF_readu2 (jcf); \
338 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
340 if (flag_print_class_info) \
342 fprintf (out, "\n inner: "); \
343 if (inner_class_info_index == 0) \
344 fprintf (out, " (no inner info index)"); \
345 else \
346 print_constant_terse_with_index (out, jcf, \
347 inner_class_info_index, \
348 CONSTANT_Class); \
349 if (inner_name_index == 0) \
350 fprintf (out, " (anonymous)"); \
351 else if (verbose || flag_print_constant_pool) \
353 fprintf (out, " ("); \
354 print_constant_terse_with_index (out, jcf, inner_name_index, \
355 CONSTANT_Utf8); \
356 fputc (')', out); \
358 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
359 print_access_flags (out, inner_class_access_flags, 'c'); \
360 fprintf (out, ", outer class: "); \
361 if (outer_class_info_index == 0) \
362 fprintf (out, "(not a member)"); \
363 else \
364 print_constant_terse_with_index (out, jcf, \
365 outer_class_info_index, \
366 CONSTANT_Class); \
369 if (flag_print_class_info) \
370 fputc ('\n', out); \
373 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
374 { int i, n = (LENGTH), c = 0; \
375 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
376 fputc ('\n', out); \
377 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
378 if (c != '\r' && c != '\n') fputc('\n', out); }
380 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \
381 { uint16 class_index, method_index; \
382 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
383 class_index = JCF_readu2 (jcf); \
384 method_index = JCF_readu2 (jcf); \
385 fprintf (out, "\n Class: "); \
386 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
387 fprintf (out, "\n Method: "); \
388 print_constant_terse_with_index (out, jcf, method_index, \
389 CONSTANT_NameAndType); \
390 fputc ('\n', out); \
393 #define HANDLE_SIGNATURE_ATTRIBUTE() \
395 uint16 signature; \
396 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
397 signature = JCF_readu2 (jcf); \
398 fprintf (out, "\n Value: "); \
399 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
400 fputc ('\n', out); \
403 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
405 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
406 print_annotations (out, jcf, 1); \
409 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
411 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
412 print_annotations (out, jcf, 1); \
415 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
417 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
418 print_parameter_annotations (out, jcf, 1); \
421 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
423 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
424 print_parameter_annotations (out, jcf, 1); \
427 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
429 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
430 print_element_value (out, jcf, 1); \
434 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
435 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
436 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
438 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
439 if (flag_print_attributes > 0) \
440 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
442 #include "javaop.h"
446 static void
447 indent (FILE *stream, int level)
449 int i;
450 for (i = 0; i < level; ++i)
451 fprintf (stream, " ");
454 static void
455 print_element_value (FILE *stream, JCF *jcf, int level)
457 uint8 tag = JCF_readu (jcf);
458 indent (stream, level);
459 switch (tag)
461 case 'B':
462 case 'C':
463 case 'S':
464 case 'Z':
465 case 'I':
467 uint16 cindex = JCF_readu2 (jcf);
468 print_constant_terse_with_index (stream, jcf, cindex,
469 CONSTANT_Integer);
471 break;
472 case 'D':
474 uint16 cindex = JCF_readu2 (jcf);
475 print_constant_terse_with_index (stream, jcf, cindex,
476 CONSTANT_Double);
478 break;
479 case 'F':
481 uint16 cindex = JCF_readu2 (jcf);
482 print_constant_terse_with_index (stream, jcf, cindex,
483 CONSTANT_Float);
485 break;
486 case 'J':
488 uint16 cindex = JCF_readu2 (jcf);
489 print_constant_terse_with_index (stream, jcf, cindex,
490 CONSTANT_Long);
492 break;
493 case 's':
495 uint16 cindex = JCF_readu2 (jcf);
496 /* Despite what the JVM spec says, compilers generate a Utf8
497 constant here, not a String. */
498 print_constant_terse_with_index (stream, jcf, cindex,
499 CONSTANT_Utf8);
501 break;
503 case 'e':
505 uint16 type_name_index = JCF_readu2 (jcf);
506 uint16 const_name_index = JCF_readu2 (jcf);
507 fprintf (stream, "enum class: ");
508 print_constant_terse_with_index (stream, jcf, type_name_index,
509 CONSTANT_Utf8);
510 fprintf (stream, "\n");
511 indent (stream, level);
512 fprintf (stream, "Field: ");
513 print_constant_terse_with_index (stream, jcf, const_name_index,
514 CONSTANT_Utf8);
516 break;
517 case 'c':
519 uint16 class_info_index = JCF_readu2 (jcf);
520 print_constant_terse_with_index (stream, jcf, class_info_index,
521 CONSTANT_Utf8);
523 break;
524 case '@':
526 fprintf (stream, "Annotation:\n");
527 print_annotation (stream, jcf, level + 1);
529 break;
530 case '[':
532 uint16 n_array_elts = JCF_readu2 (jcf);
533 fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
534 while (n_array_elts--)
535 print_element_value (stream, jcf, level + 1);
536 indent (stream, level);
537 fprintf (stream, "]");
539 break;
540 default:
541 fprintf (stream, "Unexpected tag value: %d", (int) tag);
542 break;
544 fputc ('\n', stream);
547 static void
548 print_annotation (FILE *stream, JCF *jcf, int level)
550 uint16 type_index = JCF_readu2 (jcf);
551 uint16 npairs = JCF_readu2 (jcf);
552 fprintf (stream, "\n");
553 indent (stream, level);
554 fprintf (stream, "Annotation name: ");
555 print_constant_terse_with_index (stream, jcf, type_index,
556 CONSTANT_Utf8);
557 if (npairs)
559 fprintf (stream, "\n");
560 while (npairs--)
562 uint16 name_index = JCF_readu2 (jcf);
563 indent (stream, level + 1);
564 fprintf (stream, "Name: ");
565 print_constant_terse_with_index (stream, jcf, name_index,
566 CONSTANT_Utf8);
567 fprintf (stream, "\n");
568 print_element_value (stream, jcf, level + 2);
573 static void
574 print_annotations (FILE *stream, JCF *jcf, int level)
576 uint16 num = JCF_readu2 (jcf);
577 while (num--)
578 print_annotation (stream, jcf, level);
581 static void
582 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
584 uint8 nparams = JCF_readu (jcf);
585 uint8 i;
586 for (i = 0; i < nparams; ++i)
588 indent (stream, level);
589 fprintf (stream, "Parameter annotations (%d):\n", (int) i);
590 print_annotations (stream, jcf, level + 1);
596 static void
597 print_constant_ref (FILE *stream, JCF *jcf, int index)
599 if (index <= 0 || index >= JPOOL_SIZE(jcf))
600 fprintf (stream, "<out of range>");
601 else
603 if (flag_print_constant_pool)
604 fprintf (stream, "#%d=", index);
605 fputc ('<', stream);
606 print_constant (stream, jcf, index, 1);
607 fputc ('>', stream);
611 /* Print the access flags given by FLAGS.
612 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
613 or 'm' (method flags). */
615 static void
616 print_access_flags (FILE *stream, uint16 flags, char context)
618 if (flags & ACC_PUBLIC) fprintf (stream, " public");
619 if (flags & ACC_PRIVATE) fprintf (stream, " private");
620 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
621 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
622 if (flags & ACC_STATIC) fprintf (stream, " static");
623 if (flags & ACC_FINAL) fprintf (stream, " final");
624 if (flags & ACC_TRANSIENT)
625 fprintf (stream, context == 'm' ? " varargs" : " transient");
626 if (flags & ACC_VOLATILE)
627 fprintf (stream, context == 'm' ? " bridge" : " volatile");
628 if (flags & ACC_NATIVE) fprintf (stream, " native");
629 if (flags & ACC_SYNCHRONIZED)
631 if (context == 'c')
632 fprintf (stream, " super");
633 else
634 fprintf (stream, " synchronized");
636 if (flags & ACC_INTERFACE)
637 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
638 if (flags & ACC_ENUM) fprintf (stream, " enum");
639 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
640 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
644 static void
645 print_name (FILE* stream, JCF* jcf, int name_index)
647 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
648 fprintf (stream, "<not a UTF8 constant>");
649 else
650 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
651 JPOOL_UTF_LENGTH (jcf, name_index));
654 /* If the type of the constant at INDEX matches EXPECTED,
655 print it tersely, otherwise more verbosely. */
657 static void
658 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
660 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
661 fprintf (out, "<constant pool index %d not in range>", index);
662 else if (JPOOL_TAG (jcf, index) != expected)
664 fprintf (out, "<Unexpected constant type ");
665 print_constant (out, jcf, index, 1);
666 fprintf (out, ">");
668 else
669 print_constant (out, jcf, index, 0);
672 static void
673 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
675 if (flag_print_constant_pool)
676 fprintf (out, "%d=", index);
677 print_constant_terse (out, jcf, index, expected);
680 /* Print the constant at INDEX in JCF's constant pool.
681 If verbosity==0, print very tersely (no extraneous text).
682 If verbosity==1, prefix the type of the constant.
683 If verbosity==2, add more descriptive text. */
685 static void
686 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
688 int j, n;
689 jlong num;
690 const char *str;
691 int kind = JPOOL_TAG (jcf, index);
692 switch (kind)
694 case CONSTANT_Class:
695 n = JPOOL_USHORT1 (jcf, index);
696 if (verbosity > 0)
698 if (verbosity > 1)
699 fprintf (out, "Class name: %d=", n);
700 else
701 fprintf (out, "Class ");
703 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
704 fprintf (out, "<out of range>");
705 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
707 int len = JPOOL_UTF_LENGTH (jcf, n);
708 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
710 else
711 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
712 break;
713 case CONSTANT_Fieldref:
714 str = "Field"; goto field_or_method;
715 case CONSTANT_Methodref:
716 str = "Method"; goto field_or_method;
717 case CONSTANT_InterfaceMethodref:
718 str = "InterfaceMethod"; goto field_or_method;
719 field_or_method:
721 uint16 tclass = JPOOL_USHORT1 (jcf, index);
722 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
723 if (verbosity == 2)
724 fprintf (out, "%sref class: %d=", str, tclass);
725 else if (verbosity > 0)
726 fprintf (out, "%s ", str);
727 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
728 if (verbosity < 2)
729 fprintf (out, ".");
730 else
731 fprintf (out, " name_and_type: %d=<", name_and_type);
732 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
733 if (verbosity == 2)
734 fputc ('>', out);
736 break;
737 case CONSTANT_String:
738 j = JPOOL_USHORT1 (jcf, index);
739 if (verbosity > 0)
741 if (verbosity > 1)
742 fprintf (out, "String %d=", j);
743 else
744 fprintf (out, "String ");
746 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
747 break;
748 case CONSTANT_Integer:
749 if (verbosity > 0)
750 fprintf (out, "Integer ");
751 num = JPOOL_INT (jcf, index);
752 goto integer;
753 case CONSTANT_Long:
754 if (verbosity > 0)
755 fprintf (out, "Long ");
756 num = JPOOL_LONG (jcf, index);
757 goto integer;
758 integer:
760 char buffer[25];
761 format_int (buffer, num, 10);
762 fprintf (out, "%s", buffer);
763 if (verbosity > 1)
765 format_uint (buffer, (uint64)num, 16);
766 fprintf (out, "=0x%s", buffer);
769 break;
770 case CONSTANT_Float:
772 jfloat fnum = JPOOL_FLOAT (jcf, index);
774 if (verbosity > 0)
775 fputs ("Float ", out);
777 if (fnum.negative)
778 putc ('-', out);
780 if (JFLOAT_FINITE (fnum))
782 int dummy;
783 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
784 double f;
785 uint32 mantissa = fnum.mantissa;
786 if (fnum.exponent == 0)
787 /* Denormal. */
788 exponent++;
789 else
790 /* Normal; add the implicit bit. */
791 mantissa |= ((uint32)1 << 23);
793 f = frexp (mantissa, &dummy);
794 f = ldexp (f, exponent + 1);
795 fprintf (out, "%.10g", f);
797 else
799 if (fnum.mantissa == 0)
800 fputs ("Inf", out);
801 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
802 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
803 else
804 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
807 if (verbosity > 1)
808 fprintf (out, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf, index));
810 break;
812 case CONSTANT_Double:
814 jdouble dnum = JPOOL_DOUBLE (jcf, index);
816 if (verbosity > 0)
817 fputs ("Double ", out);
819 if (dnum.negative)
820 putc ('-', out);
822 if (JDOUBLE_FINITE (dnum))
824 int dummy;
825 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
826 double d;
827 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
828 + dnum.mantissa1);
829 if (dnum.exponent == 0)
830 /* Denormal. */
831 exponent++;
832 else
833 /* Normal; add the implicit bit. */
834 mantissa |= ((uint64)1 << 52);
836 d = frexp (mantissa, &dummy);
837 d = ldexp (d, exponent + 1);
838 fprintf (out, "%.20g", d);
840 else
842 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
843 mantissa = (mantissa << 32) + dnum.mantissa1;
845 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
846 fputs ("Inf", out);
847 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
848 fprintf (out, "QNaN(%" HOST_LONG_LONG_FORMAT "u)",
849 (unsigned long long)mantissa);
850 else
851 fprintf (out, "SNaN(%" HOST_LONG_LONG_FORMAT "u)",
852 (unsigned long long)mantissa);
854 if (verbosity > 1)
856 int32 hi, lo;
857 hi = JPOOL_UINT (jcf, index);
858 lo = JPOOL_UINT (jcf, index + 1);
859 fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi,
860 (unsigned long) lo);
862 break;
864 case CONSTANT_NameAndType:
866 uint16 name = JPOOL_USHORT1 (jcf, index);
867 uint16 sig = JPOOL_USHORT2 (jcf, index);
868 if (verbosity > 0)
870 if (verbosity > 1)
871 fprintf (out, "NameAndType name: %d=", name);
872 else
873 fprintf (out, "NameAndType ");
875 print_name (out, jcf, name);
876 if (verbosity <= 1)
877 fputc (' ', out);
878 else
879 fprintf (out, ", signature: %d=", sig);
880 print_signature (out, jcf, sig, 0);
882 break;
883 case CONSTANT_Utf8:
885 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
886 int length = JPOOL_UTF_LENGTH (jcf, index);
887 if (verbosity > 0)
888 { /* Print as 8-bit bytes. */
889 fputs ("Utf8: \"", out);
890 while (--length >= 0)
891 jcf_print_char (out, *str++);
893 else
894 { /* Print as Unicode. */
895 fputc ('\"', out);
896 jcf_print_utf8 (out, str, length);
898 fputc ('\"', out);
900 break;
901 default:
902 fprintf (out, "(Unknown constant type %d)", kind);
906 static void
907 print_constant_pool (JCF *jcf)
909 int i;
910 for (i = 1; i < JPOOL_SIZE(jcf); i++)
912 int kind = JPOOL_TAG (jcf, i);
913 fprintf (out, "#%d: ", i);
914 print_constant (out, jcf, i, 2);
915 fprintf (out, "\n");
916 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
917 i++; /* These take up two slots in the constant table */
921 static void
922 print_signature_type (FILE* stream, const unsigned char **ptr,
923 const unsigned char *limit)
925 int array_size;
926 if ((*ptr) >= limit)
927 return;
928 switch (*(*ptr))
930 case '[':
931 array_size = -1;
932 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
934 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
936 print_signature_type (stream, ptr, limit);
937 if (array_size == -1)
938 fprintf (stream, "[]");
939 else
940 fprintf (stream, "[%d]", array_size);
941 break;
942 case '(':
944 int nargs = 0;
945 fputc (*(*ptr)++, stream);
946 for (; **ptr != ')' && *ptr < limit; nargs++)
948 if (nargs > 0)
949 fputc (',', stream);
950 print_signature_type (stream, ptr, limit);
952 if (*ptr < limit)
954 fputc (*(*ptr)++, stream);
955 print_signature_type (stream, ptr, limit);
957 else
958 fprintf (stream, "???");
960 break;
962 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
963 case 'C': fprintf (stream, "char"); (*ptr)++; break;
964 case 'D': fprintf (stream, "double"); (*ptr)++; break;
965 case 'F': fprintf (stream, "float"); (*ptr)++; break;
966 case 'S': fprintf (stream, "short"); (*ptr)++; break;
967 case 'I': fprintf (stream, "int"); (*ptr)++; break;
968 case 'J': fprintf (stream, "long"); (*ptr)++; break;
969 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
970 case 'V': fprintf (stream, "void"); (*ptr)++; break;
972 case 'L':
973 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
974 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
975 if (*(*ptr) == ';')
976 (*ptr)++;
977 break;
978 default:
979 jcf_print_char (stream, *(*ptr)++);
983 static void
984 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
986 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
987 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
988 else
990 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
991 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
992 const unsigned char *limit;
993 limit = str + length;
994 if (str >= limit)
995 fprintf (stream, "<empty signature string>");
996 else
998 if (options & PRINT_SIGNATURE_RESULT_ONLY)
1000 while (str < limit && *str++ != ')') ;
1002 if (options & PRINT_SIGNATURE_ARGS_ONLY)
1004 str++;
1005 fputc ('(', stream);
1006 while (str < limit && *str != ')')
1008 print_signature_type (stream, &str, limit);
1009 if (*str != ')')
1010 fputs (", ", stream);
1012 fputc (')', stream);
1014 else
1016 print_signature_type (stream, &str, limit);
1017 if (str < limit)
1019 fprintf (stream, "<junk:");
1020 jcf_print_utf8 (stream, str, limit - str);
1021 fputc ('>', stream);
1029 static void
1030 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1032 /* Print exception table. */
1033 int i = count;
1034 if (i > 0)
1036 const unsigned char *ptr = entries;
1037 fprintf (out, "Exceptions (count: %d):\n", i);
1038 for (; --i >= 0; ptr+= 8)
1040 int start_pc = GET_u2 (ptr);
1041 int end_pc = GET_u2 (ptr+2);
1042 int handler_pc = GET_u2 (ptr+4);
1043 int catch_type = GET_u2 (ptr+6);
1044 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
1045 start_pc, end_pc, handler_pc);
1046 if (catch_type == 0)
1047 fputs ("0 /* finally */", out);
1048 else
1049 print_constant_terse_with_index (out, jcf,
1050 catch_type, CONSTANT_Class);
1051 fputc ('\n', out);
1056 #include "jcf-reader.c"
1058 static void
1059 process_class (JCF *jcf)
1061 int code;
1062 if (jcf_parse_preamble (jcf) != 0)
1063 fprintf (stderr, _("Not a valid Java .class file.\n"));
1065 /* Parse and possibly print constant pool */
1066 code = jcf_parse_constant_pool (jcf);
1067 if (code != 0)
1069 fprintf (stderr, _("error while parsing constant pool\n"));
1070 exit (FATAL_EXIT_CODE);
1072 code = verify_constant_pool (jcf);
1073 if (code > 0)
1075 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1076 exit (FATAL_EXIT_CODE);
1078 if (flag_print_constant_pool)
1079 print_constant_pool (jcf);
1081 jcf_parse_class (jcf);
1082 code = jcf_parse_fields (jcf);
1083 if (code != 0)
1085 fprintf (stderr, _("error while parsing fields\n"));
1086 exit (FATAL_EXIT_CODE);
1088 code = jcf_parse_methods (jcf);
1089 if (code != 0)
1091 fprintf (stderr, _("error while parsing methods\n"));
1092 exit (FATAL_EXIT_CODE);
1094 code = jcf_parse_final_attributes (jcf);
1095 if (code != 0)
1097 fprintf (stderr, _("error while parsing final attributes\n"));
1098 exit (FATAL_EXIT_CODE);
1100 jcf->filename = NULL;
1105 /* This is used to mark options with no short value. */
1106 #define LONG_OPT(Num) ((Num) + 128)
1108 #define OPT_classpath LONG_OPT (0)
1109 #define OPT_CLASSPATH OPT_classpath
1110 #define OPT_bootclasspath LONG_OPT (1)
1111 #define OPT_extdirs LONG_OPT (2)
1112 #define OPT_HELP LONG_OPT (3)
1113 #define OPT_VERSION LONG_OPT (4)
1114 #define OPT_JAVAP LONG_OPT (5)
1116 static const struct option options[] =
1118 { "classpath", required_argument, NULL, OPT_classpath },
1119 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1120 { "extdirs", required_argument, NULL, OPT_extdirs },
1121 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
1122 { "help", no_argument, NULL, OPT_HELP },
1123 { "verbose", no_argument, NULL, 'v' },
1124 { "version", no_argument, NULL, OPT_VERSION },
1125 { "javap", no_argument, NULL, OPT_JAVAP },
1126 { "print-main", no_argument, &flag_print_main, 1 },
1127 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
1128 { NULL, no_argument, NULL, 0 }
1131 static void
1132 usage (void)
1134 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1135 exit (1);
1138 static void
1139 help (void)
1141 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1142 printf (_("Display contents of a class file in readable form.\n\n"));
1143 printf (_(" -c Disassemble method bodies\n"));
1144 printf (_(" --javap Generate output in 'javap' format\n"));
1145 printf ("\n");
1146 printf (_(" --classpath PATH Set path to find .class files\n"));
1147 printf (_(" -IDIR Append directory to class path\n"));
1148 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1149 printf (_(" --extdirs PATH Set extensions directory path\n"));
1150 printf (_(" -o FILE Set output file name\n"));
1151 printf ("\n");
1152 printf (_(" --help Print this help, then exit\n"));
1153 printf (_(" --version Print version number, then exit\n"));
1154 printf (_(" -v, --verbose Print extra information while running\n"));
1155 printf ("\n");
1156 printf (_("For bug reporting instructions, please see:\n"
1157 "%s.\n"), bug_report_url);
1158 exit (0);
1161 static void
1162 version (void)
1164 printf ("jcf-dump %s%s\n\n", pkgversion_string, version_string);
1165 printf ("Copyright %s 2011 Free Software Foundation, Inc.\n", _("(C)"));
1166 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1167 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1168 exit (0);
1172 main (int argc, char** argv)
1174 JCF jcf[1];
1175 int argi, opt;
1176 const char *p;
1178 p = argv[0] + strlen (argv[0]);
1179 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
1180 --p;
1181 progname = p;
1183 xmalloc_set_program_name (progname);
1185 /* Unlock the stdio streams. */
1186 unlock_std_streams ();
1188 gcc_init_libintl ();
1190 diagnostic_initialize (global_dc, 0);
1192 if (argc <= 1)
1194 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1195 usage ();
1198 jcf_path_init ();
1200 /* We use getopt_long_only to allow single `-' long options. For
1201 some of our options this is more natural. */
1202 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1204 switch (opt)
1206 case 0:
1207 /* Already handled. */
1208 break;
1210 case 'o':
1211 output_file = optarg;
1212 break;
1214 case 'I':
1215 jcf_path_include_arg (optarg);
1216 break;
1218 case 'v':
1219 verbose++;
1220 break;
1222 case 'c':
1223 flag_disassemble_methods = 1;
1224 break;
1226 case OPT_classpath:
1227 jcf_path_classpath_arg (optarg);
1228 break;
1230 case OPT_bootclasspath:
1231 jcf_path_bootclasspath_arg (optarg);
1232 break;
1234 case OPT_extdirs:
1235 jcf_path_extdirs_arg (optarg);
1236 break;
1238 case OPT_HELP:
1239 help ();
1240 break;
1242 case OPT_VERSION:
1243 version ();
1244 break;
1246 case OPT_JAVAP:
1247 flag_javap_compatible++;
1248 flag_print_constant_pool = 0;
1249 flag_print_attributes = 0;
1250 break;
1252 default:
1253 usage ();
1257 if (verbose && ! flag_javap_compatible)
1258 flag_print_constant_pool = 1;
1260 if (optind == argc)
1262 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1263 usage ();
1266 jcf_path_seal (verbose);
1268 if (flag_print_main)
1270 flag_print_fields = 0;
1271 flag_print_methods = 0;
1272 flag_print_constant_pool = 0;
1273 flag_print_attributes = 0;
1274 flag_print_class_info = 0;
1277 if (output_file)
1279 out = fopen (output_file, "w");
1280 if (! out)
1282 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1283 return FATAL_EXIT_CODE;
1286 else
1287 out = stdout;
1289 if (optind >= argc)
1291 fprintf (out, "Reading .class from <standard input>.\n");
1292 open_class ("<stdio>", jcf, 0, NULL);
1293 process_class (jcf);
1295 else
1297 for (argi = optind; argi < argc; argi++)
1299 char *arg = argv[argi];
1300 const char *class_filename = find_class (arg, strlen (arg), jcf);
1301 if (class_filename == NULL)
1302 class_filename = find_classfile (arg, jcf, NULL);
1303 if (class_filename == NULL)
1305 perror ("Could not find class");
1306 return FATAL_EXIT_CODE;
1308 JCF_FILL (jcf, 4);
1309 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1311 long compressed_size, member_size;
1312 int compression_method, filename_length, extra_length;
1313 const char *filename;
1314 int total_length;
1315 if (flag_print_class_info)
1316 fprintf (out, "Reading classes from archive %s.\n",
1317 class_filename);
1318 for (;;)
1320 int skip = 0;
1321 jcf_filbuf_t save_filbuf = jcf->filbuf;
1322 long magic = JCF_readu4_le (jcf);
1323 if (magic == 0x02014b50 || magic == 0x06054b50)
1324 break; /* got to central directory */
1325 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1327 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1328 return FATAL_EXIT_CODE;
1330 JCF_FILL (jcf, 26);
1331 JCF_SKIP (jcf, 2);
1332 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf);
1333 compression_method = JCF_readu2_le (jcf);
1334 JCF_SKIP (jcf, 8);
1335 compressed_size = JCF_readu4_le (jcf);
1336 member_size = JCF_readu4_le (jcf);
1337 filename_length = JCF_readu2_le (jcf);
1338 extra_length = JCF_readu2_le (jcf);
1339 total_length = filename_length + extra_length
1340 + compressed_size;
1341 if (jcf->read_end - jcf->read_ptr < total_length)
1342 jcf_trim_old_input (jcf);
1343 JCF_FILL (jcf, total_length);
1344 filename = (const char *) jcf->read_ptr;
1345 JCF_SKIP (jcf, filename_length);
1346 JCF_SKIP (jcf, extra_length);
1347 if (filename_length > 0
1348 && filename[filename_length-1] == '/')
1350 if (flag_print_class_info)
1351 fprintf (out, "[Skipping directory %.*s]\n",
1352 filename_length, filename);
1353 skip = 1;
1355 else if (compression_method != 0)
1357 if (flag_print_class_info)
1358 fprintf (out, "[Skipping compressed file %.*s]\n",
1359 filename_length, filename);
1360 skip = 1;
1362 else if (member_size < 4
1363 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1365 if (flag_print_class_info)
1366 fprintf (out, "[Skipping non-.class member %.*s]\n",
1367 filename_length, filename);
1368 skip = 1;
1370 else
1372 if (flag_print_class_info)
1373 fprintf (out, "Reading class member: %.*s.\n",
1374 filename_length, filename);
1376 if (skip)
1378 JCF_SKIP (jcf, compressed_size);
1380 else
1382 unsigned char *save_end;
1383 jcf->filbuf = jcf_unexpected_eof;
1384 save_end = jcf->read_end;
1385 jcf->read_end = jcf->read_ptr + compressed_size;
1386 process_class (jcf);
1387 jcf->filbuf = save_filbuf;
1388 jcf->read_end = save_end;
1392 else
1394 if (flag_print_class_info)
1395 fprintf (out, "Reading .class from %s.\n", class_filename);
1396 process_class (jcf);
1398 JCF_FINISH(jcf);
1402 return SUCCESS_EXIT_CODE;
1407 static void
1408 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1410 #undef PTR
1411 int PC;
1412 int i;
1413 int saw_wide = 0;
1414 if (flag_disassemble_methods == 0)
1415 return;
1416 #define BCODE byte_ops
1417 for (PC = 0; PC < len;)
1419 int oldpc = PC;
1420 int saw_index;
1421 jint INT_temp;
1422 switch (byte_ops[PC++])
1425 /* This is the actual code emitted for each of opcodes in javaops.def.
1426 The actual opcode-specific stuff is handled by the OPKIND macro.
1427 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1428 Those macros are defined below. The OPKINDs that do not have any
1429 inline parameters (such as BINOP) and therefore do mot need anything
1430 else to me printed out just use an empty body. */
1432 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1433 case OPCODE: \
1434 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1435 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1436 fputc ('\n', out); \
1437 break;
1439 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1440 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1441 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1442 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1444 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1445 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1447 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1448 These all push a constant onto the opcode stack. */
1449 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1450 saw_index = 0, i = (OPERAND_VALUE); \
1451 if (oldpc+1 == PC) /* nothing */; \
1452 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1453 else fprintf (out, " %d", i);
1455 /* Print out operand (a local variable index) for LOAD opcodes.
1456 These all push local variable onto the opcode stack. */
1457 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1458 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1460 /* Handle STORE opcodes same as LOAD opcodes.
1461 These all store a value from the opcode stack in a local variable. */
1462 #define STORE LOAD
1464 /* Handle more kind of opcodes. */
1465 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1466 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1467 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1468 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1469 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1470 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1471 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1473 /* Handle putfield and getfield opcodes, with static versions. */
1474 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1475 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1477 /* Print operand for invoke opcodes. */
1478 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1479 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1480 if (OPERAND_VALUE) /* for invokeinterface */ \
1481 { int nargs = IMMEDIATE_u1; PC++; \
1482 fprintf (out, " nargs:%d", nargs); }
1484 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1485 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1487 #define ARRAY(OPERAND_TYPE, SUBOP) \
1488 ARRAY_##SUBOP(OPERAND_TYPE)
1489 /* Handle sub-categories of ARRAY opcodes. */
1490 #define ARRAY_LOAD(TYPE) /* nothing */
1491 #define ARRAY_STORE(TYPE) /* nothing */
1492 #define ARRAY_LENGTH(TYPE) /* nothing */
1493 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1494 #define ARRAY_NEW_NUM \
1495 INT_temp = IMMEDIATE_u1; \
1496 { switch ((int) INT_temp) { \
1497 case 4: fputs (" boolean", out); break; \
1498 case 5: fputs (" char", out); break; \
1499 case 6: fputs (" float", out); break; \
1500 case 7: fputs (" double", out); break; \
1501 case 8: fputs (" byte", out); break; \
1502 case 9: fputs (" short", out); break; \
1503 case 10: fputs (" int", out); break; \
1504 case 11: fputs (" long", out); break; \
1505 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1508 #define ARRAY_NEW_PTR \
1509 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1511 #define ARRAY_NEW_MULTI \
1512 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1513 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1515 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1516 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1518 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1519 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1520 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1522 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1523 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1524 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1526 #undef RET /* Defined by config/i386/i386.h */
1527 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1528 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1529 saw_wide = 0; \
1530 fprintf (out, " %ld", (long) INT_temp);
1532 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1533 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1535 #define LOOKUP_SWITCH \
1536 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1537 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1538 while (--npairs >= 0) { \
1539 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1540 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1543 #define TABLE_SWITCH \
1544 { jint default_offset = IMMEDIATE_s4; \
1545 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1546 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1547 (long) low, (long) high, (long) default_offset+oldpc); \
1548 for (; low <= high; low++) { \
1549 jint offset = IMMEDIATE_s4; \
1550 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1553 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1554 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1556 #define SPECIAL_IINC(OPERAND_TYPE) \
1557 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1558 fprintf (out, " %d", i); \
1559 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1560 saw_wide = 0; \
1561 fprintf (out, " %d", i)
1563 #define SPECIAL_WIDE(OPERAND_TYPE) \
1564 saw_wide = 1;
1566 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1567 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1568 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1569 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1571 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1572 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1574 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1575 TEST(OPERAND_TYPE, OPERAND_VALUE)
1577 #include "javaop.def"
1579 load_store:
1580 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1581 else
1583 saw_wide = 0;
1584 fprintf (out, " %ld", (long) INT_temp);
1586 fputc ('\n', out);
1587 break;
1589 default:
1590 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);