OSDN Git Service

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