2013-01-15 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / java / jcf-dump.c
blob7438174abafac87a124536a9ccad47be56a7700a
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996-2013 Free Software Foundation, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc. */
26 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
29 jcf-dump is a program to print out the contents of class files.
30 Usage: jcf-dump [FLAGS] CLASS
31 Each CLASS is either:
32 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
33 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
34 + The name of a .zip or .jar file (which prints all the classes in the
35 archive).
37 OPTIONS:
39 Dis-assemble each method.
40 -classpath PATH
41 Overrides $CLASSPATH.
42 --print-main
43 Print nothing if there is no valid "main" method;
44 otherwise, print only the class name.
45 --javap
46 Print output in the style of Sun's javap program. VERY UNFINISHED.
50 #include "config.h"
51 #include "system.h"
52 #include "coretypes.h"
53 #include "intl.h"
54 #include "diagnostic.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 /* Print names of classes that have a "main" method. */
80 int flag_print_main = 0;
82 /* Index in constant pool of this class. */
83 int this_class_index = 0;
85 int class_access_flags = 0;
87 /* Print in format similar to javap. VERY INCOMPLETE. */
88 int flag_javap_compatible = 0;
90 static void print_access_flags (FILE *, uint16, char);
91 static void print_constant_terse (FILE*, JCF*, int, int);
92 static void print_constant_terse_with_index (FILE *, JCF *, int, int);
93 static void print_constant (FILE *, JCF *, int, int);
94 static void print_constant_ref (FILE *, JCF *, int);
95 static void disassemble_method (JCF*, const unsigned char *, int);
96 static void print_name (FILE*, JCF*, int);
97 static void print_signature (FILE*, JCF*, int, int);
98 static int utf8_equal_string (struct JCF*, int, const char *);
99 static void usage (void) ATTRIBUTE_NORETURN;
100 static void help (void) ATTRIBUTE_NORETURN;
101 static void version (void) ATTRIBUTE_NORETURN;
102 static void process_class (struct JCF *);
103 static void print_constant_pool (struct JCF *);
104 static void print_exception_table (struct JCF *, const unsigned char *entries,
105 int);
106 static void indent (FILE *, int);
107 static void print_element_value (FILE *, JCF *, int);
108 static void print_annotation (FILE *, JCF *, int);
109 static void print_annotations (FILE *, JCF *, int);
110 static void print_parameter_annotations (FILE *, JCF *, int);
112 #define PRINT_SIGNATURE_RESULT_ONLY 1
113 #define PRINT_SIGNATURE_ARGS_ONLY 2
115 static int
116 utf8_equal_string (JCF *jcf, int index, const char * value)
118 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
119 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
121 int len = strlen (value);
122 if (JPOOL_UTF_LENGTH (jcf, index) == len
123 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
124 return 1;
126 return 0;
129 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
130 this_class_index = 0; \
131 if (flag_print_class_info) \
132 fprintf (out, \
133 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
134 (unsigned long) MAGIC, (long) MINOR, (long) MAJOR)
136 #define HANDLE_START_CONSTANT_POOL(COUNT) \
137 if (flag_print_constant_pool) \
138 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
140 #define HANDLE_SOURCEFILE(INDEX) \
141 { fprintf (out, "Attribute "); \
142 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
143 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
144 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
146 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
147 this_class_index = THIS; \
148 class_access_flags = ACCESS_FLAGS; \
149 if (flag_print_class_info) \
150 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
151 print_access_flags (out, ACCESS_FLAGS, 'c'); \
152 fputc ('\n', out); \
153 fprintf (out, "This class: "); \
154 print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
155 if (flag_print_constant_pool || SUPER != 0) \
156 fprintf (out, ", super: "); \
157 if (flag_print_constant_pool) \
159 fprintf (out, "%d", SUPER); \
160 if (SUPER != 0) \
161 fputc ('=', out); \
163 if (SUPER != 0) \
164 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
165 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
168 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
169 (flag_print_attributes <= 0)
171 #define HANDLE_CLASS_INTERFACE(INDEX) \
172 if (flag_print_class_info) \
173 { fprintf (out, "- Implements: "); \
174 print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
175 fputc ('\n', out); }
177 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
178 if (flag_print_fields) \
179 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
181 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
182 if (flag_print_fields) \
183 { fprintf (out, "Field name:"); \
184 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
185 print_access_flags (out, ACCESS_FLAGS, 'f'); \
186 fprintf (out, " Descriptor: "); \
187 if (flag_print_constant_pool) \
188 fprintf (out, "%d=", SIGNATURE); \
189 print_signature (out, jcf, SIGNATURE, 0); \
190 fputc ('\n', out); } \
191 else \
192 flag_print_attributes--;
194 #define HANDLE_END_FIELD() \
195 if (! flag_print_fields) \
196 flag_print_attributes++;
198 #define HANDLE_START_METHODS(METHODS_COUNT) \
199 if (flag_print_methods) \
200 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
201 else \
202 flag_print_attributes--;
205 #define HANDLE_END_METHODS() \
206 if (! flag_print_methods) \
207 flag_print_attributes++;
209 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
211 if (flag_print_methods) \
213 if (flag_javap_compatible) \
215 fprintf (out, " "); \
216 print_access_flags (out, ACCESS_FLAGS, 'm'); \
217 fputc (' ', out); \
218 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
219 fputc (' ', out); \
220 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
221 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
222 fputc ('\n', out); \
224 else \
226 fprintf (out, "\nMethod name:"); \
227 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
228 print_access_flags (out, ACCESS_FLAGS, 'm'); \
229 fprintf (out, " Descriptor: "); \
230 if (flag_print_constant_pool) \
231 fprintf (out, "%d=", SIGNATURE); \
232 print_signature (out, jcf, SIGNATURE, 0); \
233 fputc ('\n', out); \
236 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
237 && utf8_equal_string (jcf, NAME, "main") \
238 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
239 && this_class_index > 0 \
240 && (class_access_flags & ACC_PUBLIC)) \
242 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
243 fputc ('\n', out); \
247 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
248 ( fprintf (out, "Attribute "), \
249 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
250 fprintf (out, ", length:%ld", (long) LENGTH) )
252 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
253 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
254 fprintf (out, ", value: "), \
255 print_constant_ref (out, jcf, VALUE_INDEX), \
256 fprintf (out, "\n") )
258 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
259 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
260 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
261 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
262 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
264 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
265 print_exception_table (jcf, ENTRIES, COUNT)
267 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
268 { int n = (COUNT); int i; \
269 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
270 fprintf (out, ", count: %d\n", n); \
271 for (i = 0; i < n; i++) {\
272 int ex_index = JCF_readu2 (jcf); \
273 fprintf (out, "%3d: ", i); \
274 print_constant_ref (out, jcf, ex_index); \
275 fputc ('\n', out); } }
277 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
278 { int n = (COUNT); int i; \
279 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
280 fprintf (out, ", count: %d\n", n); \
281 for (i = 0; i < n; i++) {\
282 int start_pc = JCF_readu2 (jcf); \
283 int length = JCF_readu2 (jcf); \
284 int name_index = JCF_readu2 (jcf); \
285 int signature_index = JCF_readu2 (jcf); \
286 int slot = JCF_readu2 (jcf); \
287 fprintf (out, " slot#%d: name: ", slot); \
288 if (flag_print_constant_pool) \
289 fprintf (out, "%d=", name_index); \
290 print_name (out, jcf, name_index); \
291 fprintf (out, ", type: "); \
292 if (flag_print_constant_pool) \
293 fprintf (out, "%d=", signature_index); \
294 print_signature (out, jcf, signature_index, 0); \
295 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
297 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT) \
298 { int n = (COUNT); int i; \
299 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
300 fprintf (out, ", count: %d\n", n); \
301 for (i = 0; i < n; i++) { \
302 int start_pc = JCF_readu2 (jcf); \
303 int length = JCF_readu2 (jcf); \
304 int name_index = JCF_readu2 (jcf); \
305 int signature_index = JCF_readu2 (jcf); \
306 int slot = JCF_readu2 (jcf); \
307 fprintf (out, " slot#%d: name: ", slot); \
308 if (flag_print_constant_pool) \
309 fprintf (out, "%d=", name_index); \
310 print_name (out, jcf, name_index); \
311 fprintf (out, ", type: "); \
312 if (flag_print_constant_pool) \
313 fprintf (out, "%d=", signature_index); \
314 print_signature (out, jcf, signature_index, 0); \
315 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
317 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
318 { int n = (COUNT); int i; \
319 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
320 fprintf (out, ", count: %d\n", n); \
321 if (flag_disassemble_methods) \
322 for (i = 0; i < n; i++) {\
323 int start_pc = JCF_readu2 (jcf); \
324 int line_number = JCF_readu2 (jcf); \
325 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
326 else \
327 JCF_SKIP (jcf, 4 * n); }
329 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
330 { int n = (COUNT); \
331 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
332 while (n--) \
334 uint16 inner_class_info_index = JCF_readu2 (jcf); \
335 uint16 outer_class_info_index = JCF_readu2 (jcf); \
336 uint16 inner_name_index = JCF_readu2 (jcf); \
337 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
339 if (flag_print_class_info) \
341 fprintf (out, "\n inner: "); \
342 if (inner_class_info_index == 0) \
343 fprintf (out, " (no inner info index)"); \
344 else \
345 print_constant_terse_with_index (out, jcf, \
346 inner_class_info_index, \
347 CONSTANT_Class); \
348 if (inner_name_index == 0) \
349 fprintf (out, " (anonymous)"); \
350 else if (verbose || flag_print_constant_pool) \
352 fprintf (out, " ("); \
353 print_constant_terse_with_index (out, jcf, inner_name_index, \
354 CONSTANT_Utf8); \
355 fputc (')', out); \
357 fprintf (out, ", access flags: 0x%x", inner_class_access_flags); \
358 print_access_flags (out, inner_class_access_flags, 'c'); \
359 fprintf (out, ", outer class: "); \
360 if (outer_class_info_index == 0) \
361 fprintf (out, "(not a member)"); \
362 else \
363 print_constant_terse_with_index (out, jcf, \
364 outer_class_info_index, \
365 CONSTANT_Class); \
368 if (flag_print_class_info) \
369 fputc ('\n', out); \
372 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
373 { int i, n = (LENGTH), c = 0; \
374 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
375 fputc ('\n', out); \
376 for (i = 0; i < n; i++) { c = JCF_readu(jcf); fputc(c, out); } \
377 if (c != '\r' && c != '\n') fputc('\n', out); }
379 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE() \
380 { uint16 class_index, method_index; \
381 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
382 class_index = JCF_readu2 (jcf); \
383 method_index = JCF_readu2 (jcf); \
384 fprintf (out, "\n Class: "); \
385 print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
386 fprintf (out, "\n Method: "); \
387 print_constant_terse_with_index (out, jcf, method_index, \
388 CONSTANT_NameAndType); \
389 fputc ('\n', out); \
392 #define HANDLE_SIGNATURE_ATTRIBUTE() \
394 uint16 signature; \
395 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
396 signature = JCF_readu2 (jcf); \
397 fprintf (out, "\n Value: "); \
398 print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
399 fputc ('\n', out); \
402 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
404 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
405 print_annotations (out, jcf, 1); \
408 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
410 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
411 print_annotations (out, jcf, 1); \
414 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
416 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
417 print_parameter_annotations (out, jcf, 1); \
420 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
422 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
423 print_parameter_annotations (out, jcf, 1); \
426 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
428 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
429 print_element_value (out, jcf, 1); \
432 #define HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE() \
434 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
435 fputc ('\n', out); jcf_parse_bootstrap_methods (jcf, attribute_length); \
438 #define HANDLE_END_BOOTSTRAP_METHODS(NUM_METHODS) \
440 int i; \
441 for (i = 0; i < NUM_METHODS; i++) \
443 bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; \
444 fprintf (out, " %d: ", i); \
445 print_constant (out, jcf, m->method_ref, 1); \
446 fprintf (out, "\n"); \
450 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
451 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
452 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
454 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
455 if (flag_print_attributes > 0) \
456 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
458 #include "javaop.h"
462 static void
463 indent (FILE *stream, int level)
465 int i;
466 for (i = 0; i < level; ++i)
467 fprintf (stream, " ");
470 static void
471 print_element_value (FILE *stream, JCF *jcf, int level)
473 uint8 tag = JCF_readu (jcf);
474 indent (stream, level);
475 switch (tag)
477 case 'B':
478 case 'C':
479 case 'S':
480 case 'Z':
481 case 'I':
483 uint16 cindex = JCF_readu2 (jcf);
484 print_constant_terse_with_index (stream, jcf, cindex,
485 CONSTANT_Integer);
487 break;
488 case 'D':
490 uint16 cindex = JCF_readu2 (jcf);
491 print_constant_terse_with_index (stream, jcf, cindex,
492 CONSTANT_Double);
494 break;
495 case 'F':
497 uint16 cindex = JCF_readu2 (jcf);
498 print_constant_terse_with_index (stream, jcf, cindex,
499 CONSTANT_Float);
501 break;
502 case 'J':
504 uint16 cindex = JCF_readu2 (jcf);
505 print_constant_terse_with_index (stream, jcf, cindex,
506 CONSTANT_Long);
508 break;
509 case 's':
511 uint16 cindex = JCF_readu2 (jcf);
512 /* Despite what the JVM spec says, compilers generate a Utf8
513 constant here, not a String. */
514 print_constant_terse_with_index (stream, jcf, cindex,
515 CONSTANT_Utf8);
517 break;
519 case 'e':
521 uint16 type_name_index = JCF_readu2 (jcf);
522 uint16 const_name_index = JCF_readu2 (jcf);
523 fprintf (stream, "enum class: ");
524 print_constant_terse_with_index (stream, jcf, type_name_index,
525 CONSTANT_Utf8);
526 fprintf (stream, "\n");
527 indent (stream, level);
528 fprintf (stream, "Field: ");
529 print_constant_terse_with_index (stream, jcf, const_name_index,
530 CONSTANT_Utf8);
532 break;
533 case 'c':
535 uint16 class_info_index = JCF_readu2 (jcf);
536 print_constant_terse_with_index (stream, jcf, class_info_index,
537 CONSTANT_Utf8);
539 break;
540 case '@':
542 fprintf (stream, "Annotation:\n");
543 print_annotation (stream, jcf, level + 1);
545 break;
546 case '[':
548 uint16 n_array_elts = JCF_readu2 (jcf);
549 fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
550 while (n_array_elts--)
551 print_element_value (stream, jcf, level + 1);
552 indent (stream, level);
553 fprintf (stream, "]");
555 break;
556 default:
557 fprintf (stream, "Unexpected tag value: %d", (int) tag);
558 break;
560 fputc ('\n', stream);
563 static void
564 print_annotation (FILE *stream, JCF *jcf, int level)
566 uint16 type_index = JCF_readu2 (jcf);
567 uint16 npairs = JCF_readu2 (jcf);
568 fprintf (stream, "\n");
569 indent (stream, level);
570 fprintf (stream, "Annotation name: ");
571 print_constant_terse_with_index (stream, jcf, type_index,
572 CONSTANT_Utf8);
573 if (npairs)
575 fprintf (stream, "\n");
576 while (npairs--)
578 uint16 name_index = JCF_readu2 (jcf);
579 indent (stream, level + 1);
580 fprintf (stream, "Name: ");
581 print_constant_terse_with_index (stream, jcf, name_index,
582 CONSTANT_Utf8);
583 fprintf (stream, "\n");
584 print_element_value (stream, jcf, level + 2);
589 static void
590 print_annotations (FILE *stream, JCF *jcf, int level)
592 uint16 num = JCF_readu2 (jcf);
593 while (num--)
594 print_annotation (stream, jcf, level);
597 static void
598 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
600 uint8 nparams = JCF_readu (jcf);
601 uint8 i;
602 for (i = 0; i < nparams; ++i)
604 indent (stream, level);
605 fprintf (stream, "Parameter annotations (%d):\n", (int) i);
606 print_annotations (stream, jcf, level + 1);
612 static void
613 print_constant_ref (FILE *stream, JCF *jcf, int index)
615 if (index <= 0 || index >= JPOOL_SIZE(jcf))
616 fprintf (stream, "<out of range>");
617 else
619 if (flag_print_constant_pool)
620 fprintf (stream, "#%d=", index);
621 fputc ('<', stream);
622 print_constant (stream, jcf, index, 1);
623 fputc ('>', stream);
627 /* Print the access flags given by FLAGS.
628 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
629 or 'm' (method flags). */
631 static void
632 print_access_flags (FILE *stream, uint16 flags, char context)
634 if (flags & ACC_PUBLIC) fprintf (stream, " public");
635 if (flags & ACC_PRIVATE) fprintf (stream, " private");
636 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
637 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
638 if (flags & ACC_STATIC) fprintf (stream, " static");
639 if (flags & ACC_FINAL) fprintf (stream, " final");
640 if (flags & ACC_TRANSIENT)
641 fprintf (stream, context == 'm' ? " varargs" : " transient");
642 if (flags & ACC_VOLATILE)
643 fprintf (stream, context == 'm' ? " bridge" : " volatile");
644 if (flags & ACC_NATIVE) fprintf (stream, " native");
645 if (flags & ACC_SYNCHRONIZED)
647 if (context == 'c')
648 fprintf (stream, " super");
649 else
650 fprintf (stream, " synchronized");
652 if (flags & ACC_INTERFACE)
653 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
654 if (flags & ACC_ENUM) fprintf (stream, " enum");
655 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
656 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
660 static void
661 print_name (FILE* stream, JCF* jcf, int name_index)
663 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
664 fprintf (stream, "<not a UTF8 constant>");
665 else
666 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
667 JPOOL_UTF_LENGTH (jcf, name_index));
670 /* If the type of the constant at INDEX matches EXPECTED,
671 print it tersely, otherwise more verbosely. */
673 static void
674 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
676 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
677 fprintf (out, "<constant pool index %d not in range>", index);
678 else if (JPOOL_TAG (jcf, index) != expected)
680 fprintf (out, "<Unexpected constant type ");
681 print_constant (out, jcf, index, 1);
682 fprintf (out, ">");
684 else
685 print_constant (out, jcf, index, 0);
688 static void
689 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
691 if (flag_print_constant_pool)
692 fprintf (out, "%d=", index);
693 print_constant_terse (out, jcf, index, expected);
696 /* Print the constant at INDEX in JCF's constant pool.
697 If verbosity==0, print very tersely (no extraneous text).
698 If verbosity==1, prefix the type of the constant.
699 If verbosity==2, add more descriptive text. */
701 static void
702 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
704 int j, n;
705 jlong num;
706 const char *str;
707 int kind = JPOOL_TAG (jcf, index);
708 switch (kind)
710 case CONSTANT_Class:
711 n = JPOOL_USHORT1 (jcf, index);
712 if (verbosity > 0)
714 if (verbosity > 1)
715 fprintf (out, "Class name: %d=", n);
716 else
717 fprintf (out, "Class ");
719 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
720 fprintf (out, "<out of range>");
721 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
723 int len = JPOOL_UTF_LENGTH (jcf, n);
724 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
726 else
727 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
728 break;
729 case CONSTANT_Fieldref:
730 str = "Field"; goto field_or_method;
731 case CONSTANT_Methodref:
732 str = "Method"; goto field_or_method;
733 case CONSTANT_InterfaceMethodref:
734 str = "InterfaceMethod"; goto field_or_method;
735 field_or_method:
737 uint16 tclass = JPOOL_USHORT1 (jcf, index);
738 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
739 if (verbosity == 2)
740 fprintf (out, "%sref class: %d=", str, tclass);
741 else if (verbosity > 0)
742 fprintf (out, "%s ", str);
743 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
744 if (verbosity < 2)
745 fprintf (out, ".");
746 else
747 fprintf (out, " name_and_type: %d=<", name_and_type);
748 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
749 if (verbosity == 2)
750 fputc ('>', out);
752 break;
753 case CONSTANT_String:
754 j = JPOOL_USHORT1 (jcf, index);
755 if (verbosity > 0)
757 if (verbosity > 1)
758 fprintf (out, "String %d=", j);
759 else
760 fprintf (out, "String ");
762 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
763 break;
764 case CONSTANT_Integer:
765 if (verbosity > 0)
766 fprintf (out, "Integer ");
767 num = JPOOL_INT (jcf, index);
768 goto integer;
769 case CONSTANT_Long:
770 if (verbosity > 0)
771 fprintf (out, "Long ");
772 num = JPOOL_LONG (jcf, index);
773 goto integer;
774 integer:
776 char buffer[25];
777 format_int (buffer, num, 10);
778 fprintf (out, "%s", buffer);
779 if (verbosity > 1)
781 format_uint (buffer, (uint64)num, 16);
782 fprintf (out, "=0x%s", buffer);
785 break;
786 case CONSTANT_Float:
788 jfloat fnum = JPOOL_FLOAT (jcf, index);
790 if (verbosity > 0)
791 fputs ("Float ", out);
793 if (fnum.negative)
794 putc ('-', out);
796 if (JFLOAT_FINITE (fnum))
798 int dummy;
799 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
800 double f;
801 uint32 mantissa = fnum.mantissa;
802 if (fnum.exponent == 0)
803 /* Denormal. */
804 exponent++;
805 else
806 /* Normal; add the implicit bit. */
807 mantissa |= ((uint32)1 << 23);
809 f = frexp ((float) mantissa, &dummy);
810 f = ldexp (f, exponent + 1);
811 fprintf (out, "%.10g", f);
813 else
815 if (fnum.mantissa == 0)
816 fputs ("Inf", out);
817 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
818 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
819 else
820 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
823 if (verbosity > 1)
824 fprintf (out, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf, index));
826 break;
828 case CONSTANT_Double:
830 jdouble dnum = JPOOL_DOUBLE (jcf, index);
832 if (verbosity > 0)
833 fputs ("Double ", out);
835 if (dnum.negative)
836 putc ('-', out);
838 if (JDOUBLE_FINITE (dnum))
840 int dummy;
841 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
842 double d;
843 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
844 + dnum.mantissa1);
845 if (dnum.exponent == 0)
846 /* Denormal. */
847 exponent++;
848 else
849 /* Normal; add the implicit bit. */
850 mantissa |= ((uint64)1 << 52);
852 d = frexp ((double) mantissa, &dummy);
853 d = ldexp (d, exponent + 1);
854 fprintf (out, "%.20g", d);
856 else
858 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
859 mantissa = (mantissa << 32) + dnum.mantissa1;
861 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
862 fputs ("Inf", out);
863 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
864 fprintf (out, "QNaN(%" HOST_LONG_LONG_FORMAT "u)",
865 (unsigned long long)mantissa);
866 else
867 fprintf (out, "SNaN(%" HOST_LONG_LONG_FORMAT "u)",
868 (unsigned long long)mantissa);
870 if (verbosity > 1)
872 int32 hi, lo;
873 hi = JPOOL_UINT (jcf, index);
874 lo = JPOOL_UINT (jcf, index + 1);
875 fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi,
876 (unsigned long) lo);
878 break;
880 case CONSTANT_NameAndType:
882 uint16 name = JPOOL_USHORT1 (jcf, index);
883 uint16 sig = JPOOL_USHORT2 (jcf, index);
884 if (verbosity > 0)
886 if (verbosity > 1)
887 fprintf (out, "NameAndType name: %d=", name);
888 else
889 fprintf (out, "NameAndType ");
891 print_name (out, jcf, name);
892 if (verbosity <= 1)
893 fputc (' ', out);
894 else
895 fprintf (out, ", signature: %d=", sig);
896 print_signature (out, jcf, sig, 0);
898 break;
899 case CONSTANT_Utf8:
901 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
902 int length = JPOOL_UTF_LENGTH (jcf, index);
903 if (verbosity > 0)
904 { /* Print as 8-bit bytes. */
905 fputs ("Utf8: \"", out);
906 while (--length >= 0)
907 jcf_print_char (out, *str++);
909 else
910 { /* Print as Unicode. */
911 fputc ('\"', out);
912 jcf_print_utf8 (out, str, length);
914 fputc ('\"', out);
916 break;
917 case CONSTANT_MethodHandle:
919 int kind = JPOOL_USHORT1 (jcf, index);
920 if (verbosity > 0)
921 fprintf (out, "MethodHandle kind: %d=", kind);
922 switch(kind) {
923 case 1:
924 case 2:
925 case 3:
926 case 4:
927 if (verbosity > 0)
928 fprintf (out, "Fieldref: %ld=", (long) JPOOL_USHORT2 (jcf, index));
929 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
930 case 5:
931 case 6:
932 case 7:
933 case 8:
934 if (verbosity > 0)
935 fprintf (out, "Methodref: %ld=", (long) JPOOL_USHORT2 (jcf, index));
936 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
937 break;
938 case 9:
939 if (verbosity > 0)
940 fprintf (out, "InterfaceMethodref: %ld=",
941 (long) JPOOL_USHORT2 (jcf, index));
942 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
943 break;
945 break;
947 case CONSTANT_MethodType:
948 if (verbosity > 0)
949 fprintf (out, "MethodType %ld: ", (long) JPOOL_USHORT1 (jcf, index));
950 print_signature (out, jcf, JPOOL_USHORT1 (jcf, index), 0);
951 break;
952 case CONSTANT_InvokeDynamic:
954 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
955 if (verbosity > 0)
956 fprintf (out, "InvokeDynamic: ");
957 fprintf (out, "bootstrap_method: %ld ",
958 (long) JPOOL_USHORT1 (jcf, index));
959 if (verbosity == 2)
960 fprintf (out, " name_and_type: %d=<", name_and_type);
961 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
962 if (verbosity == 2)
963 fputc ('>', out);
964 break;
966 default:
967 fprintf (out, "(Unknown constant type %d)", kind);
971 static void
972 print_constant_pool (JCF *jcf)
974 int i;
975 for (i = 1; i < JPOOL_SIZE(jcf); i++)
977 int kind = JPOOL_TAG (jcf, i);
978 fprintf (out, "#%d: ", i);
979 print_constant (out, jcf, i, 2);
980 fprintf (out, "\n");
981 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
982 i++; /* These take up two slots in the constant table */
986 static void
987 print_signature_type (FILE* stream, const unsigned char **ptr,
988 const unsigned char *limit)
990 int array_size;
991 if ((*ptr) >= limit)
992 return;
993 switch (*(*ptr))
995 case '[':
996 array_size = -1;
997 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
999 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
1001 print_signature_type (stream, ptr, limit);
1002 if (array_size == -1)
1003 fprintf (stream, "[]");
1004 else
1005 fprintf (stream, "[%d]", array_size);
1006 break;
1007 case '(':
1009 int nargs = 0;
1010 fputc (*(*ptr)++, stream);
1011 for (; **ptr != ')' && *ptr < limit; nargs++)
1013 if (nargs > 0)
1014 fputc (',', stream);
1015 print_signature_type (stream, ptr, limit);
1017 if (*ptr < limit)
1019 fputc (*(*ptr)++, stream);
1020 print_signature_type (stream, ptr, limit);
1022 else
1023 fprintf (stream, "???");
1025 break;
1027 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
1028 case 'C': fprintf (stream, "char"); (*ptr)++; break;
1029 case 'D': fprintf (stream, "double"); (*ptr)++; break;
1030 case 'F': fprintf (stream, "float"); (*ptr)++; break;
1031 case 'S': fprintf (stream, "short"); (*ptr)++; break;
1032 case 'I': fprintf (stream, "int"); (*ptr)++; break;
1033 case 'J': fprintf (stream, "long"); (*ptr)++; break;
1034 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
1035 case 'V': fprintf (stream, "void"); (*ptr)++; break;
1037 case 'L':
1038 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
1039 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
1040 if (*(*ptr) == ';')
1041 (*ptr)++;
1042 break;
1043 default:
1044 jcf_print_char (stream, *(*ptr)++);
1048 static void
1049 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
1051 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1052 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
1053 else
1055 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
1056 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1057 const unsigned char *limit;
1058 limit = str + length;
1059 if (str >= limit)
1060 fprintf (stream, "<empty signature string>");
1061 else
1063 if (options & PRINT_SIGNATURE_RESULT_ONLY)
1065 while (str < limit && *str++ != ')') ;
1067 if (options & PRINT_SIGNATURE_ARGS_ONLY)
1069 str++;
1070 fputc ('(', stream);
1071 while (str < limit && *str != ')')
1073 print_signature_type (stream, &str, limit);
1074 if (*str != ')')
1075 fputs (", ", stream);
1077 fputc (')', stream);
1079 else
1081 print_signature_type (stream, &str, limit);
1082 if (str < limit)
1084 fprintf (stream, "<junk:");
1085 jcf_print_utf8 (stream, str, limit - str);
1086 fputc ('>', stream);
1094 static void
1095 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1097 /* Print exception table. */
1098 int i = count;
1099 if (i > 0)
1101 const unsigned char *ptr = entries;
1102 fprintf (out, "Exceptions (count: %d):\n", i);
1103 for (; --i >= 0; ptr+= 8)
1105 int start_pc = GET_u2 (ptr);
1106 int end_pc = GET_u2 (ptr+2);
1107 int handler_pc = GET_u2 (ptr+4);
1108 int catch_type = GET_u2 (ptr+6);
1109 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
1110 start_pc, end_pc, handler_pc);
1111 if (catch_type == 0)
1112 fputs ("0 /* finally */", out);
1113 else
1114 print_constant_terse_with_index (out, jcf,
1115 catch_type, CONSTANT_Class);
1116 fputc ('\n', out);
1121 #include "jcf-reader.c"
1123 static void
1124 process_class (JCF *jcf)
1126 int code;
1127 if (jcf_parse_preamble (jcf) != 0)
1128 fprintf (stderr, _("Not a valid Java .class file.\n"));
1130 /* Parse and possibly print constant pool */
1131 code = jcf_parse_constant_pool (jcf);
1132 if (code != 0)
1134 fprintf (stderr, _("error while parsing constant pool\n"));
1135 exit (FATAL_EXIT_CODE);
1137 code = verify_constant_pool (jcf);
1138 if (code > 0)
1140 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1141 exit (FATAL_EXIT_CODE);
1143 if (flag_print_constant_pool)
1144 print_constant_pool (jcf);
1146 jcf_parse_class (jcf);
1147 code = jcf_parse_fields (jcf);
1148 if (code != 0)
1150 fprintf (stderr, _("error while parsing fields\n"));
1151 exit (FATAL_EXIT_CODE);
1153 code = jcf_parse_methods (jcf);
1154 if (code != 0)
1156 fprintf (stderr, _("error while parsing methods\n"));
1157 exit (FATAL_EXIT_CODE);
1159 code = jcf_parse_final_attributes (jcf);
1160 if (code != 0)
1162 fprintf (stderr, _("error while parsing final attributes\n"));
1163 exit (FATAL_EXIT_CODE);
1165 jcf->filename = NULL;
1170 /* This is used to mark options with no short value. */
1171 #define LONG_OPT(Num) ((Num) + 128)
1173 #define OPT_classpath LONG_OPT (0)
1174 #define OPT_CLASSPATH OPT_classpath
1175 #define OPT_bootclasspath LONG_OPT (1)
1176 #define OPT_extdirs LONG_OPT (2)
1177 #define OPT_HELP LONG_OPT (3)
1178 #define OPT_VERSION LONG_OPT (4)
1179 #define OPT_JAVAP LONG_OPT (5)
1181 static const struct option options[] =
1183 { "classpath", required_argument, NULL, OPT_classpath },
1184 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1185 { "extdirs", required_argument, NULL, OPT_extdirs },
1186 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
1187 { "help", no_argument, NULL, OPT_HELP },
1188 { "verbose", no_argument, NULL, 'v' },
1189 { "version", no_argument, NULL, OPT_VERSION },
1190 { "javap", no_argument, NULL, OPT_JAVAP },
1191 { "print-main", no_argument, &flag_print_main, 1 },
1192 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
1193 { NULL, no_argument, NULL, 0 }
1196 static void
1197 usage (void)
1199 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1200 exit (1);
1203 static void
1204 help (void)
1206 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1207 printf (_("Display contents of a class file in readable form.\n\n"));
1208 printf (_(" -c Disassemble method bodies\n"));
1209 printf (_(" --javap Generate output in 'javap' format\n"));
1210 printf ("\n");
1211 printf (_(" --classpath PATH Set path to find .class files\n"));
1212 printf (_(" -IDIR Append directory to class path\n"));
1213 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1214 printf (_(" --extdirs PATH Set extensions directory path\n"));
1215 printf (_(" -o FILE Set output file name\n"));
1216 printf ("\n");
1217 printf (_(" --help Print this help, then exit\n"));
1218 printf (_(" --version Print version number, then exit\n"));
1219 printf (_(" -v, --verbose Print extra information while running\n"));
1220 printf ("\n");
1221 printf (_("For bug reporting instructions, please see:\n"
1222 "%s.\n"), bug_report_url);
1223 exit (0);
1226 static void
1227 version (void)
1229 printf ("jcf-dump %s%s\n\n", pkgversion_string, version_string);
1230 printf ("Copyright %s 2013 Free Software Foundation, Inc.\n", _("(C)"));
1231 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1232 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1233 exit (0);
1237 main (int argc, char** argv)
1239 JCF jcf[1];
1240 int argi, opt;
1241 const char *p;
1243 p = argv[0] + strlen (argv[0]);
1244 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
1245 --p;
1246 progname = p;
1248 xmalloc_set_program_name (progname);
1250 /* Unlock the stdio streams. */
1251 unlock_std_streams ();
1253 gcc_init_libintl ();
1255 diagnostic_initialize (global_dc, 0);
1257 if (argc <= 1)
1259 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1260 usage ();
1263 jcf_path_init ();
1265 /* We use getopt_long_only to allow single `-' long options. For
1266 some of our options this is more natural. */
1267 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1269 switch (opt)
1271 case 0:
1272 /* Already handled. */
1273 break;
1275 case 'o':
1276 output_file = optarg;
1277 break;
1279 case 'I':
1280 jcf_path_include_arg (optarg);
1281 break;
1283 case 'v':
1284 verbose++;
1285 break;
1287 case 'c':
1288 flag_disassemble_methods = 1;
1289 break;
1291 case OPT_classpath:
1292 jcf_path_classpath_arg (optarg);
1293 break;
1295 case OPT_bootclasspath:
1296 jcf_path_bootclasspath_arg (optarg);
1297 break;
1299 case OPT_extdirs:
1300 jcf_path_extdirs_arg (optarg);
1301 break;
1303 case OPT_HELP:
1304 help ();
1305 break;
1307 case OPT_VERSION:
1308 version ();
1309 break;
1311 case OPT_JAVAP:
1312 flag_javap_compatible++;
1313 flag_print_constant_pool = 0;
1314 flag_print_attributes = 0;
1315 break;
1317 default:
1318 usage ();
1322 if (verbose && ! flag_javap_compatible)
1323 flag_print_constant_pool = 1;
1325 if (optind == argc)
1327 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1328 usage ();
1331 jcf_path_seal (verbose);
1333 if (flag_print_main)
1335 flag_print_fields = 0;
1336 flag_print_methods = 0;
1337 flag_print_constant_pool = 0;
1338 flag_print_attributes = 0;
1339 flag_print_class_info = 0;
1342 if (output_file)
1344 out = fopen (output_file, "w");
1345 if (! out)
1347 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1348 return FATAL_EXIT_CODE;
1351 else
1352 out = stdout;
1354 if (optind >= argc)
1356 fprintf (out, "Reading .class from <standard input>.\n");
1357 open_class ("<stdio>", jcf, 0, NULL);
1358 process_class (jcf);
1360 else
1362 for (argi = optind; argi < argc; argi++)
1364 char *arg = argv[argi];
1365 const char *class_filename = find_class (arg, strlen (arg), jcf);
1366 if (class_filename == NULL)
1367 class_filename = find_classfile (arg, jcf, NULL);
1368 if (class_filename == NULL)
1370 perror ("Could not find class");
1371 return FATAL_EXIT_CODE;
1373 JCF_FILL (jcf, 4);
1374 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1376 long compressed_size, member_size;
1377 int compression_method, filename_length, extra_length;
1378 const char *filename;
1379 int total_length;
1380 if (flag_print_class_info)
1381 fprintf (out, "Reading classes from archive %s.\n",
1382 class_filename);
1383 for (;;)
1385 int skip = 0;
1386 jcf_filbuf_t save_filbuf = jcf->filbuf;
1387 long magic = JCF_readu4_le (jcf);
1388 if (magic == 0x02014b50 || magic == 0x06054b50)
1389 break; /* got to central directory */
1390 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1392 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1393 return FATAL_EXIT_CODE;
1395 JCF_FILL (jcf, 26);
1396 JCF_SKIP (jcf, 2);
1397 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf);
1398 compression_method = JCF_readu2_le (jcf);
1399 JCF_SKIP (jcf, 8);
1400 compressed_size = JCF_readu4_le (jcf);
1401 member_size = JCF_readu4_le (jcf);
1402 filename_length = JCF_readu2_le (jcf);
1403 extra_length = JCF_readu2_le (jcf);
1404 total_length = filename_length + extra_length
1405 + compressed_size;
1406 if (jcf->read_end - jcf->read_ptr < total_length)
1407 jcf_trim_old_input (jcf);
1408 JCF_FILL (jcf, total_length);
1409 filename = (const char *) jcf->read_ptr;
1410 JCF_SKIP (jcf, filename_length);
1411 JCF_SKIP (jcf, extra_length);
1412 if (filename_length > 0
1413 && filename[filename_length-1] == '/')
1415 if (flag_print_class_info)
1416 fprintf (out, "[Skipping directory %.*s]\n",
1417 filename_length, filename);
1418 skip = 1;
1420 else if (compression_method != 0)
1422 if (flag_print_class_info)
1423 fprintf (out, "[Skipping compressed file %.*s]\n",
1424 filename_length, filename);
1425 skip = 1;
1427 else if (member_size < 4
1428 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1430 if (flag_print_class_info)
1431 fprintf (out, "[Skipping non-.class member %.*s]\n",
1432 filename_length, filename);
1433 skip = 1;
1435 else
1437 if (flag_print_class_info)
1438 fprintf (out, "Reading class member: %.*s.\n",
1439 filename_length, filename);
1441 if (skip)
1443 JCF_SKIP (jcf, compressed_size);
1445 else
1447 unsigned char *save_end;
1448 jcf->filbuf = jcf_unexpected_eof;
1449 save_end = jcf->read_end;
1450 jcf->read_end = jcf->read_ptr + compressed_size;
1451 process_class (jcf);
1452 jcf->filbuf = save_filbuf;
1453 jcf->read_end = save_end;
1457 else
1459 if (flag_print_class_info)
1460 fprintf (out, "Reading .class from %s.\n", class_filename);
1461 process_class (jcf);
1463 JCF_FINISH(jcf);
1467 return SUCCESS_EXIT_CODE;
1472 static void
1473 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1475 #undef PTR
1476 int PC;
1477 int i;
1478 int saw_wide = 0;
1479 if (flag_disassemble_methods == 0)
1480 return;
1481 #define BCODE byte_ops
1482 for (PC = 0; PC < len;)
1484 int oldpc = PC;
1485 int saw_index;
1486 jint INT_temp;
1487 switch (byte_ops[PC++])
1490 /* This is the actual code emitted for each of opcodes in javaops.def.
1491 The actual opcode-specific stuff is handled by the OPKIND macro.
1492 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1493 Those macros are defined below. The OPKINDs that do not have any
1494 inline parameters (such as BINOP) and therefore do mot need anything
1495 else to me printed out just use an empty body. */
1497 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1498 case OPCODE: \
1499 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1500 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1501 fputc ('\n', out); \
1502 break;
1504 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1505 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1506 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1507 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1509 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1510 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1512 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1513 These all push a constant onto the opcode stack. */
1514 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1515 saw_index = 0, i = (OPERAND_VALUE); \
1516 if (oldpc+1 == PC) /* nothing */; \
1517 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1518 else fprintf (out, " %d", i);
1520 /* Print out operand (a local variable index) for LOAD opcodes.
1521 These all push local variable onto the opcode stack. */
1522 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1523 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1525 /* Handle STORE opcodes same as LOAD opcodes.
1526 These all store a value from the opcode stack in a local variable. */
1527 #define STORE LOAD
1529 /* Handle more kind of opcodes. */
1530 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1531 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1532 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1533 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1534 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1535 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1536 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1538 /* Handle putfield and getfield opcodes, with static versions. */
1539 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1540 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1542 /* Print operand for invoke opcodes. */
1543 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1544 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1545 if (OPERAND_VALUE) /* for invokeinterface */ \
1546 { int nargs = IMMEDIATE_u1; PC++; \
1547 fprintf (out, " nargs:%d", nargs); }
1549 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1550 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1552 #define ARRAY(OPERAND_TYPE, SUBOP) \
1553 ARRAY_##SUBOP(OPERAND_TYPE)
1554 /* Handle sub-categories of ARRAY opcodes. */
1555 #define ARRAY_LOAD(TYPE) /* nothing */
1556 #define ARRAY_STORE(TYPE) /* nothing */
1557 #define ARRAY_LENGTH(TYPE) /* nothing */
1558 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1559 #define ARRAY_NEW_NUM \
1560 INT_temp = IMMEDIATE_u1; \
1561 { switch ((int) INT_temp) { \
1562 case 4: fputs (" boolean", out); break; \
1563 case 5: fputs (" char", out); break; \
1564 case 6: fputs (" float", out); break; \
1565 case 7: fputs (" double", out); break; \
1566 case 8: fputs (" byte", out); break; \
1567 case 9: fputs (" short", out); break; \
1568 case 10: fputs (" int", out); break; \
1569 case 11: fputs (" long", out); break; \
1570 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1573 #define ARRAY_NEW_PTR \
1574 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1576 #define ARRAY_NEW_MULTI \
1577 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1578 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1580 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1581 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1583 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1584 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1585 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1587 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1588 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1589 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1591 #undef RET /* Defined by config/i386/i386.h */
1592 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1593 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1594 saw_wide = 0; \
1595 fprintf (out, " %ld", (long) INT_temp);
1597 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1598 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1600 #define LOOKUP_SWITCH \
1601 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1602 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1603 while (--npairs >= 0) { \
1604 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1605 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1608 #define TABLE_SWITCH \
1609 { jint default_offset = IMMEDIATE_s4; \
1610 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1611 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1612 (long) low, (long) high, (long) default_offset+oldpc); \
1613 for (; low <= high; low++) { \
1614 jint offset = IMMEDIATE_s4; \
1615 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1618 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1619 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1621 #define SPECIAL_IINC(OPERAND_TYPE) \
1622 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1623 fprintf (out, " %d", i); \
1624 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1625 saw_wide = 0; \
1626 fprintf (out, " %d", i)
1628 #define SPECIAL_WIDE(OPERAND_TYPE) \
1629 saw_wide = 1;
1631 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1632 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1633 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1634 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1636 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1637 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1639 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1640 TEST(OPERAND_TYPE, OPERAND_VALUE)
1642 #include "javaop.def"
1644 load_store:
1645 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1646 else
1648 saw_wide = 0;
1649 fprintf (out, " %ld", (long) INT_temp);
1651 fputc ('\n', out);
1652 break;
1654 default:
1655 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);