jvm开发笔记1---class文件解析器

 笔者最近对java虚拟机产生了浓厚的兴趣, 想了解下最简单的jvm是如何写出来的,于是看起了《java虚拟机规范》,这个规范如同intel开发手册一样,是每个jvm开发人员必须掌握的。 要想翻译执行java byte code, 首先得从java class文件中把Code属性解析出来才行。 在笔者看来, java的class文件结构着实比elf文件结构复杂很多,不过在复杂的结构, 只要耐心对照着手册中的结构一一解析即可, 经过几天的努力, 用c实现了一个class文件解析器,目前它只能解析手册中规定的jvm最基本的要解析出来的一些属性:Code, StackMapTable, LineNumberTable。当然, 随着开发的深入, 它会不断的健壮起来。

下面说说我在解析java class文件格式中碰到的几个问题, 帮助后面也要自己动手写解析器的朋友少走一点弯路:

1、为了提高解析性能, 使用了mmap讲class文件全部映射到内存中, 而不是每次解析都要使用read读磁盘文件。

int mmap_class_file(const char *class_file)
{
        struct stat f_stat;

        class_fd = open(class_file, O_RDONLY);
        if (class_fd == -1) {
                perror("open");
                return -1;
        }

        if (stat(class_file, &f_stat) == -1) {
                perror("stat");
                close(class_fd);
                return -1;
        }

        class_file_len = f_stat.st_size;
        printf("%s file len: %d\n", class_file, class_file_len);

        class_start_mem = mmap(NULL, class_file_len, PROT_READ, MAP_PRIVATE, class_fd, 0);
        if (!class_start_mem) {
                perror("mmap");
                close(class_fd);
                return -1;
        }
        printf("mmap %s at %p\n", class_file, class_start_mem);

        return 0;
}



2、java class使用的是big-endian字节序,x86使用的litte-endian字节序, 所以要转换一下,就是移位操作而已。

 

#define CLASS_READ_U4(s, p)                             \
        do {                                            \
                s = (((p >> 24) & 0x000000ff) |         \
                        ((p >> 8) & 0x0000ff00) |       \
                        ((p << 24) & 0xff000000) |      \
                        ((p << 8) & 0x00ff0000));       \
        } while (0);

#define CLASS_READ_U2(s, p)                             \
        do {                                            \
                s = (((p >> 8) & 0x00ff) |              \
                        ((p << 8) & 0xff00));           \
        } while (0);

#define CLASS_READ_U1(s, p)                             \
        do {                                            \
                s = p;                                  \
        } while (0);

   

 

 

例如读一个4字节内容:

 

        u4 class_magic;

        /* read class magic number. */
        CLASS_READ_U4(class_magic, (*(u4 *)p_mem))
        p_mem = 4;

        printf("magic: 0x%x\n", class_magic);
   






下面是全部的源码:

 

jvm.h

#ifndef JVM_H
#define JVM_H

#define JVM_CLASS_MAGIC                                 0xcafebabe

#define CLASS_READ_U4(s, p)                             \
        do {                                            \
                s = (((p >> 24) & 0x000000ff) |         \
                        ((p >> 8) & 0x0000ff00) |       \
                        ((p << 24) & 0xff000000) |      \
                        ((p << 8) & 0x00ff0000));       \
        } while (0);

#define CLASS_READ_U2(s, p)                             \
        do {                                            \
                s = (((p >> 8) & 0x00ff) |              \
                        ((p << 8) & 0xff00));           \
        } while (0);

#define CLASS_READ_U1(s, p)                             \
        do {                                            \
                s = p;                                  \
        } while (0);

#define CLASS_READ_STRING(s, p, len)                    \
        do {                                            \
                memcpy(s, p, len);                      \
        } while (0);

typedef unsigned int u4;
typedef unsigned short u2;
typedef unsigned char u1;

#define CONSTANT_Class                                  7
#define CONSTANT_Fieldref                               9
#define CONSTANT_Methodref                              10
#define CONSTANT_InterfaceMethodref                     11
#define CONSTANT_String                                 8
#define CONSTANT_Integer                                3
#define CONSTANT_Float                                  4
#define CONSTANT_Long                                   5
#define CONSTANT_Double                                 6
#define CONSTANT_NameAndType                            12
#define CONSTANT_Utf8                                   1
#define CONSTANT_MethodHandle                           15
#define CONSTANT_MethodType                             16
#define CONSTANT_InvokeDynamic                          18

#define ACC_PUBLIC                                      0x0001
#define ACC_FINAL                                       0x0010
#define ACC_SUPER                                       0x0020
#define ACC_INTERFACE                                   0x0200
#define ACC_ABSTRACT                                    0X0400
#define ACC_SYNTHETIC                                   0x1000
#define ACC_ANNOTATION                                  0x2000
#define ACC_ENUM                                        0x4000

#define METHOD_ACC_PUBLIC                               0x0001
#define METHOD_ACC_PRIVATE                              0x0002
#define METHOD_ACC_PROTECTED                            0x0004
#define METHOD_ACC_STATIC                               0x0008
#define METHOD_ACC_FINAL                                0x0010
#define METHOD_ACC_SYNCHRONIED                          0x0020
#define METHOD_ACC_BRIDGE                               0x0040
#define METHOD_ACC_VARARGS                              0x0080
#define METHOD_ACC_NATIVE                               0x0100
#define METHOD_ACC_ABSTRACT                             0x0400
#define METHOD_ACC_STRICT                               0x0800
#define METHOD_ACC_SYNTHETIC                            0x1000

#define ITEM_Top                                        0
#define ITEM_Integer                                    1
#define ITEM_Float                                      2
#define ITEM_Double                                     3
#define ITEM_Long                                       4
#define ITEM_Null                                       5
#define ITEM_UninitializedThis                          6
#define ITEM_Object                                     7
#define ITEM_Uninitialized                              8

struct constant_info_st {
        u2 index;
        u1 *base;
}__attribute__ ((packed));

struct cp_info {
        u1 tag;
        u1 info[];
}__attribute__ ((packed));

struct CONSTANT_Class_info {
        //u1 tag;
        u2 name_index;
}__attribute__ ((packed));

struct CONSTANT_Fieldref_info {
        //u1 tag;
        u2 class_index;
        u2 name_and_type_index;
}__attribute__ ((packed));

struct CONSTANT_Methodref_info {
        //u1 tag;
        u2 class_index;
        u2 name_and_type_index;
}__attribute__ ((packed));

struct CONSTANT_InterfaceMethodref_info {
        //u1 tag;
        u2 class_index;
        u2 name_and_type_inex;
}__attribute__ ((packed));

struct CONSTANT_String_info {
        //u1 tag;
        u2 string_index;
}__attribute__ ((packed));

struct CONSTANT_Integer_info {
        //u1 tag;
        u4 bytes;
}__attribute__ ((packed));

struct CONSTANT_Float_info {
        //u1 tag;
        u4 bytes;
}__attribute__ ((packed));

struct CONSTANT_Long_info {
        //u1 tag;
        u4 high_bytes;
        u4 low_bytes;
}__attribute__ ((packed));

struct CONSTANT_Double_info {
        //u1 tag;
        u4 high_bytes;
        u4 low_bytes;
}__attribute__ ((packed));

struct CONSTANT_NameAndType_info {
        //u1 tag;
        u2 name_index;
        u2 descriptor_index;
}__attribute__ ((packed));

struct CONSTANT_Utf8_info {
        //u1 tag;
        u2 length;
        u1 bytes[];
}__attribute__ ((packed));

struct CONSTANT_MethodHandle_info {
        //u1 tag;
        u1 reference_kind;
        u2 reference_index;
}__attribute__ ((packed));

struct CONSTANT_MethodType_info {
        //u1 tag;
        u2 descriptor_index;
}__attribute__ ((packed));

struct CONSTANT_InvokeDynamic_info {
        //u1 tag;
        u2 bootstrap_method_attr_index;
        u2 name_and_type_index;
}__attribute__ ((packed));

#endif



classreader.c:

/*
 * classreader.c - jvm class file parser.
 *
 * (c) wzt 2012         http://www.cloud-sec.org
 *
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "jvm.h"

static int class_fd;
static int class_file_len;
static void *class_start_mem;
static char *p_mem;
static struct constant_info_st *constant_info;

int mmap_class_file(const char *class_file)
{
        struct stat f_stat;

        class_fd = open(class_file, O_RDONLY);
        if (class_fd == -1) {
                perror("open");
                return -1;
        }

        if (stat(class_file, &f_stat) == -1) {
                perror("stat");
                close(class_fd);
                return -1;
        }

        class_file_len = f_stat.st_size;
        printf("%s file len: %d\n", class_file, class_file_len);

        class_start_mem = mmap(NULL, class_file_len, PROT_READ, MAP_PRIVATE, class_fd, 0);
        if (!class_start_mem) {
                perror("mmap");
                close(class_fd);
                return -1;
        }
        printf("mmap %s at %p\n", class_file, class_start_mem);

        return 0;
}

int mmap_exit(void)
{
        if (munmap(class_start_mem, class_file_len) == -1) {
                perror("munmap");
                return -1;
        }

        close(class_fd);
        return 0;
}

int parse_class_magic(void)
{
        u4 class_magic;

        /* read class magic number. */
        CLASS_READ_U4(class_magic, (*(u4 *)p_mem))
        p_mem = 4;

        printf("magic: 0x%x\n", class_magic);
        if (class_magic != JVM_CLASS_MAGIC) {
                printf("jvm class magic not match.\n");
                return -1;
        }
        printf("jvm class magic match: 0x%x\n", class_magic);
        return 0;
}

int parse_class_version(void)
{
        u2 minor_version, major_version;
        u2 constant_pool_count;

        /* read class minor_version. */
        CLASS_READ_U2(minor_version, (*(u2 *)p_mem))
        p_mem = 2;
        printf("jvm class minor_version: %d\n", minor_version);

        /* read class major_version. */
        CLASS_READ_U2(major_version, (*(u2 *)p_mem))
        p_mem = 2;
        printf("jvm class major_version: %d\n", major_version);

        return 0;
}

int parse_class_constant(void)
{
        u2 constant_pool_count;
        u1 constant_tag;
        u2 idx;

        printf("\n-----------parse contant pool count----------------------:\n\n");
        /* read constant_pool_count */
        CLASS_READ_U2(constant_pool_count, (*(u2 *)p_mem))
        p_mem = 2;
        printf("jvm constant_pool_count: %d\n", constant_pool_count);

        constant_info = (struct constant_info_st *)
                        malloc(sizeof(struct constant_info_st) *
                                constant_pool_count);
        if (!constant_info) {
                printf("Malloc failed.\n");
                return -1;
        }

        for (idx = 1; idx <= constant_pool_count - 1; idx ) {
                CLASS_READ_U1(constant_tag, (*(u1 *)p_mem))
                p_mem = 1;
                printf("- idx: - constant tag: %d\t", idx, (int)constant_tag);
                switch (constant_tag) {
                case CONSTANT_Fieldref:
                case CONSTANT_Methodref:
                case CONSTANT_InterfaceMethodref:
                {
                        struct CONSTANT_Methodref_info methodref_info;

                        CLASS_READ_U2(methodref_info.class_index, (*(u2 *)p_mem));
                        p_mem = 2;
                        assert(methodref_info.class_index > 0 &&
                                methodref_info.class_index < constant_pool_count);

                        CLASS_READ_U2(methodref_info.name_and_type_index, (*(u2 *)p_mem));
                        p_mem = 2;
                        assert(methodref_info.class_index > 0 &&
                                methodref_info.class_index < constant_pool_count);

                        printf("class_index: %d, name_and_type_index: %d\n",
                                methodref_info.class_index,
                                methodref_info.name_and_type_index);
                        break;
                }
                case CONSTANT_Class:
                {
                        struct CONSTANT_Class_info class_info;

                        CLASS_READ_U2(class_info.name_index, (*(u2 *)p_mem));
                        p_mem = 2;
                        assert(class_info.name_index > 0 &&
                                class_info.name_index < constant_pool_count);
                        printf("name_index: %d\n", class_info.name_index);
                        break;
                }
                case CONSTANT_String:
                {
                        struct CONSTANT_String_info string_info;

                        CLASS_READ_U2(string_info.string_index, (*(u2 *)p_mem));
                        p_mem = 2;
                        assert(string_info.string_index > 0 &&
                                string_info.string_index < constant_pool_count);
                        printf("string index: %d\n", string_info.string_index);
                        break;
                }
                case CONSTANT_Long:
                {
                        struct CONSTANT_Long_info long_info;

                        CLASS_READ_U2(long_info.high_bytes, (*(u2 *)p_mem));
                        p_mem = 2;

                        CLASS_READ_U2(long_info.low_bytes, (*(u2 *)p_mem));
                        p_mem = 2;

                        printf("high bytes: %d, low bytes: %d\n",
                                long_info.high_bytes, long_info.low_bytes);
                        break;
                }
                case CONSTANT_Integer:
                {
                        struct CONSTANT_Integer_info integer_info;

                        CLASS_READ_U4(integer_info.bytes, (*(u4 *)p_mem));
                        p_mem = 4;
                        printf("bytes: %d\n", integer_info.bytes);
                        break;
                }
                case CONSTANT_Float:
                {
                        struct CONSTANT_Float_info float_info;

                        CLASS_READ_U4(float_info.bytes, (*(u4 *)p_mem));
                        p_mem = 4;
                        printf("bytes: %d\n", float_info.bytes);
                        break;
                }
                case CONSTANT_Double:
                {
                        struct CONSTANT_Double_info double_info;

                        CLASS_READ_U4(double_info.high_bytes, (*(u4 *)p_mem));
                        p_mem = 4;

                        CLASS_READ_U4(double_info.low_bytes, (*(u4 *)p_mem));
                        p_mem = 4;
                        printf("high_bytes: %d, low_bytes: %d\n",
                                double_info.high_bytes, double_info.low_bytes);
                        break;
                }
                case CONSTANT_NameAndType:
                {
                        struct CONSTANT_NameAndType_info name_type_info;

                        CLASS_READ_U2(name_type_info.name_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        CLASS_READ_U2(name_type_info.descriptor_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        printf("name_index: %d, descriptor_index: %d\n",
                                name_type_info.name_index, name_type_info.descriptor_index);
                        break;
                }
                case CONSTANT_MethodHandle:
                {
                        struct CONSTANT_MethodHandle_info method_handle_info;

                        CLASS_READ_U1(method_handle_info.reference_kind, (*(u1 *)p_mem));
                        p_mem = 1;

                        CLASS_READ_U2(method_handle_info.reference_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        printf("reference_kind: %d, reference_index: %d\n",
                                method_handle_info.reference_kind,
                                method_handle_info.reference_index);
                        break;
                }
                case CONSTANT_MethodType:
                {
                        struct CONSTANT_MethodType_info method_type_info;

                        CLASS_READ_U2(method_type_info.descriptor_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        printf("descriptor_index %d\n", method_type_info.descriptor_index);
                        break;
                }
                case CONSTANT_InvokeDynamic:
                {
                        struct CONSTANT_InvokeDynamic_info invoke_dyc_info;

                        CLASS_READ_U2(invoke_dyc_info.bootstrap_method_attr_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        CLASS_READ_U2(invoke_dyc_info.name_and_type_index, (*(u2 *)p_mem));
                        p_mem = 2;

                        printf("bootstrap_method_attr_index: %d, name_and_type_index: %d\n",
                                invoke_dyc_info.bootstrap_method_attr_index,
                                invoke_dyc_info.name_and_type_index);
                        break;
                }
                case CONSTANT_Utf8:
                {
                        u2 len;
                        char *buf;

                        CLASS_READ_U2(len, (*(u2 *)p_mem));
                        p_mem = 2;

                        buf = malloc(len 1);
                        buf[len] = '\0';
                        assert(buf != NULL);

                        memcpy(buf, p_mem, len);
                        printf("len: %d\t%s\n", len, buf);
                        p_mem = len;

                        constant_info[idx].index = idx;
                        constant_info[idx].base = buf;
                        break;
                }
                default:
                        ;
                }
        }
        printf("\n");
/*
        for (idx = 1; idx <= constant_pool_count - 1; idx )
                printf("%d: %s\n", constant_info[idx].index, constant_info[idx].base);
*/
        return 0;

out:
        mmap_exit();
        return -1;
}

int parse_class_access_flag(void)
{
        u2 access_flag;

        /* read class access flag. */
        CLASS_READ_U2(access_flag, (*(u2 *)p_mem))
        p_mem = 2;

        printf("access_flag: 0x%x\n", access_flag);
        return 0;
}
int parse_class_this_super(void)
{
        u2 this_class;
        u2 super_class;

        CLASS_READ_U2(this_class, (*(u2 *)p_mem))
        p_mem = 2;

        CLASS_READ_U2(super_class, (*(u2 *)p_mem))
        p_mem = 2;

        printf("this_class: %d\tsuper_class: %d\n\n", this_class, super_class);
        return 0;
}

int parse_class_interface(void)
{
        u2 interfaces_count;
        u2 idx, index;

        CLASS_READ_U2(interfaces_count, (*(u2 *)p_mem))
        p_mem = 2;
        printf("interfaces_count: %d\n", interfaces_count);

        for (idx = 0; idx < interfaces_count; idx ) {
                CLASS_READ_U2(index, (*(u2 *)p_mem));
                p_mem = 2;
                printf("index: %d\n", index);
        }

        return 0;
}

int parse_class_filed(void)
{
        u2 fileds_count;
        u2 idx;

        CLASS_READ_U2(fileds_count, (*(u2 *)p_mem))
        p_mem = 2;
        printf("filed_count: %d\n", fileds_count);

        return 0;
}
int __parse_exception_table(int len)
{
        u2 start_pc, end_pc;
        u2 handler_pc, catch_type;
        u2 idx;

        for (idx = 0; idx < len; idx ) {
                CLASS_READ_U2(start_pc, (*(u2 *)p_mem))
                p_mem = 2;
                printf("start_pc: %d\n", start_pc);

                CLASS_READ_U2(end_pc, (*(u2 *)p_mem))
                p_mem = 2;
                printf("end_pc: %d\n", end_pc);

                CLASS_READ_U2(handler_pc, (*(u2 *)p_mem))
                p_mem = 2;
                printf("handler_pc: %d\n", handler_pc);

                CLASS_READ_U2(catch_type, (*(u2 *)p_mem))
                p_mem = 2;
                printf("catch_type: %d\n", catch_type);
        }

        return 0;
}

int __parse_line_number_table(void)
{
        u4 attribute_length;
        u2 line_number_table_length;
        u2 start_pc, line_number;
        u2 idx;

        CLASS_READ_U4(attribute_length, (*(u4 *)p_mem))
        p_mem = 4;
        printf("\t\tattribute_length: %d\n", attribute_length);

        CLASS_READ_U2(line_number_table_length, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\t\tline_number_table_length: %d\n", line_number_table_length);

        for (idx = 0; idx < line_number_table_length; idx ) {
                CLASS_READ_U2(start_pc, (*(u2 *)p_mem))
                p_mem = 2;
                printf("\t\tstart_pc: %d\n", start_pc);

                CLASS_READ_U2(line_number, (*(u2 *)p_mem))
                p_mem = 2;
                printf("\t\tline_number: %d\n", line_number);
        }

        return 0;
}

int __parse_verification_type_info(u1 number)
{
        u1 idx, tag;

        for (idx = 0; idx < number; idx ) {
                CLASS_READ_U1(tag, (*(u1 *)p_mem))
                p_mem = 1;
                printf("\t\ttag: %d\n", tag);
                switch (tag) {
                case ITEM_Top:
                        printf("\t\tITEM_Top.\n");
                        break;
                case ITEM_Integer:
                        printf("\t\tITEM_Integer.\n");
                        break;
                case ITEM_Float:
                        printf("\t\tITEM_float.\n");
                        break;
                case ITEM_Double:
                        printf("\t\tITEM_Double.\n");
                        break;
                case ITEM_Long:
                        printf("\t\tITEM_Long.\n");
                        break;
                case ITEM_Null:
                        printf("\t\tITEM_Long.\n");
                        break;
                case ITEM_UninitializedThis:
                        printf("\t\tITEM_UninitializedThis.\n");
                        break;
                case ITEM_Object:
                {
                        u2 cpool_index;

                        printf("\t\tITEM_Object.\n");
                        CLASS_READ_U2(cpool_index, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\tcpool_index: %d\n", cpool_index);
                        break;
                }
                case ITEM_Uninitialized:
                {
                        u2 offset;

                        printf("\t\tITEM_Uninitialized.\n");
                        CLASS_READ_U2(offset, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\toffset: %d\n", offset);
                        break;
                }
                default:
                        return -1;
                }
        }

        return 0;
}

int __parse_stack_map_frame(u2 number)
{
        u1 frame_type;
        u1 offset_delta;
        u2 idx;
        u1 stack_num;
        u1 locals_num;
        u1 local_idx;

        for (idx = 0; idx < number; idx ) {
                CLASS_READ_U1(frame_type, (*(u1 *)p_mem))
                p_mem = 1;
                printf("\t\tframe_type: %d\n", frame_type);

                if (frame_type >= 0 && frame_type <= 63) {
                        offset_delta = frame_type;
                        printf("\t\tsame_frame\toffset_delta: %d\n", offset_delta);
                }
                if (frame_type >= 64 && frame_type <= 127) {
                        offset_delta = frame_type - 64;
                        stack_num = 1;
                        printf("\t\tsame_locals_l_stack_item_frame\toffset_delta: %d\n",
                                offset_delta);
                        __parse_verification_type_info(stack_num);
                }
                if (frame_type == 247) {
                        stack_num = 1;
                        CLASS_READ_U2(offset_delta, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\tsame_locals_l_stack_item_frame_extendedn\toffset_delta: %d\n",
                                offset_delta);
                        __parse_verification_type_info(stack_num);
                }
                if (frame_type >= 248 && frame_type <= 250) {
                        CLASS_READ_U2(offset_delta, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\tsame_locals_l_stack_item_frame_extended\toffset_delta: %d\n",
                                offset_delta);
                }
                if (frame_type == 251) {
                        CLASS_READ_U2(offset_delta, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\tsame_frame_extended\toffset_delta: %d\n", offset_delta);
                }
                if (frame_type >= 252 && frame_type <= 254) {
                        CLASS_READ_U2(offset_delta, (*(u2 *)p_mem))
                        p_mem = 2;
                        printf("\t\tappend_frame\toffset_delta: %d\n", offset_delta);

                        locals_num = frame_type - 251;
                        printf("\t\tlocals_num: %d\n", locals_num);

                        __parse_verification_type_info(locals_num);
                }
        }
}
int __parse_stack_map_table(void)
{
        u4 attribute_length;
        u2 number_of_entries;
        u2 idx;

        CLASS_READ_U4(attribute_length, (*(u4 *)p_mem))
        p_mem = 4;
        printf("\t\tattribute_length: %d\n", attribute_length);

        CLASS_READ_U2(number_of_entries, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\t\tnumber_of_entries: %d\n", number_of_entries);

        __parse_stack_map_frame(number_of_entries);

        return 0;
}
/* attribute_name_index has been parsed before. */
int parse_code_attribute(void)
{
        u2 attribute_name_index;
        u4 attribute_length;
        u2 max_stack;
        u2 max_locals;
        u4 code_length;
        u1 *code;
        u2 exception_table_length;
        u2 attributes_count;
        u2 idx;

        CLASS_READ_U4(attribute_length, (*(u4 *)p_mem))
        p_mem = 4;
        printf("\tattribute_length: %d\n", attribute_length);

        CLASS_READ_U2(max_stack, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\tmax_stack: %d\n", max_stack);

        CLASS_READ_U2(max_locals, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\tmax_locals: %d\n", max_locals);

        CLASS_READ_U4(code_length, (*(u4 *)p_mem))
        p_mem = 4;
        printf("\tcode_length: %d\n", code_length);

        code = (u1 *)malloc(code_length 1);
        if (!code) {
                printf("Malloc failed.\n");
                return -1;
        }
        memcpy(code, p_mem, code_length);
        code[code_length] = '\0';
        p_mem = code_length;

        CLASS_READ_U2(exception_table_length, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\texception_table_length: %d\n", exception_table_length);

        __parse_exception_table(exception_table_length);

        CLASS_READ_U2(attributes_count, (*(u2 *)p_mem))
        p_mem = 2;
        printf("\tattributes_count: %d\n", attributes_count);

        /* parse attributes */
        for (idx = 0; idx < attributes_count; idx ) {
                CLASS_READ_U2(attribute_name_index, (*(u2 *)p_mem))
                p_mem = 2;
                printf("\tidx: %d attribute_name_index: %d", idx 1, attribute_name_index);

                if (!strcmp(constant_info[attribute_name_index].base, "LineNumberTable")) {
                        printf("\n\tparse LineNumberTable:\n");
                        __parse_line_number_table();
                }
                if (!strcmp(constant_info[attribute_name_index].base, "StackMapTable")) {
                        printf("\n\tparse StackMapTable:\n");
                        __parse_stack_map_table();
                }
                if (!strcmp(constant_info[attribute_name_index].base, "LocalVariableTable")) {
                        ;
                }
                if (!strcmp(constant_info[attribute_name_index].base, "LocalVariableTypeTable")) {
                        ;
                }
                if (!strcmp(constant_info[attribute_name_index].base, "StackMapTable")) {
                        ;
                }
        }

        return 0;
}

int parse_class_method(void)
{
        u2 method_count;
        u2 access_flags, name_index;
        u2 descriptor_index, attributes_count;
        u2 idx;

        printf("\n---------------parse class method-------------------------:\n\n");
        CLASS_READ_U2(method_count, (*(u2 *)p_mem))
        p_mem = 2;
        printf("method_count: %d\n", method_count);

        for (idx = 0; idx < method_count; idx ) {
                CLASS_READ_U2(access_flags, (*(u2 *)p_mem))
                p_mem = 2;
                printf("access_flags: 0x%x\n", access_flags);

                CLASS_READ_U2(name_index, (*(u2 *)p_mem))
                p_mem = 2;
                printf("name_index: %d\n", name_index);

                CLASS_READ_U2(descriptor_index, (*(u2 *)p_mem))
                p_mem = 2;
                printf("descriptor_index: %d\n", descriptor_index);

                CLASS_READ_U2(attributes_count, (*(u2 *)p_mem))
                p_mem = 2;
                printf("attributes_count: %d\n\n", attributes_count);

                /* parse attributes */
                CLASS_READ_U2(name_index, (*(u2 *)p_mem))
                p_mem = 2;
                printf("attritbutes name_index: %d\n", name_index);

                if (!strcmp(constant_info[name_index].base, "Code")) {
                        printf("parse code attribute:\n");
                        parse_code_attribute();
                }
                if (!strcmp(constant_info[name_index].base, "Exceptions")) {
                        ;
                }
                if (!strcmp(constant_info[name_index].base, "Signature")) {
                        ;
                }
        }

        return 0;
}

int jvm_parse_class_file(const char *class_file)
{
        assert(class_file != NULL);
        if (mmap_class_file(class_file) == -1)
                return -1;

        p_mem = class_start_mem;
        if (parse_class_magic() == -1)
                goto out;

        if (parse_class_version() == -1)
                goto out;

        if (parse_class_constant() == -1)
                goto out;

        if (parse_class_access_flag() == -1)
                goto out;

        if (parse_class_this_super() == -1)
                goto out;

        if (parse_class_interface() == -1)
                goto out;

        if (parse_class_filed() == -1)
                goto out;

        if (parse_class_method() == -1)
                goto out;

        mmap_exit();
        return 0;
out:
        mmap_exit();
        return -1;
}

void jvm_usage(const char *proc)
{
        fprintf(stdout, "usage: %s \n", proc);
}

int main(int argc, char **argv)
{
        if (argc == 1) {
                jvm_usage(argv[0]);
                return 0;
        }

        jvm_parse_class_file(argv[1]);

        return 0;
}.h>.h>.h>.h>.h>.h>

 

 

root@localhost.localdomain # gcc -o classreader classreader.c -w
root@localhost.localdomain # ./classreader test.class
test.class file len: 462
mmap test.class at 0x2b0b78fa5000
magic: 0xcafebabe
jvm class magic match: 0xcafebabe
jvm class minor_version: 0
jvm class major_version: 50

-----------parse contant pool count----------------------:

jvm constant_pool_count: 30
- idx:  1 constant tag: 10      class_index: 6, name_and_type_index: 16
- idx:  2 constant tag: 9       class_index: 17, name_and_type_index: 18
- idx:  3 constant tag: 8       string index: 19
- idx:  4 constant tag: 10      class_index: 20, name_and_type_index: 21
- idx:  5 constant tag: 7       name_index: 22
- idx:  6 constant tag: 7       name_index: 23
- idx:  7 constant tag: 1       len: 6  
- idx:  8 constant tag: 1       len: 3  ()V
- idx:  9 constant tag: 1       len: 4  Code
- idx: 10 constant tag: 1       len: 15 LineNumberTable
- idx: 11 constant tag: 1       len: 4  main
- idx: 12 constant tag: 1       len: 22 ([Ljava/lang/String;)V
- idx: 13 constant tag: 1       len: 13 StackMapTable
- idx: 14 constant tag: 1       len: 10 SourceFile
- idx: 15 constant tag: 1       len: 9  test.java
- idx: 16 constant tag: 12      name_index: 7, descriptor_index: 8
- idx: 17 constant tag: 7       name_index: 24
- idx: 18 constant tag: 12      name_index: 25, descriptor_index: 26
- idx: 19 constant tag: 1       len: 4  hehe
- idx: 20 constant tag: 7       name_index: 27
- idx: 21 constant tag: 12      name_index: 28, descriptor_index: 29
- idx: 22 constant tag: 1       len: 4  test
- idx: 23 constant tag: 1       len: 16 java/lang/Object
- idx: 24 constant tag: 1       len: 16 java/lang/System
- idx: 25 constant tag: 1       len: 3  out
- idx: 26 constant tag: 1       len: 21 Ljava/io/PrintStream;
- idx: 27 constant tag: 1       len: 19 java/io/PrintStream
- idx: 28 constant tag: 1       len: 7  println
- idx: 29 constant tag: 1       len: 21 (Ljava/lang/String;)V

access_flag: 0x21
this_class: 5   super_class: 6

interfaces_count: 0
filed_count: 0

---------------parse class method-------------------------:

method_count: 2
access_flags: 0x1
name_index: 7
descriptor_index: 8
attributes_count: 1

attritbutes name_index: 9
parse code attribute:
        attribute_length: 29
        max_stack: 1
        max_locals: 1
        code_length: 5
        exception_table_length: 0
        attributes_count: 1
        idx: 1 attribute_name_index: 10
        parse LineNumberTable:
                attribute_length: 6
                line_number_table_length: 1
                start_pc: 0
                line_number: 5
access_flags: 0x9
name_index: 11
descriptor_index: 12
attributes_count: 1

attritbutes name_index: 9
parse code attribute:
        attribute_length: 77
        max_stack: 2
        max_locals: 2
        code_length: 24
        exception_table_length: 0
        attributes_count: 2
        idx: 1 attribute_name_index: 10
        parse LineNumberTable:
                attribute_length: 22
                line_number_table_length: 5
                start_pc: 0
                line_number: 7
                start_pc: 2
                line_number: 9
                start_pc: 9
                line_number: 10
                start_pc: 17
                line_number: 9
                start_pc: 23
                line_number: 11
        idx: 2 attribute_name_index: 13
        parse StackMapTable:
                attribute_length: 7
                number_of_entries: 2
                frame_type: 252
                append_frame    offset_delta: 4
                locals_num: 1
                tag: 1
                ITEM_Integer.
                frame_type: 18
                same_frame      offset_delta: 18
root@localhost.localdomain #

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值