OSDN Git Service

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