OSDN Git Service

* check-init.c (check_bool2_init, done_alternative): 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));
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         fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n);
390       if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
391         fprintf (out, "<out of range>");
392       else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
393         {
394           int len = JPOOL_UTF_LENGTH (jcf, n);
395           jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
396         }
397       else
398         print_constant_terse (out, jcf, n, CONSTANT_Utf8);
399       break;
400     case CONSTANT_Fieldref:
401       str = "Field"; goto field_or_method;
402     case CONSTANT_Methodref:
403       str = "Method"; goto field_or_method;
404     case CONSTANT_InterfaceMethodref:
405       str = "InterfaceMethod"; goto field_or_method;
406     field_or_method:
407       {
408         uint16 tclass = JPOOL_USHORT1 (jcf, index);
409         uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
410         if (verbosity == 2)
411           fprintf (out, "%sref class: %d=", str, tclass);
412         else if (verbosity > 0)
413             fprintf (out, "%s ", str);
414         print_constant_terse (out, jcf, tclass, CONSTANT_Class);
415         fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<",
416                  name_and_type);
417         print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
418         if (verbosity == 2)
419           fputc ('>', out);
420       }
421       break;
422     case CONSTANT_String:
423       j = JPOOL_USHORT1 (jcf, index);
424       if (verbosity > 0)
425         fprintf (out, verbosity > 1 ? "String %d=" : "String ", j);
426       print_constant_terse (out, jcf, j, CONSTANT_Utf8);
427       break;
428     case CONSTANT_Integer:
429       if (verbosity > 0)
430         fprintf (out, "Integer ");
431       num = JPOOL_INT (jcf, index);
432       goto integer;
433     case CONSTANT_Long:
434       if (verbosity > 0)
435         fprintf (out, "Long ");
436       num = JPOOL_LONG (jcf, index);
437       goto integer;
438     integer:
439       {
440         char buffer[25];
441         format_int (buffer, num, 10);
442         fprintf (out, "%s", buffer);
443         if (verbosity > 1)
444           {
445             format_uint (buffer, (uint64)num, 16);
446             fprintf (out, "=0x%s", buffer);
447           }
448       }
449       break;
450     case CONSTANT_Float:
451       {
452         jfloat fnum = JPOOL_FLOAT (jcf, index);
453         fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
454         if (verbosity > 1)
455           fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
456         break;
457       }
458     case CONSTANT_Double:
459       {
460         jdouble dnum = JPOOL_DOUBLE (jcf, index);
461         fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
462         if (verbosity > 1)
463           {
464             int32 hi, lo;
465             hi = JPOOL_UINT (jcf, index);
466             lo = JPOOL_UINT (jcf, index + 1);
467             fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
468           }
469         break;
470       }
471     case CONSTANT_NameAndType:
472       {
473         uint16 name = JPOOL_USHORT1 (jcf, index);
474         uint16 sig = JPOOL_USHORT2 (jcf, index);
475         if (verbosity > 0)
476           fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ",
477                    "NameAndType", name);
478         print_name (out, jcf, name);
479         if (verbosity <= 1)
480           fputc (' ', out);
481         else
482           fprintf (out, ", signature: %d=", sig);
483         print_signature (out, jcf, sig, 0);
484       }
485       break;
486     case CONSTANT_Utf8:
487       {
488         register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
489         int length = JPOOL_UTF_LENGTH (jcf, index);
490         if (verbosity > 0)
491           { /* Print as 8-bit bytes. */
492             fputs ("Utf8: \"", out);
493             while (--length >= 0)
494               jcf_print_char (out, *str++);
495           }
496         else
497           { /* Print as Unicode. */
498             fputc ('\"', out);
499             jcf_print_utf8 (out, str, length);
500           }
501         fputc ('\"', out);
502       }
503       break;
504     default:
505       fprintf (out, "(Unknown constant type %d)", kind);
506     }
507 }
508
509 static void
510 DEFUN(print_constant_pool, (jcf),
511       JCF *jcf)
512 {
513   int i;
514   for (i = 1; i < JPOOL_SIZE(jcf); i++)
515     {
516       int kind = JPOOL_TAG (jcf, i);
517       fprintf (out, "#%d: ", i);
518       print_constant (out, jcf, i, 2);
519       fprintf (out, "\n");
520       if (kind == CONSTANT_Double || kind == CONSTANT_Long)
521         i++; /* These take up two slots in the constant table */
522     }
523 }
524
525 static void
526 DEFUN(print_signature_type, (stream, ptr, limit),
527      FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
528 {
529   int array_size;
530   if ((*ptr) >= limit)
531     return;
532   switch (*(*ptr))
533     {
534     case '[':
535       array_size = -1;
536       for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
537         {
538           array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
539         }
540       print_signature_type (stream, ptr, limit);
541       if (array_size == -1)
542         fprintf (stream, "[]");
543       else
544         fprintf (stream, "[%d]", array_size);
545       break;
546     case '(':
547       {
548         int nargs = 0;
549         fputc (*(*ptr)++, stream);
550         for (; **ptr != ')' && *ptr < limit; nargs++)
551           {
552             if (nargs > 0)
553               fputc (',', stream);
554             print_signature_type (stream, ptr, limit);
555           }
556         if (*ptr < limit)
557           {
558             fputc (*(*ptr)++, stream);
559             print_signature_type (stream, ptr, limit);
560           }
561         else
562           fprintf (stream, "???");
563       }
564     break;
565       
566     case 'B':  fprintf (stream, "byte");  (*ptr)++;  break;
567     case 'C':  fprintf (stream, "char");  (*ptr)++;  break;
568     case 'D':  fprintf (stream, "double");  (*ptr)++;  break;
569     case 'F':  fprintf (stream, "float");  (*ptr)++;  break;
570     case 'S':  fprintf (stream, "short");  (*ptr)++;  break;
571     case 'I':  fprintf (stream, "int");  (*ptr)++;  break;
572     case 'J':  fprintf (stream, "long");  (*ptr)++;  break;
573     case 'Z':  fprintf (stream, "boolean");  (*ptr)++;  break;
574     case 'V':  fprintf (stream, "void");  (*ptr)++;  break;
575
576     case 'L':
577       for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
578         jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
579       if (*(*ptr) == ';')
580         (*ptr)++;
581       break;
582     default:
583       jcf_print_char (stream, *(*ptr)++);
584     }
585 }
586
587 static void
588 DEFUN(print_signature, (stream, jcf, signature_index, int options),
589       FILE* stream AND JCF *jcf AND int signature_index AND int options)
590 {
591   if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
592     print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
593   else
594     {
595       const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
596       int length = JPOOL_UTF_LENGTH (jcf, signature_index);
597       const unsigned char *limit;
598       limit = str + length;
599       if (str >= limit)
600         fprintf (stream, "<empty signature string>");
601       else
602         {
603           if (options & PRINT_SIGNATURE_RESULT_ONLY)
604             {
605               while (str < limit && *str++ != ')') ;
606             }
607           if (options & PRINT_SIGNATURE_ARGS_ONLY)
608             {
609               str++;
610               fputc ('(', stream);
611               while (str < limit && *str != ')')
612                 {
613                   print_signature_type (stream, &str, limit);
614                   if (*str != ')')
615                     fputs (", ", stream);
616                 }
617               fputc (')', stream);
618             }
619           else
620             {
621               print_signature_type (stream, &str, limit);
622               if (str < limit)
623                 {
624                   fprintf (stream, "<junk:");
625                   jcf_print_utf8 (stream, str, limit - str);
626                   fputc ('>', stream);
627                 }
628             }
629         }
630     }
631 }
632
633
634 static void
635 DEFUN(print_exception_table, (jcf, entries, count),
636       JCF *jcf AND const unsigned char *entries AND int count)
637 {
638   /* Print exception table. */
639   int i = count;
640   if (i > 0)
641     {
642       const unsigned char *ptr = entries;
643       fprintf (out, "Exceptions (count: %d):\n", i);
644       for (; --i >= 0;  ptr+= 8)
645         {
646           int start_pc = GET_u2 (ptr);
647           int end_pc = GET_u2 (ptr+2);
648           int handler_pc = GET_u2 (ptr+4);
649           int catch_type = GET_u2 (ptr+6);
650           fprintf (out, "  start: %d, end: %d, handler: %d, type: %d",
651                    start_pc, end_pc, handler_pc, catch_type);
652           if (catch_type == 0)
653             fputs (" /* finally */", out);
654           else
655             {
656               fputc('=', out);
657               print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
658             }
659           fputc ('\n', out);
660         }
661     }
662 }
663
664 #include "jcf-reader.c"
665
666 static int
667 DEFUN (usage, (), )
668 {
669   fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
670   exit(1);
671 }
672
673 static void
674 DEFUN(process_class, (jcf),
675       JCF *jcf)
676 {
677   int code;
678   if (jcf_parse_preamble (jcf) != 0)
679     fprintf (stderr, "Not a valid Java .class file.\n");    
680
681   /* Parse and possibly print constant pool */
682   code = jcf_parse_constant_pool (jcf);
683   if (code != 0)
684     {
685       fprintf (stderr, "error while parsing constant pool\n");
686       exit (FATAL_EXIT_CODE);
687     }
688   code = verify_constant_pool (jcf);
689   if (code > 0)
690     {
691       fprintf (stderr, "error in constant pool entry #%d\n", code);
692       exit (FATAL_EXIT_CODE);
693     }
694   if (flag_print_constant_pool)
695     print_constant_pool (jcf);
696
697   jcf_parse_class (jcf);
698   code = jcf_parse_fields (jcf);
699   if (code != 0)
700     {
701       fprintf (stderr, "error while parsing fields\n");
702       exit (FATAL_EXIT_CODE);
703     }
704   code = jcf_parse_methods (jcf);
705   if (code != 0)
706     {
707       fprintf (stderr, "error while parsing methods\n");
708       exit (FATAL_EXIT_CODE);
709     }
710   code = jcf_parse_final_attributes (jcf);
711   if (code != 0)
712     {
713       fprintf (stderr, "error while parsing final attributes\n");
714       exit (FATAL_EXIT_CODE);
715     }
716   jcf->filename = NULL;
717 }
718
719 int
720 DEFUN(main, (argc, argv),
721       int argc AND char** argv)
722 {
723   JCF jcf[1];
724   int argi;
725   if (argc <= 1)
726     usage ();
727
728   jcf_path_init ();
729
730   for (argi = 1; argi < argc; argi++)
731     {
732       const char *arg = argv[argi];
733
734       if (arg[0] != '-' || ! strcmp (arg, "--"))
735         break;
736
737       /* Just let all arguments be given in either "-" or "--" form.  */
738       if (arg[1] == '-')
739         ++arg;
740
741       if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
742         output_file = argv[++argi];
743       else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
744         jcf_path_classpath_arg (argv[++argi]);
745       else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
746         jcf_path_CLASSPATH_arg (argv[++argi]);
747       else if (strncmp (arg, "-I", 2) == 0)
748         jcf_path_include_arg (arg + 2);
749       else if (strcmp (arg, "-verbose") == 0)
750         verbose++;
751       else if (strcmp (arg, "-print-main") == 0)
752         flag_print_main++;
753       else if (strcmp (arg, "-c") == 0)
754         flag_disassemble_methods++;
755       else if (strcmp (arg, "-javap") == 0)
756         {
757           flag_javap_compatible++;
758           flag_print_constant_pool = 0;
759         }
760       else
761         {
762           fprintf (stderr, "%s: illegal argument\n", argv[argi]);
763           exit (FATAL_EXIT_CODE);
764         }
765     }
766
767   if (argi == argc)
768     usage ();
769
770   jcf_path_seal ();
771
772   if (flag_print_main)
773     {
774       flag_print_fields = 0;
775       flag_print_methods = 0;
776       flag_print_constant_pool = 0;
777       flag_print_attributes = 0;
778       flag_print_class_info = 0;
779     }
780
781   if (output_file)
782     {
783       out = fopen (output_file, "w");
784       if (out)
785         {
786           fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
787           exit (FATAL_EXIT_CODE);
788         }
789     }
790   else
791     out = stdout;
792
793   if (argi >= argc)
794     {
795       fprintf (out, "Reading .class from <standard input>.\n");
796 #if JCF_USE_STDIO
797       open_class ("<stdio>", jcf, stdin, NULL);
798 #else
799       open_class ("<stdio>", jcf, 0, NULL);
800 #endif
801       process_class (jcf);
802     }
803   else
804     {
805       for (; argi < argc; argi++)
806         {
807           char *arg = argv[argi];
808           const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
809           if (class_filename == NULL)
810             class_filename = find_classfile (arg, jcf, NULL);
811           if (class_filename == NULL)
812             {
813               perror ("Could not find class");
814               exit (FATAL_EXIT_CODE);
815             }
816           JCF_FILL (jcf, 4);
817           if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
818             {
819               long compressed_size, member_size;
820               int compression_method, filename_length, extra_length;
821               int general_purpose_bits;
822               const char *filename;
823               int total_length;
824               if (flag_print_class_info)
825                 fprintf (out, "Reading classes from archive %s.\n",
826                          class_filename);
827               for (;;)
828                 {
829                   int skip = 0;
830                   jcf_filbuf_t save_filbuf = jcf->filbuf;
831                   long magic = JCF_readu4_le (jcf);
832                   if (magic == 0x02014b50 || magic == 0x06054b50)
833                     break;  /* got to central directory */
834                   if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
835                     {
836                       fprintf (stderr, "bad format of .zip/.jar archive\n");
837                       exit (FATAL_EXIT_CODE);
838                     }
839                   JCF_FILL (jcf, 26);
840                   JCF_SKIP (jcf, 2);
841                   general_purpose_bits = JCF_readu2_le (jcf);
842                   compression_method = JCF_readu2_le (jcf);
843                   JCF_SKIP (jcf, 8);
844                   compressed_size = JCF_readu4_le (jcf);
845                   member_size = JCF_readu4_le (jcf);
846                   filename_length = JCF_readu2_le (jcf);
847                   extra_length = JCF_readu2_le (jcf);
848                   total_length = filename_length + extra_length
849                     + compressed_size;
850                   if (jcf->read_end - jcf->read_ptr < total_length)
851                     jcf_trim_old_input (jcf);
852                   JCF_FILL (jcf, total_length);
853                   filename = jcf->read_ptr;
854                   JCF_SKIP (jcf, filename_length);
855                   JCF_SKIP (jcf, extra_length);
856                   if (filename_length > 0
857                       && filename[filename_length-1] == '/')
858                     {
859                       if (flag_print_class_info)
860                         fprintf (out, "[Skipping directory %.*s]\n",
861                                  filename_length, filename);
862                       skip = 1;
863                     }
864                   else if (compression_method != 0)
865                     {
866                       if (flag_print_class_info)
867                         fprintf (out, "[Skipping compressed file %.*s]\n",
868                                  filename_length, filename);
869                       skip = 1;
870                     }
871                   else if (member_size < 4
872                            || GET_u4 (jcf->read_ptr) != 0xcafebabe)
873                     {
874                       if (flag_print_class_info)
875                         fprintf (out, "[Skipping non-.class member %.*s]\n",
876                                  filename_length, filename);
877                       skip = 1;
878                     }
879                   else
880                     {
881                       if (flag_print_class_info)
882                         fprintf (out, "Reading class member: %.*s.\n",
883                                  filename_length, filename);
884                     }
885                   if (skip)
886                     {
887                       JCF_SKIP (jcf, compressed_size);
888                     }
889                   else
890                     {
891                       unsigned char *save_end;
892                       jcf->filbuf = jcf_unexpected_eof;
893                       save_end = jcf->read_end;
894                       jcf->read_end = jcf->read_ptr + compressed_size;
895                       process_class (jcf);
896                       jcf->filbuf = save_filbuf;
897                       jcf->read_end = save_end;
898                     }
899                 }
900             }
901           else
902             {
903               if (flag_print_class_info)
904                 fprintf (out, "Reading .class from %s.\n", class_filename);
905               process_class (jcf);
906             }
907           JCF_FINISH(jcf);
908         }
909     }
910
911   exit (SUCCESS_EXIT_CODE);
912 }
913
914 static void
915 DEFUN(disassemble_method, (jcf, byte_ops, len),
916       JCF* jcf AND const unsigned char *byte_ops AND int len)
917 {
918 #undef AND /* Causes problems with opcodes for iand and land. */
919 #undef PTR
920   int PC;
921   int i;
922   int saw_wide = 0;
923   if (flag_disassemble_methods == 0)
924     return;
925 #define BCODE byte_ops
926   for (PC = 0; PC < len;)
927     {
928       int oldpc = PC;
929       int saw_index;
930       jint INT_temp;
931       switch (byte_ops[PC++])
932         {
933
934 /* This is the actual code emitted for each of opcodes in javaops.def.
935    The actual opcode-specific stuff is handled by the OPKIND macro.
936    I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
937    Those macros are defiend below.  The OPKINDs that do not have any
938    inline parameters (such as BINOP) and therefore do mot need anything
939    else to me printed out just use an empty body. */
940
941 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
942         case OPCODE: \
943           fprintf (out, "%3d: %s", oldpc, #OPNAME); \
944           OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
945           fputc ('\n', out); \
946           break;
947
948 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
949 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
950 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
951 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
952
953 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
954   (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
955
956 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
957    These all push a constant onto the opcode stack. */
958 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
959   saw_index = 0, i = (OPERAND_VALUE); \
960   if (oldpc+1 == PC) /* nothing */; \
961   else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
962   else fprintf (out, " %d", i);
963
964 /* Print out operand (a local variable index) for LOAD opcodes.
965    These all push local variable onto the opcode stack. */
966 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
967   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
968
969 /* Handle STORE opcodes same as LOAD opcodes.
970    These all store a value from the opcode stack in a local variable. */
971 #define STORE LOAD
972
973 /* Handle more kind of opcodes. */
974 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
975 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
976 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
977 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
978 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
979 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
980 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
981
982 /* Handle putfield and getfield opcodes, with static versions. */
983 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
984   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
985
986 /* Print operand for invoke opcodes. */
987 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
988   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
989   if (OPERAND_VALUE) /* for invokeinterface */ \
990   { int nargs = IMMEDIATE_u1;  PC++; \
991     fprintf (out, " nargs:%d", nargs); }
992
993 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
994   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
995
996 #define ARRAY(OPERAND_TYPE, SUBOP) \
997   ARRAY_##SUBOP(OPERAND_TYPE)
998 /* Handle sub-categories of ARRAY opcodes. */
999 #define ARRAY_LOAD(TYPE) /* nothing */
1000 #define ARRAY_STORE(TYPE) /* nothing */
1001 #define ARRAY_LENGTH(TYPE) /* nothing */
1002 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1003 #define ARRAY_NEW_NUM \
1004  INT_temp = IMMEDIATE_u1; \
1005  { const char *str; \
1006   switch (INT_temp) {  \
1007     case  4: str = "boolean"; break; \
1008     case  5: str = "char"; break; \
1009     case  6: str = "float"; break; \
1010     case  7: str = "double"; break; \
1011     case  8: str = "byte"; break; \
1012     case  9: str = "short"; break; \
1013     case 10: str = "int"; break; \
1014     case 11: str = "long"; break; \
1015     default: str = "<unknown type code %d>"; break; \
1016   } \
1017   fputc (' ', out); fprintf (out, str, INT_temp); }
1018
1019 #define ARRAY_NEW_PTR  \
1020   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1021
1022 #define ARRAY_NEW_MULTI \
1023   fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1024   fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1025
1026 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1027   fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1028
1029 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1030   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1031   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1032
1033 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1034   saw_index = 0, INT_temp = (OPERAND_VALUE); \
1035   fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1036
1037 #undef RET /* Defined by config/i386/i386.h */
1038 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1039   INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1040   saw_wide = 0; \
1041   fprintf (out, " %ld", (long) INT_temp);
1042
1043 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1044   PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1045
1046 #define LOOKUP_SWITCH \
1047   { jint default_offset = IMMEDIATE_s4;  jint npairs = IMMEDIATE_s4; \
1048     fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1049     while (--npairs >= 0) { \
1050      jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1051      fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1052   }
1053
1054 #define TABLE_SWITCH \
1055   { jint default_offset = IMMEDIATE_s4; \
1056     jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1057     fprintf (out, " low=%ld, high=%ld, default=%ld", \
1058       (long) low, (long) high, (long) default_offset+oldpc); \
1059     for (; low <= high; low++) { \
1060      jint offset = IMMEDIATE_s4; \
1061      fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1062   }
1063
1064 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1065   SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1066
1067 #define SPECIAL_IINC(OPERAND_TYPE) \
1068   i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1069   fprintf (out, " %d", i); \
1070   INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1071   saw_wide = 0; \
1072   fprintf (out, " %d", i)
1073
1074 #define SPECIAL_WIDE(OPERAND_TYPE) \
1075   saw_wide = 1;
1076
1077 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1078 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1079 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1080 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1081
1082 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1083   fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1084
1085 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1086    TEST(OPERAND_TYPE, OPERAND_VALUE)
1087
1088 #include "javaop.def"
1089
1090         load_store:
1091           if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1092           else
1093             {
1094               saw_wide = 0;
1095               fprintf (out, " %ld", (long) INT_temp);
1096             }
1097           fputc ('\n', out);
1098           break;
1099
1100         default:
1101           fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1102         }
1103     }
1104 }