JVM开发笔记

笔 者最近对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;
}

////////////////////////////////////////////////////////////////////////////
[email protected] # gcc -o classreader classreader.c -w
[email protected] # ./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
[email protected] #

时间: 2024-11-13 08:05:49

JVM开发笔记的相关文章

Android开发笔记

一.Android的体系结构 1.1 体系结构 从下往上进行层概述: Linux内核层: 该层主要的作用是:对系统进行管理例如:驱动管理,电源管理,进程管理,安全管理,内存管理等等. 硬件抽象层: 该层主要的作用是:对Linux底层实现进行屏蔽,向上提供接口,该层不开源,主要是为了维护商家的利益,但是会影响系统的性能 Android对硬件的支持分为两层:一层是用户空间,另一层是内核空间, 用户空间存放的是:硬件抽象层,该层提供具体的访问细节 内核空间存放的是:Linux驱动程序,该层只是提供简单

JVM学习笔记:虚拟机的类加载机制

JVM类加载机制分两部分来总结: (1)类加载过程 (2)类加载器 一.JVM类加载过程 类的加载过程:加载 →连接(验证 → 准备 → 解析)→ 初始化. 类的生命周期:加载 →连接(验证 → 准备 → 解析)→ 初始化 → 使用 →  卸载. 1 加载 1.1 加载阶段要做的3件事情 通过一个类的全限定名来获取该类对应的二进制字节流. 将这个字节流所代表的静态存储结构转化为方法区的数据结构. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

JVM学习笔记(四)------内存调优【转】

转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM. 对JVM内存的系统级的调优主要的目的是减少GC的频率和Fu

张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231

原文:张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231 GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/DS3231 注意:不包含闹钟设置

Android开发笔记(一百零三)地图与定位SDK

集成地图SDK 国内常用的地图SDK就是百度和高德了,二者的用法大同小异,可按照官网上的开发指南一步步来.下面是我在集成地图SDK时遇到的问题说明: 1.点击基本地图功能选项,不能打开地图,弹出"key验证出错!请在AndroidManifest.xml文件中检查key设置的"的红色字提示.查看日志提示"galaxy lib host missing meta-data,make sure you know the right way to integrate galaxy&

微信订阅号开发笔记(二)

微信开发的流程其实很简单 o(∩_∩)o 哈哈!在微信网站的编辑操作 额,就不说了.虽然有人问过.下面是我的微信开发过程,简单记录下. 成为开发者 材料:1.自己的服务器资源,百度的BAE,新浪的SAE都不错. 2.懂那么点编程语言. 3.注册微信公众号. 上面的都有了之后,就可以自己动手开发了.哇咔咔,好兴奋.有木有. 在登录进去之后,怎么成为开发者?不知道,自己看去. 开始coding吧. 1.验证 if (! empty ( $_GET ['echostr'] ) && ! empt

微信订阅号开发笔记(三)

1.接收语音识别结果 if($msgType=="voice"){ //收到语音消息 //MediaId 语音消息媒体id,可以调用多媒体文件下载接口拉取数据. //Format 语音格式,如amr,speex等 $format = $postObj->Format; $mediaId = $postObj->MediaId; //开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段. //注:由于客户端缓

微信订阅号开发笔记(四)

1.创建菜单 //创建菜单 public function createMenu(){ $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="; $url.=$this->getacctoken(); //目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单.一级菜单最多4个汉字, //二级菜单最多7个汉字,多出来的部分将会以"..."代替.请注意,创建自定义菜单

Swift开发笔记

Swift开发笔记(一) 刚开始接触XCode时,整个操作逻辑与Android Studio.Visual Studio等是完全不同的,因此本文围绕IOS中控件的设置.事件的注册来简单的了解IOS开发 1.新建一个Xcode项目,项目目录大致如图: 2.在Main.storyboard添加控件 首先要显示右侧的工具栏(Utilities),之后选择显示Object Library,就可以找到常用的一些控件了,然后添加几个控件到界面中 3.将控件和ViewController进行关联 此时要将Ed