Created
August 6, 2012 14:55
-
-
Save shinaisan/3275010 to your computer and use it in GitHub Desktop.
C program that analyzes a constant pool in a Java class file and prints out its contents.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* -*- mode: c; coding: utf-8-dos; indent-tabs-mode: nil; c-basic-offset: 4 */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <stddef.h> | |
| #include <limits.h> | |
| #include <arpa/inet.h> | |
| #pragma pack(1) | |
| typedef enum { | |
| CONSTANT_Class = 7, | |
| CONSTANT_Fieldref = 9, | |
| CONSTANT_Methodref = 10, | |
| CONSTANT_InterfaceMethodref = 11, | |
| CONSTANT_String = 8, | |
| CONSTANT_Integer = 3, | |
| CONSTANT_Float = 4, | |
| CONSTANT_Long = 5, | |
| CONSTANT_Double = 6, | |
| CONSTANT_NameAndType = 12, | |
| CONSTANT_Utf8 = 1, | |
| CONSTANT_MethodHandle = 15, | |
| CONSTANT_MethodType = 16, | |
| CONSTANT_InvokeDynamic = 18, | |
| } constant_type_t; | |
| typedef struct _CLASS_FILE_1 { | |
| uint32_t magic; | |
| uint16_t minor_version; | |
| uint16_t major_version; | |
| uint16_t constant_pool_count; | |
| } CLASS_FILE_1; | |
| typedef struct _CONSTANT_CLASS_INFO { | |
| uint8_t tag; | |
| uint16_t name_index; | |
| } CONSTANT_CLASS_INFO; | |
| typedef struct _CONSTANT_FIELDREF_INFO { | |
| uint8_t tag; | |
| uint16_t class_index; | |
| uint16_t name_and_type_index; | |
| } CONSTANT_FIELDREF_INFO; | |
| typedef struct _CONSTANT_METHODREF_INFO { | |
| uint8_t tag; | |
| uint16_t class_index; | |
| uint16_t name_and_type_index; | |
| } CONSTANT_METHODREF_INFO; | |
| typedef struct _CONSTANT_INTERFACEMETHODREF_INFO { | |
| uint8_t tag; | |
| uint16_t class_index; | |
| uint16_t name_and_type_index; | |
| } CONSTANT_INTERFACEMETHODREF_INFO; | |
| typedef struct _CONSTANT_STRING_INFO { | |
| uint8_t tag; | |
| uint16_t string_index; | |
| } CONSTANT_STRING_INFO; | |
| typedef struct _CONSTANT_INTEGER_INFO { | |
| uint8_t tag; | |
| uint32_t bytes; | |
| } CONSTANT_INTEGER_INFO; | |
| typedef struct _CONSTANT_FLOAT_INFO { | |
| uint8_t tag; | |
| uint32_t bytes; | |
| } CONSTANT_FLOAT_INFO; | |
| typedef struct _CONSTANT_LONG_INFO { | |
| uint8_t tag; | |
| uint32_t high_bytes; | |
| uint32_t low_bytes; | |
| } CONSTANT_LONG_INFO; | |
| typedef struct _CONSTANT_DOUBLE_INFO { | |
| uint8_t tag; | |
| uint32_t high_bytes; | |
| uint32_t low_bytes; | |
| } CONSTANT_DOUBLE_INFO; | |
| typedef struct _CONSTANT_NAMEANDTYPE_INFO { | |
| uint8_t tag; | |
| uint16_t name_index; | |
| uint16_t descriptor_index; | |
| } CONSTANT_NAMEANDTYPE_INFO; | |
| typedef struct _CONSTANT_UTF8_INFO { | |
| uint8_t tag; | |
| uint16_t length; /* The number of bytes. */ | |
| uint8_t bytes[]; | |
| } CONSTANT_UTF8_INFO; | |
| typedef struct _CONSTANT_METHODHANDLE_INFO { | |
| uint8_t tag; | |
| uint8_t reference_kind; | |
| uint8_t reference_index; | |
| } CONSTANT_METHODHANDLE_INFO; | |
| typedef struct _CONSTANT_METHODTYPE_INFO { | |
| uint8_t tag; | |
| uint16_t descriptor_index; | |
| } CONSTANT_METHODTYPE_INFO; | |
| typedef struct _CONSTANT_INVOKEDYNAMIC_INFO { | |
| uint8_t tag; | |
| uint16_t bootstrap_method_attr_index; | |
| uint16_t name_and_type_index; | |
| } CONSTANT_INVOKEDYNAMIC_INFO; | |
| int get_constant_info_size(uint8_t *bytes) { | |
| uint8_t tag; | |
| int size = 0; | |
| tag = *bytes; | |
| switch (tag) { | |
| case CONSTANT_Class: | |
| size = sizeof(CONSTANT_CLASS_INFO); | |
| break; | |
| case CONSTANT_Fieldref: | |
| size = sizeof(CONSTANT_FIELDREF_INFO); | |
| break; | |
| case CONSTANT_Methodref: | |
| size = sizeof(CONSTANT_METHODREF_INFO); | |
| break; | |
| case CONSTANT_InterfaceMethodref: | |
| size = sizeof(CONSTANT_INTERFACEMETHODREF_INFO); | |
| break; | |
| case CONSTANT_String: | |
| size = sizeof(CONSTANT_STRING_INFO); | |
| break; | |
| case CONSTANT_Integer: | |
| size = sizeof(CONSTANT_INTEGER_INFO); | |
| break; | |
| case CONSTANT_Float: | |
| size = sizeof(CONSTANT_FLOAT_INFO); | |
| break; | |
| case CONSTANT_Long: | |
| size = sizeof(CONSTANT_LONG_INFO); | |
| break; | |
| case CONSTANT_Double: | |
| size = sizeof(CONSTANT_DOUBLE_INFO); | |
| break; | |
| case CONSTANT_NameAndType: | |
| size = sizeof(CONSTANT_NAMEANDTYPE_INFO); | |
| break; | |
| case CONSTANT_Utf8: | |
| { | |
| CONSTANT_UTF8_INFO *putf8 = (CONSTANT_UTF8_INFO *)bytes; | |
| int n = ntohs(putf8->length); | |
| size = sizeof(CONSTANT_UTF8_INFO) + n; | |
| } | |
| break; | |
| case CONSTANT_MethodHandle: | |
| size = sizeof(CONSTANT_METHODHANDLE_INFO); | |
| break; | |
| case CONSTANT_MethodType: | |
| size = sizeof(CONSTANT_METHODTYPE_INFO); | |
| break; | |
| case CONSTANT_InvokeDynamic: | |
| size = sizeof(CONSTANT_INVOKEDYNAMIC_INFO); | |
| break; | |
| default: | |
| size = 0; | |
| break; | |
| } | |
| return size; | |
| } | |
| /* The memory pointed to by (*pbuf) must be freed manually after use. */ | |
| long read_class_file(FILE *fp, uint8_t **pbuf) { | |
| long buf_size = 0; | |
| fpos_t file_size = 0; | |
| long size_read = 0; | |
| if (fseek(fp, 0, SEEK_END) != 0) { | |
| return 0; | |
| } | |
| file_size = ftell(fp); | |
| if (file_size >= (fpos_t)INT_MAX) { | |
| return 0; | |
| } | |
| if (fseek(fp, 0, SEEK_SET) != 0) { | |
| return 0; | |
| } | |
| buf_size = (long)file_size; | |
| *pbuf = malloc(buf_size); | |
| if (*pbuf == NULL) { | |
| return 0; | |
| } | |
| memset(*pbuf, 0, buf_size); | |
| size_read = fread(*pbuf, 1, buf_size, fp); | |
| if (size_read < buf_size) { | |
| free(*pbuf); | |
| *pbuf = NULL; | |
| return 0; | |
| } | |
| return size_read; | |
| } | |
| int get_constant_pool(CLASS_FILE_1 *class_file_bytes, uint8_t ***ppointers) { | |
| int i; | |
| int cpcnt; | |
| uint8_t *current_bytes; | |
| cpcnt = class_file_bytes->constant_pool_count; | |
| cpcnt = ntohs(cpcnt); | |
| if (cpcnt <= 1) { | |
| return cpcnt; | |
| } | |
| *ppointers = (uint8_t **)malloc(cpcnt * sizeof(**ppointers)); | |
| (*ppointers)[0] = NULL; | |
| current_bytes = (uint8_t *)class_file_bytes; | |
| current_bytes += sizeof(*class_file_bytes); | |
| for (i = 1; i < cpcnt; i++) { | |
| int size; | |
| (*ppointers)[i] = current_bytes; | |
| size = get_constant_info_size(current_bytes); | |
| current_bytes += size; | |
| } | |
| return cpcnt; | |
| } | |
| void print_constant_info(uint8_t *bytes) { | |
| uint8_t tag; | |
| tag = *bytes; | |
| switch (tag) { | |
| case CONSTANT_Class: | |
| { | |
| CONSTANT_CLASS_INFO *p = (CONSTANT_CLASS_INFO *)bytes; | |
| printf("Class: tag=%#x, name_index=%#x\n", p->tag, ntohs(p->name_index)); | |
| } | |
| break; | |
| case CONSTANT_Fieldref: | |
| { | |
| CONSTANT_FIELDREF_INFO *p = (CONSTANT_FIELDREF_INFO *)bytes; | |
| printf("Fieldref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n", | |
| p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index)); | |
| } | |
| break; | |
| case CONSTANT_Methodref: | |
| { | |
| CONSTANT_METHODREF_INFO *p = (CONSTANT_METHODREF_INFO *)bytes; | |
| printf("Methodref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n", | |
| p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index)); | |
| } | |
| break; | |
| case CONSTANT_InterfaceMethodref: | |
| { | |
| CONSTANT_INTERFACEMETHODREF_INFO *p = (CONSTANT_INTERFACEMETHODREF_INFO *)bytes; | |
| printf("InterfaceMethodref: tag=%#x, class_index=%#x, name_and_type_index=%#x\n", | |
| p->tag, ntohs(p->class_index), ntohs(p->name_and_type_index)); | |
| } | |
| break; | |
| case CONSTANT_String: | |
| { | |
| CONSTANT_STRING_INFO *p = (CONSTANT_STRING_INFO *)bytes; | |
| printf("String: tag=%#x, string_index=%#x\n", p->tag, ntohs(p->string_index)); | |
| } | |
| break; | |
| case CONSTANT_Integer: | |
| { | |
| CONSTANT_INTEGER_INFO *p = (CONSTANT_INTEGER_INFO *)bytes; | |
| printf("Integer: tag=%#x, bytes=%#x\n", p->tag, p->bytes); | |
| } | |
| break; | |
| case CONSTANT_Float: | |
| { | |
| CONSTANT_FLOAT_INFO *p = (CONSTANT_FLOAT_INFO *)bytes; | |
| printf("Float: tag=%#x, bytes=%#x\n", p->tag, p->bytes); | |
| } | |
| break; | |
| case CONSTANT_Long: | |
| { | |
| CONSTANT_LONG_INFO *p = (CONSTANT_LONG_INFO *)bytes; | |
| printf("Long: tag=%#x, high_bytes=%#x, low_bytes=%#x\n", | |
| p->tag, p->high_bytes, p->low_bytes); | |
| } | |
| break; | |
| case CONSTANT_Double: | |
| { | |
| CONSTANT_DOUBLE_INFO *p = (CONSTANT_DOUBLE_INFO *)bytes; | |
| printf("Long: tag=%#x, high_bytes=%#x, low_bytes=%#x\n", | |
| p->tag, p->high_bytes, p->low_bytes); | |
| } | |
| break; | |
| case CONSTANT_NameAndType: | |
| { | |
| CONSTANT_NAMEANDTYPE_INFO *p = (CONSTANT_NAMEANDTYPE_INFO *)bytes; | |
| printf("NameAndType: tag=%#x, name_index=%#x, descriptor_index=%#x\n", | |
| p->tag, ntohs(p->name_index), ntohs(p->descriptor_index)); | |
| } | |
| break; | |
| case CONSTANT_Utf8: | |
| { | |
| CONSTANT_UTF8_INFO *p = (CONSTANT_UTF8_INFO *)bytes; | |
| int n = ntohs(p->length); | |
| int i; | |
| uint8_t *str = &(p->bytes[0]); | |
| printf("Utf8: tag=%#x, bytes="); | |
| for (i = 0; i < n; i++) { | |
| char c = (char)str[i]; | |
| if (isprint(c)) { | |
| printf("%c ", c); | |
| } else { | |
| printf("%02x ", c); | |
| } | |
| } | |
| printf("\n"); | |
| } | |
| break; | |
| case CONSTANT_MethodHandle: | |
| { | |
| CONSTANT_METHODHANDLE_INFO *p = (CONSTANT_METHODHANDLE_INFO *)bytes; | |
| printf("MethodHandle: tag=%#x, reference_kind=%#x, reference_index=%#x\n", | |
| p->tag, p->reference_kind, p->reference_index); | |
| } | |
| break; | |
| case CONSTANT_MethodType: | |
| { | |
| CONSTANT_METHODTYPE_INFO *p = (CONSTANT_METHODTYPE_INFO *)bytes; | |
| printf("MethodType: tag=%#x, descriptor_index=%#x\n", p->tag, ntohs(p->descriptor_index)); | |
| } | |
| break; | |
| case CONSTANT_InvokeDynamic: | |
| { | |
| CONSTANT_INVOKEDYNAMIC_INFO *p = (CONSTANT_INVOKEDYNAMIC_INFO *)bytes; | |
| printf("InvokeDynamic: tag=%#x, bootstrap_method_attr_index=%#x, name_and_type_index=%#x\n", | |
| p->tag, ntohs(p->bootstrap_method_attr_index), ntohs(p->name_and_type_index)); | |
| } | |
| break; | |
| default: | |
| { | |
| printf("Unknown: tag=%#x\n", tag); | |
| } | |
| break; | |
| } | |
| } | |
| void print_constant_pool(uint8_t **cppointers, int cpcnt) { | |
| int i; | |
| for (i = 1; i < cpcnt; i++) { | |
| uint8_t *p = cppointers[i]; | |
| printf("------------------------\n[%03x] ", i); | |
| print_constant_info(p); | |
| printf("------------------------\n"); | |
| } | |
| } | |
| int main(int argc, char *argv[]) { | |
| char *class_file_name = NULL; | |
| FILE *class_file = NULL; | |
| uint8_t *class_file_bytes = NULL; | |
| long class_file_size = 0; | |
| uint8_t **cppointers = NULL; | |
| int cpcnt = 0; | |
| int exitstat = 0; | |
| if (argc < 2) { | |
| printf("[USAGE] %s <class-file-name>\n", argv[0]); | |
| goto END; | |
| } | |
| class_file_name = argv[1]; | |
| class_file = fopen(class_file_name, "rb"); | |
| if (class_file == NULL) { | |
| exitstat = -1; | |
| goto END; | |
| } | |
| class_file_size = read_class_file(class_file, &class_file_bytes); | |
| if (class_file_bytes == NULL) { | |
| exitstat = -1; | |
| goto END; | |
| } | |
| cpcnt = get_constant_pool((CLASS_FILE_1 *)class_file_bytes, &cppointers); | |
| if (cppointers == NULL) { | |
| exitstat = -1; | |
| goto END; | |
| } | |
| print_constant_pool(cppointers, cpcnt); | |
| END: | |
| if (class_file != NULL) { | |
| fclose(class_file); | |
| } | |
| if (class_file_bytes != NULL) { | |
| free(class_file_bytes); | |
| } | |
| if (cppointers != NULL) { | |
| free(cppointers); | |
| } | |
| return exitstat; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment