OSDN Git Service

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