OSDN Git Service

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