OSDN Git Service

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