解析class文件-方法
来源:互联网 发布:帝国cms 提交表单 编辑:程序博客网 时间:2024/06/06 13:56
目前完成了对class文件方法的解析。注意,无论是对接口,域,方法,还是对常量池的解析,目前所做的工作都是试验性的。
我只是按照class格式分析,至于解析结果如何保存为合理,则到开发执行引擎时才能清楚。此次修改也调整了一些其它代码,故此贴出完整代码。
ClassFileParser.h
#pragma once#include "util.h"//u1,u2,u4分别代表1字节,2字节,4字节的无符号数。需要按照编译平台准确定义。//JVM规范中大量使用它们描述class文件格式。typedef unsigned int u4;typedef unsigned short u2;typedef unsigned char u1;//根据所在的编译平台,定义合适的4字节float,8字节long,8字节双精度浮点数typedef float JFLOAT;typedef long long JLONG;typedef double JDOUBLE;struct cp_info;struct field_info;struct method_info;struct attribute_info;#pragma pack(1)/* Class文件结构,参考JVM规范//class文件的结构,直接明了。//class文件中u2,u4,u8的存储都是big-endian顺序(高字节在前,低字节在后)ClassFile{u4 magic;u2 minor_verison;u2 major_version;u2 constant_pool_count; //按照JVM规范,此值cp_count等于cp_info的记录数+1cp_info constant_pool[constant_pool_count-1];u2 access_flags;u2 this_class;u2 super_class;u2 interfaces_count;u2 interfaces[interfaces_count];u2 fields_count;field_info fields[fields_count];u2 methods_count;method_info methods[methods_count];u2 attributes_count;attribute_info attributes[attributes_count];}cp_info{u1 tag;u1 info[];}CONSTANT_Class_info {u1 tag;u2 name_index; //常量池索引,该索引处的常量项必须是一个CONSTANT_Utf8_info}CONSTANT_Fieldref_info { u1 tag; u2 class_index; //常量池索引,必须指向一个CONSTANT_Class_info u2 name_and_type_index; //常量池索引,必须指向一个CONSTANT_NameAndType_info}CONSTANT_Methodref_info { u1 tag; u2 class_index; //常量池索引,必须指向一个CONSTANT_Class_info u2 name_and_type_index; //常量池索引,必须指向一个CONSTANT_NameAndType_info}CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; //常量池索引,必须指向一个CONSTANT_Class_info u2 name_and_type_index; //常量池索引,必须指向一个CONSTANT_NameAndType_info}CONSTANT_String_info { u1 tag; u2 string_index; //常量池索引,必须指向一个CONSTANT_Utf8_info}CONSTANT_Integer_info { u1 tag; u4 bytes; //4字节整数,高字节在前}CONSTANT_Float_info { u1 tag; u4 bytes; //4字节浮点数,IEEE 754格式,高字节在前}CONSTANT_Long_info { u1 tag; u4 high_bytes; //8字节整数,高字节在前 u4 low_bytes;}CONSTANT_Double_info { u1 tag; u4 high_bytes; //双精度浮点数,IEEE 754格式,高字节在前 u4 low_bytes;}CONSTANT_NameAndType_info { u1 tag; u2 name_index; //field或method的简单名字。该索引必须指向一个CONSTANT_Utf8_info u2 descriptor_index; //field或method的描述符。该索引必须指向一个CONSTANT_Utf8_info}CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length];}attribute_info{u2 attribute_name_index; //索引必须指向常量池的一个CONSTANT_Utf8_infou4 attribute_length;u1 info[attribute_length];}field_info{u2 access_flags;u2 name_index; //field simple name, 索引必须指向常量池的一个CONSTANT_Utf8_infou2 descriptor_index; //field desciptor, 索引必须指向常量池的一个CONSTANT_Utf8_infou2 attributes_count;attribute_info attributes[attributes_count];}struct method_info{u2 access_flags;u2 name_index;u2 descriptor_index;u2 attributes_count;attribute_info attributes[attributes_count];}Code_attribute{u2 attribute_name_index;u4 attribute_length;u2 max_stack;u2 max_locals;u4 code_length;u1 code[code_length];u2 exception_table_length;Exception_table exception_table[exception_table_length];u2 attributes_count;attribute_info attributes[attributes_count];};*///常量池项的一般格式//由于C语言不能准确描述可变长度,下面使用占位符的技巧,其他可变结构与此相似。struct cp_info{u1 tag;u1 info[0]; //占位符,不指明具体长度(或者指定为0),需要编译器支持};enum { CONSTANT_Utf8 = 1, CONSTANT_Unicode, //not used CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, CONSTANT_Double, CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref, CONSTANT_Methodref, CONSTANT_InterfaceMethodref, CONSTANT_NameAndType,};struct CONSTANT_Class_info{u1 tag;u2 name_index;};struct CONSTANT_Fieldref_info{u1 tag;u2 class_index;u2 name_and_type_index;};struct CONSTANT_Methodref_info{u1 tag;u2 class_index;u2 name_and_type_index;};struct CONSTANT_InterfaceMethodref_info{u1 tag;u2 class_index;u2 name_and_type_index;};struct CONSTANT_String_info{u1 tag;u2 string_index;};struct CONSTANT_Integer_info{u1 tag;u4 ivalue;};struct CONSTANT_Float_info{u1 tag;JFLOAT fvalue;};struct CONSTANT_Long_info{u1 tag;JLONG lvalue;};struct CONSTANT_Double_info{u1 tag;JDOUBLE dvalue;};struct CONSTANT_NameAndType_info{u1 tag;u2 name_index;u2 descriptor_index;};struct CONSTANT_Utf8_info{u1 tag;u2 length;u1 bytes[0]; //[length]};//field_info内部表示//Currently, associated attributes are: ConstantValue, Synthetic, Deprecated.//Other unknown attributes will be ignored according to JVM Specification.struct FieldInfo{u2 access_flags;u2 name_index;u2 descriptor_index;u1 is_ConstantValue;u2 constantvalue_index;u1 is_Synthetic;u1 is_Deprecated;};struct Exception_table{u2 start_pc;u2 end_pc;u2 handler_pc;u2 catch_type;};struct LineNumber_table{u2 start_pc;u2 line_number;};struct LocalVariable_table{u2 start_pc;u2 length;u2 name_index;u2 descriptor_index;u2 index;};//method_info内部表示//Currently, associated attributes are: Code, Exceptions, Synthetic, Deprecated.//Other unknown attributes will be ignored according to JVM Specification.struct MethodInfo{u2 access_flags;u2 name_index;u2 descriptor_index;u1 has_Code;u2 max_stack;u2 max_locals;u4 code_length;u1 *code;u2 exception_table_length;Exception_table *exception_table;//Currently,the possible attributes that associated with Code attribute are: //LineNumberTable and LocalVariableTable. Both of each store debugging information.int total_line_number_table;LineNumber_table *line_number_table;int total_local_variable_table;LocalVariable_table *local_variable_table;u2 number_of_exceptions; //方法可能抛出的已检查异常的数量u2 *exception_index_table; //指出每个异常的类名(每个索引指向CONSTANT_Class_info)u1 has_Exceptions;u1 is_Synthetic;u1 is_Deprecated;};#pragma pack()class ClassBufferInput;class ClassFileParser{public:ClassFileParser(const u1 *classInBuffer, int length);virtual ~ClassFileParser(void);//解析class文件的时候,根据格式,只能按照次序解析,//依次是magic, version, constant pool, ..., etc.void parseClassFile() throw (Exception);//releaseResource用于解析失败时,释放已分配的资源void releaseResource();void printSummary();private:const u1 * _class_buffer;int _buffer_length;ClassBufferInput *_classInput;bool valid_cp_index(int index, int cp_count) { return (index >= 1 && index < cp_count);}bool valid_cp_index(int index) { return (index >= 1 && index < _cp_count);}bool is_supported_version(u2 majorVersion, u2 minorVersion);bool check_utf8_string(const u1 *bytes, int length);void parseConstantPool() throw (Exception);void saveConstantPool() throw (Exception);void check_this_class(u2 this_class) throw (Exception);void check_access_flags(u2 access_flags) throw (Exception);void check_super_class(u2 super_class) throw (Exception);const cp_info * get_cp_info(int index) throw (Exception);u1 get_cp_tag(int index) throw (Exception);const u1 * get_cp_utf8(int index, u2 & length) throw (Exception);void parseInterfaces() throw (Exception);void parseFields() throw (Exception);void parseMethods() throw (Exception);void init_method_info(MethodInfo *minfo);u4 parseCodeAttribute(MethodInfo *minfo) throw (Exception);void releaseMethods();private:u2 _major_version;u2 _minor_version;int _cp_count;//用两个数组存储运行时常量池,一个为索引数组,一个为常量池数据cp_info ** _cp_index;u1 * _constant_pool;int _cp_length;u1 _tag_0;u2 _access_flags;u2 _this_class;u2 _super_class;int _interfaces_count;u1 * _interfaces;int _fields_count;FieldInfo *_fields;int _methods_count;MethodInfo *_methods;};class ClassBufferInput{public:ClassBufferInput(const u1* buffer, int length);const u1* buffer() const { return _buffer_start; }int length() const { return _buffer_end - _buffer_start; }const u1* current() const { return _current; }u1 read_u1() throw (Exception);u2 read_u2() throw (Exception);u4 read_u4() throw (Exception);void read_bytes(u1 *buf, int size) throw (Exception);void skip_u1() throw (Exception);void skip_u2() throw (Exception);void skip_u4() throw (Exception);void skip_bytes(int size) throw (Exception);void mark();void reset();static u2 read_java_u2(const u1 *buffer);static u4 read_java_u4(const u1 *buffer);private:const u1* _buffer_start;const u1* _buffer_end;const u1* _current;const u1* _marked;void guarantee_size(int size) throw (Exception);};
ClassFileParser.cpp
#include "ClassFileParser.h"#include <stdio.h>#include <string.h>#define CLASS_FILE_MAGIC_U4 0xCAFEBABEClassFileParser::ClassFileParser(const u1 *classInBuffer, int length){ _class_buffer = classInBuffer; _buffer_length = length; _classInput = new ClassBufferInput(_class_buffer, _buffer_length); _major_version = 0; _minor_version = 0; _cp_count = 0; _cp_length = -1; _constant_pool = NULL; _cp_index = NULL; _tag_0 = 0; _interfaces = NULL; _fields = NULL;}ClassFileParser::~ClassFileParser(void){ if (_classInput != NULL) { delete _classInput; } //Todo: 解析失败的情况下,需要释放已经分配的资源;解析成功的情况下,需要保留资源 //if (_constant_pool != NULL) { // delete [] _constant_pool; //}}bool ClassFileParser::is_supported_version(u2 major, u2 minor){ //实际的Java虚拟机的版本,如SUN的Hotspot,令人费解 //比如1.5版本,推测major=1,minor=5,可是SUN的Hotspot虚拟机却不认 //查看Hotspot源代码,最小版本竟从45开始 if (major > 45 && major <= 51) return true; return false;}bool ClassFileParser::check_utf8_string(const u1 *bytes, int length){ //Todo: check utf8 string return true;}const cp_info * ClassFileParser::get_cp_info(int index) throw (Exception){ assert_exception(valid_cp_index(index), "cp index out of cp range"); cp_info * p = _cp_index[index - 1]; return p;}u1 ClassFileParser::get_cp_tag(int index) throw (Exception){ const cp_info *p = get_cp_info(index); u1 tag = p->tag; return tag;}const u1 * ClassFileParser::get_cp_utf8(int index, u2 & length) throw (Exception){ const cp_info *p = get_cp_info(index); u1 tag = p->tag; assert_exception(tag == CONSTANT_Utf8, "cp indexed is not CONSTANT_Utf8"); const CONSTANT_Utf8_info *pUtf8 = (const CONSTANT_Utf8_info *)p; length = pUtf8->length; return pUtf8->bytes;}void ClassFileParser::saveConstantPool() throw (Exception){ ClassBufferInput *in = _classInput; //现在已知常量池的长度,保存到一个数组中(目前运行时常量池与原始常量池的长度相同!) //另用一个数组保存各个常量项的索引 _constant_pool = new u1 [_cp_length]; assert_exception(_constant_pool != NULL, "out of memory"); _cp_index = new cp_info * [_cp_count - 1]; assert_exception(_cp_index != NULL, "out of memory"); cp_info * current = (cp_info *)_constant_pool; for (int index = 0; index < _cp_count - 1; index++) { u1 tag = in->read_u1(); switch (tag) { case CONSTANT_Utf8: { CONSTANT_Utf8_info *pUtf8 = (CONSTANT_Utf8_info *)current; u2 length = in->read_u2(); _cp_index[index] = current; pUtf8->tag = tag; pUtf8->length = length; in->read_bytes(pUtf8->bytes, length); current += (sizeof(CONSTANT_Utf8_info) + length); } break; case CONSTANT_Integer: { CONSTANT_Integer_info *pInteger = (CONSTANT_Integer_info *)current; u4 bytes = in->read_u4(); _cp_index[index] = current; pInteger->tag = tag; pInteger->ivalue = bytes; current += sizeof(CONSTANT_Integer_info); } break; case CONSTANT_Float: { CONSTANT_Float_info *pFloat = (CONSTANT_Float_info *)current; u4 bytes = in->read_u4(); _cp_index[index] = current; pFloat->tag = tag; union { JFLOAT f; u4 bytes; } u; u.bytes = bytes; pFloat->fvalue = u.f; current += sizeof(CONSTANT_Float_info); } break; case CONSTANT_Long: { CONSTANT_Long_info *pLong = (CONSTANT_Long_info *)current; u4 high_bytes = in->read_u4(); u4 low_bytes = in->read_u4(); _cp_index[index] = current; pLong->tag = tag; pLong->lvalue = (JLONG)high_bytes << 32 | (JLONG)low_bytes; index++; //JVM规范:8字节的常量池项在计数上占两个 _cp_index[index] = (cp_info *)&_tag_0; current += sizeof(CONSTANT_Long_info); } break; case CONSTANT_Double: { CONSTANT_Double_info *pDouble = (CONSTANT_Double_info *)current; u4 high_bytes = in->read_u4(); u4 low_bytes = in->read_u4(); _cp_index[index] = current; pDouble->tag = tag; union { JDOUBLE d; JLONG l; } u; JLONG l = (JLONG)high_bytes << 32 | (JLONG)low_bytes; u.l = l; pDouble->dvalue = u.d; index++; //JVM规范:8字节的常量池项在计数上占两个 _cp_index[index] = (cp_info *)&_tag_0; current += sizeof(CONSTANT_Double_info); } break; case CONSTANT_Class: { CONSTANT_Class_info *pClass = (CONSTANT_Class_info *)current; u2 name_index = in->read_u2(); _cp_index[index] = current; pClass->tag = tag; pClass->name_index = name_index; current += sizeof(CONSTANT_Class_info); } break; case CONSTANT_String: { CONSTANT_String_info *pString = (CONSTANT_String_info *)current; u2 string_index = in->read_u2(); _cp_index[index] = current; pString->tag = tag; pString->string_index = string_index; current += sizeof(CONSTANT_String_info); } break; case CONSTANT_Fieldref: { CONSTANT_Fieldref_info *pFieldref = (CONSTANT_Fieldref_info *)current; u2 class_index = in->read_u2(); u2 name_and_type_index = in->read_u2(); _cp_index[index] = current; pFieldref->tag = tag; pFieldref->class_index = class_index; pFieldref->name_and_type_index = name_and_type_index; current += sizeof(CONSTANT_Fieldref_info); } break; case CONSTANT_Methodref: { CONSTANT_Methodref_info *pMethodref = (CONSTANT_Methodref_info *)current; u2 class_index = in->read_u2(); u2 name_and_type_index = in->read_u2(); _cp_index[index] = current; pMethodref->tag = tag; pMethodref->class_index = class_index; pMethodref->name_and_type_index = name_and_type_index; current += sizeof(CONSTANT_Methodref_info); } break; case CONSTANT_InterfaceMethodref: { CONSTANT_InterfaceMethodref_info *pInterfaceMethodref = (CONSTANT_InterfaceMethodref_info *)current; u2 class_index = in->read_u2(); u2 name_and_type_index = in->read_u2(); _cp_index[index] = current; pInterfaceMethodref->tag = tag; pInterfaceMethodref->class_index = class_index; pInterfaceMethodref->name_and_type_index = name_and_type_index; current += sizeof(CONSTANT_InterfaceMethodref_info); } break; case CONSTANT_NameAndType: { CONSTANT_NameAndType_info *pNameAndType = (CONSTANT_NameAndType_info *)current; u2 name_index = in->read_u2(); u2 descriptor_index = in->read_u2(); _cp_index[index] = current; pNameAndType->tag = tag; pNameAndType->name_index = name_index; pNameAndType->descriptor_index = descriptor_index; current += sizeof(CONSTANT_NameAndType_info); } break; default: { char msg[30]; sprintf(msg, "unknown tag: %d", tag); assert_exception(false, msg); } break; } } //验证相等(目前必定不相等,因为已经从big-endian顺序转化为本机顺序) //int magic_version_length = sizeof(u4) + sizeof(u2) + sizeof(u2); //const u1 * p1 = _class_buffer + magic_version_length + 2; //int cmp = memcmp(p1, _constant_pool, _cp_length); //检查常量项相互之间的引用是否正确 for (int index = 1; index < _cp_count; index++) { cp_info * current = _cp_index[index - 1]; u1 tag = current->tag; switch (tag) { case CONSTANT_Utf8: break; case CONSTANT_Integer: break; case CONSTANT_Float: break; case CONSTANT_Long: { index++; } break; case CONSTANT_Double: { index++; } break; case CONSTANT_Class: { CONSTANT_Class_info *pClass = (CONSTANT_Class_info *)current; u1 ref_tag = get_cp_tag(pClass->name_index); assert_exception(ref_tag == CONSTANT_Utf8, "name_index refered is not CONSTANT_Utf8"); } break; case CONSTANT_String: { CONSTANT_String_info *pString = (CONSTANT_String_info *)current; u1 ref_tag = get_cp_tag(pString->string_index); assert_exception(ref_tag == CONSTANT_Utf8, "string_index refered is not CONSTANT_Utf8"); } break; case CONSTANT_Fieldref: { CONSTANT_Fieldref_info *pFieldref = (CONSTANT_Fieldref_info *)current; u1 ref_tag1 = get_cp_tag(pFieldref->class_index); assert_exception(ref_tag1 == CONSTANT_Class, "class_index refered is not CONSTANT_Class"); u1 ref_tag2 = get_cp_tag(pFieldref->name_and_type_index); assert_exception(ref_tag2 == CONSTANT_NameAndType, "name_and_type_index refered is not CONSTANT_NameAndType"); } break; case CONSTANT_Methodref: { CONSTANT_Methodref_info *pMethodref = (CONSTANT_Methodref_info *)current; u1 ref_tag1 = get_cp_tag(pMethodref->class_index); assert_exception(ref_tag1 == CONSTANT_Class, "class_index refered is not CONSTANT_Class"); u1 ref_tag2 = get_cp_tag(pMethodref->name_and_type_index); assert_exception(ref_tag2 == CONSTANT_NameAndType, "name_and_type_index refered is not CONSTANT_NameAndType"); } break; case CONSTANT_InterfaceMethodref: { CONSTANT_InterfaceMethodref_info *pInterfaceMethodref = (CONSTANT_InterfaceMethodref_info *)current; u1 ref_tag1 = get_cp_tag(pInterfaceMethodref->class_index); assert_exception(ref_tag1 == CONSTANT_Class, "class_index refered is not CONSTANT_Class"); u1 ref_tag2 = get_cp_tag(pInterfaceMethodref->name_and_type_index); assert_exception(ref_tag2 == CONSTANT_NameAndType, "name_and_type_index refered is not CONSTANT_NameAndType"); } break; case CONSTANT_NameAndType: { CONSTANT_NameAndType_info *pNameAndType = (CONSTANT_NameAndType_info *)current; u1 ref_tag1 = get_cp_tag(pNameAndType->name_index); assert_exception(ref_tag1 == CONSTANT_Utf8, "name_index refered is not CONSTANT_Utf8"); u1 ref_tag2 = get_cp_tag(pNameAndType->descriptor_index); assert_exception(ref_tag2 == CONSTANT_Utf8, "descriptor_index refered is not CONSTANT_Utf8"); } break; } }}void ClassFileParser::parseConstantPool() throw (Exception){ ClassBufferInput *in = _classInput; u2 cp_count = in->read_u2(); //常量池项目数 + 1 assert_exception(cp_count >= 1, "bad constant pool size"); //下面遍历一遍常量池,为了统计常量池的长度(字节数),顺便执行一些检查 in->mark(); //第二遍将重读常量池,所以先标记一下 int cp_length = 0; int cp_info_length; for (int index = 1; index < cp_count; index++) { cp_info_length = -1; u1 tag = in->read_u1(); printf("index:%d, tag: %d, ", index, tag); switch (tag) { case CONSTANT_Utf8: { u2 length = in->read_u2(); //检查utf8字符串 bool isUtf8 = check_utf8_string(in->current(), length); assert_exception(isUtf8, "bad utf8 string"); in->skip_bytes(length); cp_info_length = 2 + length; } break; case CONSTANT_Integer: { in->skip_u4(); cp_info_length = 4; } break; case CONSTANT_Float: { in->skip_u4(); cp_info_length = 4; } break; case CONSTANT_Long: { in->skip_bytes(8); cp_info_length = 8; index++; //JVM规范:8字节的常量池项在计数上占两个 } break; case CONSTANT_Double: { in->skip_bytes(8); cp_info_length = 8; index++; //JVM规范:8字节的常量池项在计数上占两个 } break; case CONSTANT_Class: { u2 name_index = in->read_u2(); assert_exception(valid_cp_index(name_index, cp_count), "bad constant pool index"); cp_info_length = 2; } break; case CONSTANT_String: { u2 string_index = in->read_u2(); assert_exception(valid_cp_index(string_index, cp_count), "bad constant pool index"); cp_info_length = 2; } break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { u2 class_index = in->read_u2(); u2 name_and_type_index = in->read_u2(); assert_exception(valid_cp_index(class_index, cp_count), "bad constant pool index"); assert_exception(valid_cp_index(name_and_type_index, cp_count), "bad constant pool index"); cp_info_length = 4; } break; case CONSTANT_NameAndType: { u2 name_index = in->read_u2(); u2 descriptor_index = in->read_u2(); assert_exception(valid_cp_index(name_index, cp_count), "bad constant pool index"); assert_exception(valid_cp_index(descriptor_index, cp_count), "bad constant pool index"); cp_info_length = 4; } break; default: { char msg[30]; sprintf(msg, "unknown tag: %d", tag); assert_exception(false, msg); } break; } assert_exception(cp_info_length != -1, "internal error"); printf("length: %d\n", cp_info_length); cp_length += (cp_info_length + 1); } _cp_count = cp_count; _cp_length = cp_length; in->reset(); //重读常量池(第二遍) saveConstantPool();}void ClassFileParser::check_access_flags(u2 access_flags) throw (Exception){ //Todo:}void ClassFileParser::check_this_class(u2 this_class) throw (Exception){ assert_exception(valid_cp_index(this_class), "this_class out of cp range"); u1 tag = get_cp_tag(this_class); assert_exception(tag == CONSTANT_Class, "this_class refered is not CONSTANT_Class");}void ClassFileParser::check_super_class(u2 super_class) throw (Exception){ assert_exception(valid_cp_index(super_class), "super_class out of cp range"); u1 tag = get_cp_tag(super_class); assert_exception(tag == CONSTANT_Class, "super_class refered is not CONSTANT_Class");}void ClassFileParser::parseInterfaces() throw (Exception){ ClassBufferInput *in = _classInput; u2 interface_count = in->read_u2(); const u1 * interfaces = in->current(); for (int index = 0; index < interface_count; index++) { u2 this_interface = in->read_u2(); assert_exception(valid_cp_index(this_interface), "interface index out of cp range"); u1 tag = get_cp_tag(this_interface); assert_exception(tag == CONSTANT_Class, "interface refered is not CONSTANT_Class"); } _interfaces_count = interface_count; int length = interface_count * sizeof(u2); _interfaces = new u1 [length]; memcpy(_interfaces, interfaces, length);}void ClassFileParser::parseFields() throw (Exception){ const char *ConstantValue = "ConstantValue"; const char *Synthetic = "Synthetic"; const char *Deprecated = "Deprecated"; int ConstantValue_length = strlen(ConstantValue); int Synthetic_length = strlen(Synthetic); int Deprecated_length = strlen(Deprecated); ClassBufferInput *in = _classInput; u2 fields_count = in->read_u2(); FieldInfo *fields = new FieldInfo [fields_count]; assert_exception(fields != NULL, "out of memory"); _fields_count = fields_count; _fields = fields; for (int index = 0; index < fields_count; index++) { u2 access_flags = in->read_u2(); u2 name_index = in->read_u2(); u1 tag1 = get_cp_tag(name_index); assert_exception(tag1 == CONSTANT_Utf8, "field name_index refered is not CONSTANT_Utf8"); u2 descriptor_index = in->read_u2(); u1 tag2 = get_cp_tag(descriptor_index); assert_exception(tag2 == CONSTANT_Utf8, "field descriptor_index refered is not CONSTANT_Utf8"); u1 is_ConstantValue = 0; u1 is_Synthetic = 0; u1 is_Deprecated = 0; u2 constantvalue_index = 0; u2 attributes_count = in->read_u2(); for (int attr_index = 0; attr_index < attributes_count; attr_index++) { u2 attribute_name_index = in->read_u2(); u4 attribute_length = in->read_u4(); u2 length; const u1 * name = get_cp_utf8(attribute_name_index, length); if (length == ConstantValue_length && (memcmp(ConstantValue, name, length)) == 0) { assert_exception(is_ConstantValue == 0, "no more than one ConstantValue attribute"); is_ConstantValue = 1; assert_exception(attribute_length == 2, "bad ConstantValue attribute length"); constantvalue_index = in->read_u2(); } else if (length == Synthetic_length && (memcmp(Synthetic, name, length)) == 0) { is_Synthetic = 1; assert_exception(attribute_length == 0, "bad Synthetic attribute length"); } else if (length == Deprecated_length && (memcmp(Deprecated, name, length)) == 0) { is_Deprecated = 1; assert_exception(attribute_length == 0, "bad Deprecated attribute length"); } else { //Ignore any attribute that does not recongnize in->skip_bytes(attribute_length); } } fields[index].access_flags = access_flags; fields[index].name_index = name_index; fields[index].descriptor_index = descriptor_index; fields[index].is_ConstantValue = is_ConstantValue; fields[index].is_Synthetic = is_Synthetic; fields[index].is_Deprecated = is_Deprecated; fields[index].constantvalue_index = constantvalue_index; }}void ClassFileParser::init_method_info(MethodInfo *minfo){ minfo->has_Code = 0; minfo->code_length = 0; minfo->code = NULL; minfo->exception_table_length = 0; minfo->exception_table = NULL; minfo->total_line_number_table = 0; minfo->line_number_table = NULL; minfo->total_local_variable_table = 0; minfo->local_variable_table = NULL; minfo->number_of_exceptions = 0; minfo->exception_index_table = NULL;}u4 ClassFileParser::parseCodeAttribute(MethodInfo *minfo) throw (Exception){ u2 max_stack = 0, max_locals = 0; u4 code_length = 0; u1 *code = NULL; u2 exception_table_length; Exception_table *exception_table = NULL; int total_line_number_table = 0; LineNumber_table *line_number_table = NULL; int total_local_variable_table = 0; LocalVariable_table *local_variable_table = NULL; ClassBufferInput *in = _classInput; const u1 * start = in->current(); try { max_stack = in->read_u2(); max_locals = in->read_u2(); code_length = in->read_u4(); if (code_length > 0) { code = new u1 [code_length]; assert_exception(code != NULL, "out of memory"); in->read_bytes(code, code_length); } exception_table_length = in->read_u2(); if (exception_table_length > 0) { exception_table = new Exception_table [exception_table_length]; assert_exception(exception_table != NULL, "out of memory"); } for (int except_index = 0; except_index < exception_table_length; except_index++) { exception_table[except_index].start_pc = in->read_u2(); exception_table[except_index].end_pc = in->read_u2(); exception_table[except_index].handler_pc = in->read_u2(); exception_table[except_index].catch_type = in->read_u2(); } //读取与Code attribute关联的属性(目前只有LineNumberTable和LocalVariableTable) //扫描两遍,第一遍统计LineNumber_table或LocalVariable_table的数量 const char *LineNumberTable = "LineNumberTable"; const char *LocalVariableTable = "LocalVariableTable"; int LineNumberTable_length = strlen(LineNumberTable); int LocalVariableTable_length = strlen(LocalVariableTable); int attributes_count = in->read_u2(); in->mark(); for (int attr_index = 0; attr_index < attributes_count; attr_index++) { u2 attribute_name_index = in->read_u2(); u4 attribute_length = in->read_u4(); u2 length; const u1 * name = get_cp_utf8(attribute_name_index, length); if (length == LineNumberTable_length && (memcmp(LineNumberTable, name, length)) == 0) { u2 line_number_table_length = in->read_u2(); in->skip_bytes(line_number_table_length * sizeof(LineNumber_table)); total_line_number_table += line_number_table_length; } else if (length == LocalVariableTable_length && (memcmp(LocalVariableTable, name, length)) == 0) { u2 local_variable_table_length = in->read_u2(); in->skip_bytes(local_variable_table_length * sizeof(LocalVariable_table)); total_local_variable_table += local_variable_table_length; } else { //Ignore any attribute that does not recongnize in->skip_bytes(attribute_length); } } if (total_line_number_table > 0) { line_number_table = new LineNumber_table [total_line_number_table]; assert_exception(line_number_table != NULL, "out of memory"); } if (total_local_variable_table > 0) { local_variable_table = new LocalVariable_table [total_local_variable_table]; assert_exception(local_variable_table != NULL, "out of memory"); } in->reset(); int line_number_pos = 0; int local_variable_pos = 0; for (int attr_index = 0; attr_index < attributes_count; attr_index++) { u2 attribute_name_index = in->read_u2(); u4 attribute_length = in->read_u4(); u2 length; const u1 * name = get_cp_utf8(attribute_name_index, length); if (length == LineNumberTable_length && (memcmp(LineNumberTable, name, length)) == 0) { u2 line_number_table_length = in->read_u2(); for (int i = line_number_pos; i < (line_number_pos + line_number_table_length); i++) { line_number_table[i].start_pc = in->read_u2(); line_number_table[i].line_number = in->read_u2(); } line_number_pos += line_number_table_length; } else if (length == LocalVariableTable_length && (memcmp(LocalVariableTable, name, length)) == 0) { u2 local_variable_table_length = in->read_u2(); for (int i = local_variable_pos; i < (local_variable_pos + local_variable_table_length); i++) { local_variable_table[i].start_pc = in->read_u2(); local_variable_table[i].length = in->read_u2(); local_variable_table[i].name_index = in->read_u2(); local_variable_table[i].descriptor_index = in->read_u2(); local_variable_table[i].index = in->read_u2(); } local_variable_pos += local_variable_table_length; } else { //Ignore any attribute that does not recongnize in->skip_bytes(attribute_length); } } minfo->max_stack = max_stack; minfo->max_locals = max_locals; minfo->code_length = code_length; minfo->code = code; minfo->exception_table_length = exception_table_length; minfo->exception_table = exception_table; minfo->total_line_number_table = total_line_number_table; minfo->line_number_table = line_number_table; minfo->total_local_variable_table = total_local_variable_table; minfo->local_variable_table = local_variable_table; const u1 *end = in->current(); u4 code_attr_length = end - start; return code_attr_length; } catch (Exception e) { if (code != NULL) { delete [] code; } if (exception_table != NULL) { delete [] exception_table; } if (line_number_table != NULL) { delete [] line_number_table; } if (local_variable_table != NULL) { delete [] local_variable_table; } throw e; } return 0;}void ClassFileParser::parseMethods() throw (Exception){ const char *Code = "Code"; const char *Exceptions = "Exceptions"; const char *Synthetic = "Synthetic"; const char *Deprecated = "Deprecated"; int Code_length = strlen(Code); int Exceptions_length = strlen(Exceptions); int Synthetic_length = strlen(Synthetic); int Deprecated_length = strlen(Deprecated); ClassBufferInput *in = _classInput; u2 methods_count = in->read_u2(); MethodInfo *methods = new MethodInfo [methods_count]; assert_exception(methods != NULL, "out of memory"); _methods_count = methods_count; _methods = methods; //初始化methods,当解析失败,可以释放已申请的资源 MethodInfo minfo; init_method_info(&minfo); for (int i = 0; i < methods_count; i++) { methods[i] = minfo; } for (int index = 0; index < methods_count; index++) { u2 access_flags = in->read_u2(); u2 name_index = in->read_u2(); u1 tag1 = get_cp_tag(name_index); assert_exception(tag1 == CONSTANT_Utf8, "method name_index refered is not CONSTANT_Utf8"); u2 descriptor_index = in->read_u2(); u1 tag2 = get_cp_tag(descriptor_index); assert_exception(tag2 == CONSTANT_Utf8, "method descriptor_index refered is not CONSTANT_Utf8"); u1 has_Code = 0; u1 has_Exceptions = 0; u1 is_Synthetic = 0; u1 is_Deprecated = 0; u2 number_of_exceptions = 0; u2 *exception_index_table = NULL; u2 attributes_count = in->read_u2(); for (int attr_index = 0; attr_index < attributes_count; attr_index++) { u2 attribute_name_index = in->read_u2(); u4 attribute_length = in->read_u4(); u2 length; const u1 * name = get_cp_utf8(attribute_name_index, length); if (length == Code_length && (memcmp(Code, name, length)) == 0) { assert_exception(has_Code == 0, "no more than one Code attribute"); has_Code = 1; u4 code_attr_length = parseCodeAttribute(&methods[index]); assert_exception(attribute_length == code_attr_length, "bad Code attribute length"); } else if (length == Exceptions_length && (memcmp(Exceptions, name, length)) == 0) { assert_exception(has_Exceptions == 0, "no more than one Exceptions attribute"); has_Exceptions = 1; number_of_exceptions = in->read_u2(); if (number_of_exceptions > 0) { exception_index_table = new u2 [number_of_exceptions]; assert_exception(exception_index_table != NULL, "out of memory"); } for (int i = 0; i < number_of_exceptions; i++) { exception_index_table[i] = in->read_u2(); } u4 exceptions_attr_length = 2 + (number_of_exceptions * 2); assert_exception(attribute_length == exceptions_attr_length, "bad Exceptions attribute length"); } else if (length == Synthetic_length && (memcmp(Synthetic, name, length)) == 0) { is_Synthetic = 1; assert_exception(attribute_length == 0, "bad Synthetic attribute length"); } else if (length == Deprecated_length && (memcmp(Deprecated, name, length)) == 0) { is_Deprecated = 1; assert_exception(attribute_length == 0, "bad Deprecated attribute length"); } else { //Ignore any attribute that does not recongnize in->skip_bytes(attribute_length); } } methods[index].access_flags = access_flags; methods[index].name_index = name_index; methods[index].descriptor_index = descriptor_index; methods[index].has_Code = has_Code; methods[index].has_Exceptions = has_Exceptions; methods[index].is_Synthetic = is_Synthetic; methods[index].is_Deprecated = is_Deprecated; methods[index].number_of_exceptions = number_of_exceptions; methods[index].exception_index_table = exception_index_table; }}void ClassFileParser::parseClassFile() throw (Exception){ //parse class magic, version ClassBufferInput *in = _classInput; u4 magic = in->read_u4(); assert_exception(magic == CLASS_FILE_MAGIC_U4, "bad magic value"); u2 minorVersion = in->read_u2(); u2 majorVersion = in->read_u2(); assert_exception(is_supported_version(majorVersion, minorVersion), "unsupported class version"); _major_version = majorVersion; _minor_version = minorVersion; //parse constant pool parseConstantPool(); //parse access_flags, this_clsss, super_class _access_flags = in->read_u2(); //Todo: need check now? check_access_flags(_access_flags); _this_class = in->read_u2(); check_this_class(_this_class); _super_class = in->read_u2(); check_super_class(_super_class); //parse interfaces parseInterfaces(); //parse fields parseFields(); //parse methods parseMethods();}void ClassFileParser::releaseMethods(){ for (int i = 0; i < _methods_count; i++) { u1 *code = _methods[i].code; Exception_table *exception_table = _methods[i].exception_table; LineNumber_table *line_number_table = _methods[i].line_number_table; LocalVariable_table *local_variable_table = _methods[i].local_variable_table; u2 *exception_index_table = _methods[i].exception_index_table; if (code != NULL) { delete [] code; } if (exception_table != NULL) { delete [] exception_table; } if (line_number_table != NULL) { delete [] line_number_table; } if (local_variable_table != NULL) { delete [] local_variable_table; } if (exception_index_table != NULL) { delete [] exception_index_table; } }}void ClassFileParser::releaseResource(){ if (_cp_index != NULL) { delete [] _cp_index; } if (_constant_pool != NULL) { delete [] _constant_pool; } if (_interfaces != NULL) { delete [] _interfaces; } if (_fields != NULL) { delete [] _fields; } if (_methods != NULL) { releaseMethods(); }}void ClassFileParser::printSummary(){ printf("class version: %d.%d, cp count: %d, cp length: %d\n \ interface count: %d, field count: %d, method count: %d\n", _major_version, _minor_version, _cp_count, _cp_length, _interfaces_count, _fields_count, _methods_count);}//ClassBufferInputClassBufferInput::ClassBufferInput(const u1* buffer, int length){ _buffer_start = buffer; _buffer_end = buffer + length; _current = buffer; _marked = buffer;}void ClassBufferInput::guarantee_size(int size) throw (Exception){ if (size > (_buffer_end - _buffer_start)) { throw Exception("unexpected end of file"); }}u1 ClassBufferInput::read_u1() throw (Exception){ guarantee_size(1); u1 c = *_current++; return c;}u2 ClassBufferInput::read_u2() throw (Exception){ guarantee_size(2); u2 result = read_java_u2(_current); _current += 2; return result;}u4 ClassBufferInput::read_u4() throw (Exception){ guarantee_size(4); u4 result = read_java_u4(_current); _current += 4; return result;}void ClassBufferInput::read_bytes(u1 *buf, int size) throw (Exception){ guarantee_size(size); memcpy(buf, _current, size); _current += size;}u2 ClassBufferInput::read_java_u2(const u1 *buffer){ u1 c1 = buffer[0]; u1 c2 = buffer[1]; u2 result = (u2)c1 << 8 | (u2)c2; return result;}u4 ClassBufferInput::read_java_u4(const u1 *buffer){ u1 c1 = buffer[0]; u1 c2 = buffer[1]; u1 c3 = buffer[2]; u1 c4 = buffer[3]; u4 result = (u4)c1 << 24 | (u4)c2 << 16 | (u4)c3 << 8 | (u4)c4; return result;}void ClassBufferInput::skip_u1() throw (Exception){ guarantee_size(1); _current++;}void ClassBufferInput::skip_u2() throw (Exception){ guarantee_size(2); _current += 2;}void ClassBufferInput::skip_u4() throw (Exception){ guarantee_size(4); _current += 4;}void ClassBufferInput::skip_bytes(int size) throw (Exception){ guarantee_size(size); _current += size;}void ClassBufferInput::mark(){ _marked = _current;}void ClassBufferInput::reset(){ _current = _marked;}
JVMTest.cpp
(只贴出有修改的部分)
int main(int argc, char *argv[]){ printf("JVM Test, JVM Utilities test...\n"); if (argc < 2) { printf("Usage: JVMTest classfile\n"); return 0; } const char *classFileName = argv[1]; int bufferLength; char *classBuffer = loadClassToBuffer(classFileName, &bufferLength); if (classBuffer == NULL) { printf("\nload class file failed"); return -1; } ClassFileParser parser((const u1 *)classBuffer, bufferLength); try { parser.parseClassFile(); parser.printSummary(); } catch (Exception e) { printf("parse class file failed: %s", e.getMessage()); parser.releaseResource(); } //test //Exception e("abcdef"); return 0;}
- 解析class文件-方法
- Java Class 文件解析
- eclipse .class 文件解析
- 解析class反编译文件
- Class文件实例解析
- java class文件解析
- class文件解析
- JAVA CLASS 文件解析
- 解析java的*.class文件
- Java Class文件解析实例
- 解析class文件常量池
- java Class文件内部结构解析
- Class文件解析一:概述
- java Class文件内部结构解析
- java Class文件内部结构解析
- java Class文件内部结构解析
- JVM-class文件结构解析
- java Class文件内部结构解析
- Delphi7语言基础20130717-2
- windows eclipse cdt cygwin 搭建与其常见问题
- JAVA中使用UrlRewrite时遇到404怎么办?
- 将DataSet转换成CSV文件自己的用法
- 帮忙推荐搜索引擎
- 解析class文件-方法
- 继续前行
- vm在64位的Linux 5下安装VMwaretools
- android 启动一个最简单的 activity 时的线程
- C# List使用总结
- 让你成为更优秀程序员的10个步骤
- hdu4357
- 华为机试题
- RedHat6 如何弹出安装界面