OSDN Git Service

* java-gimplify.c: Change copyright header to refer to version 3 of the GNU
[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 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(%llu)", (unsigned long long)mantissa);
854             else
855               fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
856           }
857         if (verbosity > 1)
858           {
859             int32 hi, lo;
860             hi = JPOOL_UINT (jcf, index);
861             lo = JPOOL_UINT (jcf, index + 1);
862             fprintf (out, ", bits = 0x%08lx%08lx", (unsigned long) hi,
863                      (unsigned long) lo);
864           }
865         break;
866       }
867     case CONSTANT_NameAndType:
868       {
869         uint16 name = JPOOL_USHORT1 (jcf, index);
870         uint16 sig = JPOOL_USHORT2 (jcf, index);
871         if (verbosity > 0)
872           {
873             if (verbosity > 1)
874               fprintf (out, "NameAndType name: %d=", name);
875             else
876               fprintf (out, "NameAndType ");
877           }
878         print_name (out, jcf, name);
879         if (verbosity <= 1)
880           fputc (' ', out);
881         else
882           fprintf (out, ", signature: %d=", sig);
883         print_signature (out, jcf, sig, 0);
884       }
885       break;
886     case CONSTANT_Utf8:
887       {
888         const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
889         int length = JPOOL_UTF_LENGTH (jcf, index);
890         if (verbosity > 0)
891           { /* Print as 8-bit bytes. */
892             fputs ("Utf8: \"", out);
893             while (--length >= 0)
894               jcf_print_char (out, *str++);
895           }
896         else
897           { /* Print as Unicode. */
898             fputc ('\"', out);
899             jcf_print_utf8 (out, str, length);
900           }
901         fputc ('\"', out);
902       }
903       break;
904     default:
905       fprintf (out, "(Unknown constant type %d)", kind);
906     }
907 }
908
909 static void
910 print_constant_pool (JCF *jcf)
911 {
912   int i;
913   for (i = 1; i < JPOOL_SIZE(jcf); i++)
914     {
915       int kind = JPOOL_TAG (jcf, i);
916       fprintf (out, "#%d: ", i);
917       print_constant (out, jcf, i, 2);
918       fprintf (out, "\n");
919       if (kind == CONSTANT_Double || kind == CONSTANT_Long)
920         i++; /* These take up two slots in the constant table */
921     }
922 }
923
924 static void
925 print_signature_type (FILE* stream, const unsigned char **ptr,
926                       const unsigned char *limit)
927 {
928   int array_size;
929   if ((*ptr) >= limit)
930     return;
931   switch (*(*ptr))
932     {
933     case '[':
934       array_size = -1;
935       for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
936         {
937           array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
938         }
939       print_signature_type (stream, ptr, limit);
940       if (array_size == -1)
941         fprintf (stream, "[]");
942       else
943         fprintf (stream, "[%d]", array_size);
944       break;
945     case '(':
946       {
947         int nargs = 0;
948         fputc (*(*ptr)++, stream);
949         for (; **ptr != ')' && *ptr < limit; nargs++)
950           {
951             if (nargs > 0)
952               fputc (',', stream);
953             print_signature_type (stream, ptr, limit);
954           }
955         if (*ptr < limit)
956           {
957             fputc (*(*ptr)++, stream);
958             print_signature_type (stream, ptr, limit);
959           }
960         else
961           fprintf (stream, "???");
962       }
963     break;
964       
965     case 'B':  fprintf (stream, "byte");  (*ptr)++;  break;
966     case 'C':  fprintf (stream, "char");  (*ptr)++;  break;
967     case 'D':  fprintf (stream, "double");  (*ptr)++;  break;
968     case 'F':  fprintf (stream, "float");  (*ptr)++;  break;
969     case 'S':  fprintf (stream, "short");  (*ptr)++;  break;
970     case 'I':  fprintf (stream, "int");  (*ptr)++;  break;
971     case 'J':  fprintf (stream, "long");  (*ptr)++;  break;
972     case 'Z':  fprintf (stream, "boolean");  (*ptr)++;  break;
973     case 'V':  fprintf (stream, "void");  (*ptr)++;  break;
974
975     case 'L':
976       for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
977         jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
978       if (*(*ptr) == ';')
979         (*ptr)++;
980       break;
981     default:
982       jcf_print_char (stream, *(*ptr)++);
983     }
984 }
985
986 static void
987 print_signature (FILE* stream, JCF *jcf, int signature_index, int options)
988 {
989   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
990     print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
991   else
992     {
993       const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
994       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
995       const unsigned char *limit;
996       limit = str + length;
997       if (str >= limit)
998         fprintf (stream, "<empty signature string>");
999       else
1000         {
1001           if (options & PRINT_SIGNATURE_RESULT_ONLY)
1002             {
1003               while (str < limit && *str++ != ')') ;
1004             }
1005           if (options & PRINT_SIGNATURE_ARGS_ONLY)
1006             {
1007               str++;
1008               fputc ('(', stream);
1009               while (str < limit && *str != ')')
1010                 {
1011                   print_signature_type (stream, &str, limit);
1012                   if (*str != ')')
1013                     fputs (", ", stream);
1014                 }
1015               fputc (')', stream);
1016             }
1017           else
1018             {
1019               print_signature_type (stream, &str, limit);
1020               if (str < limit)
1021                 {
1022                   fprintf (stream, "<junk:");
1023                   jcf_print_utf8 (stream, str, limit - str);
1024                   fputc ('>', stream);
1025                 }
1026             }
1027         }
1028     }
1029 }
1030
1031
1032 static void
1033 print_exception_table (JCF *jcf, const unsigned char *entries, int count)
1034 {
1035   /* Print exception table. */
1036   int i = count;
1037   if (i > 0)
1038     {
1039       const unsigned char *ptr = entries;
1040       fprintf (out, "Exceptions (count: %d):\n", i);
1041       for (; --i >= 0;  ptr+= 8)
1042         {
1043           int start_pc = GET_u2 (ptr);
1044           int end_pc = GET_u2 (ptr+2);
1045           int handler_pc = GET_u2 (ptr+4);
1046           int catch_type = GET_u2 (ptr+6);
1047           fprintf (out, "  start: %d, end: %d, handler: %d, type: ",
1048                    start_pc, end_pc, handler_pc);
1049           if (catch_type == 0)
1050             fputs ("0 /* finally */", out);
1051           else
1052             print_constant_terse_with_index (out, jcf,
1053                                              catch_type, CONSTANT_Class);
1054           fputc ('\n', out);
1055         }
1056     }
1057 }
1058
1059 #include "jcf-reader.c"
1060
1061 static void
1062 process_class (JCF *jcf)
1063 {
1064   int code;
1065   if (jcf_parse_preamble (jcf) != 0)
1066     fprintf (stderr, _("Not a valid Java .class file.\n"));    
1067
1068   /* Parse and possibly print constant pool */
1069   code = jcf_parse_constant_pool (jcf);
1070   if (code != 0)
1071     {
1072       fprintf (stderr, _("error while parsing constant pool\n"));
1073       exit (FATAL_EXIT_CODE);
1074     }
1075   code = verify_constant_pool (jcf);
1076   if (code > 0)
1077     {
1078       fprintf (stderr, _("error in constant pool entry #%d\n"), code);
1079       exit (FATAL_EXIT_CODE);
1080     }
1081   if (flag_print_constant_pool)
1082     print_constant_pool (jcf);
1083
1084   jcf_parse_class (jcf);
1085   code = jcf_parse_fields (jcf);
1086   if (code != 0)
1087     {
1088       fprintf (stderr, _("error while parsing fields\n"));
1089       exit (FATAL_EXIT_CODE);
1090     }
1091   code = jcf_parse_methods (jcf);
1092   if (code != 0)
1093     {
1094       fprintf (stderr, _("error while parsing methods\n"));
1095       exit (FATAL_EXIT_CODE);
1096     }
1097   code = jcf_parse_final_attributes (jcf);
1098   if (code != 0)
1099     {
1100       fprintf (stderr, _("error while parsing final attributes\n"));
1101       exit (FATAL_EXIT_CODE);
1102     }
1103   jcf->filename = NULL;
1104 }
1105
1106 \f
1107
1108 /* This is used to mark options with no short value.  */
1109 #define LONG_OPT(Num)  ((Num) + 128)
1110
1111 #define OPT_classpath     LONG_OPT (0)
1112 #define OPT_CLASSPATH     OPT_classpath
1113 #define OPT_bootclasspath LONG_OPT (1)
1114 #define OPT_extdirs       LONG_OPT (2)
1115 #define OPT_HELP          LONG_OPT (3)
1116 #define OPT_VERSION       LONG_OPT (4)
1117 #define OPT_JAVAP         LONG_OPT (5)
1118
1119 static const struct option options[] =
1120 {
1121   { "classpath",     required_argument, NULL, OPT_classpath },
1122   { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
1123   { "extdirs",       required_argument, NULL, OPT_extdirs },
1124   { "CLASSPATH",     required_argument, NULL, OPT_CLASSPATH },
1125   { "help",          no_argument,       NULL, OPT_HELP },
1126   { "verbose",       no_argument,       NULL, 'v' },
1127   { "version",       no_argument,       NULL, OPT_VERSION },
1128   { "javap",         no_argument,       NULL, OPT_JAVAP },
1129   { "print-main",    no_argument,       &flag_print_main, 1 },
1130   { "print-constants", no_argument,     &flag_print_constant_pool, 1 },
1131   { NULL,            no_argument,       NULL, 0 }
1132 };
1133
1134 static void
1135 usage (void)
1136 {
1137   fprintf (stderr, _("Try 'jcf-dump --help' for more information.\n"));
1138   exit (1);
1139 }
1140
1141 static void
1142 help (void)
1143 {
1144   printf (_("Usage: jcf-dump [OPTION]... CLASS...\n\n"));
1145   printf (_("Display contents of a class file in readable form.\n\n"));
1146   printf (_("  -c                      Disassemble method bodies\n"));
1147   printf (_("  --javap                 Generate output in 'javap' format\n"));
1148   printf ("\n");
1149   printf (_("  --classpath PATH        Set path to find .class files\n"));
1150   printf (_("  -IDIR                   Append directory to class path\n"));
1151   printf (_("  --bootclasspath PATH    Override built-in class path\n"));
1152   printf (_("  --extdirs PATH          Set extensions directory path\n"));
1153   printf (_("  -o FILE                 Set output file name\n"));
1154   printf ("\n");
1155   printf (_("  --help                  Print this help, then exit\n"));
1156   printf (_("  --version               Print version number, then exit\n"));
1157   printf (_("  -v, --verbose           Print extra information while running\n"));
1158   printf ("\n");
1159   printf (_("For bug reporting instructions, please see:\n"
1160             "%s.\n"), bug_report_url);
1161   exit (0);
1162 }
1163
1164 static void
1165 version (void)
1166 {
1167   printf ("jcf-dump (GCC) %s\n\n", version_string);
1168   printf ("Copyright %s 2006 Free Software Foundation, Inc.\n", _("(C)"));
1169   printf (_("This is free software; see the source for copying conditions.  There is NO\n"
1170             "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
1171   exit (0);
1172 }
1173
1174 int
1175 main (int argc, char** argv)
1176 {
1177   JCF jcf[1];
1178   int argi, opt;
1179
1180   /* Unlock the stdio streams.  */
1181   unlock_std_streams ();
1182
1183   gcc_init_libintl ();
1184
1185   if (argc <= 1)
1186     {
1187       fprintf (stderr, _("jcf-dump: no classes specified\n"));
1188       usage ();
1189     }
1190
1191   jcf_path_init ();
1192
1193   /* We use getopt_long_only to allow single `-' long options.  For
1194      some of our options this is more natural.  */
1195   while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
1196     {
1197       switch (opt)
1198         {
1199         case 0:
1200           /* Already handled.  */
1201           break;
1202
1203         case 'o':
1204           output_file = optarg;
1205           break;
1206
1207         case 'I':
1208           jcf_path_include_arg (optarg);
1209           break;
1210
1211         case 'v':
1212           verbose++;
1213           break;
1214
1215         case 'c':
1216           flag_disassemble_methods = 1;
1217           break;
1218
1219         case OPT_classpath:
1220           jcf_path_classpath_arg (optarg);
1221           break;
1222
1223         case OPT_bootclasspath:
1224           jcf_path_bootclasspath_arg (optarg);
1225           break;
1226
1227         case OPT_extdirs:
1228           jcf_path_extdirs_arg (optarg);
1229           break;
1230
1231         case OPT_HELP:
1232           help ();
1233           break;
1234
1235         case OPT_VERSION:
1236           version ();
1237           break;
1238
1239         case OPT_JAVAP:
1240           flag_javap_compatible++;
1241           flag_print_constant_pool = 0;
1242           flag_print_attributes = 0;
1243           break;
1244
1245         default:
1246           usage ();
1247         }
1248     }
1249
1250   if (verbose && ! flag_javap_compatible)
1251     flag_print_constant_pool = 1;
1252
1253   if (optind == argc)
1254     {
1255       fprintf (stderr, _("jcf-dump: no classes specified\n"));
1256       usage ();
1257     }
1258
1259   jcf_path_seal (verbose);
1260
1261   if (flag_print_main)
1262     {
1263       flag_print_fields = 0;
1264       flag_print_methods = 0;
1265       flag_print_constant_pool = 0;
1266       flag_print_attributes = 0;
1267       flag_print_class_info = 0;
1268     }
1269
1270   if (output_file)
1271     {
1272       out = fopen (output_file, "w");
1273       if (! out)
1274         {
1275           fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file);
1276           return FATAL_EXIT_CODE;
1277         }
1278     }
1279   else
1280     out = stdout;
1281
1282   if (optind >= argc)
1283     {
1284       fprintf (out, "Reading .class from <standard input>.\n");
1285       open_class ("<stdio>", jcf, 0, NULL);
1286       process_class (jcf);
1287     }
1288   else
1289     {
1290       for (argi = optind; argi < argc; argi++)
1291         {
1292           char *arg = argv[argi];
1293           const char *class_filename = find_class (arg, strlen (arg), jcf);
1294           if (class_filename == NULL)
1295             class_filename = find_classfile (arg, jcf, NULL);
1296           if (class_filename == NULL)
1297             {
1298               perror ("Could not find class");
1299               return FATAL_EXIT_CODE;
1300             }
1301           JCF_FILL (jcf, 4);
1302           if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1303             {
1304               long compressed_size, member_size;
1305               int compression_method, filename_length, extra_length;
1306               int general_purpose_bits;
1307               const char *filename;
1308               int total_length;
1309               if (flag_print_class_info)
1310                 fprintf (out, "Reading classes from archive %s.\n",
1311                          class_filename);
1312               for (;;)
1313                 {
1314                   int skip = 0;
1315                   jcf_filbuf_t save_filbuf = jcf->filbuf;
1316                   long magic = JCF_readu4_le (jcf);
1317                   if (magic == 0x02014b50 || magic == 0x06054b50)
1318                     break;  /* got to central directory */
1319                   if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1320                     {
1321                       fprintf (stderr, _("bad format of .zip/.jar archive\n"));
1322                       return FATAL_EXIT_CODE;
1323                     }
1324                   JCF_FILL (jcf, 26);
1325                   JCF_SKIP (jcf, 2);
1326                   general_purpose_bits = JCF_readu2_le (jcf);
1327                   compression_method = JCF_readu2_le (jcf);
1328                   JCF_SKIP (jcf, 8);
1329                   compressed_size = JCF_readu4_le (jcf);
1330                   member_size = JCF_readu4_le (jcf);
1331                   filename_length = JCF_readu2_le (jcf);
1332                   extra_length = JCF_readu2_le (jcf);
1333                   total_length = filename_length + extra_length
1334                     + compressed_size;
1335                   if (jcf->read_end - jcf->read_ptr < total_length)
1336                     jcf_trim_old_input (jcf);
1337                   JCF_FILL (jcf, total_length);
1338                   filename = (const char *) jcf->read_ptr;
1339                   JCF_SKIP (jcf, filename_length);
1340                   JCF_SKIP (jcf, extra_length);
1341                   if (filename_length > 0
1342                       && filename[filename_length-1] == '/')
1343                     {
1344                       if (flag_print_class_info)
1345                         fprintf (out, "[Skipping directory %.*s]\n",
1346                                  filename_length, filename);
1347                       skip = 1;
1348                     }
1349                   else if (compression_method != 0)
1350                     {
1351                       if (flag_print_class_info)
1352                         fprintf (out, "[Skipping compressed file %.*s]\n",
1353                                  filename_length, filename);
1354                       skip = 1;
1355                     }
1356                   else if (member_size < 4
1357                            || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1358                     {
1359                       if (flag_print_class_info)
1360                         fprintf (out, "[Skipping non-.class member %.*s]\n",
1361                                  filename_length, filename);
1362                       skip = 1;
1363                     }
1364                   else
1365                     {
1366                       if (flag_print_class_info)
1367                         fprintf (out, "Reading class member: %.*s.\n",
1368                                  filename_length, filename);
1369                     }
1370                   if (skip)
1371                     {
1372                       JCF_SKIP (jcf, compressed_size);
1373                     }
1374                   else
1375                     {
1376                       unsigned char *save_end;
1377                       jcf->filbuf = jcf_unexpected_eof;
1378                       save_end = jcf->read_end;
1379                       jcf->read_end = jcf->read_ptr + compressed_size;
1380                       process_class (jcf);
1381                       jcf->filbuf = save_filbuf;
1382                       jcf->read_end = save_end;
1383                     }
1384                 }
1385             }
1386           else
1387             {
1388               if (flag_print_class_info)
1389                 fprintf (out, "Reading .class from %s.\n", class_filename);
1390               process_class (jcf);
1391             }
1392           JCF_FINISH(jcf);
1393         }
1394     }
1395
1396   return SUCCESS_EXIT_CODE;
1397 }
1398
1399 \f
1400
1401 static void
1402 disassemble_method (JCF* jcf, const unsigned char *byte_ops, int len)
1403 {
1404 #undef PTR
1405   int PC;
1406   int i;
1407   int saw_wide = 0;
1408   if (flag_disassemble_methods == 0)
1409     return;
1410 #define BCODE byte_ops
1411   for (PC = 0; PC < len;)
1412     {
1413       int oldpc = PC;
1414       int saw_index;
1415       jint INT_temp;
1416       switch (byte_ops[PC++])
1417         {
1418
1419 /* This is the actual code emitted for each of opcodes in javaops.def.
1420    The actual opcode-specific stuff is handled by the OPKIND macro.
1421    I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1422    Those macros are defined below.  The OPKINDs that do not have any
1423    inline parameters (such as BINOP) and therefore do mot need anything
1424    else to me printed out just use an empty body. */
1425
1426 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1427         case OPCODE: \
1428           fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1429           OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1430           fputc ('\n', out); \
1431           break;
1432
1433 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1434 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1435 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1436 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1437
1438 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1439   (fprintf(stderr, _("Bad byte codes.\n")), exit(-1), 0) : 1)
1440
1441 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1442    These all push a constant onto the opcode stack. */
1443 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1444   saw_index = 0, i = (OPERAND_VALUE); \
1445   if (oldpc+1 == PC) /* nothing */; \
1446   else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1447   else fprintf (out, " %d", i);
1448
1449 /* Print out operand (a local variable index) for LOAD opcodes.
1450    These all push local variable onto the opcode stack. */
1451 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1452   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1453
1454 /* Handle STORE opcodes same as LOAD opcodes.
1455    These all store a value from the opcode stack in a local variable. */
1456 #define STORE LOAD
1457
1458 /* Handle more kind of opcodes. */
1459 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1460 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1461 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1462 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1463 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1464 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1465 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1466
1467 /* Handle putfield and getfield opcodes, with static versions. */
1468 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1469   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1470
1471 /* Print operand for invoke opcodes. */
1472 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1473   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1474   if (OPERAND_VALUE) /* for invokeinterface */ \
1475   { int nargs = IMMEDIATE_u1;  PC++; \
1476     fprintf (out, " nargs:%d", nargs); }
1477
1478 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1479   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1480
1481 #define ARRAY(OPERAND_TYPE, SUBOP) \
1482   ARRAY_##SUBOP(OPERAND_TYPE)
1483 /* Handle sub-categories of ARRAY opcodes. */
1484 #define ARRAY_LOAD(TYPE) /* nothing */
1485 #define ARRAY_STORE(TYPE) /* nothing */
1486 #define ARRAY_LENGTH(TYPE) /* nothing */
1487 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1488 #define ARRAY_NEW_NUM \
1489  INT_temp = IMMEDIATE_u1; \
1490  { switch ((int) INT_temp) {  \
1491     case  4: fputs (" boolean", out); break; \
1492     case  5: fputs (" char", out); break; \
1493     case  6: fputs (" float", out); break; \
1494     case  7: fputs (" double", out); break; \
1495     case  8: fputs (" byte", out); break; \
1496     case  9: fputs (" short", out); break; \
1497     case 10: fputs (" int", out); break; \
1498     case 11: fputs (" long", out); break; \
1499     default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1500   } }
1501
1502 #define ARRAY_NEW_PTR  \
1503   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1504
1505 #define ARRAY_NEW_MULTI \
1506   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1507   fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1508
1509 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1510   fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1511
1512 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1513   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1514   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1515
1516 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1517   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1518   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1519
1520 #undef RET /* Defined by config/i386/i386.h */
1521 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1522   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1523   saw_wide = 0; \
1524   fprintf (out, " %ld", (long) INT_temp);
1525
1526 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1527   PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1528
1529 #define LOOKUP_SWITCH \
1530   { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4; \
1531     fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1532     while (--npairs >= 0) { \
1533      jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1534      fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1535   }
1536
1537 #define TABLE_SWITCH \
1538   { jint default_offset = IMMEDIATE_s4; \
1539     jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1540     fprintf (out, " low=%ld, high=%ld, default=%ld", \
1541       (long) low, (long) high, (long) default_offset+oldpc); \
1542     for (; low <= high; low++) { \
1543      jint offset = IMMEDIATE_s4; \
1544      fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1545   }
1546
1547 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1548   SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1549
1550 #define SPECIAL_IINC(OPERAND_TYPE) \
1551   i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1552   fprintf (out, " %d", i); \
1553   i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1554   saw_wide = 0; \
1555   fprintf (out, " %d", i)
1556
1557 #define SPECIAL_WIDE(OPERAND_TYPE) \
1558   saw_wide = 1;
1559
1560 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1561 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1562 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1563 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1564
1565 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1566   fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1567
1568 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1569    TEST(OPERAND_TYPE, OPERAND_VALUE)
1570
1571 #include "javaop.def"
1572
1573         load_store:
1574           if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1575           else
1576             {
1577               saw_wide = 0;
1578               fprintf (out, " %ld", (long) INT_temp);
1579             }
1580           fputc ('\n', out);
1581           break;
1582
1583         default:
1584           fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1585         }
1586     }
1587 }