* jcf-write.c (write_classfile): Add output class file as target.
[official-gcc.git] / gcc / java / jcf-dump.c
blob25243228bffb19cd43e007991d29514c867d8bc6
1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
4 Copyright (C) 1996, 1997, 1998 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 <stdio.h>
53 #include "jcf.h"
55 /* Outout file. */
56 FILE *out;
57 /* Name of output file, if NULL if stdout. */
58 char *output_file = NULL;
60 int verbose = 0;
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;
69 /* Print names of classes that have a "main" method. */
70 int flag_print_main = 0;
72 /* Index in constant pool of this class. */
73 int this_class_index = 0;
75 int class_access_flags = 0;
77 /* Print in format similar to javap. VERY IMCOMPLETE. */
78 int flag_javap_compatible = 0;
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));
88 #define PRINT_SIGNATURE_RESULT_ONLY 1
89 #define PRINT_SIGNATURE_ARGS_ONLY 2
91 extern char* open_class();
93 int
94 DEFUN(utf8_equal_string, (jcf, index, value),
95 JCF *jcf AND int index AND char * value)
97 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
98 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
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;
105 return 0;
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)
115 #define HANDLE_START_CONSTANT_POOL(COUNT) \
116 if (flag_print_constant_pool) \
117 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
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); }
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) \
140 fprintf (out, "%d", SUPER); \
141 if (SUPER != 0) \
142 fputc ('=', out); \
144 if (SUPER != 0) \
145 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
146 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
149 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
150 (flag_print_attributes <= 0)
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); }
158 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
159 if (flag_print_fields) \
160 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
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--;
175 #define HANDLE_END_FIELD() \
176 if (! flag_print_fields) \
177 flag_print_attributes++;
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--;
186 #define HANDLE_END_METHODS() \
187 if (! flag_print_methods) \
188 flag_print_attributes++;
190 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
192 if (flag_print_methods) \
194 if (flag_javap_compatible) \
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); \
205 else \
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); \
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)) \
223 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
224 fputc ('\n', out); \
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) )
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") )
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); }
245 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
246 print_exception_table (jcf, ENTRIES, COUNT)
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); } }
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); }}
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); }
286 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
287 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
288 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
290 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
291 if (flag_print_attributes > 0) \
292 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
294 #include "javaop.h"
296 static void
297 DEFUN(print_constant_ref, (stream, jcf, index),
298 FILE *stream AND JCF *jcf AND int index)
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);
308 static int
309 DEFUN (print_access_flags, (stream, flags),
310 FILE *stream AND uint16 flags)
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");
326 static void
327 DEFUN(print_name, (stream, jcf, name_index),
328 FILE* stream AND JCF* jcf AND int name_index)
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));
337 /* If the type of the constant at INDEX matches EXPECTED,
338 print it tersely, otherwise more verbosely. */
340 void
341 DEFUN(print_constant_terse, (out, jcf, index, expected),
342 FILE *out AND JCF *jcf AND int index AND int expected)
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)
348 fprintf (out, "<Unexpected constant type ");
349 print_constant (out, jcf, index, 1);
350 fprintf (out, ">");
352 else
353 print_constant (out, jcf, index, 0);
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. */
361 static void
362 DEFUN(print_constant, (out, jcf, index, verbosity),
363 FILE *out AND JCF *jcf AND int index AND int verbosity)
365 int j, n;
366 jlong num;
367 char *str;
368 int kind = JPOOL_TAG (jcf, index);
369 switch (kind)
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)
379 int len = JPOOL_UTF_LENGTH (jcf, n);
380 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
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:
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);
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:
425 char buffer[25];
426 format_int (buffer, num, 10);
427 fprintf (out, "%s", buffer);
428 if (verbosity > 1)
430 format_uint (buffer, (uint64)num, 16);
431 fprintf (out, "=0x%s", buffer);
434 break;
435 case CONSTANT_Float:
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;
443 case CONSTANT_Double:
445 jdouble dnum = JPOOL_DOUBLE (jcf, index);
446 fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum);
447 if (verbosity > 1)
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);
454 break;
456 case CONSTANT_NameAndType:
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);
470 break;
471 case CONSTANT_Utf8:
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++);
481 else
482 { /* Print as Unicode. */
483 fputc ('\"', out);
484 jcf_print_utf8 (out, str, length);
486 fputc ('\"', out);
488 break;
489 default:
490 fprintf (out, "(Unknown constant type %d)", kind);
494 void
495 DEFUN(print_constant_pool, (jcf),
496 JCF *jcf)
498 int i;
499 for (i = 1; i < JPOOL_SIZE(jcf); i++)
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 */
510 static void
511 DEFUN(print_signature_type, (stream, ptr, limit),
512 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
514 int array_size;
515 if ((*ptr) >= limit)
516 return;
517 switch (*(*ptr))
519 case '[':
520 array_size = -1;
521 for ((*ptr)++; (*ptr) < limit && isdigit (**ptr); (*ptr)++)
523 int digit =
524 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
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 '(':
534 int nargs = 0;
535 fputc (*(*ptr)++, stream);
536 for (; **ptr != ')' && *ptr < limit; nargs++)
538 if (nargs > 0)
539 fputc (',', stream);
540 print_signature_type (stream, ptr, limit);
542 if (*ptr < limit)
544 fputc (*(*ptr)++, stream);
545 print_signature_type (stream, ptr, limit);
547 else
548 fprintf (stream, "???");
550 break;
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;
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)++);
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)
577 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
578 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
579 else
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
590 if (options & PRINT_SIGNATURE_RESULT_ONLY)
592 while (str < limit && *str++ != ')') ;
594 if (options & PRINT_SIGNATURE_ARGS_ONLY)
596 *str++;
597 fputc ('(', stream);
598 while (str < limit && *str != ')')
600 print_signature_type (stream, &str, limit);
601 if (*str != ')')
602 fputs (", ", stream);
604 fputc (')', stream);
606 else
608 print_signature_type (stream, &str, limit);
609 if (str < limit)
611 fprintf (stream, "<junk:");
612 jcf_print_utf8 (stream, str, limit - str);
613 fputc ('>', stream);
621 static void
622 DEFUN(print_exception_table, (jcf, entries, count),
623 JCF *jcf AND unsigned char *entries AND int count)
625 /* Print exception table. */
626 int i = count;
627 if (i > 0)
629 unsigned char *ptr = entries;
630 fprintf (out, "Exceptions (count: %d):\n", i);
631 for (; --i >= 0; ptr+= 8)
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
643 fputc('=', out);
644 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
646 fputc ('\n', out);
651 #include "jcf-reader.c"
654 DEFUN (usage, (), )
656 fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n");
657 exit(1);
660 void
661 DEFUN(process_class, (jcf),
662 JCF *jcf)
664 int code;
665 if (jcf_parse_preamble (jcf) != 0)
666 fprintf (stderr, "Not a valid Java .class file.\n");
668 /* Parse and possibly print constant pool */
669 code = jcf_parse_constant_pool (jcf);
670 if (code != 0)
672 fprintf (stderr, "error while parsing constant pool\n");
673 exit (FATAL_EXIT_CODE);
675 code = verify_constant_pool (jcf);
676 if (code > 0)
678 fprintf (stderr, "error in constant pool entry #%d\n", code);
679 exit (FATAL_EXIT_CODE);
681 if (flag_print_constant_pool)
682 print_constant_pool (jcf);
684 jcf_parse_class (jcf);
685 code = jcf_parse_fields (jcf);
686 if (code != 0)
688 fprintf (stderr, "error while parsing fields\n");
689 exit (FATAL_EXIT_CODE);
691 code = jcf_parse_methods (jcf);
692 if (code != 0)
694 fprintf (stderr, "error while parsing methods\n");
695 exit (FATAL_EXIT_CODE);
697 code = jcf_parse_final_attributes (jcf);
698 if (code != 0)
700 fprintf (stderr, "error while parsing final attributes\n");
701 exit (FATAL_EXIT_CODE);
703 jcf->filename = NULL;
707 DEFUN(main, (argc, argv),
708 int argc AND char** argv)
710 JCF jcf[1];
711 int argi;
712 if (argc <= 1)
713 usage ();
715 for (argi = 1; argi < argc; argi++)
717 char *arg = argv[argi];
718 if (arg[0] == '-')
720 if (strcmp (arg, "-o") == 0 && argi + 1 < argc)
721 output_file = argv[++argi];
722 else if (arg[1] == '-')
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)
733 flag_javap_compatible++;
734 flag_print_constant_pool = 0;
736 else if (arg[2] == '\0')
737 break;
738 else
740 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
741 exit (FATAL_EXIT_CODE);
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
755 fprintf (stderr, "%s: illegal argument\n", argv[argi]);
756 exit (FATAL_EXIT_CODE);
759 else
760 break;
762 if (argi == argc)
763 usage ();
764 if (flag_print_main)
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;
773 if (classpath == NULL)
775 classpath = (char *) getenv ("CLASSPATH");
776 if (classpath == NULL)
777 classpath = "";
780 if (output_file)
782 out = fopen (output_file, "w");
783 if (out)
785 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
786 exit (FATAL_EXIT_CODE);
789 else
790 out = stdout;
792 if (argi >= argc)
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);
802 else
804 for (; argi < argc; argi++)
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)
812 perror ("Could not find class");
813 exit (FATAL_EXIT_CODE);
815 JCF_FILL (jcf, 4);
816 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
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 (;;)
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) */
835 fprintf (stderr, "bad format of .zip archine\n");
836 exit (FATAL_EXIT_CODE);
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] == '/')
858 if (flag_print_class_info)
859 fprintf (out, "[Skipping directory %.*s]\n",
860 filename_length, filename);
861 skip = 1;
863 else if (compression_method != 0)
865 if (flag_print_class_info)
866 fprintf (out, "[Skipping compressed file %.*s]\n",
867 filename_length, filename);
868 skip = 1;
870 else if (member_size < 4
871 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
873 if (flag_print_class_info)
874 fprintf (out, "[Skipping non-.class member %.*s]\n",
875 filename_length, filename);
876 skip = 1;
878 else
880 if (flag_print_class_info)
881 fprintf (out, "Reading class member: %.*s.\n",
882 filename_length, filename);
884 if (skip)
886 JCF_SKIP (jcf, compressed_size);
888 else
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;
900 else
902 if (flag_print_class_info)
903 fprintf (out, "Reading .class from %s.\n", class_filename);
904 process_class (jcf);
906 JCF_FINISH(jcf);
910 exit (SUCCESS_EXIT_CODE);
913 static void
914 DEFUN(disassemble_method, (jcf, byte_ops, len),
915 JCF* jcf AND unsigned char *byte_ops AND int len)
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;)
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++])
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. */
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;
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)
955 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
956 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
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);
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;
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
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 */
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)
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 */;
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 { 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, " %d", 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, " %d", 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, " %d", 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=%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)); } \
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)); } \
1064 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1065 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
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)
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, " %d", INT_temp);
1097 fputc ('\n', out);
1098 break;
1100 default:
1101 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);