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