OSDN Git Service

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