|
|
@ -1,4 +1,5 @@
|
|
|
|
#include "classfile.h"
|
|
|
|
#include "classfile.h"
|
|
|
|
|
|
|
|
#include "instruction.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <memory.h>
|
|
|
|
#include <memory.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stddef.h>
|
|
|
@ -63,112 +64,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) {
|
|
|
|
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;
|
|
|
|
char* name = (char*)cf->constant_pool[base->attribute_name_index - 1].info.utf8_info.bytes;
|
|
|
|
if (strcmp("ConstantValue", name) == 0) {
|
|
|
|
base->_tag = attribute_tag(name);
|
|
|
|
read_u2(&(base->info.constant_value_attribute.constantvalue_index), 1, file);
|
|
|
|
switch (base->_tag) {
|
|
|
|
} else if (strcmp("Code", name) == 0) {
|
|
|
|
case UNKNOWN:
|
|
|
|
read_u2(&(base->info.code_attribute.max_stack), 2, file);
|
|
|
|
printf("unhandled attribute type: %s\n", name);
|
|
|
|
read_u4(&(base->info.code_attribute.code_length), 1, file);
|
|
|
|
fseek(file, base->attribute_length, SEEK_CUR);
|
|
|
|
base->info.code_attribute.code = (u1*)malloc(base->info.code_attribute.code_length);
|
|
|
|
break;
|
|
|
|
fread(base->info.code_attribute.code, base->info.code_attribute.code_length, 1, file);
|
|
|
|
case CONSTANT_VALUE:
|
|
|
|
read_u2(&(base->info.code_attribute.exception_table_length), 1, file);
|
|
|
|
read_u2(&(base->info.constant_value_attribute.constantvalue_index), 1, file);
|
|
|
|
base->info.code_attribute.exception_table = malloc(sizeof(u2) * 4 * base->info.code_attribute.exception_table_length);
|
|
|
|
break;
|
|
|
|
for (u2 i = 0; i < base->info.code_attribute.exception_table_length; i++) {
|
|
|
|
case CODE:
|
|
|
|
read_u2(&(base->info.code_attribute.exception_table[i].start_pc), 4, file);
|
|
|
|
read_u2(&(base->info.code_attribute.max_stack), 2, file);
|
|
|
|
}
|
|
|
|
read_u4(&(base->info.code_attribute.code_length), 1, file);
|
|
|
|
read_u2(&(base->info.code_attribute.attributes_count), 1, file);
|
|
|
|
base->info.code_attribute.code = (u1*)malloc(base->info.code_attribute.code_length);
|
|
|
|
base->info.code_attribute.attributes = malloc(sizeof(attribute_info) * base->info.code_attribute.attributes_count);
|
|
|
|
fread(base->info.code_attribute.code, base->info.code_attribute.code_length, 1, file);
|
|
|
|
for (u2 i = 0; i < base->info.code_attribute.attributes_count; i++) {
|
|
|
|
read_u2(&(base->info.code_attribute.exception_table_length), 1, file);
|
|
|
|
attribute_info* attr = &(base->info.code_attribute.attributes[i]);
|
|
|
|
base->info.code_attribute.exception_table = malloc(sizeof(u2) * 4 * base->info.code_attribute.exception_table_length);
|
|
|
|
read_u2(&(attr->attribute_name_index), 1, file);
|
|
|
|
for (u2 i = 0; i < base->info.code_attribute.exception_table_length; i++) {
|
|
|
|
read_u4(&(attr->attribute_length), 1, file);
|
|
|
|
read_u2(&(base->info.code_attribute.exception_table[i].start_pc), 4, 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;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
case NEST_HOST:
|
|
|
|
read_u2(&(base->info.nest_host_attribute.host_class_index), 1, file);
|
|
|
|
read_u2(&(base->info.nest_host_attribute.host_class_index), 1, file);
|
|
|
|
} else if (strcmp("NestMembers", name) == 0) {
|
|
|
|
break;
|
|
|
|
read_u2(&(base->info.nest_members_attribute.number_of_classes), 1, file);
|
|
|
|
case NEST_MEMBERS:
|
|
|
|
base->info.nest_members_attribute.classes = malloc(sizeof(u2) * base->info.nest_members_attribute.number_of_classes);
|
|
|
|
read_u2(&(base->info.nest_members_attribute.number_of_classes), 1, file);
|
|
|
|
read_u2(base->info.nest_members_attribute.classes, base->info.nest_members_attribute.number_of_classes, file);
|
|
|
|
base->info.nest_members_attribute.classes = malloc(sizeof(u2) * base->info.nest_members_attribute.number_of_classes);
|
|
|
|
} else if (strcmp("PermittedSubclasses", name) == 0) {
|
|
|
|
read_u2(base->info.nest_members_attribute.classes, base->info.nest_members_attribute.number_of_classes, file);
|
|
|
|
read_u2(&(base->info.permitted_subclasses_attribute.number_of_classes), 1, file);
|
|
|
|
break;
|
|
|
|
base->info.permitted_subclasses_attribute.classes = malloc(sizeof(u2) * base->info.permitted_subclasses_attribute.number_of_classes);
|
|
|
|
case PERMITTED_SUBCLASSES:
|
|
|
|
read_u2(base->info.permitted_subclasses_attribute.classes, base->info.permitted_subclasses_attribute.number_of_classes, file);
|
|
|
|
read_u2(&(base->info.permitted_subclasses_attribute.number_of_classes), 1, file);
|
|
|
|
} else {
|
|
|
|
base->info.permitted_subclasses_attribute.classes = malloc(sizeof(u2) * base->info.permitted_subclasses_attribute.number_of_classes);
|
|
|
|
printf("unhandled attribute type: %s\n", name);
|
|
|
|
read_u2(base->info.permitted_subclasses_attribute.classes, base->info.permitted_subclasses_attribute.number_of_classes, file);
|
|
|
|
fseek(file, base->attribute_length, SEEK_CUR);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ATTRIBUTE_TAGS_END:
|
|
|
|
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -324,18 +360,18 @@ ClassFile* ClassFile_load(const char* path) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ClassFile_info(const ClassFile* cf) {
|
|
|
|
void ClassFile_info(const ClassFile* cf) {
|
|
|
|
printf(
|
|
|
|
printf("Metadata:\n"
|
|
|
|
"magic=%X\n"
|
|
|
|
"\tmagic=%X\n"
|
|
|
|
"minor_version=%hu\n"
|
|
|
|
"\tminor_version=%hu\n"
|
|
|
|
"major_version=%hu\n"
|
|
|
|
"\tmajor_version=%hu\n"
|
|
|
|
"constant_pool_count=%hu\n"
|
|
|
|
"\tconstant_pool_count=%hu\n"
|
|
|
|
"access_flags=%hx\n"
|
|
|
|
"\taccess_flags=%hx\n"
|
|
|
|
"this_class=%hu\n"
|
|
|
|
"\tthis_class=%hu\n"
|
|
|
|
"super_class=%hu\n"
|
|
|
|
"\tsuper_class=%hu\n"
|
|
|
|
"interfaces_count=%hu\n"
|
|
|
|
"\tinterfaces_count=%hu\n"
|
|
|
|
"fields_count=%hu\n"
|
|
|
|
"\tfields_count=%hu\n"
|
|
|
|
"methods_count=%hu\n"
|
|
|
|
"\tmethods_count=%hu\n"
|
|
|
|
"attributes_count=%hu\n",
|
|
|
|
"\tattributes_count=%hu\n\n",
|
|
|
|
cf->magic, cf->minor_version, cf->major_version, cf->constant_pool_count, cf->access_flags, cf->this_class, cf->super_class, cf->interfaces_count,
|
|
|
|
cf->magic, cf->minor_version, cf->major_version, cf->constant_pool_count, cf->access_flags, cf->this_class, cf->super_class, cf->interfaces_count,
|
|
|
|
cf->fields_count, cf->methods_count, cf->attributes_count);
|
|
|
|
cf->fields_count, cf->methods_count, cf->attributes_count);
|
|
|
|
|
|
|
|
|
|
|
@ -362,10 +398,12 @@ void ClassFile_info(const ClassFile* cf) {
|
|
|
|
case CONSTANT_Long:
|
|
|
|
case CONSTANT_Long:
|
|
|
|
merged = merge_bytes(cf->constant_pool[i].info.long_info.high_bytes, cf->constant_pool[i].info.long_info.low_bytes);
|
|
|
|
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);
|
|
|
|
printf("\t%ld\n", *(long*)&merged);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case CONSTANT_Double:
|
|
|
|
case CONSTANT_Double:
|
|
|
|
merged = merge_bytes(cf->constant_pool[i].info.double_info.high_bytes, cf->constant_pool[i].info.double_info.low_bytes);
|
|
|
|
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);
|
|
|
|
printf("\t%lf\n", *(double*)&merged);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case CONSTANT_Class:
|
|
|
|
case CONSTANT_Class:
|
|
|
|
printf("\t#%hu\t\t\t// %s\n", cf->constant_pool[i].info.class_info.name_index,
|
|
|
|
printf("\t#%hu\t\t\t// %s\n", cf->constant_pool[i].info.class_info.name_index,
|
|
|
@ -389,15 +427,69 @@ void ClassFile_info(const ClassFile* cf) {
|
|
|
|
buffer);
|
|
|
|
buffer);
|
|
|
|
free(buffer);
|
|
|
|
free(buffer);
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
putchar('\n');
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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("\n%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
|
|
|
|
// 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
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: print field attributes
|
|
|
|
|
|
|
|
for (u2 j = 0; j < cf->fields[i].attributes_count; j++) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf(";\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// methods
|
|
|
|
// methods
|
|
|
|
|
|
|
|
for (u2 i = 0; i < cf->methods_count; i++) {
|
|
|
|
|
|
|
|
u2 flags = cf->methods[i].access_flags;
|
|
|
|
|
|
|
|
char* access = flags & ACC_PUBLIC ? "public" : flags & ACC_PRIVATE ? "private" : flags & ACC_PROTECTED ? "protected" : "";
|
|
|
|
|
|
|
|
char* descriptor = (char*)cf->constant_pool[cf->methods[i].descriptor_index - 1].info.utf8_info.bytes;
|
|
|
|
|
|
|
|
char* name = (char*)cf->constant_pool[cf->methods[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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: print field attributes
|
|
|
|
|
|
|
|
for (u2 j = 0; j < cf->methods[i].attributes_count; j++) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("{\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// code
|
|
|
|
|
|
|
|
for (u2 j = 0; j < cf->methods[i].attributes_count; j++) {
|
|
|
|
|
|
|
|
if (cf->methods[i].attributes[j]._tag == CODE) {
|
|
|
|
|
|
|
|
Instruction* code = Instruction_parse(cf->methods[i].attributes[j].info.code_attribute.code_length, cf->methods[i].attributes[j].info.code_attribute.code);
|
|
|
|
|
|
|
|
Instruction_print_code(code);
|
|
|
|
|
|
|
|
// TODO: free code
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("\t}\n\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char* ClassFile_resolve_NameAnyType(const ClassFile* cf, CONSTANT_NameAndType_info info) {
|
|
|
|
char* ClassFile_resolve_NameAnyType(const ClassFile* cf, CONSTANT_NameAndType_info info) {
|
|
|
|