* tree.c (make_node): Set TREE_SIDE_EFFECTS for expressions that
[official-gcc.git] / gcc / java / jcf-dump.c
blob2f20e30025d3212dee97db3932306af8a901888a
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
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.
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.
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.
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. */
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
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).
36 OPTIONS:
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.
49 #include "config.h"
50 #include "system.h"
52 #include "jcf.h"
53 #include "tree.h"
54 #include "java-tree.h"
56 /* Outout file. */
57 FILE *out;
58 /* Name of output file, if NULL if stdout. */
59 char *output_file = NULL;
61 int verbose = 0;
63 int flag_disassemble_methods = 0;
64 int flag_print_class_info = 1;
65 int flag_print_constant_pool = 1;
66 int flag_print_fields = 1;
67 int flag_print_methods = 1;
68 int flag_print_attributes = 1;
70 /* Print names of classes that have a "main" method. */
71 int flag_print_main = 0;
73 /* Index in constant pool of this class. */
74 int this_class_index = 0;
76 int class_access_flags = 0;
78 /* Print in format similar to javap. VERY IMCOMPLETE. */
79 int flag_javap_compatible = 0;
81 static void print_access_flags PROTO ((FILE *, uint16, char));
82 static void print_constant_terse PROTO ((FILE*, JCF*, int, int));
83 static void print_constant PROTO ((FILE *, JCF *, int, int));
84 static void print_constant_ref PROTO ((FILE *, JCF *, int));
85 static void disassemble_method PROTO ((JCF*, const unsigned char *, int));
86 static void print_name PROTO ((FILE*, JCF*, int));
87 static void print_signature PROTO ((FILE*, JCF*, int, int));
88 static int utf8_equal_string PROTO ((struct JCF*, int, const char *));
89 static int usage PROTO ((void)) ATTRIBUTE_NORETURN;
90 static void process_class PROTO ((struct JCF *));
91 static void print_constant_pool PROTO ((struct JCF *));
92 static void print_exception_table PROTO ((struct JCF *,
93 const unsigned char *entries, int));
95 #define PRINT_SIGNATURE_RESULT_ONLY 1
96 #define PRINT_SIGNATURE_ARGS_ONLY 2
98 static int
99 DEFUN(utf8_equal_string, (jcf, index, value),
100 JCF *jcf AND int index AND const char * value)
102 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
103 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
105 int len = strlen (value);
106 if (JPOOL_UTF_LENGTH (jcf, index) == len
107 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
108 return 1;
110 return 0;
113 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
114 this_class_index = 0; \
115 if (flag_print_class_info) \
116 fprintf (out, \
117 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
118 (long) MAGIC, (long) MINOR, (long) MAJOR)
120 #define HANDLE_START_CONSTANT_POOL(COUNT) \
121 if (flag_print_constant_pool) \
122 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
124 #define HANDLE_SOURCEFILE(INDEX) \
125 { fprintf (out, "Attribute "); \
126 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
127 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
128 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
130 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
131 this_class_index = THIS; \
132 class_access_flags = ACCESS_FLAGS; \
133 if (flag_print_class_info) \
134 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
135 print_access_flags (out, ACCESS_FLAGS, 'c'); \
136 fputc ('\n', out); \
137 fprintf (out, "This class: "); \
138 if (flag_print_constant_pool) \
139 fprintf (out, "%d=", THIS); \
140 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
141 if (flag_print_constant_pool || SUPER != 0) \
142 fprintf (out, ", super: "); \
143 if (flag_print_constant_pool) \
145 fprintf (out, "%d", SUPER); \
146 if (SUPER != 0) \
147 fputc ('=', out); \
149 if (SUPER != 0) \
150 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
151 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
154 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
155 (flag_print_attributes <= 0)
157 #define HANDLE_CLASS_INTERFACE(INDEX) \
158 if (flag_print_class_info) \
159 { fprintf (out, "- Implements: %d=", INDEX); \
160 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
161 fputc ('\n', out); }
163 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
164 if (flag_print_fields) \
165 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
167 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
168 if (flag_print_fields) \
169 { fprintf (out, "Field name:"); \
170 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
171 print_access_flags (out, ACCESS_FLAGS, 'f'); \
172 fprintf (out, " Signature: "); \
173 if (flag_print_constant_pool) \
174 fprintf (out, "%d=", SIGNATURE); \
175 print_signature (out, jcf, SIGNATURE, 0); \
176 fputc ('\n', out); } \
177 else \
178 flag_print_attributes--;
180 #define HANDLE_END_FIELD() \
181 if (! flag_print_fields) \
182 flag_print_attributes++;
184 #define HANDLE_START_METHODS(METHODS_COUNT) \
185 if (flag_print_methods) \
186 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
187 else \
188 flag_print_attributes--;
191 #define HANDLE_END_METHODS() \
192 if (! flag_print_methods) \
193 flag_print_attributes++;
195 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
197 if (flag_print_methods) \
199 if (flag_javap_compatible) \
201 fprintf (out, " "); \
202 print_access_flags (out, ACCESS_FLAGS, 'm'); \
203 fputc (' ', out); \
204 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
205 fputc (' ', out); \
206 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
207 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
208 fputc ('\n', out); \
210 else \
212 fprintf (out, "\nMethod name:"); \
213 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
214 print_access_flags (out, ACCESS_FLAGS, 'm'); \
215 fprintf (out, " Signature: "); \
216 if (flag_print_constant_pool) \
217 fprintf (out, "%d=", SIGNATURE); \
218 print_signature (out, jcf, SIGNATURE, 0); \
219 fputc ('\n', out); \
222 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
223 && utf8_equal_string (jcf, NAME, "main") \
224 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
225 && this_class_index > 0 \
226 && (class_access_flags & ACC_PUBLIC)) \
228 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
229 fputc ('\n', out); \
233 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
234 ( fprintf (out, "Attribute "), \
235 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
236 fprintf (out, ", length:%ld", (long) LENGTH) )
238 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
239 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
240 fprintf (out, ", value: "), \
241 print_constant_ref (out, jcf, VALUE_INDEX), \
242 fprintf (out, "\n") )
244 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
245 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
246 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
247 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
248 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
250 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
251 print_exception_table (jcf, ENTRIES, COUNT)
253 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
254 { int n = (COUNT); int i; \
255 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
256 fprintf (out, ", count: %d\n", n); \
257 for (i = 0; i < n; i++) {\
258 int ex_index = JCF_readu2 (jcf); \
259 fprintf (out, "%3d: ", i); \
260 print_constant_ref (out, jcf, ex_index); \
261 fputc ('\n', out); } }
263 #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \
264 { int n = (COUNT); int i; \
265 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
266 fprintf (out, ", count: %d\n", n); \
267 for (i = 0; i < n; i++) {\
268 int start_pc = JCF_readu2 (jcf); \
269 int length = JCF_readu2 (jcf); \
270 int name_index = JCF_readu2 (jcf); \
271 int signature_index = JCF_readu2 (jcf); \
272 int slot = JCF_readu2 (jcf); \
273 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
274 print_name (out, jcf, name_index); \
275 fprintf (out, ", type: %d=", signature_index); \
276 print_signature (out, jcf, signature_index, 0); \
277 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
279 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
280 { int n = (COUNT); int i; \
281 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
282 fprintf (out, ", count: %d\n", n); \
283 if (flag_disassemble_methods) \
284 for (i = 0; i < n; i++) {\
285 int start_pc = JCF_readu2 (jcf); \
286 int line_number = JCF_readu2 (jcf); \
287 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
288 else \
289 JCF_SKIP (jcf, 4 * n); }
291 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
292 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
293 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
295 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
296 if (flag_print_attributes > 0) \
297 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
299 #include "javaop.h"
301 static void
302 DEFUN(print_constant_ref, (stream, jcf, index),
303 FILE *stream AND JCF *jcf AND int index)
305 fprintf (stream, "#%d=<", index);
306 if (index <= 0 || index >= JPOOL_SIZE(jcf))
307 fprintf (stream, "out of range");
308 else
309 print_constant (stream, jcf, index, 1);
310 fprintf (stream, ">");
313 /* Print the access flags given by FLAGS.
314 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
315 or 'm' (method flags). */
317 static void
318 DEFUN (print_access_flags, (stream, flags, context),
319 FILE *stream AND uint16 flags AND char context)
321 if (flags & ACC_PUBLIC) fprintf (stream, " public");
322 if (flags & ACC_PRIVATE) fprintf (stream, " private");
323 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
324 if (flags & ACC_STATIC) fprintf (stream, " static");
325 if (flags & ACC_FINAL) fprintf (stream, " final");
326 if (flags & ACC_SYNCHRONIZED)
328 if (context == 'c')
329 fprintf (stream, " super");
330 else
331 fprintf (stream, " synchronized");
333 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
334 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
335 if (flags & ACC_NATIVE) fprintf (stream, " native");
336 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
337 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
341 static void
342 DEFUN(print_name, (stream, jcf, name_index),
343 FILE* stream AND JCF* jcf AND int name_index)
345 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
346 fprintf (stream, "<not a UTF8 constant>");
347 else
348 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
349 JPOOL_UTF_LENGTH (jcf, name_index));
352 /* If the type of the constant at INDEX matches EXPECTED,
353 print it tersely, otherwise more verbosely. */
355 static void
356 DEFUN(print_constant_terse, (out, jcf, index, expected),
357 FILE *out AND JCF *jcf AND int index AND int expected)
359 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
360 fprintf (out, "<constant pool index %d not in range>", index);
361 else if (JPOOL_TAG (jcf, index) != expected)
363 fprintf (out, "<Unexpected constant type ");
364 print_constant (out, jcf, index, 1);
365 fprintf (out, ">");
367 else
368 print_constant (out, jcf, index, 0);
371 /* Print the constant at INDEX in JCF's constant pool.
372 If verbosity==0, print very tersely (no extraneous text).
373 If verbosity==1, prefix the type of the constant.
374 If verbosity==2, add more descriptive text. */
376 static void
377 DEFUN(print_constant, (out, jcf, index, verbosity),
378 FILE *out AND JCF *jcf AND int index AND int verbosity)
380 int j, n;
381 jlong num;
382 const char *str;
383 int kind = JPOOL_TAG (jcf, index);
384 switch (kind)
386 case CONSTANT_Class:
387 n = JPOOL_USHORT1 (jcf, index);
388 if (verbosity > 0)
389 fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n);
390 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
391 fprintf (out, "<out of range>");
392 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
394 int len = JPOOL_UTF_LENGTH (jcf, n);
395 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
397 else
398 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
399 break;
400 case CONSTANT_Fieldref:
401 str = "Field"; goto field_or_method;
402 case CONSTANT_Methodref:
403 str = "Method"; goto field_or_method;
404 case CONSTANT_InterfaceMethodref:
405 str = "InterfaceMethod"; goto field_or_method;
406 field_or_method:
408 uint16 tclass = JPOOL_USHORT1 (jcf, index);
409 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
410 if (verbosity == 2)
411 fprintf (out, "%sref class: %d=", str, tclass);
412 else if (verbosity > 0)
413 fprintf (out, "%s ", str);
414 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
415 fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<",
416 name_and_type);
417 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
418 if (verbosity == 2)
419 fputc ('>', out);
421 break;
422 case CONSTANT_String:
423 j = JPOOL_USHORT1 (jcf, index);
424 if (verbosity > 0)
425 fprintf (out, verbosity > 1 ? "String %d=" : "String ", j);
426 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
427 break;
428 case CONSTANT_Integer:
429 if (verbosity > 0)
430 fprintf (out, "Integer ");
431 num = JPOOL_INT (jcf, index);
432 goto integer;
433 case CONSTANT_Long:
434 if (verbosity > 0)
435 fprintf (out, "Long ");
436 num = JPOOL_LONG (jcf, index);
437 goto integer;
438 integer:
440 char buffer[25];
441 format_int (buffer, num, 10);
442 fprintf (out, "%s", buffer);
443 if (verbosity > 1)
445 format_uint (buffer, (uint64)num, 16);
446 fprintf (out, "=0x%s", buffer);
449 break;
450 case CONSTANT_Float:
452 jfloat fnum = JPOOL_FLOAT (jcf, index);
453 fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum);
454 if (verbosity > 1)
455 fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum));
456 break;
458 case CONSTANT_Double:
460 jdouble dnum = JPOOL_DOUBLE (jcf, index);
461 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
462 if (verbosity > 1)
464 int32 hi, lo;
465 hi = JPOOL_UINT (jcf, index);
466 lo = JPOOL_UINT (jcf, index + 1);
467 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
469 break;
471 case CONSTANT_NameAndType:
473 uint16 name = JPOOL_USHORT1 (jcf, index);
474 uint16 sig = JPOOL_USHORT2 (jcf, index);
475 if (verbosity > 0)
476 fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ",
477 "NameAndType", name);
478 print_name (out, jcf, name);
479 if (verbosity <= 1)
480 fputc (' ', out);
481 else
482 fprintf (out, ", signature: %d=", sig);
483 print_signature (out, jcf, sig, 0);
485 break;
486 case CONSTANT_Utf8:
488 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
489 int length = JPOOL_UTF_LENGTH (jcf, index);
490 if (verbosity > 0)
491 { /* Print as 8-bit bytes. */
492 fputs ("Utf8: \"", out);
493 while (--length >= 0)
494 jcf_print_char (out, *str++);
496 else
497 { /* Print as Unicode. */
498 fputc ('\"', out);
499 jcf_print_utf8 (out, str, length);
501 fputc ('\"', out);
503 break;
504 default:
505 fprintf (out, "(Unknown constant type %d)", kind);
509 static void
510 DEFUN(print_constant_pool, (jcf),
511 JCF *jcf)
513 int i;
514 for (i = 1; i < JPOOL_SIZE(jcf); i++)
516 int kind = JPOOL_TAG (jcf, i);
517 fprintf (out, "#%d: ", i);
518 print_constant (out, jcf, i, 2);
519 fprintf (out, "\n");
520 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
521 i++; /* These take up two slots in the constant table */
525 static void
526 DEFUN(print_signature_type, (stream, ptr, limit),
527 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
529 int array_size;
530 if ((*ptr) >= limit)
531 return;
532 switch (*(*ptr))
534 case '[':
535 array_size = -1;
536 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
538 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
540 print_signature_type (stream, ptr, limit);
541 if (array_size == -1)
542 fprintf (stream, "[]");
543 else
544 fprintf (stream, "[%d]", array_size);
545 break;
546 case '(':
548 int nargs = 0;
549 fputc (*(*ptr)++, stream);
550 for (; **ptr != ')' && *ptr < limit; nargs++)
552 if (nargs > 0)
553 fputc (',', stream);
554 print_signature_type (stream, ptr, limit);
556 if (*ptr < limit)
558 fputc (*(*ptr)++, stream);
559 print_signature_type (stream, ptr, limit);
561 else
562 fprintf (stream, "???");
564 break;
566 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
567 case 'C': fprintf (stream, "char"); (*ptr)++; break;
568 case 'D': fprintf (stream, "double"); (*ptr)++; break;
569 case 'F': fprintf (stream, "float"); (*ptr)++; break;
570 case 'S': fprintf (stream, "short"); (*ptr)++; break;
571 case 'I': fprintf (stream, "int"); (*ptr)++; break;
572 case 'J': fprintf (stream, "long"); (*ptr)++; break;
573 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
574 case 'V': fprintf (stream, "void"); (*ptr)++; break;
576 case 'L':
577 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
578 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
579 if (*(*ptr) == ';')
580 (*ptr)++;
581 break;
582 default:
583 jcf_print_char (stream, *(*ptr)++);
587 static void
588 DEFUN(print_signature, (stream, jcf, signature_index, int options),
589 FILE* stream AND JCF *jcf AND int signature_index AND int options)
591 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
592 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
593 else
595 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
596 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
597 const unsigned char *limit;
598 limit = str + length;
599 if (str >= limit)
600 fprintf (stream, "<empty signature string>");
601 else
603 if (options & PRINT_SIGNATURE_RESULT_ONLY)
605 while (str < limit && *str++ != ')') ;
607 if (options & PRINT_SIGNATURE_ARGS_ONLY)
609 str++;
610 fputc ('(', stream);
611 while (str < limit && *str != ')')
613 print_signature_type (stream, &str, limit);
614 if (*str != ')')
615 fputs (", ", stream);
617 fputc (')', stream);
619 else
621 print_signature_type (stream, &str, limit);
622 if (str < limit)
624 fprintf (stream, "<junk:");
625 jcf_print_utf8 (stream, str, limit - str);
626 fputc ('>', stream);
634 static void
635 DEFUN(print_exception_table, (jcf, entries, count),
636 JCF *jcf AND const unsigned char *entries AND int count)
638 /* Print exception table. */
639 int i = count;
640 if (i > 0)
642 const unsigned char *ptr = entries;
643 fprintf (out, "Exceptions (count: %d):\n", i);
644 for (; --i >= 0; ptr+= 8)
646 int start_pc = GET_u2 (ptr);
647 int end_pc = GET_u2 (ptr+2);
648 int handler_pc = GET_u2 (ptr+4);
649 int catch_type = GET_u2 (ptr+6);
650 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
651 start_pc, end_pc, handler_pc, catch_type);
652 if (catch_type == 0)
653 fputs (" /* finally */", out);
654 else
656 fputc('=', out);
657 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
659 fputc ('\n', out);
664 #include "jcf-reader.c"
666 static int
667 DEFUN (usage, (), )
669 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
670 exit(1);
673 static void
674 DEFUN(process_class, (jcf),
675 JCF *jcf)
677 int code;
678 if (jcf_parse_preamble (jcf) != 0)
679 fprintf (stderr, "Not a valid Java .class file.\n");
681 /* Parse and possibly print constant pool */
682 code = jcf_parse_constant_pool (jcf);
683 if (code != 0)
685 fprintf (stderr, "error while parsing constant pool\n");
686 exit (FATAL_EXIT_CODE);
688 code = verify_constant_pool (jcf);
689 if (code > 0)
691 fprintf (stderr, "error in constant pool entry #%d\n", code);
692 exit (FATAL_EXIT_CODE);
694 if (flag_print_constant_pool)
695 print_constant_pool (jcf);
697 jcf_parse_class (jcf);
698 code = jcf_parse_fields (jcf);
699 if (code != 0)
701 fprintf (stderr, "error while parsing fields\n");
702 exit (FATAL_EXIT_CODE);
704 code = jcf_parse_methods (jcf);
705 if (code != 0)
707 fprintf (stderr, "error while parsing methods\n");
708 exit (FATAL_EXIT_CODE);
710 code = jcf_parse_final_attributes (jcf);
711 if (code != 0)
713 fprintf (stderr, "error while parsing final attributes\n");
714 exit (FATAL_EXIT_CODE);
716 jcf->filename = NULL;
720 DEFUN(main, (argc, argv),
721 int argc AND char** argv)
723 JCF jcf[1];
724 int argi;
725 if (argc <= 1)
726 usage ();
728 jcf_path_init ();
730 for (argi = 1; argi < argc; argi++)
732 const char *arg = argv[argi];
734 if (arg[0] != '-' || ! strcmp (arg, "--"))
735 break;
737 /* Just let all arguments be given in either "-" or "--" form. */
738 if (arg[1] == '-')
739 ++arg;
741 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
742 output_file = argv[++argi];
743 else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc)
744 jcf_path_classpath_arg (argv[++argi]);
745 else if (strcmp (arg, "-CLASSPATH") == 0 && argi + 1 < argc)
746 jcf_path_CLASSPATH_arg (argv[++argi]);
747 else if (strncmp (arg, "-I", 2) == 0)
748 jcf_path_include_arg (arg + 2);
749 else if (strcmp (arg, "-verbose") == 0)
750 verbose++;
751 else if (strcmp (arg, "-print-main") == 0)
752 flag_print_main++;
753 else if (strcmp (arg, "-c") == 0)
754 flag_disassemble_methods++;
755 else if (strcmp (arg, "-javap") == 0)
757 flag_javap_compatible++;
758 flag_print_constant_pool = 0;
760 else
762 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
763 return FATAL_EXIT_CODE;
767 if (argi == argc)
768 usage ();
770 jcf_path_seal ();
772 if (flag_print_main)
774 flag_print_fields = 0;
775 flag_print_methods = 0;
776 flag_print_constant_pool = 0;
777 flag_print_attributes = 0;
778 flag_print_class_info = 0;
781 if (output_file)
783 out = fopen (output_file, "w");
784 if (out)
786 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
787 return FATAL_EXIT_CODE;
790 else
791 out = stdout;
793 if (argi >= argc)
795 fprintf (out, "Reading .class from <standard input>.\n");
796 #if JCF_USE_STDIO
797 open_class ("<stdio>", jcf, stdin, NULL);
798 #else
799 open_class ("<stdio>", jcf, 0, NULL);
800 #endif
801 process_class (jcf);
803 else
805 for (; argi < argc; argi++)
807 char *arg = argv[argi];
808 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
809 if (class_filename == NULL)
810 class_filename = find_classfile (arg, jcf, NULL);
811 if (class_filename == NULL)
813 perror ("Could not find class");
814 return FATAL_EXIT_CODE;
816 JCF_FILL (jcf, 4);
817 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
819 long compressed_size, member_size;
820 int compression_method, filename_length, extra_length;
821 int general_purpose_bits;
822 const char *filename;
823 int total_length;
824 if (flag_print_class_info)
825 fprintf (out, "Reading classes from archive %s.\n",
826 class_filename);
827 for (;;)
829 int skip = 0;
830 jcf_filbuf_t save_filbuf = jcf->filbuf;
831 long magic = JCF_readu4_le (jcf);
832 if (magic == 0x02014b50 || magic == 0x06054b50)
833 break; /* got to central directory */
834 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
836 fprintf (stderr, "bad format of .zip/.jar archive\n");
837 return FATAL_EXIT_CODE;
839 JCF_FILL (jcf, 26);
840 JCF_SKIP (jcf, 2);
841 general_purpose_bits = JCF_readu2_le (jcf);
842 compression_method = JCF_readu2_le (jcf);
843 JCF_SKIP (jcf, 8);
844 compressed_size = JCF_readu4_le (jcf);
845 member_size = JCF_readu4_le (jcf);
846 filename_length = JCF_readu2_le (jcf);
847 extra_length = JCF_readu2_le (jcf);
848 total_length = filename_length + extra_length
849 + compressed_size;
850 if (jcf->read_end - jcf->read_ptr < total_length)
851 jcf_trim_old_input (jcf);
852 JCF_FILL (jcf, total_length);
853 filename = jcf->read_ptr;
854 JCF_SKIP (jcf, filename_length);
855 JCF_SKIP (jcf, extra_length);
856 if (filename_length > 0
857 && filename[filename_length-1] == '/')
859 if (flag_print_class_info)
860 fprintf (out, "[Skipping directory %.*s]\n",
861 filename_length, filename);
862 skip = 1;
864 else if (compression_method != 0)
866 if (flag_print_class_info)
867 fprintf (out, "[Skipping compressed file %.*s]\n",
868 filename_length, filename);
869 skip = 1;
871 else if (member_size < 4
872 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
874 if (flag_print_class_info)
875 fprintf (out, "[Skipping non-.class member %.*s]\n",
876 filename_length, filename);
877 skip = 1;
879 else
881 if (flag_print_class_info)
882 fprintf (out, "Reading class member: %.*s.\n",
883 filename_length, filename);
885 if (skip)
887 JCF_SKIP (jcf, compressed_size);
889 else
891 unsigned char *save_end;
892 jcf->filbuf = jcf_unexpected_eof;
893 save_end = jcf->read_end;
894 jcf->read_end = jcf->read_ptr + compressed_size;
895 process_class (jcf);
896 jcf->filbuf = save_filbuf;
897 jcf->read_end = save_end;
901 else
903 if (flag_print_class_info)
904 fprintf (out, "Reading .class from %s.\n", class_filename);
905 process_class (jcf);
907 JCF_FINISH(jcf);
911 return SUCCESS_EXIT_CODE;
914 static void
915 DEFUN(disassemble_method, (jcf, byte_ops, len),
916 JCF* jcf AND const unsigned char *byte_ops AND int len)
918 #undef AND /* Causes problems with opcodes for iand and land. */
919 #undef PTR
920 int PC;
921 int i;
922 int saw_wide = 0;
923 if (flag_disassemble_methods == 0)
924 return;
925 #define BCODE byte_ops
926 for (PC = 0; PC < len;)
928 int oldpc = PC;
929 int saw_index;
930 jint INT_temp;
931 switch (byte_ops[PC++])
934 /* This is the actual code emitted for each of opcodes in javaops.def.
935 The actual opcode-specific stuff is handled by the OPKIND macro.
936 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
937 Those macros are defiend below. The OPKINDs that do not have any
938 inline parameters (such as BINOP) and therefore do mot need anything
939 else to me printed out just use an empty body. */
941 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
942 case OPCODE: \
943 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
944 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
945 fputc ('\n', out); \
946 break;
948 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
949 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
950 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
951 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
953 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
954 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
956 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
957 These all push a constant onto the opcode stack. */
958 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
959 saw_index = 0, i = (OPERAND_VALUE); \
960 if (oldpc+1 == PC) /* nothing */; \
961 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
962 else fprintf (out, " %d", i);
964 /* Print out operand (a local variable index) for LOAD opcodes.
965 These all push local variable onto the opcode stack. */
966 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
967 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
969 /* Handle STORE opcodes same as LOAD opcodes.
970 These all store a value from the opcode stack in a local variable. */
971 #define STORE LOAD
973 /* Handle more kind of opcodes. */
974 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
975 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
976 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
977 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
978 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
979 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
980 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
982 /* Handle putfield and getfield opcodes, with static versions. */
983 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
984 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
986 /* Print operand for invoke opcodes. */
987 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
988 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
989 if (OPERAND_VALUE) /* for invokeinterface */ \
990 { int nargs = IMMEDIATE_u1; PC++; \
991 fprintf (out, " nargs:%d", nargs); }
993 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
994 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
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 { const 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; \
1017 fputc (' ', out); fprintf (out, str, INT_temp); }
1019 #define ARRAY_NEW_PTR \
1020 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1022 #define ARRAY_NEW_MULTI \
1023 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1024 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1026 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1027 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1029 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1030 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1031 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1033 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1034 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1035 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
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, " %ld", (long) INT_temp);
1043 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1044 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1046 #define LOOKUP_SWITCH \
1047 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1048 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) 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)); } \
1054 #define TABLE_SWITCH \
1055 { jint default_offset = IMMEDIATE_s4; \
1056 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1057 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1058 (long) low, (long) high, (long) default_offset+oldpc); \
1059 for (; low <= high; low++) { \
1060 jint offset = IMMEDIATE_s4; \
1061 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1064 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1065 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1067 #define SPECIAL_IINC(OPERAND_TYPE) \
1068 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1069 fprintf (out, " %d", i); \
1070 INT_temp = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1071 saw_wide = 0; \
1072 fprintf (out, " %d", i)
1074 #define SPECIAL_WIDE(OPERAND_TYPE) \
1075 saw_wide = 1;
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 */
1082 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1083 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1085 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1086 TEST(OPERAND_TYPE, OPERAND_VALUE)
1088 #include "javaop.def"
1090 load_store:
1091 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1092 else
1094 saw_wide = 0;
1095 fprintf (out, " %ld", (long) INT_temp);
1097 fputc ('\n', out);
1098 break;
1100 default:
1101 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);