OSDN Git Service

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