OSDN Git Service

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