OSDN Git Service

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