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