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