#include "classfile.h" #include #include #include #include #include #define SWAP_ENDIANNESS void read_u2(void *ptr, size_t n, FILE *file) { u2 buffer[n]; fread(&buffer, sizeof(u2), n, file); #ifdef SWAP_ENDIANNESS for (size_t i = 0; i < n; i++) { buffer[i] = (buffer[i] >> 8) | (buffer[i] << 8); } #endif memcpy(ptr, &buffer, n * sizeof(u2)); } void read_u4(void *ptr, size_t n, FILE *file) { u4 buffer[n]; fread(&buffer, sizeof(u4), n, file); #ifdef SWAP_ENDIANNESS for (size_t i = 0; i < n; i++) { buffer[i] = ((buffer[i] >> 24) & 0xff) | // move byte 3 to byte 0 ((buffer[i] << 8) & 0xff0000) | // move byte 1 to byte 2 ((buffer[i] >> 8) & 0xff00) | // move byte 2 to byte 1 ((buffer[i] << 24) & 0xff000000); } #endif memcpy(ptr, &buffer, n * sizeof(u4)); } ClassFile *ClassFile_load(const char *path) { FILE *file = fopen(path, "rb"); if (file == NULL) return NULL; ClassFile *cf = (ClassFile *)malloc(sizeof(ClassFile)); // magic 4bytes, minor_version 2bytes, major_version 2bytes, // constant_pool_count 2bytes read_u4(&(cf->magic), 1, file); read_u2(&(cf->minor_version), 3, file); // constant_pool cf->constant_pool = (cp_info *)malloc(sizeof(cp_info) * (cf->constant_pool_count - 1)); for (u2 i = 0; i < (cf->constant_pool_count - 1); i++) { // cp_info.tag 2bytes fread(&(cf->constant_pool[i].tag), 1, 1, file); size_t size; switch (cf->constant_pool[i].tag) { case CONSTANT_Class: read_u2(&(cf->constant_pool[i].info.class_info.name_index), 1, file); break; case CONSTANT_Fieldref: read_u2(&(cf->constant_pool[i].info.fieldref_info.class_index), 1, file); read_u2(&(cf->constant_pool[i].info.fieldref_info.name_and_type_index), 1, file); break; case CONSTANT_Methodref: read_u2(&(cf->constant_pool[i].info.methodref_info.class_index), 1, file); read_u2(&(cf->constant_pool[i].info.methodref_info.name_and_type_index), 1, file); break; case CONSTANT_InterfaceMethodref: read_u2(&(cf->constant_pool[i].info.interface_methodred_info.class_index), 1, file); read_u2(&(cf->constant_pool[i] .info.interface_methodred_info.name_and_type_index), 1, file); break; case CONSTANT_String: read_u2(&(cf->constant_pool[i].info.string_info.string_index), 1, file); break; case CONSTANT_Integer: read_u4(&(cf->constant_pool[i].info.integer_info.bytes), 1, file); break; case CONSTANT_Float: read_u4(&(cf->constant_pool[i].info.float_info.bytes), 1, file); break; case CONSTANT_Long: read_u4(&(cf->constant_pool[i].info.long_info.high_bytes), 1, file); read_u4(&(cf->constant_pool[i].info.long_info.low_bytes), 1, file); break; case CONSTANT_Double: read_u4(&(cf->constant_pool[i].info.double_info.high_bytes), 1, file); read_u4(&(cf->constant_pool[i].info.double_info.low_bytes), 1, file); break; case CONSTANT_NameAndType: read_u2(&(cf->constant_pool[i].info.name_and_type_info.name_index), 1, file); read_u2(&(cf->constant_pool[i].info.name_and_type_info.descriptor_index), 1, file); break; case CONSTANT_Utf8: read_u2(&(cf->constant_pool[i].info.utf8_info.length), 1, file); fread(&(cf->constant_pool[i].info.utf8_info.bytes), cf->constant_pool[i].info.utf8_info.length, 1, file); break; case CONSTANT_MethodHandle: fread(&(cf->constant_pool[i].info.method_handle_info.reference_kind), 1, 1, file); read_u2(&(cf->constant_pool[i].info.method_handle_info.reference_index), 1, file); break; case CONSTANT_MethodType: read_u2(&(cf->constant_pool[i].info.method_type_info.descriptor_index), 1, file); break; case CONSTANT_Dynamic: read_u2( &(cf->constant_pool[i].info.dynamic_info.bootstrap_method_attr_index), 1, file); read_u2(&(cf->constant_pool[i].info.dynamic_info.name_and_type_index), 1, file); break; case CONSTANT_InvokeDynamic: read_u2(&(cf->constant_pool[i] .info.invoke_dynamic_info.bootstrap_method_attr_index), 1, file); read_u2( &(cf->constant_pool[i].info.invoke_dynamic_info.name_and_type_index), 1, file); break; case CONSTANT_Module: read_u2(&(cf->constant_pool[i].info.module_info.name_index), 1, file); break; case CONSTANT_Package: read_u2(&(cf->constant_pool[i].info.package_info.name_index), 1, file); break; default: printf("unknown constant tag: %hhu\n", cf->constant_pool[i].tag); // assert(0); } } // access_flags 2bytes, this_class 2bytes, super_class 2bytes, interface_count // 2byte read_u2(&(cf->access_flags), 4, file); // interfaces cf->interfaces = (u2 *)malloc(2 * cf->interfaces_count); read_u2(cf->interfaces, cf->interfaces_count, file); // fields_count 2bytes read_u2(&(cf->fields_count), 1, file); // fields cf->fields = (field_info *)malloc(sizeof(field_info) * cf->fields_count); for (u2 i = 0; i < cf->fields_count; i++) { // access_flags 2bytes, name_index 2bytes, descriptor_index 2bytes, // attributes_count 2bytes read_u2(&(cf->fields[i].access_flags), 4, file); cf->fields[i].attributes = (attribute_info *)malloc( sizeof(attribute_info) * cf->fields[i].attributes_count); for (u2 j = 0; j < cf->fields[i].attributes_count; j++) { // attribute_name_index 2bytes, attribute_length 4bytes read_u2(&(cf->fields[i].attributes[j].attribute_name_index), 1, file); read_u4(&(cf->fields[i].attributes[j].attribute_length), 1, file); cf->fields[i].attributes[j].info = (u1 *)malloc(cf->fields[i].attributes[j].attribute_length); fread(cf->fields[i].attributes[j].info, cf->fields[i].attributes[j].attribute_length, 1, file); } } // methods_count 2bytes read_u2(&(cf->methods_count), 1, file); // methods cf->methods = (method_info *)malloc(sizeof(method_info) * cf->methods_count); for (u2 i = 0; i < cf->methods_count; i++) { // access_flags 2bytes, name_index 2bytes, descriptor_index 2bytes, // attributes_count 2bytes read_u2(&(cf->methods[i].access_flags), 4, file); cf->methods[i].attributes = (attribute_info *)malloc( sizeof(attribute_info) * cf->methods[i].attributes_count); for (u2 j = 0; j < cf->methods[i].attributes_count; j++) { // attribute_name_index 2bytes, attribute_length 4bytes read_u2(&(cf->methods[i].attributes[j].attribute_name_index), 1, file); read_u4(&(cf->methods[i].attributes[j].attribute_length), 1, file); cf->methods[i].attributes[j].info = (u1 *)malloc(cf->methods[i].attributes[j].attribute_length); fread(cf->methods[i].attributes[j].info, cf->methods[i].attributes[j].attribute_length, 1, file); } } // attributes_count 2bytes read_u2(&(cf->attributes_count), 1, file); // attributes cf->attributes = (attribute_info *)malloc(sizeof(attribute_info) * cf->attributes_count); for (u2 i = 0; i < cf->attributes_count; i++) { // attribute_name_index 2bytes, attribute_length 4bytes read_u2(&(cf->attributes[i].attribute_name_index), 1, file); read_u4(&(cf->attributes[i].attribute_length), 1, file); cf->attributes[i].info = (u1 *)malloc(cf->attributes[i].attribute_length); fread(cf->attributes[i].info, cf->attributes[i].attribute_length, 1, file); } fclose(file); return cf; } void ClassFile_info(const ClassFile *cf) { printf("magic=%X\n" "minor_version=%hu\n" "major_version=%hu\n" "constant_pool_count=%hu\n" "access_flags=%hx\n" "this_class=%hu\n" "super_class=%hu\n" "interfaces_count=%hu\n" "fields_count=%hu\n" "methods_count=%hu\n" "attributes_count=%hu\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->fields_count, cf->methods_count, cf->attributes_count); }