xref: /openbsd-src/gnu/usr.bin/gcc/gcc/java/jcf-dump.c (revision c87b03e512fc05ed6e0222f6fb0ae86264b1d05b)
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 Free Software Foundation, Inc.
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
24 
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
26 
27 /*
28   jcf-dump is a program to print out the contents of class files.
29   Usage:  jcf-dump [FLAGS] CLASS
30   Each CLASS is either:
31   + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
32   + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
33   + The name of a .zip or .jar file (which prints all the classes in the
34   archive).
35 
36   OPTIONS:
37   -c
38 	Dis-assemble each method.
39   -classpath PATH
40 	Overrides $CLASSPATH.
41   --print-main
42 	Print nothing if there is no valid "main" method;
43 	otherwise, print only the class name.
44   --javap
45 	Print output in the style of Sun's javap program.  VERY UNFINISHED.
46  */
47 
48 
49 #include "config.h"
50 #include "system.h"
51 
52 #include "jcf.h"
53 #include "tree.h"
54 #include "java-tree.h"
55 
56 #include "version.h"
57 
58 #include <getopt.h>
59 #include <math.h>
60 
61 /* Outout file. */
62 FILE *out;
63 /* Name of output file, if NULL if stdout. */
64 char *output_file = NULL;
65 
66 int verbose = 0;
67 
68 int flag_disassemble_methods = 0;
69 int flag_print_class_info = 1;
70 int flag_print_constant_pool = 1;
71 int flag_print_fields = 1;
72 int flag_print_methods = 1;
73 int flag_print_attributes = 1;
74 
75 /* When nonzero, warn when source file is newer than matching class
76    file.  */
77 int flag_newer = 1;
78 
79 /* Print names of classes that have a "main" method. */
80 int flag_print_main = 0;
81 
82 /* Index in constant pool of this class. */
83 int this_class_index = 0;
84 
85 int class_access_flags = 0;
86 
87 /* Print in format similar to javap.  VERY IMCOMPLETE. */
88 int flag_javap_compatible = 0;
89 
90 static void print_access_flags PARAMS ((FILE *, uint16, char));
91 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
92 static void print_constant PARAMS ((FILE *, JCF *, int, int));
93 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
94 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
95 static void print_name PARAMS ((FILE*, JCF*, int));
96 static void print_signature PARAMS ((FILE*, JCF*, int, int));
97 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
98 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
99 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
100 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
101 static void process_class PARAMS ((struct JCF *));
102 static void print_constant_pool PARAMS ((struct JCF *));
103 static void print_exception_table PARAMS ((struct JCF *,
104 					  const unsigned char *entries, int));
105 
106 #define PRINT_SIGNATURE_RESULT_ONLY 1
107 #define PRINT_SIGNATURE_ARGS_ONLY 2
108 
109 static int
110 DEFUN(utf8_equal_string, (jcf, index, value),
111       JCF *jcf AND int index AND const char * value)
112 {
113   if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
114       && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
115     {
116       int len = strlen (value);
117       if (JPOOL_UTF_LENGTH (jcf, index) == len
118 	  && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
119 	return 1;
120     }
121   return 0;
122 }
123 
124 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
125   this_class_index = 0; \
126   if (flag_print_class_info) \
127     fprintf (out, \
128              "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
129 	     (long) MAGIC, (long) MINOR, (long) MAJOR)
130 
131 #define HANDLE_START_CONSTANT_POOL(COUNT) \
132   if (flag_print_constant_pool) \
133     fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
134 
135 #define HANDLE_SOURCEFILE(INDEX) \
136 { fprintf (out, "Attribute "); \
137   print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
138   fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
139   print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
140 
141 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
142   this_class_index = THIS; \
143   class_access_flags = ACCESS_FLAGS; \
144   if (flag_print_class_info) \
145     { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
146       print_access_flags (out, ACCESS_FLAGS, 'c'); \
147       fputc ('\n', out); \
148       fprintf (out, "This class: "); \
149       if (flag_print_constant_pool) \
150         fprintf (out, "%d=", THIS); \
151       print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
152       if (flag_print_constant_pool || SUPER != 0) \
153         fprintf (out, ", super: "); \
154       if (flag_print_constant_pool) \
155         { \
156           fprintf (out, "%d", SUPER); \
157           if (SUPER != 0) \
158             fputc ('=', out); \
159         } \
160       if (SUPER != 0) \
161         print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
162       fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
163     }
164 
165 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
166   (flag_print_attributes <= 0)
167 
168 #define HANDLE_CLASS_INTERFACE(INDEX) \
169   if (flag_print_class_info) \
170     { fprintf (out, "- Implements: %d=", INDEX); \
171       print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
172       fputc ('\n', out); }
173 
174 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
175   if (flag_print_fields) \
176     fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
177 
178 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
179   if (flag_print_fields) \
180     { fprintf (out, "Field name:"); \
181       print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
182       print_access_flags (out, ACCESS_FLAGS, 'f'); \
183       fprintf (out, " Signature: "); \
184       if (flag_print_constant_pool) \
185         fprintf (out, "%d=", SIGNATURE); \
186       print_signature (out, jcf, SIGNATURE, 0); \
187       fputc ('\n', out); } \
188   else \
189     flag_print_attributes--;
190 
191 #define HANDLE_END_FIELD() \
192   if (! flag_print_fields) \
193     flag_print_attributes++;
194 
195 #define HANDLE_START_METHODS(METHODS_COUNT) \
196   if (flag_print_methods) \
197     fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
198   else \
199     flag_print_attributes--;
200 
201 
202 #define HANDLE_END_METHODS() \
203   if (! flag_print_methods) \
204     flag_print_attributes++;
205 
206 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
207 { \
208   if (flag_print_methods) \
209     { \
210       if (flag_javap_compatible) \
211         { \
212 	  fprintf (out, "    "); \
213 	  print_access_flags (out, ACCESS_FLAGS, 'm'); \
214 	  fputc (' ', out); \
215 	  print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
216 	  fputc (' ', out); \
217 	  print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
218 	  print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
219 	  fputc ('\n', out); \
220 	} \
221       else \
222 	{ \
223 	  fprintf (out, "\nMethod name:"); \
224 	  print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
225 	  print_access_flags (out, ACCESS_FLAGS, 'm'); \
226 	  fprintf (out, " Signature: "); \
227 	  if (flag_print_constant_pool) \
228 	    fprintf (out, "%d=", SIGNATURE); \
229 	  print_signature (out, jcf, SIGNATURE, 0); \
230 	  fputc ('\n', out); \
231 	} \
232     } \
233   if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
234       && utf8_equal_string (jcf, NAME, "main") \
235       && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
236       && this_class_index > 0 \
237       && (class_access_flags & ACC_PUBLIC)) \
238     { \
239       print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
240       fputc  ('\n', out); \
241    } \
242 }
243 
244 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
245 ( fprintf (out, "Attribute "), \
246   print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
247   fprintf (out, ", length:%ld", (long) LENGTH) )
248 
249 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
250 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
251   fprintf (out, ", value: "), \
252   print_constant_ref (out, jcf, VALUE_INDEX), \
253   fprintf (out, "\n") )
254 
255 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
256 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
257   fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
258     (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
259   disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
260 
261 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
262   print_exception_table (jcf, ENTRIES, COUNT)
263 
264 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
265 { int n = (COUNT); int i; \
266   COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
267   fprintf (out, ", count: %d\n", n); \
268   for (i = 0; i < n; i++) {\
269     int ex_index = JCF_readu2 (jcf); \
270     fprintf (out, "%3d: ", i); \
271     print_constant_ref (out, jcf, ex_index); \
272     fputc ('\n', out); } }
273 
274 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
275 { int n = (COUNT); int i; \
276   COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
277   fprintf (out, ", count: %d\n", n); \
278   for (i = 0; i < n; i++) {\
279     int start_pc = JCF_readu2 (jcf); \
280     int length = JCF_readu2 (jcf); \
281     int name_index = JCF_readu2 (jcf); \
282     int signature_index = JCF_readu2 (jcf); \
283     int slot = JCF_readu2 (jcf); \
284     fprintf (out, "  slot#%d: name: %d=", slot, name_index); \
285     print_name (out, jcf, name_index); \
286     fprintf (out, ", type: %d=", signature_index); \
287     print_signature (out, jcf, signature_index, 0); \
288     fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
289 
290 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
291 { int n = (COUNT); int i; \
292   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
293   fprintf (out, ", count: %d\n", n); \
294   if (flag_disassemble_methods) \
295     for (i = 0; i < n; i++) {\
296       int start_pc = JCF_readu2 (jcf); \
297       int line_number = JCF_readu2 (jcf); \
298       fprintf (out, "  line: %d at pc: %d\n", line_number, start_pc); }\
299   else \
300     JCF_SKIP (jcf, 4 * n); }
301 
302 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT)				    \
303 { int n = (COUNT);							    \
304   COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length);	    \
305   while (n--)								    \
306     {									    \
307       uint16 inner_class_info_index = JCF_readu2 (jcf);			    \
308       uint16 outer_class_info_index = JCF_readu2 (jcf);			    \
309       uint16 inner_name_index = JCF_readu2 (jcf);			    \
310       uint16 inner_class_access_flags = JCF_readu2 (jcf);		    \
311 									    \
312       if (flag_print_class_info)					    \
313 	{								    \
314 	  fprintf (out, "\n  class: ");					    \
315 	  if (flag_print_constant_pool)					    \
316 	    fprintf (out, "%d=", inner_class_info_index);		    \
317 	  print_constant_terse (out, jcf,				    \
318 				inner_class_info_index, CONSTANT_Class);    \
319 	  fprintf (out, " (%d=", inner_name_index);			    \
320 	  print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
321 	  fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
322 	  print_access_flags (out, inner_class_access_flags, 'c');	    \
323 	  fprintf (out, ", outer class: ");				    \
324 	  if (flag_print_constant_pool)					    \
325 	    fprintf (out, "%d=", outer_class_info_index);		    \
326 	  print_constant_terse (out, jcf,				    \
327 				outer_class_info_index, CONSTANT_Class);    \
328 	}								    \
329     }									    \
330       if (flag_print_class_info)					    \
331 	fputc ('\n', out);						    \
332 }
333 
334 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
335 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
336   fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
337 
338 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
339   if (flag_print_attributes > 0) \
340     fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
341 
342 #include "javaop.h"
343 
344 static void
345 DEFUN(print_constant_ref, (stream, jcf, index),
346       FILE *stream AND JCF *jcf AND int index)
347 {
348   fprintf (stream, "#%d=<", index);
349   if (index <= 0 || index >= JPOOL_SIZE(jcf))
350     fprintf (stream, "out of range");
351   else
352     print_constant (stream, jcf, index, 1);
353   fprintf (stream, ">");
354 }
355 
356 /* Print the access flags given by FLAGS.
357    The CONTEXT is one of 'c' (class flags), 'f' (field flags),
358    or 'm' (method flags). */
359 
360 static void
361 DEFUN (print_access_flags, (stream, flags, context),
362        FILE *stream AND uint16 flags AND char context)
363 {
364   if (flags & ACC_PUBLIC) fprintf (stream, " public");
365   if (flags & ACC_PRIVATE) fprintf (stream, " private");
366   if (flags & ACC_PROTECTED) fprintf (stream, " protected");
367   if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
368   if (flags & ACC_STATIC) fprintf (stream, " static");
369   if (flags & ACC_FINAL) fprintf (stream, " final");
370   if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
371   if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
372   if (flags & ACC_NATIVE) fprintf (stream, " native");
373   if (flags & ACC_SYNCHRONIZED)
374     {
375       if (context == 'c')
376 	fprintf (stream, " super");
377       else
378 	fprintf (stream, " synchronized");
379     }
380   if (flags & ACC_INTERFACE) fprintf (stream, " interface");
381   if (flags & ACC_STRICT) fprintf (stream, " strictfp");
382 }
383 
384 
385 static void
386 DEFUN(print_name, (stream, jcf, name_index),
387       FILE* stream AND JCF* jcf AND int name_index)
388 {
389   if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
390     fprintf (stream, "<not a UTF8 constant>");
391   else
392     jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
393 		    JPOOL_UTF_LENGTH (jcf, name_index));
394 }
395 
396 /* If the type of the constant at INDEX matches EXPECTED,
397    print it tersely, otherwise more verbosely. */
398 
399 static void
400 DEFUN(print_constant_terse, (out, jcf, index, expected),
401       FILE *out AND JCF *jcf AND int index AND 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 DEFUN(print_constant, (out, jcf, index, verbosity),
422       FILE *out AND JCF *jcf AND int index AND 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 DEFUN(print_constant_pool, (jcf),
641       JCF *jcf)
642 {
643   int i;
644   for (i = 1; i < JPOOL_SIZE(jcf); i++)
645     {
646       int kind = JPOOL_TAG (jcf, i);
647       fprintf (out, "#%d: ", i);
648       print_constant (out, jcf, i, 2);
649       fprintf (out, "\n");
650       if (kind == CONSTANT_Double || kind == CONSTANT_Long)
651 	i++; /* These take up two slots in the constant table */
652     }
653 }
654 
655 static void
656 DEFUN(print_signature_type, (stream, ptr, limit),
657      FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
658 {
659   int array_size;
660   if ((*ptr) >= limit)
661     return;
662   switch (*(*ptr))
663     {
664     case '[':
665       array_size = -1;
666       for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
667 	{
668 	  array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
669 	}
670       print_signature_type (stream, ptr, limit);
671       if (array_size == -1)
672 	fprintf (stream, "[]");
673       else
674 	fprintf (stream, "[%d]", array_size);
675       break;
676     case '(':
677       {
678 	int nargs = 0;
679 	fputc (*(*ptr)++, stream);
680 	for (; **ptr != ')' && *ptr < limit; nargs++)
681 	  {
682 	    if (nargs > 0)
683 	      fputc (',', stream);
684 	    print_signature_type (stream, ptr, limit);
685 	  }
686 	if (*ptr < limit)
687 	  {
688 	    fputc (*(*ptr)++, stream);
689 	    print_signature_type (stream, ptr, limit);
690 	  }
691 	else
692 	  fprintf (stream, "???");
693       }
694     break;
695 
696     case 'B':  fprintf (stream, "byte");  (*ptr)++;  break;
697     case 'C':  fprintf (stream, "char");  (*ptr)++;  break;
698     case 'D':  fprintf (stream, "double");  (*ptr)++;  break;
699     case 'F':  fprintf (stream, "float");  (*ptr)++;  break;
700     case 'S':  fprintf (stream, "short");  (*ptr)++;  break;
701     case 'I':  fprintf (stream, "int");  (*ptr)++;  break;
702     case 'J':  fprintf (stream, "long");  (*ptr)++;  break;
703     case 'Z':  fprintf (stream, "boolean");  (*ptr)++;  break;
704     case 'V':  fprintf (stream, "void");  (*ptr)++;  break;
705 
706     case 'L':
707       for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
708 	jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
709       if (*(*ptr) == ';')
710 	(*ptr)++;
711       break;
712     default:
713       jcf_print_char (stream, *(*ptr)++);
714     }
715 }
716 
717 static void
718 DEFUN(print_signature, (stream, jcf, signature_index, int options),
719       FILE* stream AND JCF *jcf AND int signature_index AND int options)
720 {
721   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
722     print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
723   else
724     {
725       const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
726       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
727       const unsigned char *limit;
728       limit = str + length;
729       if (str >= limit)
730 	fprintf (stream, "<empty signature string>");
731       else
732 	{
733 	  if (options & PRINT_SIGNATURE_RESULT_ONLY)
734 	    {
735 	      while (str < limit && *str++ != ')') ;
736 	    }
737 	  if (options & PRINT_SIGNATURE_ARGS_ONLY)
738 	    {
739 	      str++;
740 	      fputc ('(', stream);
741 	      while (str < limit && *str != ')')
742 		{
743 		  print_signature_type (stream, &str, limit);
744 		  if (*str != ')')
745 		    fputs (", ", stream);
746 		}
747 	      fputc (')', stream);
748 	    }
749 	  else
750 	    {
751 	      print_signature_type (stream, &str, limit);
752 	      if (str < limit)
753 		{
754 		  fprintf (stream, "<junk:");
755 		  jcf_print_utf8 (stream, str, limit - str);
756 		  fputc ('>', stream);
757 		}
758 	    }
759 	}
760     }
761 }
762 
763 
764 static void
765 DEFUN(print_exception_table, (jcf, entries, count),
766       JCF *jcf AND const unsigned char *entries AND int count)
767 {
768   /* Print exception table. */
769   int i = count;
770   if (i > 0)
771     {
772       const unsigned char *ptr = entries;
773       fprintf (out, "Exceptions (count: %d):\n", i);
774       for (; --i >= 0;  ptr+= 8)
775 	{
776 	  int start_pc = GET_u2 (ptr);
777 	  int end_pc = GET_u2 (ptr+2);
778 	  int handler_pc = GET_u2 (ptr+4);
779 	  int catch_type = GET_u2 (ptr+6);
780 	  fprintf (out, "  start: %d, end: %d, handler: %d, type: %d",
781 		   start_pc, end_pc, handler_pc, catch_type);
782 	  if (catch_type == 0)
783 	    fputs (" /* finally */", out);
784 	  else
785 	    {
786 	      fputc('=', out);
787 	      print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
788 	    }
789 	  fputc ('\n', out);
790 	}
791     }
792 }
793 
794 #include "jcf-reader.c"
795 
796 static void
797 DEFUN(process_class, (jcf),
798       JCF *jcf)
799 {
800   int code;
801   if (jcf_parse_preamble (jcf) != 0)
802     fprintf (stderr, "Not a valid Java .class file.\n");
803 
804   /* Parse and possibly print constant pool */
805   code = jcf_parse_constant_pool (jcf);
806   if (code != 0)
807     {
808       fprintf (stderr, "error while parsing constant pool\n");
809       exit (FATAL_EXIT_CODE);
810     }
811   code = verify_constant_pool (jcf);
812   if (code > 0)
813     {
814       fprintf (stderr, "error in constant pool entry #%d\n", code);
815       exit (FATAL_EXIT_CODE);
816     }
817   if (flag_print_constant_pool)
818     print_constant_pool (jcf);
819 
820   jcf_parse_class (jcf);
821   code = jcf_parse_fields (jcf);
822   if (code != 0)
823     {
824       fprintf (stderr, "error while parsing fields\n");
825       exit (FATAL_EXIT_CODE);
826     }
827   code = jcf_parse_methods (jcf);
828   if (code != 0)
829     {
830       fprintf (stderr, "error while parsing methods\n");
831       exit (FATAL_EXIT_CODE);
832     }
833   code = jcf_parse_final_attributes (jcf);
834   if (code != 0)
835     {
836       fprintf (stderr, "error while parsing final attributes\n");
837       exit (FATAL_EXIT_CODE);
838     }
839   jcf->filename = NULL;
840 }
841 
842 
843 
844 /* This is used to mark options with no short value.  */
845 #define LONG_OPT(Num)  ((Num) + 128)
846 
847 #define OPT_classpath     LONG_OPT (0)
848 #define OPT_CLASSPATH     OPT_classpath
849 #define OPT_bootclasspath LONG_OPT (1)
850 #define OPT_extdirs       LONG_OPT (2)
851 #define OPT_HELP          LONG_OPT (3)
852 #define OPT_VERSION       LONG_OPT (4)
853 #define OPT_JAVAP         LONG_OPT (5)
854 
855 static const struct option options[] =
856 {
857   { "classpath",     required_argument, NULL, OPT_classpath },
858   { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
859   { "extdirs",       required_argument, NULL, OPT_extdirs },
860   { "CLASSPATH",     required_argument, NULL, OPT_CLASSPATH },
861   { "help",          no_argument,       NULL, OPT_HELP },
862   { "verbose",       no_argument,       NULL, 'v' },
863   { "version",       no_argument,       NULL, OPT_VERSION },
864   { "javap",         no_argument,       NULL, OPT_JAVAP },
865   { "print-main",    no_argument,      &flag_print_main, 1 },
866   { NULL,            no_argument,       NULL, 0 }
867 };
868 
869 static void
usage()870 usage ()
871 {
872   fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
873   exit (1);
874 }
875 
876 static void
help()877 help ()
878 {
879   printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
880   printf ("Display contents of a class file in readable form.\n\n");
881   printf ("  -c                      Disassemble method bodies\n");
882   printf ("  --javap                 Generate output in `javap' format\n");
883   printf ("\n");
884   printf ("  --classpath PATH        Set path to find .class files\n");
885   printf ("  -IDIR                   Append directory to class path\n");
886   printf ("  --bootclasspath PATH    Override built-in class path\n");
887   printf ("  --extdirs PATH          Set extensions directory path\n");
888   printf ("  -o FILE                 Set output file name\n");
889   printf ("\n");
890   printf ("  --help                  Print this help, then exit\n");
891   printf ("  --version               Print version number, then exit\n");
892   printf ("  -v, --verbose           Print extra information while running\n");
893   printf ("\n");
894   printf ("For bug reporting instructions, please see:\n");
895   printf ("%s.\n", bug_report_url);
896   exit (0);
897 }
898 
899 static void
version()900 version ()
901 {
902   printf ("jcf-dump (GCC) %s\n\n", version_string);
903   printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
904   printf ("This is free software; see the source for copying conditions.  There is NO\n");
905   printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
906   exit (0);
907 }
908 
909 int
910 DEFUN(main, (argc, argv),
911       int argc AND char** argv)
912 {
913   JCF jcf[1];
914   int argi, opt;
915 
916   if (argc <= 1)
917     {
918       fprintf (stderr, "jcf-dump: no classes specified\n");
919       usage ();
920     }
921 
922   jcf_path_init ();
923 
924   /* We use getopt_long_only to allow single `-' long options.  For
925      some of our options this is more natural.  */
926   while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
927     {
928       switch (opt)
929 	{
930 	case 0:
931 	  /* Already handled.  */
932 	  break;
933 
934         case 'o':
935 	  output_file = optarg;
936 	  break;
937 
938 	case 'I':
939 	  jcf_path_include_arg (optarg);
940 	  break;
941 
942 	case 'v':
943 	  verbose++;
944 	  break;
945 
946 	case 'c':
947 	  flag_disassemble_methods = 1;
948 	  break;
949 
950 	case OPT_classpath:
951 	  jcf_path_classpath_arg (optarg);
952 	  break;
953 
954 	case OPT_bootclasspath:
955 	  jcf_path_bootclasspath_arg (optarg);
956 	  break;
957 
958 	case OPT_extdirs:
959 	  jcf_path_extdirs_arg (optarg);
960 	  break;
961 
962 	case OPT_HELP:
963 	  help ();
964 	  break;
965 
966 	case OPT_VERSION:
967 	  version ();
968 	  break;
969 
970 	case OPT_JAVAP:
971 	  flag_javap_compatible++;
972 	  flag_print_constant_pool = 0;
973 	  flag_print_attributes = 0;
974 	  break;
975 
976 	default:
977 	  usage ();
978 	}
979     }
980 
981   if (optind == argc)
982     {
983       fprintf (stderr, "jcf-dump: no classes specified\n");
984       usage ();
985     }
986 
987   jcf_path_seal (verbose);
988 
989   if (flag_print_main)
990     {
991       flag_print_fields = 0;
992       flag_print_methods = 0;
993       flag_print_constant_pool = 0;
994       flag_print_attributes = 0;
995       flag_print_class_info = 0;
996     }
997 
998   if (output_file)
999     {
1000       out = fopen (output_file, "w");
1001       if (! out)
1002 	{
1003 	  fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
1004 	  return FATAL_EXIT_CODE;
1005 	}
1006     }
1007   else
1008     out = stdout;
1009 
1010   if (optind >= argc)
1011     {
1012       fprintf (out, "Reading .class from <standard input>.\n");
1013       open_class ("<stdio>", jcf, 0, NULL);
1014       process_class (jcf);
1015     }
1016   else
1017     {
1018       for (argi = optind; argi < argc; argi++)
1019 	{
1020 	  char *arg = argv[argi];
1021 	  const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1022 	  if (class_filename == NULL)
1023 	    class_filename = find_classfile (arg, jcf, NULL);
1024 	  if (class_filename == NULL)
1025 	    {
1026 	      perror ("Could not find class");
1027 	      return FATAL_EXIT_CODE;
1028 	    }
1029 	  JCF_FILL (jcf, 4);
1030 	  if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1031 	    {
1032 	      long compressed_size, member_size;
1033 	      int compression_method, filename_length, extra_length;
1034 	      int general_purpose_bits;
1035 	      const char *filename;
1036 	      int total_length;
1037 	      if (flag_print_class_info)
1038 		fprintf (out, "Reading classes from archive %s.\n",
1039 			 class_filename);
1040 	      for (;;)
1041 		{
1042 		  int skip = 0;
1043 		  jcf_filbuf_t save_filbuf = jcf->filbuf;
1044 		  long magic = JCF_readu4_le (jcf);
1045 		  if (magic == 0x02014b50 || magic == 0x06054b50)
1046 		    break;  /* got to central directory */
1047 		  if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1048 		    {
1049 		      fprintf (stderr, "bad format of .zip/.jar archive\n");
1050 		      return FATAL_EXIT_CODE;
1051 		    }
1052 		  JCF_FILL (jcf, 26);
1053 		  JCF_SKIP (jcf, 2);
1054 		  general_purpose_bits = JCF_readu2_le (jcf);
1055 		  compression_method = JCF_readu2_le (jcf);
1056 		  JCF_SKIP (jcf, 8);
1057 		  compressed_size = JCF_readu4_le (jcf);
1058 		  member_size = JCF_readu4_le (jcf);
1059 		  filename_length = JCF_readu2_le (jcf);
1060 		  extra_length = JCF_readu2_le (jcf);
1061 		  total_length = filename_length + extra_length
1062 		    + compressed_size;
1063 		  if (jcf->read_end - jcf->read_ptr < total_length)
1064 		    jcf_trim_old_input (jcf);
1065 		  JCF_FILL (jcf, total_length);
1066 		  filename = jcf->read_ptr;
1067 		  JCF_SKIP (jcf, filename_length);
1068 		  JCF_SKIP (jcf, extra_length);
1069 		  if (filename_length > 0
1070 		      && filename[filename_length-1] == '/')
1071 		    {
1072 		      if (flag_print_class_info)
1073 			fprintf (out, "[Skipping directory %.*s]\n",
1074 				 filename_length, filename);
1075 		      skip = 1;
1076 		    }
1077 		  else if (compression_method != 0)
1078 		    {
1079 		      if (flag_print_class_info)
1080 			fprintf (out, "[Skipping compressed file %.*s]\n",
1081 				 filename_length, filename);
1082 		      skip = 1;
1083 		    }
1084 		  else if (member_size < 4
1085 			   || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1086 		    {
1087 		      if (flag_print_class_info)
1088 			fprintf (out, "[Skipping non-.class member %.*s]\n",
1089 				 filename_length, filename);
1090 		      skip = 1;
1091 		    }
1092 		  else
1093 		    {
1094 		      if (flag_print_class_info)
1095 			fprintf (out, "Reading class member: %.*s.\n",
1096 				 filename_length, filename);
1097 		    }
1098 		  if (skip)
1099 		    {
1100 		      JCF_SKIP (jcf, compressed_size);
1101 		    }
1102 		  else
1103 		    {
1104 		      unsigned char *save_end;
1105 		      jcf->filbuf = jcf_unexpected_eof;
1106 		      save_end = jcf->read_end;
1107 		      jcf->read_end = jcf->read_ptr + compressed_size;
1108 		      process_class (jcf);
1109 		      jcf->filbuf = save_filbuf;
1110 		      jcf->read_end = save_end;
1111 		    }
1112 		}
1113 	    }
1114 	  else
1115 	    {
1116 	      if (flag_print_class_info)
1117 		fprintf (out, "Reading .class from %s.\n", class_filename);
1118 	      process_class (jcf);
1119 	    }
1120 	  JCF_FINISH(jcf);
1121 	}
1122     }
1123 
1124   return SUCCESS_EXIT_CODE;
1125 }
1126 
1127 
1128 
1129 static void
1130 DEFUN(disassemble_method, (jcf, byte_ops, len),
1131       JCF* jcf AND const unsigned char *byte_ops AND int len)
1132 {
1133 #undef AND /* Causes problems with opcodes for iand and land. */
1134 #undef PTR
1135   int PC;
1136   int i;
1137   int saw_wide = 0;
1138   if (flag_disassemble_methods == 0)
1139     return;
1140 #define BCODE byte_ops
1141   for (PC = 0; PC < len;)
1142     {
1143       int oldpc = PC;
1144       int saw_index;
1145       jint INT_temp;
1146       switch (byte_ops[PC++])
1147 	{
1148 
1149 /* This is the actual code emitted for each of opcodes in javaops.def.
1150    The actual opcode-specific stuff is handled by the OPKIND macro.
1151    I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1152    Those macros are defiend below.  The OPKINDs that do not have any
1153    inline parameters (such as BINOP) and therefore do mot need anything
1154    else to me printed out just use an empty body. */
1155 
1156 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1157         case OPCODE: \
1158 	  fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1159 	  OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1160 	  fputc ('\n', out); \
1161 	  break;
1162 
1163 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1164 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1165 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1166 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1167 
1168 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1169   (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1170 
1171 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1172    These all push a constant onto the opcode stack. */
1173 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1174   saw_index = 0, i = (OPERAND_VALUE); \
1175   if (oldpc+1 == PC) /* nothing */; \
1176   else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1177   else fprintf (out, " %d", i);
1178 
1179 /* Print out operand (a local variable index) for LOAD opcodes.
1180    These all push local variable onto the opcode stack. */
1181 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1182   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1183 
1184 /* Handle STORE opcodes same as LOAD opcodes.
1185    These all store a value from the opcode stack in a local variable. */
1186 #define STORE LOAD
1187 
1188 /* Handle more kind of opcodes. */
1189 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1190 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1191 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1192 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1193 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1194 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1195 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1196 
1197 /* Handle putfield and getfield opcodes, with static versions. */
1198 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1199   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1200 
1201 /* Print operand for invoke opcodes. */
1202 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1203   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1204   if (OPERAND_VALUE) /* for invokeinterface */ \
1205   { int nargs = IMMEDIATE_u1;  PC++; \
1206     fprintf (out, " nargs:%d", nargs); }
1207 
1208 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1209   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1210 
1211 #define ARRAY(OPERAND_TYPE, SUBOP) \
1212   ARRAY_##SUBOP(OPERAND_TYPE)
1213 /* Handle sub-categories of ARRAY opcodes. */
1214 #define ARRAY_LOAD(TYPE) /* nothing */
1215 #define ARRAY_STORE(TYPE) /* nothing */
1216 #define ARRAY_LENGTH(TYPE) /* nothing */
1217 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1218 #define ARRAY_NEW_NUM \
1219  INT_temp = IMMEDIATE_u1; \
1220  { switch ((int) INT_temp) {  \
1221     case  4: fputs (" boolean", out); break; \
1222     case  5: fputs (" char", out); break; \
1223     case  6: fputs (" float", out); break; \
1224     case  7: fputs (" double", out); break; \
1225     case  8: fputs (" byte", out); break; \
1226     case  9: fputs (" short", out); break; \
1227     case 10: fputs (" int", out); break; \
1228     case 11: fputs (" long", out); break; \
1229     default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1230   } }
1231 
1232 #define ARRAY_NEW_PTR  \
1233   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1234 
1235 #define ARRAY_NEW_MULTI \
1236   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1237   fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1238 
1239 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1240   fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1241 
1242 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1243   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1244   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1245 
1246 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1247   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1248   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1249 
1250 #undef RET /* Defined by config/i386/i386.h */
1251 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1252   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1253   saw_wide = 0; \
1254   fprintf (out, " %ld", (long) INT_temp);
1255 
1256 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1257   PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1258 
1259 #define LOOKUP_SWITCH \
1260   { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4; \
1261     fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1262     while (--npairs >= 0) { \
1263      jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1264      fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1265   }
1266 
1267 #define TABLE_SWITCH \
1268   { jint default_offset = IMMEDIATE_s4; \
1269     jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1270     fprintf (out, " low=%ld, high=%ld, default=%ld", \
1271       (long) low, (long) high, (long) default_offset+oldpc); \
1272     for (; low <= high; low++) { \
1273      jint offset = IMMEDIATE_s4; \
1274      fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1275   }
1276 
1277 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1278   SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1279 
1280 #define SPECIAL_IINC(OPERAND_TYPE) \
1281   i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1282   fprintf (out, " %d", i); \
1283   i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1284   saw_wide = 0; \
1285   fprintf (out, " %d", i)
1286 
1287 #define SPECIAL_WIDE(OPERAND_TYPE) \
1288   saw_wide = 1;
1289 
1290 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1291 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1292 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1293 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1294 
1295 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1296   fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1297 
1298 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1299    TEST(OPERAND_TYPE, OPERAND_VALUE)
1300 
1301 #include "javaop.def"
1302 
1303 	load_store:
1304 	  if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1305 	  else
1306 	    {
1307 	      saw_wide = 0;
1308 	      fprintf (out, " %ld", (long) INT_temp);
1309 	    }
1310 	  fputc ('\n', out);
1311 	  break;
1312 
1313 	default:
1314 	  fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1315 	}
1316     }
1317 }
1318