/* Read attributes. */ static int jcf_parse_final_attributes (JCF *jcf) { int i; uint16 attributes_count = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); #ifdef START_FINAL_ATTRIBUTES START_FINAL_ATTRIBUTES (attributes_count) #endif for (i = 0; i < attributes_count; i++) { int code = get_attribute (jcf, i, JV_CLASS_ATTR); if (code != 0) return code; } return 0; }
static int jcf_parse_methods (JCF* jcf) { int i; uint16 methods_count; JCF_FILL (jcf, 2); methods_count = JCF_readu2 (jcf); #ifdef HANDLE_START_METHODS HANDLE_START_METHODS (methods_count); #endif for (i = 0; i < methods_count; i++) { int code = jcf_parse_one_method (jcf, i); if (code != 0) return code; } #ifdef HANDLE_END_METHODS HANDLE_END_METHODS (); #endif return 0; }
static int jcf_parse_one_method (JCF* jcf, int index) { int i; uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf)); uint16 name_index = JCF_readu2 (jcf); uint16 signature_index = JCF_readu2 (jcf); uint16 attribute_count = JCF_readu2 (jcf); #ifdef HANDLE_METHOD HANDLE_METHOD(access_flags, name_index, signature_index, attribute_count); #endif for (i = 0; i < attribute_count; i++) { int code = get_attribute (jcf, index, JV_METHOD_ATTR); if (code != 0) return code; } #ifdef HANDLE_END_METHOD HANDLE_END_METHOD (); #endif return 0; }
int main (int argc, char** argv) { JCF jcf[1]; int argi, opt; /* Unlock the stdio streams. */ unlock_std_streams (); gcc_init_libintl (); if (argc <= 1) { fprintf (stderr, _("jcf-dump: no classes specified\n")); usage (); } jcf_path_init (); /* We use getopt_long_only to allow single `-' long options. For some of our options this is more natural. */ while ((opt = getopt_long_only (argc, argv, "o:I:vc", options, NULL)) != -1) { switch (opt) { case 0: /* Already handled. */ break; case 'o': output_file = optarg; break; case 'I': jcf_path_include_arg (optarg); break; case 'v': verbose++; break; case 'c': flag_disassemble_methods = 1; break; case OPT_classpath: jcf_path_classpath_arg (optarg); break; case OPT_bootclasspath: jcf_path_bootclasspath_arg (optarg); break; case OPT_extdirs: jcf_path_extdirs_arg (optarg); break; case OPT_HELP: help (); break; case OPT_VERSION: version (); break; case OPT_JAVAP: flag_javap_compatible++; flag_print_constant_pool = 0; flag_print_attributes = 0; break; default: usage (); } } if (verbose && ! flag_javap_compatible) flag_print_constant_pool = 1; if (optind == argc) { fprintf (stderr, _("jcf-dump: no classes specified\n")); usage (); } jcf_path_seal (verbose); if (flag_print_main) { flag_print_fields = 0; flag_print_methods = 0; flag_print_constant_pool = 0; flag_print_attributes = 0; flag_print_class_info = 0; } if (output_file) { out = fopen (output_file, "w"); if (! out) { fprintf (stderr, _("Cannot open '%s' for output.\n"), output_file); return FATAL_EXIT_CODE; } } else out = stdout; if (optind >= argc) { fprintf (out, "Reading .class from <standard input>.\n"); open_class ("<stdio>", jcf, 0, NULL); process_class (jcf); } else { for (argi = optind; argi < argc; argi++) { char *arg = argv[argi]; const char *class_filename = find_class (arg, strlen (arg), jcf, 0); if (class_filename == NULL) class_filename = find_classfile (arg, jcf, NULL); if (class_filename == NULL) { perror ("Could not find class"); return FATAL_EXIT_CODE; } JCF_FILL (jcf, 4); if (GET_u4 (jcf->read_ptr) == ZIPMAGIC) { long compressed_size, member_size; int compression_method, filename_length, extra_length; int general_purpose_bits; const char *filename; int total_length; if (flag_print_class_info) fprintf (out, "Reading classes from archive %s.\n", class_filename); for (;;) { int skip = 0; jcf_filbuf_t save_filbuf = jcf->filbuf; long magic = JCF_readu4_le (jcf); if (magic == 0x02014b50 || magic == 0x06054b50) break; /* got to central directory */ if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */ { fprintf (stderr, _("bad format of .zip/.jar archive\n")); return FATAL_EXIT_CODE; } JCF_FILL (jcf, 26); JCF_SKIP (jcf, 2); general_purpose_bits = JCF_readu2_le (jcf); compression_method = JCF_readu2_le (jcf); JCF_SKIP (jcf, 8); compressed_size = JCF_readu4_le (jcf); member_size = JCF_readu4_le (jcf); filename_length = JCF_readu2_le (jcf); extra_length = JCF_readu2_le (jcf); total_length = filename_length + extra_length + compressed_size; if (jcf->read_end - jcf->read_ptr < total_length) jcf_trim_old_input (jcf); JCF_FILL (jcf, total_length); filename = (const char *) jcf->read_ptr; JCF_SKIP (jcf, filename_length); JCF_SKIP (jcf, extra_length); if (filename_length > 0 && filename[filename_length-1] == '/') { if (flag_print_class_info) fprintf (out, "[Skipping directory %.*s]\n", filename_length, filename); skip = 1; } else if (compression_method != 0) { if (flag_print_class_info) fprintf (out, "[Skipping compressed file %.*s]\n", filename_length, filename); skip = 1; } else if (member_size < 4 || GET_u4 (jcf->read_ptr) != 0xcafebabe) { if (flag_print_class_info) fprintf (out, "[Skipping non-.class member %.*s]\n", filename_length, filename); skip = 1; } else { if (flag_print_class_info) fprintf (out, "Reading class member: %.*s.\n", filename_length, filename); } if (skip) { JCF_SKIP (jcf, compressed_size); } else { unsigned char *save_end; jcf->filbuf = jcf_unexpected_eof; save_end = jcf->read_end; jcf->read_end = jcf->read_ptr + compressed_size; process_class (jcf); jcf->filbuf = save_filbuf; jcf->read_end = save_end; } } } else { if (flag_print_class_info) fprintf (out, "Reading .class from %s.\n", class_filename); process_class (jcf); } JCF_FINISH(jcf); } } return SUCCESS_EXIT_CODE; }
/* Read and handle the constant pool. Return 0 if OK. Return -2 if a bad cross-reference (index of other constant) was seen. */ static int jcf_parse_constant_pool (JCF* jcf) { int i, n; JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); jcf->cpool.tags = (uint8 *) ggc_alloc_atomic (JPOOL_SIZE (jcf)); jcf->cpool.data = ggc_alloc_cpool_entry (sizeof (jword) * JPOOL_SIZE (jcf)); jcf->cpool.tags[0] = 0; #ifdef HANDLE_START_CONSTANT_POOL HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf)); #endif for (i = 1; i < (int) JPOOL_SIZE (jcf); i++) { int constant_kind; /* Make sure at least 9 bytes are available. This is enough for all fixed-sized constant pool entries (so we don't need many more JCF_FILL calls below), but is is small enough that we are guaranteed to not hit EOF (in a valid .class file). */ JCF_FILL (jcf, 9); constant_kind = JCF_readu (jcf); jcf->cpool.tags[i] = constant_kind; switch (constant_kind) { case CONSTANT_String: case CONSTANT_Class: jcf->cpool.data[i].w = JCF_readu2 (jcf); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: jcf->cpool.data[i].w = JCF_readu2 (jcf); jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; break; case CONSTANT_Integer: case CONSTANT_Float: jcf->cpool.data[i].w = JCF_readu4 (jcf); break; case CONSTANT_Long: case CONSTANT_Double: jcf->cpool.data[i].w = JCF_readu4 (jcf); i++; /* These take up two spots in the constant pool */ jcf->cpool.tags[i] = 0; jcf->cpool.data[i].w = JCF_readu4 (jcf); break; case CONSTANT_Utf8: n = JCF_readu2 (jcf); JCF_FILL (jcf, n); #ifdef HANDLE_CONSTANT_Utf8 HANDLE_CONSTANT_Utf8(jcf, i, n); #else jcf->cpool.data[i].w = JCF_TELL(jcf) - 2; JCF_SKIP (jcf, n); #endif break; case CONSTANT_MethodHandle: jcf->cpool.data[i].w = JCF_readu (jcf); jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; break; case CONSTANT_MethodType: jcf->cpool.data[i].w = JCF_readu2 (jcf); break; case CONSTANT_InvokeDynamic: jcf->cpool.data[i].w = JCF_readu2 (jcf); jcf->cpool.data[i].w |= JCF_readu2 (jcf) << 16; break; default: return i; } } return 0; }
static int get_attribute (JCF *jcf, int index, jv_attr_type attr_type ATTRIBUTE_UNUSED) { uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf)); uint32 attribute_length = JCF_readu4 (jcf); uint32 start_pos = JCF_TELL(jcf); int name_length; const unsigned char *name_data; JCF_FILL (jcf, (long) attribute_length); if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)) return -2; if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8) return -2; name_length = JPOOL_UTF_LENGTH (jcf, attribute_name); name_data = JPOOL_UTF_DATA (jcf, attribute_name); #define MATCH_ATTRIBUTE(S) \ (name_length == sizeof (S)-1 && memcmp (name_data, S, sizeof (S)-1) == 0) #ifdef IGNORE_ATTRIBUTE if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length)) { JCF_SKIP (jcf, attribute_length); } else #endif #ifdef HANDLE_SOURCEFILE if (MATCH_ATTRIBUTE ("SourceFile")) { uint16 sourcefile_index = JCF_readu2 (jcf); HANDLE_SOURCEFILE(sourcefile_index); } else #endif #ifdef HANDLE_CONSTANTVALUE if (MATCH_ATTRIBUTE ("ConstantValue")) { uint16 constantvalue_index = JCF_readu2 (jcf); if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf)) return -2; HANDLE_CONSTANTVALUE(constantvalue_index); } else #endif #ifdef HANDLE_CODE_ATTRIBUTE if (MATCH_ATTRIBUTE ("Code")) { uint16 j; uint16 max_stack ATTRIBUTE_UNUSED = JCF_readu2 (jcf); uint16 max_locals ATTRIBUTE_UNUSED = JCF_readu2 (jcf); uint32 code_length = JCF_readu4 (jcf); uint16 exception_table_length, attributes_count; if (code_length + 12 > attribute_length) return -1; HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length); JCF_SKIP (jcf, code_length); exception_table_length = JCF_readu2 (jcf); if (code_length + 8 * exception_table_length + 12 > attribute_length) return -1; #ifdef HANDLE_EXCEPTION_TABLE HANDLE_EXCEPTION_TABLE (jcf->read_ptr, exception_table_length); #endif JCF_SKIP (jcf, 2 * 4 * exception_table_length); attributes_count = JCF_readu2 (jcf); for (j = 0; j < attributes_count; j++) { int code = get_attribute (jcf, index, JV_METHOD_ATTR); if (code != 0) return code; } } else #endif /* HANDLE_CODE_ATTRIBUTE */ #ifdef HANDLE_EXCEPTIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("Exceptions")) { uint16 count = JCF_readu2 (jcf); HANDLE_EXCEPTIONS_ATTRIBUTE (count); } else #endif #ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE if (MATCH_ATTRIBUTE ("LineNumberTable")) { uint16 count = JCF_readu2 (jcf); HANDLE_LINENUMBERTABLE_ATTRIBUTE (count); } else #endif #ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE if (MATCH_ATTRIBUTE ("LocalVariableTable")) { uint16 count = JCF_readu2 (jcf); HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count); } else #endif #ifdef HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE if (MATCH_ATTRIBUTE ("LocalVariableTypeTable")) { uint16 count = JCF_readu2 (jcf); HANDLE_LOCALVARIABLETYPETABLE_ATTRIBUTE (count); } else #endif #ifdef HANDLE_INNERCLASSES_ATTRIBUTE if (MATCH_ATTRIBUTE ("InnerClasses")) { uint16 count = JCF_readu2 (jcf); HANDLE_INNERCLASSES_ATTRIBUTE (count); } else #endif #ifdef HANDLE_SYNTHETIC_ATTRIBUTE if (MATCH_ATTRIBUTE ("Synthetic")) { HANDLE_SYNTHETIC_ATTRIBUTE (); } else #endif #ifdef HANDLE_GCJCOMPILED_ATTRIBUTE if (MATCH_ATTRIBUTE ("gnu.gcj.gcj-compiled")) { HANDLE_GCJCOMPILED_ATTRIBUTE (); } else #endif #ifdef HANDLE_DEPRECATED_ATTRIBUTE if (MATCH_ATTRIBUTE ("Deprecated")) { HANDLE_DEPRECATED_ATTRIBUTE (); } else #endif #ifdef HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE if (MATCH_ATTRIBUTE ("SourceDebugExtension")) /* JSR 45 */ { HANDLE_SOURCEDEBUGEXTENSION_ATTRIBUTE (attribute_length); } else #endif #ifdef HANDLE_ENCLOSINGMETHOD_ATTRIBUTE if (MATCH_ATTRIBUTE ("EnclosingMethod")) { HANDLE_ENCLOSINGMETHOD_ATTRIBUTE (); } else #endif #ifdef HANDLE_SIGNATURE_ATTRIBUTE if (MATCH_ATTRIBUTE ("Signature")) { HANDLE_SIGNATURE_ATTRIBUTE (); } else #endif #ifdef HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("RuntimeVisibleAnnotations")) { HANDLE_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE (); } else #endif #ifdef HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("RuntimeInvisibleAnnotations")) { HANDLE_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE (); } else #endif #ifdef HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("RuntimeVisibleParameterAnnotations")) { HANDLE_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE (); } else #endif #ifdef HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("RuntimeInvisibleParameterAnnotations")) { HANDLE_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE (); } else #endif #ifdef HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE if (MATCH_ATTRIBUTE ("AnnotationDefault")) { HANDLE_ANNOTATIONDEFAULT_ATTRIBUTE (); } else #endif if (MATCH_ATTRIBUTE ("BootstrapMethods")) { #ifdef HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE HANDLE_BOOTSTRAP_METHODS_ATTRIBUTE(); #else JCF_SKIP (jcf, attribute_length); #endif } else { #ifdef PROCESS_OTHER_ATTRIBUTE PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length); #else JCF_SKIP (jcf, attribute_length); #endif } if ((long) (start_pos + attribute_length) != JCF_TELL(jcf)) return -1; return 0; }
static int get_attribute (JCF *jcf) { uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf)); uint32 attribute_length = JCF_readu4 (jcf); uint32 start_pos = JCF_TELL(jcf); int name_length; const unsigned char *name_data; JCF_FILL (jcf, (long) attribute_length); if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)) return -2; if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8) return -2; name_length = JPOOL_UTF_LENGTH (jcf, attribute_name); name_data = JPOOL_UTF_DATA (jcf, attribute_name); #define MATCH_ATTRIBUTE(S) \ (name_length == sizeof (S)-1 && memcmp (name_data, S, sizeof (S)-1) == 0) #ifdef IGNORE_ATTRIBUTE if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length)) { JCF_SKIP (jcf, attribute_length); } else #endif #ifdef HANDLE_SOURCEFILE if (MATCH_ATTRIBUTE ("SourceFile")) { uint16 sourcefile_index = JCF_readu2 (jcf); HANDLE_SOURCEFILE(sourcefile_index); } else #endif #ifdef HANDLE_CONSTANTVALUE if (MATCH_ATTRIBUTE ("ConstantValue")) { uint16 constantvalue_index = JCF_readu2 (jcf); if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf)) return -2; HANDLE_CONSTANTVALUE(constantvalue_index); } else #endif #ifdef HANDLE_CODE_ATTRIBUTE if (MATCH_ATTRIBUTE ("Code")) { uint16 j; uint16 max_stack ATTRIBUTE_UNUSED = JCF_readu2 (jcf); uint16 max_locals ATTRIBUTE_UNUSED = JCF_readu2 (jcf); uint32 code_length = JCF_readu4 (jcf); uint16 exception_table_length, attributes_count; if (code_length + 12 > attribute_length) return -1; HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length); JCF_SKIP (jcf, code_length); exception_table_length = JCF_readu2 (jcf); if (code_length + 8 * exception_table_length + 12 > attribute_length) return -1; #ifdef HANDLE_EXCEPTION_TABLE HANDLE_EXCEPTION_TABLE (jcf->read_ptr, exception_table_length); #endif JCF_SKIP (jcf, 2 * 4 * exception_table_length); attributes_count = JCF_readu2 (jcf); for (j = 0; j < attributes_count; j++) { int code = get_attribute (jcf); if (code != 0) return code; } } else #endif /* HANDLE_CODE_ATTRIBUTE */ #ifdef HANDLE_EXCEPTIONS_ATTRIBUTE if (MATCH_ATTRIBUTE ("Exceptions")) { uint16 count = JCF_readu2 (jcf); HANDLE_EXCEPTIONS_ATTRIBUTE (count); } else #endif #ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE if (MATCH_ATTRIBUTE ("LineNumberTable")) { uint16 count = JCF_readu2 (jcf); HANDLE_LINENUMBERTABLE_ATTRIBUTE (count); } else #endif #ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE if (MATCH_ATTRIBUTE ("LocalVariableTable")) { uint16 count = JCF_readu2 (jcf); HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count); } else #endif #ifdef HANDLE_INNERCLASSES_ATTRIBUTE if (MATCH_ATTRIBUTE ("InnerClasses")) { uint16 count = JCF_readu2 (jcf); HANDLE_INNERCLASSES_ATTRIBUTE (count); } else #endif #ifdef HANDLE_SYNTHETIC_ATTRIBUTE if (MATCH_ATTRIBUTE ("Synthetic")) { HANDLE_SYNTHETIC_ATTRIBUTE (); } else #endif #ifdef HANDLE_GCJCOMPILED_ATTRIBUTE if (MATCH_ATTRIBUTE ("gnu.gcj.gcj-compiled")) { HANDLE_GCJCOMPILED_ATTRIBUTE (); } else #endif #ifdef HANDLE_DEPRECATED_ATTRIBUTE if (MATCH_ATTRIBUTE ("Deprecated")) { HANDLE_DEPRECATED_ATTRIBUTE (); } else #endif { #ifdef PROCESS_OTHER_ATTRIBUTE PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length); #else JCF_SKIP (jcf, attribute_length); #endif } if ((long) (start_pos + attribute_length) != JCF_TELL(jcf)) return -1; return 0; }