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