diff --git a/classfile.c b/classfile.c index 07bbfa0..8d4b609 100644 --- a/classfile.c +++ b/classfile.c @@ -63,112 +63,147 @@ stack_frame_type stack_frame_type_enum(u2 frame_type) { } } +ATTRIBUTE_TAGS attribute_tag(char* name) { + for (size_t i = 1; i < ATTRIBUTE_TAGS_END; i++) { + if (strcmp(ATTRIBUTE_TAGS_STRINGS[i - 1], name) == 0) + return (ATTRIBUTE_TAGS)i; + } + return UNKNOWN; +} + +char* constant_to_string(ClassFile* cf, cp_info info) {} + void parse_attribute(ClassFile* cf, attribute_info* base, FILE* file) { char* name = (char*)cf->constant_pool[base->attribute_name_index - 1].info.utf8_info.bytes; - if (strcmp("ConstantValue", name) == 0) { - read_u2(&(base->info.constant_value_attribute.constantvalue_index), 1, file); - } else if (strcmp("Code", name) == 0) { - read_u2(&(base->info.code_attribute.max_stack), 2, file); - read_u4(&(base->info.code_attribute.code_length), 1, file); - base->info.code_attribute.code = (u1*)malloc(base->info.code_attribute.code_length); - fread(base->info.code_attribute.code, base->info.code_attribute.code_length, 1, file); - read_u2(&(base->info.code_attribute.exception_table_length), 1, file); - base->info.code_attribute.exception_table = malloc(sizeof(u2) * 4 * base->info.code_attribute.exception_table_length); - for (u2 i = 0; i < base->info.code_attribute.exception_table_length; i++) { - read_u2(&(base->info.code_attribute.exception_table[i].start_pc), 4, file); - } - read_u2(&(base->info.code_attribute.attributes_count), 1, file); - base->info.code_attribute.attributes = malloc(sizeof(attribute_info) * base->info.code_attribute.attributes_count); - for (u2 i = 0; i < base->info.code_attribute.attributes_count; i++) { - attribute_info* attr = &(base->info.code_attribute.attributes[i]); - read_u2(&(attr->attribute_name_index), 1, file); - read_u4(&(attr->attribute_length), 1, file); - parse_attribute(cf, attr, file); - } - } else if (strcmp("StackMapTable", name) == 0) { - read_u2(&(base->info.stack_map_table_attribute.number_of_entries), 1, file); - base->info.stack_map_table_attribute.entries = malloc(sizeof(stack_map_frame) * base->info.stack_map_table_attribute.number_of_entries); - for (u2 i = 0; i < base->info.stack_map_table_attribute.number_of_entries; i++) { - stack_map_frame* entry = &(base->info.stack_map_table_attribute.entries[i]); - fread(&(entry->frame_type), 1, 1, file); - u1 frame_type = entry->frame_type; - switch (stack_frame_type_enum(frame_type)) { - case SAME: - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME: - fread(&(entry->same_locals_1_stack_item_frame.stack[0].tag), 1, 1, file); - if (entry->same_locals_1_stack_item_frame.stack[0].tag == ITEM_Object) { - read_u2(&(entry->same_locals_1_stack_item_frame.stack[0].Object_variable_info.cpool_index), 1, file); - } else if (entry->same_locals_1_stack_item_frame.stack[0].tag == ITEM_Uninitialized) { - read_u2(&(entry->same_locals_1_stack_item_frame.stack[0].Uninitialized_variable_info.offset), 1, file); - } - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - read_u2(&(entry->same_locals_1_stack_item_frame_extended.offset_delta), 1, file); - fread(&(entry->same_locals_1_stack_item_frame_extended.stack[0].tag), 1, 1, file); - if (entry->same_locals_1_stack_item_frame_extended.stack[0].tag == ITEM_Object) { - read_u2(&(entry->same_locals_1_stack_item_frame_extended.stack[0].Object_variable_info.cpool_index), 1, file); - } else if (entry->same_locals_1_stack_item_frame_extended.stack[0].tag == ITEM_Uninitialized) { - read_u2(&(entry->same_locals_1_stack_item_frame_extended.stack[0].Uninitialized_variable_info.offset), 1, file); - } - break; - case CHOP: - read_u2(&(entry->chop_frame.offset_delta), 1, file); - break; - case SAME_FRAME_EXTENDED: - read_u2(&(entry->same_frame_extended.offset_delta), 1, file); - break; - case APPEND: - read_u2(&(entry->append_frame.offset_delta), 1, file); - u2 count = frame_type - 251; - entry->append_frame.locals = malloc(sizeof(verification_type_info) * count); - for (u2 j = 0; j < count; j++) { - fread(&(entry->append_frame.locals[j].tag), 1, 1, file); - if (entry->append_frame.locals[j].tag == ITEM_Object) { - read_u2(&(entry->append_frame.locals[j].Object_variable_info.cpool_index), 1, file); - } else if (entry->append_frame.locals[j].tag == ITEM_Uninitialized) { - read_u2(&(entry->append_frame.locals[j].Uninitialized_variable_info.offset), 1, file); - } - } - break; - case FULL_FRAME: - read_u2(&(entry->full_frame.offset_delta), 1, file); - read_u2(&(entry->full_frame.number_of_locals), 1, file); - entry->full_frame.locals = malloc(sizeof(verification_type_info) * entry->full_frame.number_of_locals); - for (u2 j = 0; j < entry->full_frame.number_of_locals; j++) { - fread(&(entry->full_frame.locals[j].tag), 1, 1, file); - if (entry->full_frame.locals[j].tag == ITEM_Object) { - read_u2(&(entry->full_frame.locals[j].Object_variable_info.cpool_index), 1, file); - } else if (entry->full_frame.locals[j].tag == ITEM_Uninitialized) { - read_u2(&(entry->full_frame.locals[j].Uninitialized_variable_info.offset), 1, file); - } - } - read_u2(&(entry->full_frame.number_of_stack_items), 1, file); - entry->full_frame.stack = malloc(sizeof(verification_type_info) * entry->full_frame.number_of_stack_items); - for (u2 j = 0; j < entry->full_frame.number_of_stack_items; j++) { - fread(&(entry->full_frame.stack[j].tag), 1, 1, file); - if (entry->full_frame.stack[j].tag == ITEM_Object) { - read_u2(&(entry->full_frame.stack[j].Object_variable_info.cpool_index), 1, file); - } else if (entry->full_frame.stack[j].tag == ITEM_Uninitialized) { - read_u2(&(entry->full_frame.stack[j].Uninitialized_variable_info.offset), 1, file); - } - } - break; + base->_tag = attribute_tag(name); + switch (base->_tag) { + case UNKNOWN: + printf("unhandled attribute type: %s\n", name); + fseek(file, base->attribute_length, SEEK_CUR); + break; + case CONSTANT_VALUE: + read_u2(&(base->info.constant_value_attribute.constantvalue_index), 1, file); + break; + case CODE: + read_u2(&(base->info.code_attribute.max_stack), 2, file); + read_u4(&(base->info.code_attribute.code_length), 1, file); + base->info.code_attribute.code = (u1*)malloc(base->info.code_attribute.code_length); + fread(base->info.code_attribute.code, base->info.code_attribute.code_length, 1, file); + read_u2(&(base->info.code_attribute.exception_table_length), 1, file); + base->info.code_attribute.exception_table = malloc(sizeof(u2) * 4 * base->info.code_attribute.exception_table_length); + for (u2 i = 0; i < base->info.code_attribute.exception_table_length; i++) { + read_u2(&(base->info.code_attribute.exception_table[i].start_pc), 4, file); } + read_u2(&(base->info.code_attribute.attributes_count), 1, file); + base->info.code_attribute.attributes = malloc(sizeof(attribute_info) * base->info.code_attribute.attributes_count); + for (u2 i = 0; i < base->info.code_attribute.attributes_count; i++) { + attribute_info* attr = &(base->info.code_attribute.attributes[i]); + read_u2(&(attr->attribute_name_index), 1, file); + read_u4(&(attr->attribute_length), 1, file); + parse_attribute(cf, attr, file); + } + break; + case STACK_MAP_TABLE: + read_u2(&(base->info.stack_map_table_attribute.number_of_entries), 1, file); + base->info.stack_map_table_attribute.entries = malloc(sizeof(stack_map_frame) * base->info.stack_map_table_attribute.number_of_entries); + for (u2 i = 0; i < base->info.stack_map_table_attribute.number_of_entries; i++) { + stack_map_frame* entry = &(base->info.stack_map_table_attribute.entries[i]); + fread(&(entry->frame_type), 1, 1, file); + u1 frame_type = entry->frame_type; + switch (stack_frame_type_enum(frame_type)) { + case SAME: + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + fread(&(entry->same_locals_1_stack_item_frame.stack[0].tag), 1, 1, file); + if (entry->same_locals_1_stack_item_frame.stack[0].tag == ITEM_Object) { + read_u2(&(entry->same_locals_1_stack_item_frame.stack[0].Object_variable_info.cpool_index), 1, file); + } else if (entry->same_locals_1_stack_item_frame.stack[0].tag == ITEM_Uninitialized) { + read_u2(&(entry->same_locals_1_stack_item_frame.stack[0].Uninitialized_variable_info.offset), 1, file); + } + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + read_u2(&(entry->same_locals_1_stack_item_frame_extended.offset_delta), 1, file); + fread(&(entry->same_locals_1_stack_item_frame_extended.stack[0].tag), 1, 1, file); + if (entry->same_locals_1_stack_item_frame_extended.stack[0].tag == ITEM_Object) { + read_u2(&(entry->same_locals_1_stack_item_frame_extended.stack[0].Object_variable_info.cpool_index), 1, file); + } else if (entry->same_locals_1_stack_item_frame_extended.stack[0].tag == ITEM_Uninitialized) { + read_u2(&(entry->same_locals_1_stack_item_frame_extended.stack[0].Uninitialized_variable_info.offset), 1, file); + } + break; + case CHOP: + read_u2(&(entry->chop_frame.offset_delta), 1, file); + break; + case SAME_FRAME_EXTENDED: + read_u2(&(entry->same_frame_extended.offset_delta), 1, file); + break; + case APPEND: + read_u2(&(entry->append_frame.offset_delta), 1, file); + u2 count = frame_type - 251; + entry->append_frame.locals = malloc(sizeof(verification_type_info) * count); + for (u2 j = 0; j < count; j++) { + fread(&(entry->append_frame.locals[j].tag), 1, 1, file); + if (entry->append_frame.locals[j].tag == ITEM_Object) { + read_u2(&(entry->append_frame.locals[j].Object_variable_info.cpool_index), 1, file); + } else if (entry->append_frame.locals[j].tag == ITEM_Uninitialized) { + read_u2(&(entry->append_frame.locals[j].Uninitialized_variable_info.offset), 1, file); + } + } + break; + case FULL_FRAME: + read_u2(&(entry->full_frame.offset_delta), 1, file); + read_u2(&(entry->full_frame.number_of_locals), 1, file); + entry->full_frame.locals = malloc(sizeof(verification_type_info) * entry->full_frame.number_of_locals); + for (u2 j = 0; j < entry->full_frame.number_of_locals; j++) { + fread(&(entry->full_frame.locals[j].tag), 1, 1, file); + if (entry->full_frame.locals[j].tag == ITEM_Object) { + read_u2(&(entry->full_frame.locals[j].Object_variable_info.cpool_index), 1, file); + } else if (entry->full_frame.locals[j].tag == ITEM_Uninitialized) { + read_u2(&(entry->full_frame.locals[j].Uninitialized_variable_info.offset), 1, file); + } + } + read_u2(&(entry->full_frame.number_of_stack_items), 1, file); + entry->full_frame.stack = malloc(sizeof(verification_type_info) * entry->full_frame.number_of_stack_items); + for (u2 j = 0; j < entry->full_frame.number_of_stack_items; j++) { + fread(&(entry->full_frame.stack[j].tag), 1, 1, file); + if (entry->full_frame.stack[j].tag == ITEM_Object) { + read_u2(&(entry->full_frame.stack[j].Object_variable_info.cpool_index), 1, file); + } else if (entry->full_frame.stack[j].tag == ITEM_Uninitialized) { + read_u2(&(entry->full_frame.stack[j].Uninitialized_variable_info.offset), 1, file); + } + } + break; + } + } + break; + case BOOTSTRAP_METHODS: { + BootstrapMethods_attribute* attr = &base->info.bootstrap_methods_attribute; + + read_u2(&(attr->num_bootstrap_methods), 1, file); + attr->bootstrap_methods = malloc(sizeof(BootstrapMethod) * attr->num_bootstrap_methods); + + for (u2 i = 0; i < attr->num_bootstrap_methods; i++) { + BootstrapMethod* method = &attr->bootstrap_methods[i]; + read_u2(&(method->bootstrap_method_ref), 2, file); + method->bootstrap_arguments = malloc(sizeof(u2) * method->num_bootstrap_arguments); + read_u2(method->bootstrap_arguments, method->num_bootstrap_arguments, file); + } + break; } - } else if (strcmp("NestHost", name) == 0) { - read_u2(&(base->info.nest_host_attribute.host_class_index), 1, file); - } else if (strcmp("NestMembers", name) == 0) { - read_u2(&(base->info.nest_members_attribute.number_of_classes), 1, file); - base->info.nest_members_attribute.classes = malloc(sizeof(u2) * base->info.nest_members_attribute.number_of_classes); - read_u2(base->info.nest_members_attribute.classes, base->info.nest_members_attribute.number_of_classes, file); - } else if (strcmp("PermittedSubclasses", name) == 0) { - read_u2(&(base->info.permitted_subclasses_attribute.number_of_classes), 1, file); - base->info.permitted_subclasses_attribute.classes = malloc(sizeof(u2) * base->info.permitted_subclasses_attribute.number_of_classes); - read_u2(base->info.permitted_subclasses_attribute.classes, base->info.permitted_subclasses_attribute.number_of_classes, file); - } else { - printf("unhandled attribute type: %s\n", name); - fseek(file, base->attribute_length, SEEK_CUR); + case NEST_HOST: + read_u2(&(base->info.nest_host_attribute.host_class_index), 1, file); + break; + case NEST_MEMBERS: + read_u2(&(base->info.nest_members_attribute.number_of_classes), 1, file); + base->info.nest_members_attribute.classes = malloc(sizeof(u2) * base->info.nest_members_attribute.number_of_classes); + read_u2(base->info.nest_members_attribute.classes, base->info.nest_members_attribute.number_of_classes, file); + break; + case PERMITTED_SUBCLASSES: + read_u2(&(base->info.permitted_subclasses_attribute.number_of_classes), 1, file); + base->info.permitted_subclasses_attribute.classes = malloc(sizeof(u2) * base->info.permitted_subclasses_attribute.number_of_classes); + read_u2(base->info.permitted_subclasses_attribute.classes, base->info.permitted_subclasses_attribute.number_of_classes, file); + break; + case ATTRIBUTE_TAGS_END: + assert(0); } } @@ -362,10 +397,12 @@ void ClassFile_info(const ClassFile* cf) { case CONSTANT_Long: merged = merge_bytes(cf->constant_pool[i].info.long_info.high_bytes, cf->constant_pool[i].info.long_info.low_bytes); printf("\t%ld\n", *(long*)&merged); + i++; break; case CONSTANT_Double: merged = merge_bytes(cf->constant_pool[i].info.double_info.high_bytes, cf->constant_pool[i].info.double_info.low_bytes); printf("\t%lf\n", *(double*)&merged); + i++; break; case CONSTANT_Class: printf("\t#%hu\t\t\t// %s\n", cf->constant_pool[i].info.class_info.name_index, @@ -393,9 +430,51 @@ void ClassFile_info(const ClassFile* cf) { } } + // class + char* this_name = (char*)cf->constant_pool[cf->constant_pool[cf->this_class - 1].info.class_info.name_index - 1].info.utf8_info.bytes; + char* super_name = + cf->super_class != 0 ? (char*)cf->constant_pool[cf->constant_pool[cf->super_class - 1].info.class_info.name_index - 1].info.utf8_info.bytes : NULL; + char* type = (cf->access_flags & ACC_INTERFACE ? "interface" : (cf->access_flags & ACC_ENUM ? "enum" : (cf->access_flags & ACC_MODULE ? "module" : "class"))); + printf("%s%s%s%s %s%s%s ", cf->access_flags & ACC_PUBLIC ? "public " : "", cf->access_flags & ACC_FINAL ? "final " : "", + cf->access_flags & ACC_ABSTRACT ? "abstract " : "", type, this_name, super_name ? " extends " : "", super_name ? super_name : ""); + // interfaces + if (cf->interfaces_count > 0) + printf("implements "); + for (u2 i = 0; i < cf->interfaces_count; i++) { + printf("%s ", cf->constant_pool[cf->interfaces[i] - 1].info.utf8_info.bytes); + } + + printf("{\n"); // fields + for (u2 i = 0; i < cf->fields_count; i++) { + u2 flags = cf->fields[i].access_flags; + char* access = flags & ACC_PUBLIC ? "public" : flags & ACC_PRIVATE ? "private" : flags & ACC_PROTECTED ? "protected" : ""; + char* descriptor = (char*)cf->constant_pool[cf->fields[i].descriptor_index - 1].info.utf8_info.bytes; + char* name = (char*)cf->constant_pool[cf->fields[i].name_index - 1].info.utf8_info.bytes; + printf("\t%s %s%s%s%s %s", access, flags & ACC_STATIC ? "static " : "", flags & ACC_FINAL ? "final " : "", flags & ACC_VOLATLE ? "volatile " : "", + descriptor, name); + + for (u2 j = 0; j < cf->fields[i].attributes_count; j++) { + switch (cf->fields[i].attributes[j]._tag) { + case CONSTANT_VALUE: + break; + case BOOTSTRAP_METHODS: + break; + case NEST_HOST: + break; + case NEST_MEMBERS: + break; + case PERMITTED_SUBCLASSES: + break; + default: + break; + } + } + + printf(";\n"); + } // methods } diff --git a/classfile.h b/classfile.h index 3aa2cf5..01ba851 100644 --- a/classfile.h +++ b/classfile.h @@ -260,13 +260,15 @@ typedef struct { stack_map_frame* entries; } StackMapTable_attribute; +typedef struct { + u2 bootstrap_method_ref; + u2 num_bootstrap_arguments; + u2* bootstrap_arguments; +} BootstrapMethod; + typedef struct { u2 num_bootstrap_methods; - struct { - u2 bootstrap_method_ref; - u2 num_bootstrap_arguments; - u2* bootstrap_arguments; - } * bootstrap_methods; + BootstrapMethod* bootstrap_methods; } BootstrapMethods_attribute; typedef struct { @@ -283,9 +285,26 @@ typedef struct { u2* classes; } PermittedSubclasses_attribute; +typedef enum { + UNKNOWN, + CONSTANT_VALUE, + CODE, + STACK_MAP_TABLE, + BOOTSTRAP_METHODS, + NEST_HOST, + NEST_MEMBERS, + PERMITTED_SUBCLASSES, + ATTRIBUTE_TAGS_END +} ATTRIBUTE_TAGS; + +static const char* ATTRIBUTE_TAGS_STRINGS[] = { + "ConstantValue", "Code", "StackMapTable", "BootstrapMethods", "NestHost", "NestMembers", "PermittedSubclasses", +}; + typedef struct { u2 attribute_name_index; u4 attribute_length; + ATTRIBUTE_TAGS _tag; union { ConstantValue_attribute constant_value_attribute; Code_attribute code_attribute;