OSDN Git Service

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