OSDN Git Service

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