OSDN Git Service

Merged gcj-eclipse branch to trunk.
[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 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 2, 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 COPYING.  If not, write to
21 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.  
23
24 Java and all Java-based marks are trademarks or registered trademarks
25 of Sun Microsystems, Inc. in the United States and other countries.
26 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
27
28 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
29
30 /*
31   jcf-dump is a program to print out the contents of class files.
32   Usage:  jcf-dump [FLAGS] CLASS
33   Each CLASS is either:
34   + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
35   + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
36   + The name of a .zip or .jar file (which prints all the classes in the
37   archive).
38
39   OPTIONS:
40   -c
41         Dis-assemble each method.
42   -classpath PATH
43         Overrides $CLASSPATH.
44   --print-main
45         Print nothing if there is no valid "main" method;
46         otherwise, print only the class name.
47   --javap
48         Print output in the style of Sun's javap program.  VERY UNFINISHED.
49  */
50     
51
52 #include "config.h"
53 #include "system.h"
54 #include "coretypes.h"
55 #include "tm.h"
56 #include "ggc.h"
57 #include "intl.h"
58
59 #include "jcf.h"
60 #include "tree.h"
61 #include "java-tree.h"
62
63 #include "version.h"
64
65 #include <getopt.h>
66 #include <math.h>
67
68 /* Output file. */
69 FILE *out;
70 /* Name of output file, if NULL if stdout. */
71 char *output_file = NULL;
72
73 int verbose = 0;
74
75 int flag_disassemble_methods = 0;
76 int flag_print_class_info = 1;
77 int flag_print_constant_pool = 0;
78 int flag_print_fields = 1;
79 int flag_print_methods = 1;
80 int flag_print_attributes = 1;
81
82 /* When nonzero, warn when source file is newer than matching class
83    file.  */
84 int flag_newer = 1;
85
86 /* Print names of classes that have a "main" method. */
87 int flag_print_main = 0;
88
89 /* Index in constant pool of this class. */
90 int this_class_index = 0;
91
92 int class_access_flags = 0;
93
94 /* Print in format similar to javap.  VERY INCOMPLETE. */
95 int flag_javap_compatible = 0;
96
97 static void print_access_flags (FILE *, uint16, char);
98 static void print_constant_terse (FILE*, JCF*, int, int);
99 static void print_constant_terse_with_index (FILE *, JCF *, int, int);
100 static void print_constant (FILE *, JCF *, int, int);
101 static void print_constant_ref (FILE *, JCF *, int);
102 static void disassemble_method (JCF*, const unsigned char *, int);
103 static void print_name (FILE*, JCF*, int);
104 static void print_signature (FILE*, JCF*, int, int);
105 static int utf8_equal_string (struct JCF*, int, const char *);
106 static void usage (void) ATTRIBUTE_NORETURN;
107 static void help (void) ATTRIBUTE_NORETURN;
108 static void version (void) ATTRIBUTE_NORETURN;
109 static void process_class (struct JCF *);
110 static void print_constant_pool (struct JCF *);
111 static void print_exception_table (struct JCF *, const unsigned char *entries,
112                                    int);
113 static void indent (FILE *, int);
114 static void print_element_value (FILE *, JCF *, int);
115 static void print_annotation (FILE *, JCF *, int);
116 static void print_annotations (FILE *, JCF *, int);
117 static void print_parameter_annotations (FILE *, JCF *, int);
118
119 #define PRINT_SIGNATURE_RESULT_ONLY 1
120 #define PRINT_SIGNATURE_ARGS_ONLY 2
121
122 static int
123 utf8_equal_string (JCF *jcf, int index, const char * value)
124 {
125   if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
126       && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
127     {
128       int len = strlen (value);
129       if (JPOOL_UTF_LENGTH (jcf, index) == len
130           && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
131         return 1;
132     }
133   return 0;
134 }
135
136 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
137   this_class_index = 0; \
138   if (flag_print_class_info) \
139     fprintf (out, \
140              "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
141              (long) MAGIC, (long) MINOR, (long) MAJOR)
142
143 #define HANDLE_START_CONSTANT_POOL(COUNT) \
144   if (flag_print_constant_pool) \
145     fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
146
147 #define HANDLE_SOURCEFILE(INDEX) \
148 { fprintf (out, "Attribute "); \
149   print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
150   fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
151   print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
152
153 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
154   this_class_index = THIS; \
155   class_access_flags = ACCESS_FLAGS; \
156   if (flag_print_class_info) \
157     { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
158       print_access_flags (out, ACCESS_FLAGS, 'c'); \
159       fputc ('\n', out); \
160       fprintf (out, "This class: "); \
161       print_constant_terse_with_index (out, jcf, THIS, CONSTANT_Class); \
162       if (flag_print_constant_pool || SUPER != 0) \
163         fprintf (out, ", super: "); \
164       if (flag_print_constant_pool) \
165         { \
166           fprintf (out, "%d", SUPER); \
167           if (SUPER != 0) \
168             fputc ('=', out); \
169         } \
170       if (SUPER != 0) \
171         print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
172       fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
173     }
174
175 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
176   (flag_print_attributes <= 0)
177
178 #define HANDLE_CLASS_INTERFACE(INDEX) \
179   if (flag_print_class_info) \
180     { fprintf (out, "- Implements: "); \
181       print_constant_terse_with_index (out, jcf, INDEX, CONSTANT_Class); \
182       fputc ('\n', out); }
183
184 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
185   if (flag_print_fields) \
186     fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
187
188 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
189   if (flag_print_fields) \
190     { fprintf (out, "Field name:"); \
191       print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
192       print_access_flags (out, ACCESS_FLAGS, 'f'); \
193       fprintf (out, " Descriptor: "); \
194       if (flag_print_constant_pool) \
195         fprintf (out, "%d=", SIGNATURE); \
196       print_signature (out, jcf, SIGNATURE, 0); \
197       fputc ('\n', out); } \
198   else \
199     flag_print_attributes--;
200
201 #define HANDLE_END_FIELD() \
202   if (! flag_print_fields) \
203     flag_print_attributes++;
204
205 #define HANDLE_START_METHODS(METHODS_COUNT) \
206   if (flag_print_methods) \
207     fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
208   else \
209     flag_print_attributes--;
210
211
212 #define HANDLE_END_METHODS() \
213   if (! flag_print_methods) \
214     flag_print_attributes++;
215
216 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
217 { \
218   if (flag_print_methods) \
219     { \
220       if (flag_javap_compatible) \
221         { \
222           fprintf (out, "    "); \
223           print_access_flags (out, ACCESS_FLAGS, 'm'); \
224           fputc (' ', out); \
225           print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
226           fputc (' ', out); \
227           print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
228           print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
229           fputc ('\n', out); \
230         } \
231       else \
232         { \
233           fprintf (out, "\nMethod name:"); \
234           print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
235           print_access_flags (out, ACCESS_FLAGS, 'm'); \
236           fprintf (out, " Descriptor: "); \
237           if (flag_print_constant_pool) \
238             fprintf (out, "%d=", SIGNATURE); \
239           print_signature (out, jcf, SIGNATURE, 0); \
240           fputc ('\n', out); \
241         } \
242     } \
243   if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
244       && utf8_equal_string (jcf, NAME, "main") \
245       && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
246       && this_class_index > 0 \
247       && (class_access_flags & ACC_PUBLIC)) \
248     { \
249       print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
250       fputc  ('\n', out); \
251    } \
252 }
253
254 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
255 ( fprintf (out, "Attribute "), \
256   print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
257   fprintf (out, ", length:%ld", (long) LENGTH) )
258
259 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
260 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
261   fprintf (out, ", value: "), \
262   print_constant_ref (out, jcf, VALUE_INDEX), \
263   fprintf (out, "\n") )
264
265 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
266 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
267   fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
268     (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
269   disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
270
271 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
272   print_exception_table (jcf, ENTRIES, COUNT)
273
274 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
275 { int n = (COUNT); int i; \
276   COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
277   fprintf (out, ", count: %d\n", n); \
278   for (i = 0; i < n; i++) {\
279     int ex_index = JCF_readu2 (jcf); \
280     fprintf (out, "%3d: ", i); \
281     print_constant_ref (out, jcf, ex_index); \
282     fputc ('\n', out); } }
283
284 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
285 { int n = (COUNT); int i; \
286   COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
287   fprintf (out, ", count: %d\n", n); \
288   for (i = 0; i < n; i++) {\
289     int start_pc = JCF_readu2 (jcf); \
290     int length = JCF_readu2 (jcf); \
291     int name_index = JCF_readu2 (jcf); \
292     int signature_index = JCF_readu2 (jcf); \
293     int slot = JCF_readu2 (jcf); \
294     fprintf (out, "  slot#%d: name: ", slot); \
295     if (flag_print_constant_pool) \
296       fprintf (out, "%d=", name_index); \
297     print_name (out, jcf, name_index); \
298     fprintf (out, ", type: "); \
299     if (flag_print_constant_pool) \
300       fprintf (out, "%d=", signature_index); \
301     print_signature (out, jcf, signature_index, 0); \
302     fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
303
304 #define HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE(COUNT)                  \
305 { int n = (COUNT); int i;                                               \
306   COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length);       \
307   fprintf (out, ", count: %d\n", n);                                    \
308   for (i = 0; i < n; i++) {                                             \
309     int start_pc = JCF_readu2 (jcf);                                    \
310     int length = JCF_readu2 (jcf);                                      \
311     int name_index = JCF_readu2 (jcf);                                  \
312     int signature_index = JCF_readu2 (jcf);                             \
313     int slot = JCF_readu2 (jcf);                                        \
314     fprintf (out, "  slot#%d: name: ", slot);                           \
315     if (flag_print_constant_pool)                                       \
316       fprintf (out, "%d=", name_index);                                 \
317     print_name (out, jcf, name_index);                                  \
318     fprintf (out, ", type: ");                                          \
319     if (flag_print_constant_pool)                                       \
320       fprintf (out, "%d=", signature_index);                            \
321     print_signature (out, jcf, signature_index, 0);                     \
322     fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
323
324 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
325 { int n = (COUNT); int i; \
326   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
327   fprintf (out, ", count: %d\n", n); \
328   if (flag_disassemble_methods) \
329     for (i = 0; i < n; i++) {\
330       int start_pc = JCF_readu2 (jcf); \
331       int line_number = JCF_readu2 (jcf); \
332       fprintf (out, "  line: %d at pc: %d\n", line_number, start_pc); }\
333   else \
334     JCF_SKIP (jcf, 4 * n); }
335
336 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT)                                \
337 { int n = (COUNT);                                                          \
338   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);           \
339   while (n--)                                                               \
340     {                                                                       \
341       uint16 inner_class_info_index = JCF_readu2 (jcf);                     \
342       uint16 outer_class_info_index = JCF_readu2 (jcf);                     \
343       uint16 inner_name_index = JCF_readu2 (jcf);                           \
344       uint16 inner_class_access_flags = JCF_readu2 (jcf);                   \
345                                                                             \
346       if (flag_print_class_info)                                            \
347         {                                                                   \
348           fprintf (out, "\n  inner: ");                                     \
349           if (inner_class_info_index == 0)                                  \
350             fprintf (out, " (no inner info index)");                        \
351           else                                                              \
352             print_constant_terse_with_index (out, jcf,                      \
353                                              inner_class_info_index,        \
354                                              CONSTANT_Class);               \
355           if (inner_name_index == 0)                                        \
356             fprintf (out, " (anonymous)");                                  \
357           else if (verbose || flag_print_constant_pool)                     \
358             {                                                               \
359               fprintf (out, " (");                                          \
360               print_constant_terse_with_index (out, jcf, inner_name_index,  \
361                                                CONSTANT_Utf8);              \
362               fputc (')', out);                                             \
363             }                                                               \
364           fprintf (out, ", access flags: 0x%x", inner_class_access_flags);  \
365           print_access_flags (out, inner_class_access_flags, 'c');          \
366           fprintf (out, ", outer class: ");                                 \
367           if (outer_class_info_index == 0)                                  \
368             fprintf (out, "(not a member)");                                \
369           else                                                              \
370             print_constant_terse_with_index (out, jcf,                      \
371                                              outer_class_info_index,        \
372                                              CONSTANT_Class);               \
373         }                                                                   \
374     }                                                                       \
375   if (flag_print_class_info)                                                \
376     fputc ('\n', out);                                                      \
377 }
378
379 #define HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE(LENGTH) \
380 { int i, n = (LENGTH), c = 0;                                     \
381   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
382   fputc ('\n', out); \
383   for (i = 0;  i < n;  i++) { c = JCF_readu(jcf); fputc(c, out); } \
384   if (c != '\r' && c != '\n') fputc('\n', out); }
385
386 #define HANDLE_ENCLOSINGMETHOD_ATTRIBUTE()                              \
387   { uint16 class_index, method_index;                                   \
388   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
389   class_index = JCF_readu2 (jcf);                                       \
390   method_index = JCF_readu2 (jcf);                                      \
391   fprintf (out, "\n  Class: ");                                         \
392   print_constant_terse_with_index (out, jcf, class_index, CONSTANT_Class); \
393   fprintf (out, "\n  Method: ");                                        \
394   print_constant_terse_with_index (out, jcf, method_index,              \
395                                    CONSTANT_NameAndType);               \
396   fputc ('\n', out);                                                    \
397 }
398
399 #define HANDLE_SIGNATURE_ATTRIBUTE()                                    \
400 {                                                                       \
401   uint16 signature;                                                     \
402   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
403   signature = JCF_readu2 (jcf);                                         \
404   fprintf (out, "\n  Value: ");                                         \
405   print_constant_terse_with_index (out, jcf, signature, CONSTANT_Utf8); \
406   fputc ('\n', out);                                                    \
407 }
408
409 #define HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE()                    \
410 {                                                                       \
411   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
412   print_annotations (out, jcf, 1);                                      \
413 }
414
415 #define HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE()                  \
416 {                                                                       \
417   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
418   print_annotations (out, jcf, 1);                                      \
419 }
420
421 #define HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE()           \
422 {                                                                       \
423   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
424   print_parameter_annotations (out, jcf, 1);                            \
425 }
426
427 #define HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE()         \
428 {                                                                       \
429   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
430   print_parameter_annotations (out, jcf, 1);                            \
431 }
432
433 #define HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE()                            \
434 {                                                                       \
435   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);       \
436   print_element_value (out, jcf, 1);                                    \
437 }
438
439
440 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
441 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
442   fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
443
444 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
445   if (flag_print_attributes > 0) \
446     fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
447
448 #include "javaop.h"
449
450 \f
451
452 static void
453 indent (FILE *stream, int level)
454 {
455   int i;
456   for (i = 0; i < level; ++i)
457     fprintf (stream, "  ");
458 }
459
460 static void
461 print_element_value (FILE *stream, JCF *jcf, int level)
462 {
463   uint8 tag = JCF_readu (jcf);
464   indent (stream, level);
465   switch (tag)
466     {
467     case 'B':
468     case 'C':
469     case 'S':
470     case 'Z':
471     case 'I':
472       {
473         uint16 cindex = JCF_readu2 (jcf);
474         print_constant_terse_with_index (stream, jcf, cindex,
475                                          CONSTANT_Integer);
476       }
477       break;
478     case 'D':
479       {
480         uint16 cindex = JCF_readu2 (jcf);
481         print_constant_terse_with_index (stream, jcf, cindex,
482                                          CONSTANT_Double);
483       }
484       break;
485     case 'F':
486       {
487         uint16 cindex = JCF_readu2 (jcf);
488         print_constant_terse_with_index (stream, jcf, cindex,
489                                          CONSTANT_Float);
490       }
491       break;
492     case 'J':
493       {
494         uint16 cindex = JCF_readu2 (jcf);
495         print_constant_terse_with_index (stream, jcf, cindex,
496                                          CONSTANT_Long);
497       }
498       break;
499     case 's':
500       {
501         uint16 cindex = JCF_readu2 (jcf);
502         /* Despite what the JVM spec says, compilers generate a Utf8
503            constant here, not a String.  */
504         print_constant_terse_with_index (stream, jcf, cindex,
505                                          CONSTANT_Utf8);
506       }
507       break;
508
509     case 'e':
510       {
511         uint16 type_name_index = JCF_readu2 (jcf);
512         uint16 const_name_index = JCF_readu2 (jcf);
513         fprintf (stream, "enum class: ");
514         print_constant_terse_with_index (stream, jcf, type_name_index,
515                                          CONSTANT_Utf8);
516         fprintf (stream, "\n");
517         indent (stream, level);
518         fprintf (stream, "Field: ");
519         print_constant_terse_with_index (stream, jcf, const_name_index,
520                                          CONSTANT_Utf8);
521       }
522       break;
523     case 'c':
524       {
525         uint16 class_info_index = JCF_readu2 (jcf);
526         print_constant_terse_with_index (stream, jcf, class_info_index,
527                                          CONSTANT_Utf8);
528       }
529       break;
530     case '@':
531       {
532         fprintf (stream, "Annotation:\n");
533         print_annotation (stream, jcf, level + 1);
534       }
535       break;
536     case '[':
537       {
538         uint16 n_array_elts = JCF_readu2 (jcf);
539         fprintf (stream, "array[%d]: [\n", (int) n_array_elts);
540         while (n_array_elts--)
541           print_element_value (stream, jcf, level + 1);
542         indent (stream, level);
543         fprintf (stream, "]");
544       }
545       break;
546     default:
547       fprintf (stream, "Unexpected tag value: %d", (int) tag);
548       break;
549     }
550   fputc ('\n', stream);
551 }
552
553 static void
554 print_annotation (FILE *stream, JCF *jcf, int level)
555 {
556   uint16 type_index = JCF_readu2 (jcf);
557   uint16 npairs = JCF_readu2 (jcf);
558   fprintf (stream, "\n");
559   indent (stream, level);
560   fprintf (stream, "Annotation name: ");
561   print_constant_terse_with_index (stream, jcf, type_index,
562                                    CONSTANT_Utf8);
563   if (npairs)
564     {
565       fprintf (stream, "\n");
566       while (npairs--)
567         {
568           uint16 name_index = JCF_readu2 (jcf);
569           indent (stream, level + 1);
570           fprintf (stream, "Name: ");
571           print_constant_terse_with_index (stream, jcf, name_index,
572                                            CONSTANT_Utf8);
573           fprintf (stream, "\n");
574           print_element_value (stream, jcf, level + 2);
575         }
576     }
577 }
578
579 static void
580 print_annotations (FILE *stream, JCF *jcf, int level)
581 {
582   uint16 num = JCF_readu2 (jcf);
583   while (num--)
584     print_annotation (stream, jcf, level);
585 }
586
587 static void
588 print_parameter_annotations (FILE *stream, JCF *jcf, int level)
589 {
590   uint8 nparams = JCF_readu (jcf);
591   uint8 i;
592   for (i = 0; i < nparams; ++i)
593     {
594       indent (stream, level);
595       fprintf (stream, "Parameter annotations (%d):\n", (int) i);
596       print_annotations (stream, jcf, level + 1);
597     }
598 }
599
600 \f
601
602 static void
603 print_constant_ref (FILE *stream, JCF *jcf, int index)
604 {
605   if (index <= 0 || index >= JPOOL_SIZE(jcf))
606     fprintf (stream, "<out of range>");
607   else
608     {
609       if (flag_print_constant_pool)
610         fprintf (stream, "#%d=", index);
611       fputc ('<', stream);
612       print_constant (stream, jcf, index, 1);
613       fputc ('>', stream);
614     }
615 }
616
617 /* Print the access flags given by FLAGS.
618    The CONTEXT is one of 'c' (class flags), 'f' (field flags),
619    or 'm' (method flags). */
620
621 static void
622 print_access_flags (FILE *stream, uint16 flags, char context)
623 {
624   if (flags & ACC_PUBLIC) fprintf (stream, " public");
625   if (flags & ACC_PRIVATE) fprintf (stream, " private");
626   if (flags & ACC_PROTECTED) fprintf (stream, " protected");
627   if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
628   if (flags & ACC_STATIC) fprintf (stream, " static");
629   if (flags & ACC_FINAL) fprintf (stream, " final");
630   if (flags & ACC_TRANSIENT)
631     fprintf (stream, context == 'm' ? " varargs" : " transient");
632   if (flags & ACC_VOLATILE)
633     fprintf (stream, context == 'm' ? " bridge" : " volatile");
634   if (flags & ACC_NATIVE) fprintf (stream, " native");
635   if (flags & ACC_SYNCHRONIZED)
636     {
637       if (context == 'c')
638         fprintf (stream, " super");
639       else
640         fprintf (stream, " synchronized");
641     }
642   if (flags & ACC_INTERFACE)
643     fprintf (stream, (flags & ACC_ANNOTATION) ? " @interface" : " interface");
644   if (flags & ACC_ENUM) fprintf (stream, " enum");
645   if (flags & ACC_STRICT) fprintf (stream, " strictfp");
646   if (flags & ACC_SYNTHETIC) fprintf (stream, " synthetic");
647 }
648
649
650 static void
651 print_name (FILE* stream, JCF* jcf, int name_index)
652 {
653   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
654     fprintf (stream, "<not a UTF8 constant>");
655   else
656     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
657                     JPOOL_UTF_LENGTH (jcf, name_index));
658 }
659
660 /* If the type of the constant at INDEX matches EXPECTED,
661    print it tersely, otherwise more verbosely. */
662
663 static void
664 print_constant_terse (FILE *out, JCF *jcf, int index, int expected)
665 {
666   if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
667     fprintf (out, "<constant pool index %d not in range>", index);
668   else if (JPOOL_TAG (jcf, index) != expected)
669     {
670       fprintf (out, "<Unexpected constant type ");
671       print_constant (out, jcf, index, 1);
672       fprintf (out, ">");
673     }
674   else
675     print_constant (out, jcf, index, 0);
676 }
677
678 static void
679 print_constant_terse_with_index (FILE *out, JCF *jcf, int index, int expected)
680 {
681   if (flag_print_constant_pool)
682     fprintf (out, "%d=", index);
683   print_constant_terse (out, jcf, index, expected);
684 }
685
686 /* Print the constant at INDEX in JCF's constant pool.
687    If verbosity==0, print very tersely (no extraneous text).
688    If verbosity==1, prefix the type of the constant.
689    If verbosity==2, add more descriptive text. */
690
691 static void
692 print_constant (FILE *out, JCF *jcf, int index, int verbosity)
693 {
694   int j, n;
695   jlong num;
696   const char *str;
697   int kind = JPOOL_TAG (jcf, index);
698   switch (kind)
699     {
700     case CONSTANT_Class:
701       n = JPOOL_USHORT1 (jcf, index);
702       if (verbosity > 0)
703         {
704           if (verbosity > 1)
705             fprintf (out, "Class name: %d=", n);
706           else
707             fprintf (out, "Class ");
708         }
709       if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
710         fprintf (out, "<out of range>");
711       else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
712         {
713           int len = JPOOL_UTF_LENGTH (jcf, n);
714           jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
715         }
716       else
717         print_constant_terse (out, jcf, n, CONSTANT_Utf8);
718       break;
719     case CONSTANT_Fieldref:
720       str = "Field"; goto field_or_method;
721     case CONSTANT_Methodref:
722       str = "Method"; goto field_or_method;
723     case CONSTANT_InterfaceMethodref:
724       str = "InterfaceMethod"; goto field_or_method;
725     field_or_method:
726       {
727         uint16 tclass = JPOOL_USHORT1 (jcf, index);
728         uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
729         if (verbosity == 2)
730           fprintf (out, "%sref class: %d=", str, tclass);
731         else if (verbosity > 0)
732             fprintf (out, "%s ", str);
733         print_constant_terse (out, jcf, tclass, CONSTANT_Class);
734         if (verbosity < 2)
735           fprintf (out, ".");
736         else
737           fprintf (out, " name_and_type: %d=<", name_and_type);
738         print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
739         if (verbosity == 2)
740           fputc ('>', out);
741       }
742       break;
743     case CONSTANT_String:
744       j = JPOOL_USHORT1 (jcf, index);
745       if (verbosity > 0)
746         {
747           if (verbosity > 1)
748             fprintf (out, "String %d=", j);
749           else
750             fprintf (out, "String ");
751         }
752       print_constant_terse (out, jcf, j, CONSTANT_Utf8);
753       break;
754     case CONSTANT_Integer:
755       if (verbosity > 0)
756         fprintf (out, "Integer ");
757       num = JPOOL_INT (jcf, index);
758       goto integer;
759     case CONSTANT_Long:
760       if (verbosity > 0)
761         fprintf (out, "Long ");
762       num = JPOOL_LONG (jcf, index);
763       goto integer;
764     integer:
765       {
766         char buffer[25];
767         format_int (buffer, num, 10);
768         fprintf (out, "%s", buffer);
769         if (verbosity > 1)
770           {
771             format_uint (buffer, (uint64)num, 16);
772             fprintf (out, "=0x%s", buffer);
773           }
774       }
775       break;
776     case CONSTANT_Float:
777       {
778         jfloat fnum = JPOOL_FLOAT (jcf, index);
779
780         if (verbosity > 0)
781           fputs ("Float ", out);
782
783         if (fnum.negative)
784           putc ('-', out);
785
786         if (JFLOAT_FINITE (fnum))
787           {
788             int dummy;
789             int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
790             double f;
791             uint32 mantissa = fnum.mantissa;
792             if (fnum.exponent == 0)
793               /* Denormal.  */
794               exponent++;
795             else
796               /* Normal; add the implicit bit.  */
797               mantissa |= ((uint32)1 << 23);
798             
799             f = frexp (mantissa, &dummy);
800             f = ldexp (f, exponent + 1);
801             fprintf (out, "%.10g", f);
802           }
803         else
804           {
805             if (fnum.mantissa == 0)
806               fputs ("Inf", out);
807             else if (fnum.mantissa & JFLOAT_QNAN_MASK)
808               fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
809             else
810               fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
811           }
812
813         if (verbosity > 1)
814           fprintf (out, ", bits = 0x%08lx", (long) JPOOL_UINT (jcf, index));
815         
816         break;
817       }
818     case CONSTANT_Double:
819       {
820         jdouble dnum = JPOOL_DOUBLE (jcf, index);
821
822         if (verbosity > 0)
823           fputs ("Double ", out);
824
825         if (dnum.negative)
826           putc ('-', out);
827
828         if (JDOUBLE_FINITE (dnum))
829           {
830             int dummy;
831             int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
832             double d;
833             uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
834                                + dnum.mantissa1);
835             if (dnum.exponent == 0)
836               /* Denormal.  */
837               exponent++;
838             else
839               /* Normal; add the implicit bit.  */
840               mantissa |= ((uint64)1 << 52);
841
842             d = frexp (mantissa, &dummy);
843             d = ldexp (d, exponent + 1);
844             fprintf (out, "%.20g", d);
845           }
846         else
847           {
848             uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
849             mantissa = (mantissa << 32) + dnum.mantissa1;
850
851             if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
852               fputs ("Inf", out);
853             else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
854               fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
855             else
856               fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
857           }
858         if (verbosity > 1)
859           {
860             int32 hi, lo;
861             hi = JPOOL_UINT (jcf, index);
862             lo = JPOOL_UINT (jcf, index + 1);
863             fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (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, 0);
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 }