OSDN Git Service

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