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