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