jcf.h (bootstrap_method): New.
[gcc.git] / gcc / java / jcf-dump.c
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
3
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
6
7 This file is part of GCC.
8
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.
13
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.
18
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/>.
22
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. */
26
27 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
28
29 /*
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).
37
38 OPTIONS:
39 -c
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.
48 */
49
50
51 #include "config.h"
52 #include "system.h"
53 #include "coretypes.h"
54 #include "intl.h"
55 #include "diagnostic.h"
56
57 #include "jcf.h"
58 #include "tree.h"
59 #include "java-tree.h"
60
61 #include "version.h"
62
63 #include <getopt.h>
64 #include <math.h>
65
66 /* Output file. */
67 FILE *out;
68 /* Name of output file, if NULL if stdout. */
69 char *output_file = NULL;
70
71 int verbose = 0;
72
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;
79
80 /* Print names of classes that have a "main" method. */
81 int flag_print_main = 0;
82
83 /* Index in constant pool of this class. */
84 int this_class_index = 0;
85
86 int class_access_flags = 0;
87
88 /* Print in format similar to javap. VERY INCOMPLETE. */
89 int flag_javap_compatible = 0;
90
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);
112
113 #define PRINT_SIGNATURE_RESULT_ONLY 1
114 #define PRINT_SIGNATURE_ARGS_ONLY 2
115
116 static int
117 utf8_equal_string (JCF *jcf, int index, const char * value)
118 {
119 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
120 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
121 {
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;
126 }
127 return 0;
128 }
129
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)
136
137 #define HANDLE_START_CONSTANT_POOL(COUNT) \
138 if (flag_print_constant_pool) \
139 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
140
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); }
146
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) \
159 { \
160 fprintf (out, "%d", SUPER); \
161 if (SUPER != 0) \
162 fputc ('=', out); \
163 } \
164 if (SUPER != 0) \
165 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
166 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
167 }
168
169 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
170 (flag_print_attributes <= 0)
171
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); }
177
178 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
179 if (flag_print_fields) \
180 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
181
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--;
194
195 #define HANDLE_END_FIELD() \
196 if (! flag_print_fields) \
197 flag_print_attributes++;
198
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--;
204
205
206 #define HANDLE_END_METHODS() \
207 if (! flag_print_methods) \
208 flag_print_attributes++;
209
210 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
211 { \
212 if (flag_print_methods) \
213 { \
214 if (flag_javap_compatible) \
215 { \
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); \
224 } \
225 else \
226 { \
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); \
235 } \
236 } \
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)) \
242 { \
243 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
244 fputc ('\n', out); \
245 } \
246 }
247
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) )
252
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") )
258
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); }
264
265 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
266 print_exception_table (jcf, ENTRIES, COUNT)
267
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); } }
277
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); }}
297
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); }}
317
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); }
329
330 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
331 { int n = (COUNT); \
332 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
333 while (n--) \
334 { \
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); \
339 \
340 if (flag_print_class_info) \
341 { \
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) \
352 { \
353 fprintf (out, " ("); \
354 print_constant_terse_with_index (out, jcf, inner_name_index, \
355 CONSTANT_Utf8); \
356 fputc (')', out); \
357 } \
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); \
367 } \
368 } \
369 if (flag_print_class_info) \
370 fputc ('\n', out); \
371 }
372
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); }
379
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); \
391 }
392
393 #define HANDLE_SIGNATURE_ATTRIBUTE() \
394 { \
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); \
401 }
402
403 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE() \
404 { \
405 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
406 print_annotations (out, jcf, 1); \
407 }
408
409 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE() \
410 { \
411 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
412 print_annotations (out, jcf, 1); \
413 }
414
415 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
416 { \
417 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
418 print_parameter_annotations (out, jcf, 1); \
419 }
420
421 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE() \
422 { \
423 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
424 print_parameter_annotations (out, jcf, 1); \
425 }
426
427 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE() \
428 { \
429 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
430 print_element_value (out, jcf, 1); \
431 }
432
433 #define HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE() \
434 { \
435 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
436 fputc ('\n', out); jcf_parse_bootstrap_methods (jcf, attribute_length); \
437 }
438
439 #define HANDLE_END_BOOTSTRAP_METHODS(NUM_METHODS) \
440 { \
441 int i; \
442 for (i = 0; i < NUM_METHODS; i++) \
443 { \
444 bootstrap_method *m = &jcf->bootstrap_methods.methods[i]; \
445 fprintf (out, " %d: ", i); \
446 print_constant (out, jcf, m->method_ref, 1); \
447 fprintf (out, "\n"); \
448 } \
449 }
450
451 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
452 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
453 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
454
455 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
456 if (flag_print_attributes > 0) \
457 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
458
459 #include "javaop.h"
460
461 \f
462
463 static void
464 indent (FILE *stream, int level)
465 {
466 int i;
467 for (i = 0; i < level; ++i)
468 fprintf (stream, " ");
469 }
470
471 static void
472 print_element_value (FILE *stream, JCF *jcf, int level)
473 {
474 uint8 tag = JCF_readu (jcf);
475 indent (stream, level);
476 switch (tag)
477 {
478 case 'B':
479 case 'C':
480 case 'S':
481 case 'Z':
482 case 'I':
483 {
484 uint16 cindex = JCF_readu2 (jcf);
485 print_constant_terse_with_index (stream, jcf, cindex,
486 CONSTANT_Integer);
487 }
488 break;
489 case 'D':
490 {
491 uint16 cindex = JCF_readu2 (jcf);
492 print_constant_terse_with_index (stream, jcf, cindex,
493 CONSTANT_Double);
494 }
495 break;
496 case 'F':
497 {
498 uint16 cindex = JCF_readu2 (jcf);
499 print_constant_terse_with_index (stream, jcf, cindex,
500 CONSTANT_Float);
501 }
502 break;
503 case 'J':
504 {
505 uint16 cindex = JCF_readu2 (jcf);
506 print_constant_terse_with_index (stream, jcf, cindex,
507 CONSTANT_Long);
508 }
509 break;
510 case 's':
511 {
512 uint16 cindex = JCF_readu2 (jcf);
513 /* Despite what the JVM spec says, compilers generate a Utf8
514 constant here, not a String. */
515 print_constant_terse_with_index (stream, jcf, cindex,
516 CONSTANT_Utf8);
517 }
518 break;
519
520 case 'e':
521 {
522 uint16 type_name_index = JCF_readu2 (jcf);
523 uint16 const_name_index = JCF_readu2 (jcf);
524 fprintf (stream, "enum class: ");
525 print_constant_terse_with_index (stream, jcf, type_name_index,
526 CONSTANT_Utf8);
527 fprintf (stream, "\n");
528 indent (stream, level);
529 fprintf (stream, "Field: ");
530 print_constant_terse_with_index (stream, jcf, const_name_index,
531 CONSTANT_Utf8);
532 }
533 break;
534 case 'c':
535 {
536 uint16 class_info_index = JCF_readu2 (jcf);
537 print_constant_terse_with_index (stream, jcf, class_info_index,
538 CONSTANT_Utf8);
539 }
540 break;
541 case '@':
542 {
543 fprintf (stream, "Annotation:\n");
544 print_annotation (stream, jcf, level + 1);
545 }
546 break;
547 case '[':
548 {
549 uint16 n_array_elts = JCF_readu2 (jcf);
550 fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
551 while (n_array_elts--)
552 print_element_value (stream, jcf, level + 1);
553 indent (stream, level);
554 fprintf (stream, "]");
555 }
556 break;
557 default:
558 fprintf (stream, "Unexpected tag value: %d", (int) tag);
559 break;
560 }
561 fputc ('\n', stream);
562 }
563
564 static void
565 print_annotation (FILE *stream, JCF *jcf, int level)
566 {
567 uint16 type_index = JCF_readu2 (jcf);
568 uint16 npairs = JCF_readu2 (jcf);
569 fprintf (stream, "\n");
570 indent (stream, level);
571 fprintf (stream, "Annotation name: ");
572 print_constant_terse_with_index (stream, jcf, type_index,
573 CONSTANT_Utf8);
574 if (npairs)
575 {
576 fprintf (stream, "\n");
577 while (npairs--)
578 {
579 uint16 name_index = JCF_readu2 (jcf);
580 indent (stream, level + 1);
581 fprintf (stream, "Name: ");
582 print_constant_terse_with_index (stream, jcf, name_index,
583 CONSTANT_Utf8);
584 fprintf (stream, "\n");
585 print_element_value (stream, jcf, level + 2);
586 }
587 }
588 }
589
590 static void
591 print_annotations (FILE *stream, JCF *jcf, int level)
592 {
593 uint16 num = JCF_readu2 (jcf);
594 while (num--)
595 print_annotation (stream, jcf, level);
596 }
597
598 static void
599 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
600 {
601 uint8 nparams = JCF_readu (jcf);
602 uint8 i;
603 for (i = 0; i < nparams; ++i)
604 {
605 indent (stream, level);
606 fprintf (stream, "Parameter annotations (%d):\n", (int) i);
607 print_annotations (stream, jcf, level + 1);
608 }
609 }
610
611 \f
612
613 static void
614 print_constant_ref (FILE *stream, JCF *jcf, int index)
615 {
616 if (index <= 0 || index >= JPOOL_SIZE(jcf))
617 fprintf (stream, "<out of range>");
618 else
619 {
620 if (flag_print_constant_pool)
621 fprintf (stream, "#%d=", index);
622 fputc ('<', stream);
623 print_constant (stream, jcf, index, 1);
624 fputc ('>', stream);
625 }
626 }
627
628 /* Print the access flags given by FLAGS.
629 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
630 or 'm' (method flags). */
631
632 static void
633 print_access_flags (FILE *stream, uint16 flags, char context)
634 {
635 if (flags & ACC_PUBLIC) fprintf (stream, " public");
636 if (flags & ACC_PRIVATE) fprintf (stream, " private");
637 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
638 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
639 if (flags & ACC_STATIC) fprintf (stream, " static");
640 if (flags & ACC_FINAL) fprintf (stream, " final");
641 if (flags & ACC_TRANSIENT)
642 fprintf (stream, context == 'm' ? " varargs" : " transient");
643 if (flags & ACC_VOLATILE)
644 fprintf (stream, context == 'm' ? " bridge" : " volatile");
645 if (flags & ACC_NATIVE) fprintf (stream, " native");
646 if (flags & ACC_SYNCHRONIZED)
647 {
648 if (context == 'c')
649 fprintf (stream, " super");
650 else
651 fprintf (stream, " synchronized");
652 }
653 if (flags & ACC_INTERFACE)
654 fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
655 if (flags & ACC_ENUM) fprintf (stream, " enum");
656 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
657 if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
658 }
659
660
661 static void
662 print_name (FILE* stream, JCF* jcf, int name_index)
663 {
664 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
665 fprintf (stream, "<not a UTF8 constant>");
666 else
667 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
668 JPOOL_UTF_LENGTH (jcf, name_index));
669 }
670
671 /* If the type of the constant at INDEX matches EXPECTED,
672 print it tersely, otherwise more verbosely. */
673
674 static void
675 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
676 {
677 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
678 fprintf (out, "<constant pool index %d not in range>", index);
679 else if (JPOOL_TAG (jcf, index) != expected)
680 {
681 fprintf (out, "<Unexpected constant type ");
682 print_constant (out, jcf, index, 1);
683 fprintf (out, ">");
684 }
685 else
686 print_constant (out, jcf, index, 0);
687 }
688
689 static void
690 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
691 {
692 if (flag_print_constant_pool)
693 fprintf (out, "%d=", index);
694 print_constant_terse (out, jcf, index, expected);
695 }
696
697 /* Print the constant at INDEX in JCF's constant pool.
698 If verbosity==0, print very tersely (no extraneous text).
699 If verbosity==1, prefix the type of the constant.
700 If verbosity==2, add more descriptive text. */
701
702 static void
703 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
704 {
705 int j, n;
706 jlong num;
707 const char *str;
708 int kind = JPOOL_TAG (jcf, index);
709 switch (kind)
710 {
711 case CONSTANT_Class:
712 n = JPOOL_USHORT1 (jcf, index);
713 if (verbosity > 0)
714 {
715 if (verbosity > 1)
716 fprintf (out, "Class name: %d=", n);
717 else
718 fprintf (out, "Class ");
719 }
720 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
721 fprintf (out, "<out of range>");
722 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
723 {
724 int len = JPOOL_UTF_LENGTH (jcf, n);
725 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
726 }
727 else
728 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
729 break;
730 case CONSTANT_Fieldref:
731 str = "Field"; goto field_or_method;
732 case CONSTANT_Methodref:
733 str = "Method"; goto field_or_method;
734 case CONSTANT_InterfaceMethodref:
735 str = "InterfaceMethod"; goto field_or_method;
736 field_or_method:
737 {
738 uint16 tclass = JPOOL_USHORT1 (jcf, index);
739 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
740 if (verbosity == 2)
741 fprintf (out, "%sref class: %d=", str, tclass);
742 else if (verbosity > 0)
743 fprintf (out, "%s ", str);
744 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
745 if (verbosity < 2)
746 fprintf (out, ".");
747 else
748 fprintf (out, " name_and_type: %d=<", name_and_type);
749 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
750 if (verbosity == 2)
751 fputc ('>', out);
752 }
753 break;
754 case CONSTANT_String:
755 j = JPOOL_USHORT1 (jcf, index);
756 if (verbosity > 0)
757 {
758 if (verbosity > 1)
759 fprintf (out, "String %d=", j);
760 else
761 fprintf (out, "String ");
762 }
763 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
764 break;
765 case CONSTANT_Integer:
766 if (verbosity > 0)
767 fprintf (out, "Integer ");
768 num = JPOOL_INT (jcf, index);
769 goto integer;
770 case CONSTANT_Long:
771 if (verbosity > 0)
772 fprintf (out, "Long ");
773 num = JPOOL_LONG (jcf, index);
774 goto integer;
775 integer:
776 {
777 char buffer[25];
778 format_int (buffer, num, 10);
779 fprintf (out, "%s", buffer);
780 if (verbosity > 1)
781 {
782 format_uint (buffer, (uint64)num, 16);
783 fprintf (out, "=0x%s", buffer);
784 }
785 }
786 break;
787 case CONSTANT_Float:
788 {
789 jfloat fnum = JPOOL_FLOAT (jcf, index);
790
791 if (verbosity > 0)
792 fputs ("Float ", out);
793
794 if (fnum.negative)
795 putc ('-', out);
796
797 if (JFLOAT_FINITE (fnum))
798 {
799 int dummy;
800 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
801 double f;
802 uint32 mantissa = fnum.mantissa;
803 if (fnum.exponent == 0)
804 /* Denormal. */
805 exponent++;
806 else
807 /* Normal; add the implicit bit. */
808 mantissa |= ((uint32)1 << 23);
809
810 f = frexp ((float) mantissa, &dummy);
811 f = ldexp (f, exponent + 1);
812 fprintf (out, "%.10g", f);
813 }
814 else
815 {
816 if (fnum.mantissa == 0)
817 fputs ("Inf", out);
818 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
819 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
820 else
821 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
822 }
823
824 if (verbosity > 1)
825 fprintf (out, ", bits = 0x%08lx", (unsigned long) JPOOL_UINT (jcf, index));
826
827 break;
828 }
829 case CONSTANT_Double:
830 {
831 jdouble dnum = JPOOL_DOUBLE (jcf, index);
832
833 if (verbosity > 0)
834 fputs ("Double ", out);
835
836 if (dnum.negative)
837 putc ('-', out);
838
839 if (JDOUBLE_FINITE (dnum))
840 {
841 int dummy;
842 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
843 double d;
844 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
845 + dnum.mantissa1);
846 if (dnum.exponent == 0)
847 /* Denormal. */
848 exponent++;
849 else
850 /* Normal; add the implicit bit. */
851 mantissa |= ((uint64)1 << 52);
852
853 d = frexp ((double) mantissa, &dummy);
854 d = ldexp (d, exponent + 1);
855 fprintf (out, "%.20g", d);
856 }
857 else
858 {
859 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
860 mantissa = (mantissa << 32) + dnum.mantissa1;
861
862 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
863 fputs ("Inf", out);
864 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
865 fprintf (out, "QNaN(%" HOST_LONG_LONG_FORMAT "u)",
866 (unsigned long long)mantissa);
867 else
868 fprintf (out, "SNaN(%" HOST_LONG_LONG_FORMAT "u)",
869 (unsigned long long)mantissa);
870 }
871 if (verbosity > 1)
872 {
873 int32 hi, lo;
874 hi = JPOOL_UINT (jcf, index);
875 lo = JPOOL_UINT (jcf, index + 1);
876 fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi,
877 (unsigned long) lo);
878 }
879 break;
880 }
881 case CONSTANT_NameAndType:
882 {
883 uint16 name = JPOOL_USHORT1 (jcf, index);
884 uint16 sig = JPOOL_USHORT2 (jcf, index);
885 if (verbosity > 0)
886 {
887 if (verbosity > 1)
888 fprintf (out, "NameAndType name: %d=", name);
889 else
890 fprintf (out, "NameAndType ");
891 }
892 print_name (out, jcf, name);
893 if (verbosity <= 1)
894 fputc (' ', out);
895 else
896 fprintf (out, ", signature: %d=", sig);
897 print_signature (out, jcf, sig, 0);
898 }
899 break;
900 case CONSTANT_Utf8:
901 {
902 const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
903 int length = JPOOL_UTF_LENGTH (jcf, index);
904 if (verbosity > 0)
905 { /* Print as 8-bit bytes. */
906 fputs ("Utf8: \"", out);
907 while (--length >= 0)
908 jcf_print_char (out, *str++);
909 }
910 else
911 { /* Print as Unicode. */
912 fputc ('\"', out);
913 jcf_print_utf8 (out, str, length);
914 }
915 fputc ('\"', out);
916 }
917 break;
918 case CONSTANT_MethodHandle:
919 {
920 int kind = JPOOL_USHORT1 (jcf, index);
921 if (verbosity > 0)
922 fprintf (out, "MethodHandle kind: %d=", kind);
923 switch(kind) {
924 case 1:
925 case 2:
926 case 3:
927 case 4:
928 if (verbosity > 0)
929 fprintf (out, "Fieldref: %ld=", JPOOL_USHORT2 (jcf, index));
930 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
931 case 5:
932 case 6:
933 case 7:
934 case 8:
935 if (verbosity > 0)
936 fprintf (out, "Methodref: %ld=", JPOOL_USHORT2 (jcf, index));
937 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
938 break;
939 case 9:
940 if (verbosity > 0)
941 fprintf (out, "InterfaceMethodref: %ld=", JPOOL_USHORT2 (jcf, index));
942 print_constant (out, jcf, JPOOL_USHORT2 (jcf, index), 0);
943 break;
944 }
945 break;
946 }
947 case CONSTANT_MethodType:
948 if (verbosity > 0)
949 fprintf (out, "MethodType %ld: ", JPOOL_USHORT1 (jcf, index));
950 print_signature (out, jcf, JPOOL_USHORT1 (jcf, index), 0);
951 break;
952 case CONSTANT_InvokeDynamic:
953 {
954 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
955 if (verbosity > 0)
956 fprintf (out, "InvokeDynamic: ");
957 fprintf (out, "bootstrap_method: %ld ", JPOOL_USHORT1 (jcf, index));
958 if (verbosity == 2)
959 fprintf (out, " name_and_type: %d=<", name_and_type);
960 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
961 if (verbosity == 2)
962 fputc ('>', out);
963 break;
964 }
965 default:
966 fprintf (out, "(Unknown constant type %d)", kind);
967 }
968 }
969
970 static void
971 print_constant_pool (JCF *jcf)
972 {
973 int i;
974 for (i = 1; i < JPOOL_SIZE(jcf); i++)
975 {
976 int kind = JPOOL_TAG (jcf, i);
977 fprintf (out, "#%d: ", i);
978 print_constant (out, jcf, i, 2);
979 fprintf (out, "\n");
980 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
981 i++; /* These take up two slots in the constant table */
982 }
983 }
984
985 static void
986 print_signature_type (FILE* stream, const unsigned char **ptr,
987 const unsigned char *limit)
988 {
989 int array_size;
990 if ((*ptr) >= limit)
991 return;
992 switch (*(*ptr))
993 {
994 case '[':
995 array_size = -1;
996 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
997 {
998 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
999 }
1000 print_signature_type (stream, ptr, limit);
1001 if (array_size == -1)
1002 fprintf (stream, "[]");
1003 else
1004 fprintf (stream, "[%d]", array_size);
1005 break;
1006 case '(':
1007 {
1008 int nargs = 0;
1009 fputc (*(*ptr)++, stream);
1010 for (; **ptr != ')' && *ptr < limit; nargs++)
1011 {
1012 if (nargs > 0)
1013 fputc (',', stream);
1014 print_signature_type (stream, ptr, limit);
1015 }
1016 if (*ptr < limit)
1017 {
1018 fputc (*(*ptr)++, stream);
1019 print_signature_type (stream, ptr, limit);
1020 }
1021 else
1022 fprintf (stream, "???");
1023 }
1024 break;
1025
1026 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
1027 case 'C': fprintf (stream, "char"); (*ptr)++; break;
1028 case 'D': fprintf (stream, "double"); (*ptr)++; break;
1029 case 'F': fprintf (stream, "float"); (*ptr)++; break;
1030 case 'S': fprintf (stream, "short"); (*ptr)++; break;
1031 case 'I': fprintf (stream, "int"); (*ptr)++; break;
1032 case 'J': fprintf (stream, "long"); (*ptr)++; break;
1033 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
1034 case 'V': fprintf (stream, "void"); (*ptr)++; break;
1035
1036 case 'L':
1037 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
1038 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
1039 if (*(*ptr) == ';')
1040 (*ptr)++;
1041 break;
1042 default:
1043 jcf_print_char (stream, *(*ptr)++);
1044 }
1045 }
1046
1047 static void
1048 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
1049 {
1050 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
1051 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
1052 else
1053 {
1054 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
1055 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
1056 const unsigned char *limit;
1057 limit = str + length;
1058 if (str >= limit)
1059 fprintf (stream, "<empty signature string>");
1060 else
1061 {
1062 if (options & PRINT_SIGNATURE_RESULT_ONLY)
1063 {
1064 while (str < limit && *str++ != ')') ;
1065 }
1066 if (options & PRINT_SIGNATURE_ARGS_ONLY)
1067 {
1068 str++;
1069 fputc ('(', stream);
1070 while (str < limit && *str != ')')
1071 {
1072 print_signature_type (stream, &str, limit);
1073 if (*str != ')')
1074 fputs (", ", stream);
1075 }
1076 fputc (')', stream);
1077 }
1078 else
1079 {
1080 print_signature_type (stream, &str, limit);
1081 if (str < limit)
1082 {
1083 fprintf (stream, "<junk:");
1084 jcf_print_utf8 (stream, str, limit - str);
1085 fputc ('>', stream);
1086 }
1087 }
1088 }
1089 }
1090 }
1091
1092
1093 static void
1094 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1095 {
1096 /* Print exception table. */
1097 int i = count;
1098 if (i > 0)
1099 {
1100 const unsigned char *ptr = entries;
1101 fprintf (out, "Exceptions (count: %d):\n", i);
1102 for (; --i >= 0; ptr+= 8)
1103 {
1104 int start_pc = GET_u2 (ptr);
1105 int end_pc = GET_u2 (ptr+2);
1106 int handler_pc = GET_u2 (ptr+4);
1107 int catch_type = GET_u2 (ptr+6);
1108 fprintf (out, " start: %d, end: %d, handler: %d, type: ",
1109 start_pc, end_pc, handler_pc);
1110 if (catch_type == 0)
1111 fputs ("0 /* finally */", out);
1112 else
1113 print_constant_terse_with_index (out, jcf,
1114 catch_type, CONSTANT_Class);
1115 fputc ('\n', out);
1116 }
1117 }
1118 }
1119
1120 #include "jcf-reader.c"
1121
1122 static void
1123 process_class (JCF *jcf)
1124 {
1125 int code;
1126 if (jcf_parse_preamble (jcf) != 0)
1127 fprintf (stderr, _("Not a valid Java .class file.\n"));
1128
1129 /* Parse and possibly print constant pool */
1130 code = jcf_parse_constant_pool (jcf);
1131 if (code != 0)
1132 {
1133 fprintf (stderr, _("error while parsing constant pool\n"));
1134 exit (FATAL_EXIT_CODE);
1135 }
1136 code = verify_constant_pool (jcf);
1137 if (code > 0)
1138 {
1139 fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1140 exit (FATAL_EXIT_CODE);
1141 }
1142 if (flag_print_constant_pool)
1143 print_constant_pool (jcf);
1144
1145 jcf_parse_class (jcf);
1146 code = jcf_parse_fields (jcf);
1147 if (code != 0)
1148 {
1149 fprintf (stderr, _("error while parsing fields\n"));
1150 exit (FATAL_EXIT_CODE);
1151 }
1152 code = jcf_parse_methods (jcf);
1153 if (code != 0)
1154 {
1155 fprintf (stderr, _("error while parsing methods\n"));
1156 exit (FATAL_EXIT_CODE);
1157 }
1158 code = jcf_parse_final_attributes (jcf);
1159 if (code != 0)
1160 {
1161 fprintf (stderr, _("error while parsing final attributes\n"));
1162 exit (FATAL_EXIT_CODE);
1163 }
1164 jcf->filename = NULL;
1165 }
1166
1167 \f
1168
1169 /* This is used to mark options with no short value. */
1170 #define LONG_OPT(Num) ((Num) + 128)
1171
1172 #define OPT_classpath LONG_OPT (0)
1173 #define OPT_CLASSPATH OPT_classpath
1174 #define OPT_bootclasspath LONG_OPT (1)
1175 #define OPT_extdirs LONG_OPT (2)
1176 #define OPT_HELP LONG_OPT (3)
1177 #define OPT_VERSION LONG_OPT (4)
1178 #define OPT_JAVAP LONG_OPT (5)
1179
1180 static const struct option options[] =
1181 {
1182 { "classpath", required_argument, NULL, OPT_classpath },
1183 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1184 { "extdirs", required_argument, NULL, OPT_extdirs },
1185 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
1186 { "help", no_argument, NULL, OPT_HELP },
1187 { "verbose", no_argument, NULL, 'v' },
1188 { "version", no_argument, NULL, OPT_VERSION },
1189 { "javap", no_argument, NULL, OPT_JAVAP },
1190 { "print-main", no_argument, &flag_print_main, 1 },
1191 { "print-constants", no_argument, &flag_print_constant_pool, 1 },
1192 { NULL, no_argument, NULL, 0 }
1193 };
1194
1195 static void
1196 usage (void)
1197 {
1198 fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1199 exit (1);
1200 }
1201
1202 static void
1203 help (void)
1204 {
1205 printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1206 printf (_("Display contents of a class file in readable form.\n\n"));
1207 printf (_(" -c Disassemble method bodies\n"));
1208 printf (_(" --javap Generate output in 'javap' format\n"));
1209 printf ("\n");
1210 printf (_(" --classpath PATH Set path to find .class files\n"));
1211 printf (_(" -IDIR Append directory to class path\n"));
1212 printf (_(" --bootclasspath PATH Override built-in class path\n"));
1213 printf (_(" --extdirs PATH Set extensions directory path\n"));
1214 printf (_(" -o FILE Set output file name\n"));
1215 printf ("\n");
1216 printf (_(" --help Print this help, then exit\n"));
1217 printf (_(" --version Print version number, then exit\n"));
1218 printf (_(" -v, --verbose Print extra information while running\n"));
1219 printf ("\n");
1220 printf (_("For bug reporting instructions, please see:\n"
1221 "%s.\n"), bug_report_url);
1222 exit (0);
1223 }
1224
1225 static void
1226 version (void)
1227 {
1228 printf ("jcf-dump %s%s\n\n", pkgversion_string, version_string);
1229 printf ("Copyright %s 2012 Free Software Foundation, Inc.\n", _("(C)"));
1230 printf (_("This is free software; see the source for copying conditions. There is NO\n"
1231 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1232 exit (0);
1233 }
1234
1235 int
1236 main (int argc, char** argv)
1237 {
1238 JCF jcf[1];
1239 int argi, opt;
1240 const char *p;
1241
1242 p = argv[0] + strlen (argv[0]);
1243 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
1244 --p;
1245 progname = p;
1246
1247 xmalloc_set_program_name (progname);
1248
1249 /* Unlock the stdio streams. */
1250 unlock_std_streams ();
1251
1252 gcc_init_libintl ();
1253
1254 diagnostic_initialize (global_dc, 0);
1255
1256 if (argc <= 1)
1257 {
1258 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1259 usage ();
1260 }
1261
1262 jcf_path_init ();
1263
1264 /* We use getopt_long_only to allow single `-' long options. For
1265 some of our options this is more natural. */
1266 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1267 {
1268 switch (opt)
1269 {
1270 case 0:
1271 /* Already handled. */
1272 break;
1273
1274 case 'o':
1275 output_file = optarg;
1276 break;
1277
1278 case 'I':
1279 jcf_path_include_arg (optarg);
1280 break;
1281
1282 case 'v':
1283 verbose++;
1284 break;
1285
1286 case 'c':
1287 flag_disassemble_methods = 1;
1288 break;
1289
1290 case OPT_classpath:
1291 jcf_path_classpath_arg (optarg);
1292 break;
1293
1294 case OPT_bootclasspath:
1295 jcf_path_bootclasspath_arg (optarg);
1296 break;
1297
1298 case OPT_extdirs:
1299 jcf_path_extdirs_arg (optarg);
1300 break;
1301
1302 case OPT_HELP:
1303 help ();
1304 break;
1305
1306 case OPT_VERSION:
1307 version ();
1308 break;
1309
1310 case OPT_JAVAP:
1311 flag_javap_compatible++;
1312 flag_print_constant_pool = 0;
1313 flag_print_attributes = 0;
1314 break;
1315
1316 default:
1317 usage ();
1318 }
1319 }
1320
1321 if (verbose && ! flag_javap_compatible)
1322 flag_print_constant_pool = 1;
1323
1324 if (optind == argc)
1325 {
1326 fprintf (stderr, _("jcf-dump: no classes specified\n"));
1327 usage ();
1328 }
1329
1330 jcf_path_seal (verbose);
1331
1332 if (flag_print_main)
1333 {
1334 flag_print_fields = 0;
1335 flag_print_methods = 0;
1336 flag_print_constant_pool = 0;
1337 flag_print_attributes = 0;
1338 flag_print_class_info = 0;
1339 }
1340
1341 if (output_file)
1342 {
1343 out = fopen (output_file, "w");
1344 if (! out)
1345 {
1346 fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1347 return FATAL_EXIT_CODE;
1348 }
1349 }
1350 else
1351 out = stdout;
1352
1353 if (optind >= argc)
1354 {
1355 fprintf (out, "Reading .class from <standard input>.\n");
1356 open_class ("<stdio>", jcf, 0, NULL);
1357 process_class (jcf);
1358 }
1359 else
1360 {
1361 for (argi = optind; argi < argc; argi++)
1362 {
1363 char *arg = argv[argi];
1364 const char *class_filename = find_class (arg, strlen (arg), jcf);
1365 if (class_filename == NULL)
1366 class_filename = find_classfile (arg, jcf, NULL);
1367 if (class_filename == NULL)
1368 {
1369 perror ("Could not find class");
1370 return FATAL_EXIT_CODE;
1371 }
1372 JCF_FILL (jcf, 4);
1373 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1374 {
1375 long compressed_size, member_size;
1376 int compression_method, filename_length, extra_length;
1377 const char *filename;
1378 int total_length;
1379 if (flag_print_class_info)
1380 fprintf (out, "Reading classes from archive %s.\n",
1381 class_filename);
1382 for (;;)
1383 {
1384 int skip = 0;
1385 jcf_filbuf_t save_filbuf = jcf->filbuf;
1386 long magic = JCF_readu4_le (jcf);
1387 if (magic == 0x02014b50 || magic == 0x06054b50)
1388 break; /* got to central directory */
1389 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1390 {
1391 fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1392 return FATAL_EXIT_CODE;
1393 }
1394 JCF_FILL (jcf, 26);
1395 JCF_SKIP (jcf, 2);
1396 (void) /* general_purpose_bits = */ JCF_readu2_le (jcf);
1397 compression_method = JCF_readu2_le (jcf);
1398 JCF_SKIP (jcf, 8);
1399 compressed_size = JCF_readu4_le (jcf);
1400 member_size = JCF_readu4_le (jcf);
1401 filename_length = JCF_readu2_le (jcf);
1402 extra_length = JCF_readu2_le (jcf);
1403 total_length = filename_length + extra_length
1404 + compressed_size;
1405 if (jcf->read_end - jcf->read_ptr < total_length)
1406 jcf_trim_old_input (jcf);
1407 JCF_FILL (jcf, total_length);
1408 filename = (const char *) jcf->read_ptr;
1409 JCF_SKIP (jcf, filename_length);
1410 JCF_SKIP (jcf, extra_length);
1411 if (filename_length > 0
1412 && filename[filename_length-1] == '/')
1413 {
1414 if (flag_print_class_info)
1415 fprintf (out, "[Skipping directory %.*s]\n",
1416 filename_length, filename);
1417 skip = 1;
1418 }
1419 else if (compression_method != 0)
1420 {
1421 if (flag_print_class_info)
1422 fprintf (out, "[Skipping compressed file %.*s]\n",
1423 filename_length, filename);
1424 skip = 1;
1425 }
1426 else if (member_size < 4
1427 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1428 {
1429 if (flag_print_class_info)
1430 fprintf (out, "[Skipping non-.class member %.*s]\n",
1431 filename_length, filename);
1432 skip = 1;
1433 }
1434 else
1435 {
1436 if (flag_print_class_info)
1437 fprintf (out, "Reading class member: %.*s.\n",
1438 filename_length, filename);
1439 }
1440 if (skip)
1441 {
1442 JCF_SKIP (jcf, compressed_size);
1443 }
1444 else
1445 {
1446 unsigned char *save_end;
1447 jcf->filbuf = jcf_unexpected_eof;
1448 save_end = jcf->read_end;
1449 jcf->read_end = jcf->read_ptr + compressed_size;
1450 process_class (jcf);
1451 jcf->filbuf = save_filbuf;
1452 jcf->read_end = save_end;
1453 }
1454 }
1455 }
1456 else
1457 {
1458 if (flag_print_class_info)
1459 fprintf (out, "Reading .class from %s.\n", class_filename);
1460 process_class (jcf);
1461 }
1462 JCF_FINISH(jcf);
1463 }
1464 }
1465
1466 return SUCCESS_EXIT_CODE;
1467 }
1468
1469 \f
1470
1471 static void
1472 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1473 {
1474 #undef PTR
1475 int PC;
1476 int i;
1477 int saw_wide = 0;
1478 if (flag_disassemble_methods == 0)
1479 return;
1480 #define BCODE byte_ops
1481 for (PC = 0; PC < len;)
1482 {
1483 int oldpc = PC;
1484 int saw_index;
1485 jint INT_temp;
1486 switch (byte_ops[PC++])
1487 {
1488
1489 /* This is the actual code emitted for each of opcodes in javaops.def.
1490 The actual opcode-specific stuff is handled by the OPKIND macro.
1491 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1492 Those macros are defined below. The OPKINDs that do not have any
1493 inline parameters (such as BINOP) and therefore do mot need anything
1494 else to me printed out just use an empty body. */
1495
1496 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1497 case OPCODE: \
1498 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1499 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1500 fputc ('\n', out); \
1501 break;
1502
1503 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1504 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1505 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1506 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1507
1508 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1509 (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1510
1511 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1512 These all push a constant onto the opcode stack. */
1513 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1514 saw_index = 0, i = (OPERAND_VALUE); \
1515 if (oldpc+1 == PC) /* nothing */; \
1516 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1517 else fprintf (out, " %d", i);
1518
1519 /* Print out operand (a local variable index) for LOAD opcodes.
1520 These all push local variable onto the opcode stack. */
1521 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1522 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1523
1524 /* Handle STORE opcodes same as LOAD opcodes.
1525 These all store a value from the opcode stack in a local variable. */
1526 #define STORE LOAD
1527
1528 /* Handle more kind of opcodes. */
1529 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1530 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1531 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1532 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1533 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1534 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1535 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1536
1537 /* Handle putfield and getfield opcodes, with static versions. */
1538 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1539 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1540
1541 /* Print operand for invoke opcodes. */
1542 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1543 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1544 if (OPERAND_VALUE) /* for invokeinterface */ \
1545 { int nargs = IMMEDIATE_u1; PC++; \
1546 fprintf (out, " nargs:%d", nargs); }
1547
1548 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1549 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1550
1551 #define ARRAY(OPERAND_TYPE, SUBOP) \
1552 ARRAY_##SUBOP(OPERAND_TYPE)
1553 /* Handle sub-categories of ARRAY opcodes. */
1554 #define ARRAY_LOAD(TYPE) /* nothing */
1555 #define ARRAY_STORE(TYPE) /* nothing */
1556 #define ARRAY_LENGTH(TYPE) /* nothing */
1557 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1558 #define ARRAY_NEW_NUM \
1559 INT_temp = IMMEDIATE_u1; \
1560 { switch ((int) INT_temp) { \
1561 case 4: fputs (" boolean", out); break; \
1562 case 5: fputs (" char", out); break; \
1563 case 6: fputs (" float", out); break; \
1564 case 7: fputs (" double", out); break; \
1565 case 8: fputs (" byte", out); break; \
1566 case 9: fputs (" short", out); break; \
1567 case 10: fputs (" int", out); break; \
1568 case 11: fputs (" long", out); break; \
1569 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1570 } }
1571
1572 #define ARRAY_NEW_PTR \
1573 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1574
1575 #define ARRAY_NEW_MULTI \
1576 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1577 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1578
1579 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1580 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1581
1582 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1583 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1584 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1585
1586 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1587 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1588 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1589
1590 #undef RET /* Defined by config/i386/i386.h */
1591 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1592 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1593 saw_wide = 0; \
1594 fprintf (out, " %ld", (long) INT_temp);
1595
1596 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1597 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1598
1599 #define LOOKUP_SWITCH \
1600 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1601 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1602 while (--npairs >= 0) { \
1603 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1604 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1605 }
1606
1607 #define TABLE_SWITCH \
1608 { jint default_offset = IMMEDIATE_s4; \
1609 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1610 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1611 (long) low, (long) high, (long) default_offset+oldpc); \
1612 for (; low <= high; low++) { \
1613 jint offset = IMMEDIATE_s4; \
1614 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1615 }
1616
1617 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1618 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1619
1620 #define SPECIAL_IINC(OPERAND_TYPE) \
1621 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1622 fprintf (out, " %d", i); \
1623 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1624 saw_wide = 0; \
1625 fprintf (out, " %d", i)
1626
1627 #define SPECIAL_WIDE(OPERAND_TYPE) \
1628 saw_wide = 1;
1629
1630 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1631 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1632 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1633 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1634
1635 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1636 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1637
1638 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1639 TEST(OPERAND_TYPE, OPERAND_VALUE)
1640
1641 #include "javaop.def"
1642
1643 load_store:
1644 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1645 else
1646 {
1647 saw_wide = 0;
1648 fprintf (out, " %ld", (long) INT_temp);
1649 }
1650 fputc ('\n', out);
1651 break;
1652
1653 default:
1654 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1655 }
1656 }
1657 }