1 /* Program to dump out a Java(TM) .class file.
2 Functionally similar to Sun's javap.
3
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21 Java and all Java-based marks are trademarks or registered trademarks
22 of Sun Microsystems, Inc. in the United States and other countries.
23 The Free Software Foundation is independent of Sun Microsystems, Inc. */
24
25 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
26
27 /*
28 jcf-dump is a program to print out the contents of class files.
29 Usage: jcf-dump [FLAGS] CLASS
30 Each CLASS is either:
31 + the name of a class in the CLASSPATH (e.g "java.lang.String"), or
32 + the name of a class *file* (e.g. "/home/me/work/package/Foo.class").
33 + The name of a .zip or .jar file (which prints all the classes in the
34 archive).
35
36 OPTIONS:
37 -c
38 Dis-assemble each method.
39 -classpath PATH
40 Overrides $CLASSPATH.
41 --print-main
42 Print nothing if there is no valid "main" method;
43 otherwise, print only the class name.
44 --javap
45 Print output in the style of Sun's javap program. VERY UNFINISHED.
46 */
47
48
49 #include "config.h"
50 #include "system.h"
51
52 #include "jcf.h"
53 #include "tree.h"
54 #include "java-tree.h"
55
56 #include "version.h"
57
58 #include <getopt.h>
59 #include <math.h>
60
61 /* Outout file. */
62 FILE *out;
63 /* Name of output file, if NULL if stdout. */
64 char *output_file = NULL;
65
66 int verbose = 0;
67
68 int flag_disassemble_methods = 0;
69 int flag_print_class_info = 1;
70 int flag_print_constant_pool = 1;
71 int flag_print_fields = 1;
72 int flag_print_methods = 1;
73 int flag_print_attributes = 1;
74
75 /* When nonzero, warn when source file is newer than matching class
76 file. */
77 int flag_newer = 1;
78
79 /* Print names of classes that have a "main" method. */
80 int flag_print_main = 0;
81
82 /* Index in constant pool of this class. */
83 int this_class_index = 0;
84
85 int class_access_flags = 0;
86
87 /* Print in format similar to javap. VERY IMCOMPLETE. */
88 int flag_javap_compatible = 0;
89
90 static void print_access_flags PARAMS ((FILE *, uint16, char));
91 static void print_constant_terse PARAMS ((FILE*, JCF*, int, int));
92 static void print_constant PARAMS ((FILE *, JCF *, int, int));
93 static void print_constant_ref PARAMS ((FILE *, JCF *, int));
94 static void disassemble_method PARAMS ((JCF*, const unsigned char *, int));
95 static void print_name PARAMS ((FILE*, JCF*, int));
96 static void print_signature PARAMS ((FILE*, JCF*, int, int));
97 static int utf8_equal_string PARAMS ((struct JCF*, int, const char *));
98 static void usage PARAMS ((void)) ATTRIBUTE_NORETURN;
99 static void help PARAMS ((void)) ATTRIBUTE_NORETURN;
100 static void version PARAMS ((void)) ATTRIBUTE_NORETURN;
101 static void process_class PARAMS ((struct JCF *));
102 static void print_constant_pool PARAMS ((struct JCF *));
103 static void print_exception_table PARAMS ((struct JCF *,
104 const unsigned char *entries, int));
105
106 #define PRINT_SIGNATURE_RESULT_ONLY 1
107 #define PRINT_SIGNATURE_ARGS_ONLY 2
108
109 static int
110 DEFUN(utf8_equal_string, (jcf, index, value),
111 JCF *jcf AND int index AND const char * value)
112 {
113 if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index)
114 && JPOOL_TAG (jcf, index) == CONSTANT_Utf8)
115 {
116 int len = strlen (value);
117 if (JPOOL_UTF_LENGTH (jcf, index) == len
118 && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0)
119 return 1;
120 }
121 return 0;
122 }
123
124 #define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \
125 this_class_index = 0; \
126 if (flag_print_class_info) \
127 fprintf (out, \
128 "Magic number: 0x%0lx, minor_version: %ld, major_version: %ld.\n",\
129 (long) MAGIC, (long) MINOR, (long) MAJOR)
130
131 #define HANDLE_START_CONSTANT_POOL(COUNT) \
132 if (flag_print_constant_pool) \
133 fprintf (out, "\nConstant pool (count: %d):\n", COUNT)
134
135 #define HANDLE_SOURCEFILE(INDEX) \
136 { fprintf (out, "Attribute "); \
137 print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \
138 fprintf (out, ", length:%ld, #%d=", (long) attribute_length, INDEX); \
139 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); }
140
141 #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \
142 this_class_index = THIS; \
143 class_access_flags = ACCESS_FLAGS; \
144 if (flag_print_class_info) \
145 { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \
146 print_access_flags (out, ACCESS_FLAGS, 'c'); \
147 fputc ('\n', out); \
148 fprintf (out, "This class: "); \
149 if (flag_print_constant_pool) \
150 fprintf (out, "%d=", THIS); \
151 print_constant_terse (out, jcf, THIS, CONSTANT_Class); \
152 if (flag_print_constant_pool || SUPER != 0) \
153 fprintf (out, ", super: "); \
154 if (flag_print_constant_pool) \
155 { \
156 fprintf (out, "%d", SUPER); \
157 if (SUPER != 0) \
158 fputc ('=', out); \
159 } \
160 if (SUPER != 0) \
161 print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \
162 fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \
163 }
164
165 #define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \
166 (flag_print_attributes <= 0)
167
168 #define HANDLE_CLASS_INTERFACE(INDEX) \
169 if (flag_print_class_info) \
170 { fprintf (out, "- Implements: %d=", INDEX); \
171 print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \
172 fputc ('\n', out); }
173
174 #define HANDLE_START_FIELDS(FIELDS_COUNT) \
175 if (flag_print_fields) \
176 fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT)
177
178 #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
179 if (flag_print_fields) \
180 { fprintf (out, "Field name:"); \
181 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
182 print_access_flags (out, ACCESS_FLAGS, 'f'); \
183 fprintf (out, " Signature: "); \
184 if (flag_print_constant_pool) \
185 fprintf (out, "%d=", SIGNATURE); \
186 print_signature (out, jcf, SIGNATURE, 0); \
187 fputc ('\n', out); } \
188 else \
189 flag_print_attributes--;
190
191 #define HANDLE_END_FIELD() \
192 if (! flag_print_fields) \
193 flag_print_attributes++;
194
195 #define HANDLE_START_METHODS(METHODS_COUNT) \
196 if (flag_print_methods) \
197 fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \
198 else \
199 flag_print_attributes--;
200
201
202 #define HANDLE_END_METHODS() \
203 if (! flag_print_methods) \
204 flag_print_attributes++;
205
206 #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \
207 { \
208 if (flag_print_methods) \
209 { \
210 if (flag_javap_compatible) \
211 { \
212 fprintf (out, " "); \
213 print_access_flags (out, ACCESS_FLAGS, 'm'); \
214 fputc (' ', out); \
215 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \
216 fputc (' ', out); \
217 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
218 print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \
219 fputc ('\n', out); \
220 } \
221 else \
222 { \
223 fprintf (out, "\nMethod name:"); \
224 print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \
225 print_access_flags (out, ACCESS_FLAGS, 'm'); \
226 fprintf (out, " Signature: "); \
227 if (flag_print_constant_pool) \
228 fprintf (out, "%d=", SIGNATURE); \
229 print_signature (out, jcf, SIGNATURE, 0); \
230 fputc ('\n', out); \
231 } \
232 } \
233 if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \
234 && utf8_equal_string (jcf, NAME, "main") \
235 && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \
236 && this_class_index > 0 \
237 && (class_access_flags & ACC_PUBLIC)) \
238 { \
239 print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \
240 fputc ('\n', out); \
241 } \
242 }
243
244 #define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \
245 ( fprintf (out, "Attribute "), \
246 print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \
247 fprintf (out, ", length:%ld", (long) LENGTH) )
248
249 #define HANDLE_CONSTANTVALUE(VALUE_INDEX) \
250 ( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \
251 fprintf (out, ", value: "), \
252 print_constant_ref (out, jcf, VALUE_INDEX), \
253 fprintf (out, "\n") )
254
255 #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \
256 { COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
257 fprintf (out, ", max_stack:%ld, max_locals:%ld, code_length:%ld\n", \
258 (long) MAX_STACK, (long) MAX_LOCALS, (long) CODE_LENGTH); \
259 disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); }
260
261 #define HANDLE_EXCEPTION_TABLE(ENTRIES, COUNT) \
262 print_exception_table (jcf, ENTRIES, COUNT)
263
264 #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \
265 { int n = (COUNT); int i; \
266 COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \
267 fprintf (out, ", count: %d\n", n); \
268 for (i = 0; i < n; i++) {\
269 int ex_index = JCF_readu2 (jcf); \
270 fprintf (out, "%3d: ", i); \
271 print_constant_ref (out, jcf, ex_index); \
272 fputc ('\n', out); } }
273
274 #define HANDLE_LOCALVARIABLETABLE_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 for (i = 0; i < n; i++) {\
279 int start_pc = JCF_readu2 (jcf); \
280 int length = JCF_readu2 (jcf); \
281 int name_index = JCF_readu2 (jcf); \
282 int signature_index = JCF_readu2 (jcf); \
283 int slot = JCF_readu2 (jcf); \
284 fprintf (out, " slot#%d: name: %d=", slot, name_index); \
285 print_name (out, jcf, name_index); \
286 fprintf (out, ", type: %d=", signature_index); \
287 print_signature (out, jcf, signature_index, 0); \
288 fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }}
289
290 #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \
291 { int n = (COUNT); int i; \
292 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
293 fprintf (out, ", count: %d\n", n); \
294 if (flag_disassemble_methods) \
295 for (i = 0; i < n; i++) {\
296 int start_pc = JCF_readu2 (jcf); \
297 int line_number = JCF_readu2 (jcf); \
298 fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\
299 else \
300 JCF_SKIP (jcf, 4 * n); }
301
302 #define HANDLE_INNERCLASSES_ATTRIBUTE(COUNT) \
303 { int n = (COUNT); \
304 COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \
305 while (n--) \
306 { \
307 uint16 inner_class_info_index = JCF_readu2 (jcf); \
308 uint16 outer_class_info_index = JCF_readu2 (jcf); \
309 uint16 inner_name_index = JCF_readu2 (jcf); \
310 uint16 inner_class_access_flags = JCF_readu2 (jcf); \
311 \
312 if (flag_print_class_info) \
313 { \
314 fprintf (out, "\n class: "); \
315 if (flag_print_constant_pool) \
316 fprintf (out, "%d=", inner_class_info_index); \
317 print_constant_terse (out, jcf, \
318 inner_class_info_index, CONSTANT_Class); \
319 fprintf (out, " (%d=", inner_name_index); \
320 print_constant_terse (out, jcf, inner_name_index, CONSTANT_Utf8); \
321 fprintf (out, "), access flags: 0x%x", inner_class_access_flags); \
322 print_access_flags (out, inner_class_access_flags, 'c'); \
323 fprintf (out, ", outer class: "); \
324 if (flag_print_constant_pool) \
325 fprintf (out, "%d=", outer_class_info_index); \
326 print_constant_terse (out, jcf, \
327 outer_class_info_index, CONSTANT_Class); \
328 } \
329 } \
330 if (flag_print_class_info) \
331 fputc ('\n', out); \
332 }
333
334 #define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \
335 { COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \
336 fputc ('\n', out); JCF_SKIP (JCF, LENGTH); }
337
338 #define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \
339 if (flag_print_attributes > 0) \
340 fprintf (out, "\nAttributes (count: %d):\n", attributes_count);
341
342 #include "javaop.h"
343
344 static void
345 DEFUN(print_constant_ref, (stream, jcf, index),
346 FILE *stream AND JCF *jcf AND int index)
347 {
348 fprintf (stream, "#%d=<", index);
349 if (index <= 0 || index >= JPOOL_SIZE(jcf))
350 fprintf (stream, "out of range");
351 else
352 print_constant (stream, jcf, index, 1);
353 fprintf (stream, ">");
354 }
355
356 /* Print the access flags given by FLAGS.
357 The CONTEXT is one of 'c' (class flags), 'f' (field flags),
358 or 'm' (method flags). */
359
360 static void
361 DEFUN (print_access_flags, (stream, flags, context),
362 FILE *stream AND uint16 flags AND char context)
363 {
364 if (flags & ACC_PUBLIC) fprintf (stream, " public");
365 if (flags & ACC_PRIVATE) fprintf (stream, " private");
366 if (flags & ACC_PROTECTED) fprintf (stream, " protected");
367 if (flags & ACC_ABSTRACT) fprintf (stream, " abstract");
368 if (flags & ACC_STATIC) fprintf (stream, " static");
369 if (flags & ACC_FINAL) fprintf (stream, " final");
370 if (flags & ACC_TRANSIENT) fprintf (stream, " transient");
371 if (flags & ACC_VOLATILE) fprintf (stream, " volatile");
372 if (flags & ACC_NATIVE) fprintf (stream, " native");
373 if (flags & ACC_SYNCHRONIZED)
374 {
375 if (context == 'c')
376 fprintf (stream, " super");
377 else
378 fprintf (stream, " synchronized");
379 }
380 if (flags & ACC_INTERFACE) fprintf (stream, " interface");
381 if (flags & ACC_STRICT) fprintf (stream, " strictfp");
382 }
383
384
385 static void
386 DEFUN(print_name, (stream, jcf, name_index),
387 FILE* stream AND JCF* jcf AND int name_index)
388 {
389 if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8)
390 fprintf (stream, "<not a UTF8 constant>");
391 else
392 jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index),
393 JPOOL_UTF_LENGTH (jcf, name_index));
394 }
395
396 /* If the type of the constant at INDEX matches EXPECTED,
397 print it tersely, otherwise more verbosely. */
398
399 static void
400 DEFUN(print_constant_terse, (out, jcf, index, expected),
401 FILE *out AND JCF *jcf AND int index AND int expected)
402 {
403 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, index))
404 fprintf (out, "<constant pool index %d not in range>", index);
405 else if (JPOOL_TAG (jcf, index) != expected)
406 {
407 fprintf (out, "<Unexpected constant type ");
408 print_constant (out, jcf, index, 1);
409 fprintf (out, ">");
410 }
411 else
412 print_constant (out, jcf, index, 0);
413 }
414
415 /* Print the constant at INDEX in JCF's constant pool.
416 If verbosity==0, print very tersely (no extraneous text).
417 If verbosity==1, prefix the type of the constant.
418 If verbosity==2, add more descriptive text. */
419
420 static void
421 DEFUN(print_constant, (out, jcf, index, verbosity),
422 FILE *out AND JCF *jcf AND int index AND int verbosity)
423 {
424 int j, n;
425 jlong num;
426 const char *str;
427 int kind = JPOOL_TAG (jcf, index);
428 switch (kind)
429 {
430 case CONSTANT_Class:
431 n = JPOOL_USHORT1 (jcf, index);
432 if (verbosity > 0)
433 {
434 if (verbosity > 1)
435 fprintf (out, "Class name: %d=", n);
436 else
437 fprintf (out, "Class ");
438 }
439 if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n))
440 fprintf (out, "<out of range>");
441 else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8)
442 {
443 int len = JPOOL_UTF_LENGTH (jcf, n);
444 jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.');
445 }
446 else
447 print_constant_terse (out, jcf, n, CONSTANT_Utf8);
448 break;
449 case CONSTANT_Fieldref:
450 str = "Field"; goto field_or_method;
451 case CONSTANT_Methodref:
452 str = "Method"; goto field_or_method;
453 case CONSTANT_InterfaceMethodref:
454 str = "InterfaceMethod"; goto field_or_method;
455 field_or_method:
456 {
457 uint16 tclass = JPOOL_USHORT1 (jcf, index);
458 uint16 name_and_type = JPOOL_USHORT2 (jcf, index);
459 if (verbosity == 2)
460 fprintf (out, "%sref class: %d=", str, tclass);
461 else if (verbosity > 0)
462 fprintf (out, "%s ", str);
463 print_constant_terse (out, jcf, tclass, CONSTANT_Class);
464 if (verbosity < 2)
465 fprintf (out, ".");
466 else
467 fprintf (out, " name_and_type: %d=<", name_and_type);
468 print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType);
469 if (verbosity == 2)
470 fputc ('>', out);
471 }
472 break;
473 case CONSTANT_String:
474 j = JPOOL_USHORT1 (jcf, index);
475 if (verbosity > 0)
476 {
477 if (verbosity > 1)
478 fprintf (out, "String %d=", j);
479 else
480 fprintf (out, "String ");
481 }
482 print_constant_terse (out, jcf, j, CONSTANT_Utf8);
483 break;
484 case CONSTANT_Integer:
485 if (verbosity > 0)
486 fprintf (out, "Integer ");
487 num = JPOOL_INT (jcf, index);
488 goto integer;
489 case CONSTANT_Long:
490 if (verbosity > 0)
491 fprintf (out, "Long ");
492 num = JPOOL_LONG (jcf, index);
493 goto integer;
494 integer:
495 {
496 char buffer[25];
497 format_int (buffer, num, 10);
498 fprintf (out, "%s", buffer);
499 if (verbosity > 1)
500 {
501 format_uint (buffer, (uint64)num, 16);
502 fprintf (out, "=0x%s", buffer);
503 }
504 }
505 break;
506 case CONSTANT_Float:
507 {
508 jfloat fnum = JPOOL_FLOAT (jcf, index);
509
510 if (verbosity > 0)
511 fputs ("Float ", out);
512
513 if (fnum.negative)
514 putc ('-', out);
515
516 if (JFLOAT_FINITE (fnum))
517 {
518 int dummy;
519 int exponent = fnum.exponent - JFLOAT_EXP_BIAS;
520 double f;
521 uint32 mantissa = fnum.mantissa;
522 if (fnum.exponent == 0)
523 /* Denormal. */
524 exponent++;
525 else
526 /* Normal; add the implicit bit. */
527 mantissa |= ((uint32)1 << 23);
528
529 f = frexp (mantissa, &dummy);
530 f = ldexp (f, exponent + 1);
531 fprintf (out, "%.10g", f);
532 }
533 else
534 {
535 if (fnum.mantissa == 0)
536 fputs ("Inf", out);
537 else if (fnum.mantissa & JFLOAT_QNAN_MASK)
538 fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
539 else
540 fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
541 }
542
543 if (verbosity > 1)
544 fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
545
546 break;
547 }
548 case CONSTANT_Double:
549 {
550 jdouble dnum = JPOOL_DOUBLE (jcf, index);
551
552 if (verbosity > 0)
553 fputs ("Double ", out);
554
555 if (dnum.negative)
556 putc ('-', out);
557
558 if (JDOUBLE_FINITE (dnum))
559 {
560 int dummy;
561 int exponent = dnum.exponent - JDOUBLE_EXP_BIAS;
562 double d;
563 uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
564 + dnum.mantissa1);
565 if (dnum.exponent == 0)
566 /* Denormal. */
567 exponent++;
568 else
569 /* Normal; add the implicit bit. */
570 mantissa |= ((uint64)1 << 52);
571
572 d = frexp (mantissa, &dummy);
573 d = ldexp (d, exponent + 1);
574 fprintf (out, "%.20g", d);
575 }
576 else
577 {
578 uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
579 mantissa = (mantissa << 32) + dnum.mantissa1;
580
581 if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
582 fputs ("Inf", out);
583 else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
584 fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
585 else
586 fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
587 }
588 if (verbosity > 1)
589 {
590 int32 hi, lo;
591 hi = JPOOL_UINT (jcf, index);
592 lo = JPOOL_UINT (jcf, index + 1);
593 fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo);
594 }
595 break;
596 }
597 case CONSTANT_NameAndType:
598 {
599 uint16 name = JPOOL_USHORT1 (jcf, index);
600 uint16 sig = JPOOL_USHORT2 (jcf, index);
601 if (verbosity > 0)
602 {
603 if (verbosity > 1)
604 fprintf (out, "NameAndType name: %d=", name);
605 else
606 fprintf (out, "NameAndType ");
607 }
608 print_name (out, jcf, name);
609 if (verbosity <= 1)
610 fputc (' ', out);
611 else
612 fprintf (out, ", signature: %d=", sig);
613 print_signature (out, jcf, sig, 0);
614 }
615 break;
616 case CONSTANT_Utf8:
617 {
618 register const unsigned char *str = JPOOL_UTF_DATA (jcf, index);
619 int length = JPOOL_UTF_LENGTH (jcf, index);
620 if (verbosity > 0)
621 { /* Print as 8-bit bytes. */
622 fputs ("Utf8: \"", out);
623 while (--length >= 0)
624 jcf_print_char (out, *str++);
625 }
626 else
627 { /* Print as Unicode. */
628 fputc ('\"', out);
629 jcf_print_utf8 (out, str, length);
630 }
631 fputc ('\"', out);
632 }
633 break;
634 default:
635 fprintf (out, "(Unknown constant type %d)", kind);
636 }
637 }
638
639 static void
640 DEFUN(print_constant_pool, (jcf),
641 JCF *jcf)
642 {
643 int i;
644 for (i = 1; i < JPOOL_SIZE(jcf); i++)
645 {
646 int kind = JPOOL_TAG (jcf, i);
647 fprintf (out, "#%d: ", i);
648 print_constant (out, jcf, i, 2);
649 fprintf (out, "\n");
650 if (kind == CONSTANT_Double || kind == CONSTANT_Long)
651 i++; /* These take up two slots in the constant table */
652 }
653 }
654
655 static void
656 DEFUN(print_signature_type, (stream, ptr, limit),
657 FILE* stream AND const unsigned char **ptr AND const unsigned char *limit)
658 {
659 int array_size;
660 if ((*ptr) >= limit)
661 return;
662 switch (*(*ptr))
663 {
664 case '[':
665 array_size = -1;
666 for ((*ptr)++; (*ptr) < limit && ISDIGIT (**ptr); (*ptr)++)
667 {
668 array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0';
669 }
670 print_signature_type (stream, ptr, limit);
671 if (array_size == -1)
672 fprintf (stream, "[]");
673 else
674 fprintf (stream, "[%d]", array_size);
675 break;
676 case '(':
677 {
678 int nargs = 0;
679 fputc (*(*ptr)++, stream);
680 for (; **ptr != ')' && *ptr < limit; nargs++)
681 {
682 if (nargs > 0)
683 fputc (',', stream);
684 print_signature_type (stream, ptr, limit);
685 }
686 if (*ptr < limit)
687 {
688 fputc (*(*ptr)++, stream);
689 print_signature_type (stream, ptr, limit);
690 }
691 else
692 fprintf (stream, "???");
693 }
694 break;
695
696 case 'B': fprintf (stream, "byte"); (*ptr)++; break;
697 case 'C': fprintf (stream, "char"); (*ptr)++; break;
698 case 'D': fprintf (stream, "double"); (*ptr)++; break;
699 case 'F': fprintf (stream, "float"); (*ptr)++; break;
700 case 'S': fprintf (stream, "short"); (*ptr)++; break;
701 case 'I': fprintf (stream, "int"); (*ptr)++; break;
702 case 'J': fprintf (stream, "long"); (*ptr)++; break;
703 case 'Z': fprintf (stream, "boolean"); (*ptr)++; break;
704 case 'V': fprintf (stream, "void"); (*ptr)++; break;
705
706 case 'L':
707 for ((*ptr)++; (*ptr)<limit && *(*ptr) != ';'; (*ptr)++)
708 jcf_print_char (stream, *(*ptr) == '/' ? '.' : *(*ptr));
709 if (*(*ptr) == ';')
710 (*ptr)++;
711 break;
712 default:
713 jcf_print_char (stream, *(*ptr)++);
714 }
715 }
716
717 static void
718 DEFUN(print_signature, (stream, jcf, signature_index, int options),
719 FILE* stream AND JCF *jcf AND int signature_index AND int options)
720 {
721 if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8)
722 print_constant_terse (out, jcf, signature_index, CONSTANT_Utf8);
723 else
724 {
725 const unsigned char *str = JPOOL_UTF_DATA (jcf, signature_index);
726 int length = JPOOL_UTF_LENGTH (jcf, signature_index);
727 const unsigned char *limit;
728 limit = str + length;
729 if (str >= limit)
730 fprintf (stream, "<empty signature string>");
731 else
732 {
733 if (options & PRINT_SIGNATURE_RESULT_ONLY)
734 {
735 while (str < limit && *str++ != ')') ;
736 }
737 if (options & PRINT_SIGNATURE_ARGS_ONLY)
738 {
739 str++;
740 fputc ('(', stream);
741 while (str < limit && *str != ')')
742 {
743 print_signature_type (stream, &str, limit);
744 if (*str != ')')
745 fputs (", ", stream);
746 }
747 fputc (')', stream);
748 }
749 else
750 {
751 print_signature_type (stream, &str, limit);
752 if (str < limit)
753 {
754 fprintf (stream, "<junk:");
755 jcf_print_utf8 (stream, str, limit - str);
756 fputc ('>', stream);
757 }
758 }
759 }
760 }
761 }
762
763
764 static void
765 DEFUN(print_exception_table, (jcf, entries, count),
766 JCF *jcf AND const unsigned char *entries AND int count)
767 {
768 /* Print exception table. */
769 int i = count;
770 if (i > 0)
771 {
772 const unsigned char *ptr = entries;
773 fprintf (out, "Exceptions (count: %d):\n", i);
774 for (; --i >= 0; ptr+= 8)
775 {
776 int start_pc = GET_u2 (ptr);
777 int end_pc = GET_u2 (ptr+2);
778 int handler_pc = GET_u2 (ptr+4);
779 int catch_type = GET_u2 (ptr+6);
780 fprintf (out, " start: %d, end: %d, handler: %d, type: %d",
781 start_pc, end_pc, handler_pc, catch_type);
782 if (catch_type == 0)
783 fputs (" /* finally */", out);
784 else
785 {
786 fputc('=', out);
787 print_constant_terse (out, jcf, catch_type, CONSTANT_Class);
788 }
789 fputc ('\n', out);
790 }
791 }
792 }
793
794 #include "jcf-reader.c"
795
796 static void
797 DEFUN(process_class, (jcf),
798 JCF *jcf)
799 {
800 int code;
801 if (jcf_parse_preamble (jcf) != 0)
802 fprintf (stderr, "Not a valid Java .class file.\n");
803
804 /* Parse and possibly print constant pool */
805 code = jcf_parse_constant_pool (jcf);
806 if (code != 0)
807 {
808 fprintf (stderr, "error while parsing constant pool\n");
809 exit (FATAL_EXIT_CODE);
810 }
811 code = verify_constant_pool (jcf);
812 if (code > 0)
813 {
814 fprintf (stderr, "error in constant pool entry #%d\n", code);
815 exit (FATAL_EXIT_CODE);
816 }
817 if (flag_print_constant_pool)
818 print_constant_pool (jcf);
819
820 jcf_parse_class (jcf);
821 code = jcf_parse_fields (jcf);
822 if (code != 0)
823 {
824 fprintf (stderr, "error while parsing fields\n");
825 exit (FATAL_EXIT_CODE);
826 }
827 code = jcf_parse_methods (jcf);
828 if (code != 0)
829 {
830 fprintf (stderr, "error while parsing methods\n");
831 exit (FATAL_EXIT_CODE);
832 }
833 code = jcf_parse_final_attributes (jcf);
834 if (code != 0)
835 {
836 fprintf (stderr, "error while parsing final attributes\n");
837 exit (FATAL_EXIT_CODE);
838 }
839 jcf->filename = NULL;
840 }
841
842
843
844 /* This is used to mark options with no short value. */
845 #define LONG_OPT(Num) ((Num) + 128)
846
847 #define OPT_classpath LONG_OPT (0)
848 #define OPT_CLASSPATH OPT_classpath
849 #define OPT_bootclasspath LONG_OPT (1)
850 #define OPT_extdirs LONG_OPT (2)
851 #define OPT_HELP LONG_OPT (3)
852 #define OPT_VERSION LONG_OPT (4)
853 #define OPT_JAVAP LONG_OPT (5)
854
855 static const struct option options[] =
856 {
857 { "classpath", required_argument, NULL, OPT_classpath },
858 { "bootclasspath", required_argument, NULL, OPT_bootclasspath },
859 { "extdirs", required_argument, NULL, OPT_extdirs },
860 { "CLASSPATH", required_argument, NULL, OPT_CLASSPATH },
861 { "help", no_argument, NULL, OPT_HELP },
862 { "verbose", no_argument, NULL, 'v' },
863 { "version", no_argument, NULL, OPT_VERSION },
864 { "javap", no_argument, NULL, OPT_JAVAP },
865 { "print-main", no_argument, &flag_print_main, 1 },
866 { NULL, no_argument, NULL, 0 }
867 };
868
869 static void
usage()870 usage ()
871 {
872 fprintf (stderr, "Try `jcf-dump --help' for more information.\n");
873 exit (1);
874 }
875
876 static void
help()877 help ()
878 {
879 printf ("Usage: jcf-dump [OPTION]... CLASS...\n\n");
880 printf ("Display contents of a class file in readable form.\n\n");
881 printf (" -c Disassemble method bodies\n");
882 printf (" --javap Generate output in `javap' format\n");
883 printf ("\n");
884 printf (" --classpath PATH Set path to find .class files\n");
885 printf (" -IDIR Append directory to class path\n");
886 printf (" --bootclasspath PATH Override built-in class path\n");
887 printf (" --extdirs PATH Set extensions directory path\n");
888 printf (" -o FILE Set output file name\n");
889 printf ("\n");
890 printf (" --help Print this help, then exit\n");
891 printf (" --version Print version number, then exit\n");
892 printf (" -v, --verbose Print extra information while running\n");
893 printf ("\n");
894 printf ("For bug reporting instructions, please see:\n");
895 printf ("%s.\n", bug_report_url);
896 exit (0);
897 }
898
899 static void
version()900 version ()
901 {
902 printf ("jcf-dump (GCC) %s\n\n", version_string);
903 printf ("Copyright (C) 2002 Free Software Foundation, Inc.\n");
904 printf ("This is free software; see the source for copying conditions. There is NO\n");
905 printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
906 exit (0);
907 }
908
909 int
910 DEFUN(main, (argc, argv),
911 int argc AND char** argv)
912 {
913 JCF jcf[1];
914 int argi, opt;
915
916 if (argc <= 1)
917 {
918 fprintf (stderr, "jcf-dump: no classes specified\n");
919 usage ();
920 }
921
922 jcf_path_init ();
923
924 /* We use getopt_long_only to allow single `-' long options. For
925 some of our options this is more natural. */
926 while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1)
927 {
928 switch (opt)
929 {
930 case 0:
931 /* Already handled. */
932 break;
933
934 case 'o':
935 output_file = optarg;
936 break;
937
938 case 'I':
939 jcf_path_include_arg (optarg);
940 break;
941
942 case 'v':
943 verbose++;
944 break;
945
946 case 'c':
947 flag_disassemble_methods = 1;
948 break;
949
950 case OPT_classpath:
951 jcf_path_classpath_arg (optarg);
952 break;
953
954 case OPT_bootclasspath:
955 jcf_path_bootclasspath_arg (optarg);
956 break;
957
958 case OPT_extdirs:
959 jcf_path_extdirs_arg (optarg);
960 break;
961
962 case OPT_HELP:
963 help ();
964 break;
965
966 case OPT_VERSION:
967 version ();
968 break;
969
970 case OPT_JAVAP:
971 flag_javap_compatible++;
972 flag_print_constant_pool = 0;
973 flag_print_attributes = 0;
974 break;
975
976 default:
977 usage ();
978 }
979 }
980
981 if (optind == argc)
982 {
983 fprintf (stderr, "jcf-dump: no classes specified\n");
984 usage ();
985 }
986
987 jcf_path_seal (verbose);
988
989 if (flag_print_main)
990 {
991 flag_print_fields = 0;
992 flag_print_methods = 0;
993 flag_print_constant_pool = 0;
994 flag_print_attributes = 0;
995 flag_print_class_info = 0;
996 }
997
998 if (output_file)
999 {
1000 out = fopen (output_file, "w");
1001 if (! out)
1002 {
1003 fprintf (stderr, "Cannot open '%s' for output.\n", output_file);
1004 return FATAL_EXIT_CODE;
1005 }
1006 }
1007 else
1008 out = stdout;
1009
1010 if (optind >= argc)
1011 {
1012 fprintf (out, "Reading .class from <standard input>.\n");
1013 open_class ("<stdio>", jcf, 0, NULL);
1014 process_class (jcf);
1015 }
1016 else
1017 {
1018 for (argi = optind; argi < argc; argi++)
1019 {
1020 char *arg = argv[argi];
1021 const char *class_filename = find_class (arg, strlen (arg), jcf, 0);
1022 if (class_filename == NULL)
1023 class_filename = find_classfile (arg, jcf, NULL);
1024 if (class_filename == NULL)
1025 {
1026 perror ("Could not find class");
1027 return FATAL_EXIT_CODE;
1028 }
1029 JCF_FILL (jcf, 4);
1030 if (GET_u4 (jcf->read_ptr) == ZIPMAGIC)
1031 {
1032 long compressed_size, member_size;
1033 int compression_method, filename_length, extra_length;
1034 int general_purpose_bits;
1035 const char *filename;
1036 int total_length;
1037 if (flag_print_class_info)
1038 fprintf (out, "Reading classes from archive %s.\n",
1039 class_filename);
1040 for (;;)
1041 {
1042 int skip = 0;
1043 jcf_filbuf_t save_filbuf = jcf->filbuf;
1044 long magic = JCF_readu4_le (jcf);
1045 if (magic == 0x02014b50 || magic == 0x06054b50)
1046 break; /* got to central directory */
1047 if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */
1048 {
1049 fprintf (stderr, "bad format of .zip/.jar archive\n");
1050 return FATAL_EXIT_CODE;
1051 }
1052 JCF_FILL (jcf, 26);
1053 JCF_SKIP (jcf, 2);
1054 general_purpose_bits = JCF_readu2_le (jcf);
1055 compression_method = JCF_readu2_le (jcf);
1056 JCF_SKIP (jcf, 8);
1057 compressed_size = JCF_readu4_le (jcf);
1058 member_size = JCF_readu4_le (jcf);
1059 filename_length = JCF_readu2_le (jcf);
1060 extra_length = JCF_readu2_le (jcf);
1061 total_length = filename_length + extra_length
1062 + compressed_size;
1063 if (jcf->read_end - jcf->read_ptr < total_length)
1064 jcf_trim_old_input (jcf);
1065 JCF_FILL (jcf, total_length);
1066 filename = jcf->read_ptr;
1067 JCF_SKIP (jcf, filename_length);
1068 JCF_SKIP (jcf, extra_length);
1069 if (filename_length > 0
1070 && filename[filename_length-1] == '/')
1071 {
1072 if (flag_print_class_info)
1073 fprintf (out, "[Skipping directory %.*s]\n",
1074 filename_length, filename);
1075 skip = 1;
1076 }
1077 else if (compression_method != 0)
1078 {
1079 if (flag_print_class_info)
1080 fprintf (out, "[Skipping compressed file %.*s]\n",
1081 filename_length, filename);
1082 skip = 1;
1083 }
1084 else if (member_size < 4
1085 || GET_u4 (jcf->read_ptr) != 0xcafebabe)
1086 {
1087 if (flag_print_class_info)
1088 fprintf (out, "[Skipping non-.class member %.*s]\n",
1089 filename_length, filename);
1090 skip = 1;
1091 }
1092 else
1093 {
1094 if (flag_print_class_info)
1095 fprintf (out, "Reading class member: %.*s.\n",
1096 filename_length, filename);
1097 }
1098 if (skip)
1099 {
1100 JCF_SKIP (jcf, compressed_size);
1101 }
1102 else
1103 {
1104 unsigned char *save_end;
1105 jcf->filbuf = jcf_unexpected_eof;
1106 save_end = jcf->read_end;
1107 jcf->read_end = jcf->read_ptr + compressed_size;
1108 process_class (jcf);
1109 jcf->filbuf = save_filbuf;
1110 jcf->read_end = save_end;
1111 }
1112 }
1113 }
1114 else
1115 {
1116 if (flag_print_class_info)
1117 fprintf (out, "Reading .class from %s.\n", class_filename);
1118 process_class (jcf);
1119 }
1120 JCF_FINISH(jcf);
1121 }
1122 }
1123
1124 return SUCCESS_EXIT_CODE;
1125 }
1126
1127
1128
1129 static void
1130 DEFUN(disassemble_method, (jcf, byte_ops, len),
1131 JCF* jcf AND const unsigned char *byte_ops AND int len)
1132 {
1133 #undef AND /* Causes problems with opcodes for iand and land. */
1134 #undef PTR
1135 int PC;
1136 int i;
1137 int saw_wide = 0;
1138 if (flag_disassemble_methods == 0)
1139 return;
1140 #define BCODE byte_ops
1141 for (PC = 0; PC < len;)
1142 {
1143 int oldpc = PC;
1144 int saw_index;
1145 jint INT_temp;
1146 switch (byte_ops[PC++])
1147 {
1148
1149 /* This is the actual code emitted for each of opcodes in javaops.def.
1150 The actual opcode-specific stuff is handled by the OPKIND macro.
1151 I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called.
1152 Those macros are defiend below. The OPKINDs that do not have any
1153 inline parameters (such as BINOP) and therefore do mot need anything
1154 else to me printed out just use an empty body. */
1155
1156 #define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
1157 case OPCODE: \
1158 fprintf (out, "%3d: %s", oldpc, #OPNAME); \
1159 OPKIND(OPERAND_TYPE, OPERAND_VALUE); \
1160 fputc ('\n', out); \
1161 break;
1162
1163 #define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1164 #define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1165 #define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1)
1166 #define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2)
1167
1168 #define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \
1169 (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1)
1170
1171 /* Print out operand (if not implied by the opcode) for PUSCH opcodes.
1172 These all push a constant onto the opcode stack. */
1173 #define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \
1174 saw_index = 0, i = (OPERAND_VALUE); \
1175 if (oldpc+1 == PC) /* nothing */; \
1176 else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, i); \
1177 else fprintf (out, " %d", i);
1178
1179 /* Print out operand (a local variable index) for LOAD opcodes.
1180 These all push local variable onto the opcode stack. */
1181 #define LOAD(OPERAND_TYPE, OPERAND_VALUE) \
1182 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); goto load_store;
1183
1184 /* Handle STORE opcodes same as LOAD opcodes.
1185 These all store a value from the opcode stack in a local variable. */
1186 #define STORE LOAD
1187
1188 /* Handle more kind of opcodes. */
1189 #define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1190 #define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1191 #define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1192 #define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1193 #define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1194 #define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1195 #define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */
1196
1197 /* Handle putfield and getfield opcodes, with static versions. */
1198 #define FIELD(MAYBE_STATIC, PUT_OR_GET) \
1199 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2)
1200
1201 /* Print operand for invoke opcodes. */
1202 #define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \
1203 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\
1204 if (OPERAND_VALUE) /* for invokeinterface */ \
1205 { int nargs = IMMEDIATE_u1; PC++; \
1206 fprintf (out, " nargs:%d", nargs); }
1207
1208 #define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \
1209 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1210
1211 #define ARRAY(OPERAND_TYPE, SUBOP) \
1212 ARRAY_##SUBOP(OPERAND_TYPE)
1213 /* Handle sub-categories of ARRAY opcodes. */
1214 #define ARRAY_LOAD(TYPE) /* nothing */
1215 #define ARRAY_STORE(TYPE) /* nothing */
1216 #define ARRAY_LENGTH(TYPE) /* nothing */
1217 #define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE
1218 #define ARRAY_NEW_NUM \
1219 INT_temp = IMMEDIATE_u1; \
1220 { switch ((int) INT_temp) { \
1221 case 4: fputs (" boolean", out); break; \
1222 case 5: fputs (" char", out); break; \
1223 case 6: fputs (" float", out); break; \
1224 case 7: fputs (" double", out); break; \
1225 case 8: fputs (" byte", out); break; \
1226 case 9: fputs (" short", out); break; \
1227 case 10: fputs (" int", out); break; \
1228 case 11: fputs (" long", out); break; \
1229 default: fprintf (out, " <unknown type code %ld>", (long)INT_temp); break;\
1230 } }
1231
1232 #define ARRAY_NEW_PTR \
1233 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);
1234
1235 #define ARRAY_NEW_MULTI \
1236 fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \
1237 fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */
1238
1239 #define TEST(OPERAND_TYPE, OPERAND_VALUE) \
1240 fprintf (out, " %d", oldpc + IMMEDIATE_s2)
1241
1242 #define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \
1243 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1244 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1245
1246 #define JSR(OPERAND_TYPE, OPERAND_VALUE) \
1247 saw_index = 0, INT_temp = (OPERAND_VALUE); \
1248 fprintf (out, " %ld", (long) (saw_index ? INT_temp : oldpc + INT_temp))
1249
1250 #undef RET /* Defined by config/i386/i386.h */
1251 #define RET(OPERAND_TYPE, OPERAND_VALUE) \
1252 INT_temp = saw_wide ? IMMEDIATE_u2 : (OPERAND_VALUE); \
1253 saw_wide = 0; \
1254 fprintf (out, " %ld", (long) INT_temp);
1255
1256 #define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \
1257 PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH
1258
1259 #define LOOKUP_SWITCH \
1260 { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \
1261 fprintf (out, " npairs=%ld, default=%ld", (long) npairs, (long) default_offset+oldpc); \
1262 while (--npairs >= 0) { \
1263 jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \
1264 fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \
1265 }
1266
1267 #define TABLE_SWITCH \
1268 { jint default_offset = IMMEDIATE_s4; \
1269 jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \
1270 fprintf (out, " low=%ld, high=%ld, default=%ld", \
1271 (long) low, (long) high, (long) default_offset+oldpc); \
1272 for (; low <= high; low++) { \
1273 jint offset = IMMEDIATE_s4; \
1274 fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \
1275 }
1276
1277 #define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \
1278 SPECIAL_##OPERAND_VALUE(OPERAND_TYPE)
1279
1280 #define SPECIAL_IINC(OPERAND_TYPE) \
1281 i = saw_wide ? IMMEDIATE_u2 : IMMEDIATE_u1; \
1282 fprintf (out, " %d", i); \
1283 i = saw_wide ? IMMEDIATE_s2 : IMMEDIATE_s1; \
1284 saw_wide = 0; \
1285 fprintf (out, " %d", i)
1286
1287 #define SPECIAL_WIDE(OPERAND_TYPE) \
1288 saw_wide = 1;
1289
1290 #define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */
1291 #define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */
1292 #define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */
1293 #define SPECIAL_THROW(OPERAND_TYPE) /* nothing */
1294
1295 #define IMPL(OPERAND_TYPE, OPERAND_VALUE) \
1296 fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE)
1297
1298 #define COND(OPERAND_TYPE, OPERAND_VALUE) \
1299 TEST(OPERAND_TYPE, OPERAND_VALUE)
1300
1301 #include "javaop.def"
1302
1303 load_store:
1304 if (oldpc+1 == PC) /* nothing - local index implied by opcode */;
1305 else
1306 {
1307 saw_wide = 0;
1308 fprintf (out, " %ld", (long) INT_temp);
1309 }
1310 fputc ('\n', out);
1311 break;
1312
1313 default:
1314 fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]);
1315 }
1316 }
1317 }
1318