From 5228c765efb1e27cd4df67a3cc43757b036ef3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedek=20L=C3=A1szl=C3=B3?= Date: Sat, 13 Apr 2024 11:56:14 +0200 Subject: [PATCH] better info printing --- classfile.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++- classfile.h | 25 ++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/classfile.c b/classfile.c index 9c46468..07bbfa0 100644 --- a/classfile.c +++ b/classfile.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,10 @@ void read_u4(void* ptr, size_t n, FILE* file) { memcpy(ptr, &buffer, n * sizeof(u4)); } +uint64_t merge_bytes(uint32_t high, uint32_t low) { + return ((uint64_t)high) << 32 | low; +} + stack_frame_type stack_frame_type_enum(u2 frame_type) { if (0 <= frame_type && frame_type <= 63) { return SAME; @@ -214,10 +219,12 @@ ClassFile* ClassFile_load(const char* path) { case CONSTANT_Long: read_u4(&(cp->info.long_info.high_bytes), 1, file); read_u4(&(cp->info.long_info.low_bytes), 1, file); + i++; // Oracle docs: 4.4.5: 'In retrospect, making 8-byte constants take two constant pool entries was a poor choice.' break; case CONSTANT_Double: read_u4(&(cp->info.double_info.high_bytes), 1, file); read_u4(&(cp->info.double_info.low_bytes), 1, file); + i++; // Oracle docs: 4.4.5: 'In retrospect, making 8-byte constants take two constant pool entries was a poor choice.' break; case CONSTANT_NameAndType: read_u2(&(cp->info.name_and_type_info.name_index), 1, file); @@ -251,7 +258,7 @@ ClassFile* ClassFile_load(const char* path) { break; default: printf("unknown constant tag: %hhu\n", cp->tag); - // assert(0); + assert(0); } } @@ -331,4 +338,90 @@ void ClassFile_info(const ClassFile* cf) { "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); + + // constants + printf("Constant pool:\n"); + for (u2 i = 0; i < cf->constant_pool_count - 1; i++) { + char name[6]; + sprintf(name, "#%d", i + 1); + printf("%5s = %s\t", name, CONSTANT_TAGS_STRINGS[cf->constant_pool[i].tag]); + + uint64_t merged; + char* buffer; + + switch (cf->constant_pool[i].tag) { + case CONSTANT_Utf8: + printf("\t%s\n", cf->constant_pool[i].info.utf8_info.bytes); + break; + case CONSTANT_Integer: + printf("%d\n", cf->constant_pool[i].info.integer_info.bytes); + break; + case CONSTANT_Float: + printf("%f\n", (float)cf->constant_pool[i].info.float_info.bytes); + break; + 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); + 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); + break; + case CONSTANT_Class: + printf("\t#%hu\t\t\t// %s\n", cf->constant_pool[i].info.class_info.name_index, + cf->constant_pool[cf->constant_pool[i].info.class_info.name_index - 1].info.utf8_info.bytes); + break; + case CONSTANT_String: + printf("\t#%hu\t\t\t// %s\n", cf->constant_pool[i].info.string_info.string_index, + cf->constant_pool[cf->constant_pool[i].info.string_info.string_index - 1].info.utf8_info.bytes); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + buffer = ClassFile_resolve_Fieldref_Methodref_InterfaceMethodref(cf, cf->constant_pool[i].info.fieldref_info); + printf("#%hu.#%hu\t\t\t// %s", cf->constant_pool[i].info.fieldref_info.class_index, cf->constant_pool[i].info.fieldref_info.name_and_type_index, + buffer); + free(buffer); + break; + case CONSTANT_NameAndType: + buffer = ClassFile_resolve_NameAnyType(cf, cf->constant_pool[i].info.name_and_type_info); + printf("#%hu:#%hu\t\t\t// %s", cf->constant_pool[i].info.name_and_type_info.name_index, cf->constant_pool[i].info.name_and_type_info.descriptor_index, + buffer); + free(buffer); + default: + putchar('\n'); + } + } + + // interfaces + + // fields + + // methods +} + +char* ClassFile_resolve_NameAnyType(const ClassFile* cf, CONSTANT_NameAndType_info info) { + CONSTANT_Utf8_info name = cf->constant_pool[info.name_index - 1].info.utf8_info; + CONSTANT_Utf8_info descriptor = cf->constant_pool[info.descriptor_index - 1].info.utf8_info; + + char* buffer = (char*)malloc(name.length + descriptor.length + 2); + + sprintf(buffer, "%s:%s", name.bytes, descriptor.bytes); + + return buffer; +} + +char* ClassFile_resolve_Fieldref_Methodref_InterfaceMethodref(const ClassFile* cf, CONSTANT_Fieldref_info info) { + CONSTANT_Class_info class_info = cf->constant_pool[info.class_index - 1].info.class_info; + CONSTANT_NameAndType_info name_and_type_info = cf->constant_pool[info.name_and_type_index - 1].info.name_and_type_info; + + CONSTANT_Utf8_info class_name = cf->constant_pool[class_info.name_index - 1].info.utf8_info; + CONSTANT_Utf8_info name = cf->constant_pool[name_and_type_info.name_index - 1].info.utf8_info; + CONSTANT_Utf8_info descriptor = cf->constant_pool[name_and_type_info.descriptor_index - 1].info.utf8_info; + + char* buffer = (char*)malloc(class_name.length + name.length + descriptor.length + 3); + + sprintf(buffer, "%s.%s:%s\n", class_name.bytes, name.bytes, descriptor.bytes); + + return buffer; } \ No newline at end of file diff --git a/classfile.h b/classfile.h index 413e469..3aa2cf5 100644 --- a/classfile.h +++ b/classfile.h @@ -51,6 +51,28 @@ typedef enum { CONSTANT_Package = 20, } CONSTANT_TAGS; +static const char* CONSTANT_TAGS_STRINGS[] = {"", + "UTF-8", + "", + "Interger", + "Float", + "Long", + "Double", + "Class", + "String", + "Fieldref", + "Methodref", + "InterfaceMethodref", + "NameAndType", + "", + "", + "MethodHandle", + "MethodType", + "Dynamic", + "InvokeDynamic", + "Module", + "Package"}; + typedef struct { u2 name_index; } CONSTANT_Class_info; @@ -313,4 +335,7 @@ typedef struct { ClassFile* ClassFile_load(const char* path); void ClassFile_info(const ClassFile* cf); +char* ClassFile_resolve_Fieldref_Methodref_InterfaceMethodref(const ClassFile* cf, CONSTANT_Fieldref_info info); +char* ClassFile_resolve_NameAnyType(const ClassFile* cf, CONSTANT_NameAndType_info info); + #pragma pack() \ No newline at end of file