三、解析class文件
一、class文件
https://blog.csdn.net/tyyj90/article/details/78472986
https://blog.csdn.net/sinat_38259539/article/details/78248454
二、 解析class文件
java语言类型 | go语言类型 |
byte | int8 |
short | int16 |
char | uint16 |
int | int32 |
long | int64 |
float | float32 |
double | float64 |
在%GOPATH%\src\jvmgo\classfile文件夹下创建以下文件
1、读取数据
创建class_reader.go
- package classfile
- import "encoding/binary"
- type ClassReader struct {
- data []byte
- }
- // u1
- func (self *ClassReader) readUint8() uint8 {
- val := self.data[0]
- self.data = self.data[1:]
- return val
- }
- // u2
- func (self *ClassReader) readUint16() uint16 {
- val := binary.BigEndian.Uint16(self.data)
- self.data = self.data[2:]
- return val
- }
- // u4
- func (self *ClassReader) readUint32() uint32 {
- val := binary.BigEndian.Uint32(self.data)
- self.data = self.data[4:]
- return val
- }
- func (self *ClassReader) readUint64() uint64 {
- val := binary.BigEndian.Uint64(self.data)
- self.data = self.data[8:]
- return val
- }
- func (self *ClassReader) readUint16s() []uint16 {
- n := self.readUint16()
- s := make([]uint16, n)
- for i := range s {
- s[i] = self.readUint16()
- }
- return s
- }
- func (self *ClassReader) readBytes(n uint32) []byte {
- bytes := self.data[:n]
- self.data = self.data[n:]
- return bytes
- }
ClassReader结构是[]byte类型的包装,依据Go语言的reslice语法跳过已经读取的数据。readUint8()是读取u1类型数据,readUint16()是读取u2类型数据,encoding/binary中有一个变量BigEndian,可以从[]byte中读取多字节,readUint32()读取u4类型数据,readUint64()读取uint64类型数据。readUint16s()读取uint16表,表的大小由开头的uint16数据指出。最后一个是readBytes()读取指定数量的字节。
2、整体结构
创建class_file.go文件
- package classfile
- import "fmt"
- /*
- ClassFile {
- u4 magic;
- u2 minor_version;
- u2 major_version;
- u2 constant_pool_count;
- cp_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];
- }
- */
- type ClassFile struct {
- //magic uint32
- minorVersion uint16
- majorVersion uint16
- constantPool ConstantPool
- accessFlags uint16
- thisClass uint16
- superClass uint16
- interfaces []uint16
- fields []*MemberInfo
- methods []*MemberInfo
- attributes []AttributeInfo
- }
- func Parse(classData []byte) (cf *ClassFile, err error) {
- defer func() {
- if r := recover(); r != nil {
- var ok bool
- err, ok = r.(error)
- if !ok {
- err = fmt.Errorf("%v", r)
- }
- }
- }()
- cr := &ClassReader{classData}
- cf = &ClassFile{}
- cf.read(cr)
- return
- }
- func (self *ClassFile) read(reader *ClassReader) {
- self.readAndCheckMagic(reader)
- self.readAndCheckVersion(reader)
- self.constantPool = readConstantPool(reader)
- self.accessFlags = reader.readUint16()
- self.thisClass = reader.readUint16()
- self.superClass = reader.readUint16()
- self.interfaces = reader.readUint16s()
- self.fields = readMembers(reader, self.constantPool)
- self.methods = readMembers(reader, self.constantPool)
- self.attributes = readAttributes(reader, self.constantPool)
- }
- func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
- magic := reader.readUint32()
- if magic != 0xCAFEBABE {
- panic("java.lang.ClassFormatError: magic!")
- }
- }
- func (self *ClassFile) readAndCheckVersion(reader *ClassReader) {
- self.minorVersion = reader.readUint16()
- self.majorVersion = reader.readUint16()
- switch self.majorVersion {
- case 45:
- return
- case 46, 47, 48, 49, 50, 51, 52:
- if self.minorVersion == 0 {
- return
- }
- }
- panic("java.lang.UnsupportedClassVersionError!")
- }
- func (self *ClassFile) MinorVersion() uint16 {
- return self.minorVersion
- }
- func (self *ClassFile) MajorVersion() uint16 {
- return self.majorVersion
- }
- func (self *ClassFile) ConstantPool() ConstantPool {
- return self.constantPool
- }
- func (self *ClassFile) AccessFlags() uint16 {
- return self.accessFlags
- }
- func (self *ClassFile) Fields() []*MemberInfo {
- return self.fields
- }
- func (self *ClassFile) Methods() []*MemberInfo {
- return self.methods
- }
- func (self *ClassFile) ClassName() string {
- return self.constantPool.getClassName(self.thisClass)
- }
- func (self *ClassFile) SuperClassName() string {
- if self.superClass > 0 {
- return self.constantPool.getClassName(self.superClass)
- }
- return ""
- }
- func (self *ClassFile) InterfaceNames() []string {
- interfaceNames := make([]string, len(self.interfaces))
- for i, cpIndex := range self.interfaces {
- interfaceNames[i] = self.constantPool.getClassName(cpIndex)
- }
- return interfaceNames
- }
go语言中首字母大写是公有的,小写是私有的。ClassFile结构体反映了class文件的格式。Parse()函数把[]byte解析成ClassFile结构体。read()依次调用其他方法解析class文件,MajorVersion()等6个方法是Getter方法,把结构体的字段暴漏给其他包使用,ClassName()从常量池查找类名,SuperClassName()从常量池中查找超类名,InterfaceNames()从常量池查找接口名
3、魔数
class文件的魔数是“0xCAFEBABE”,class_file.go中的readAndCheckMagic()函数对文件的魔数进行查验。
4、版本号
jdk1.8的版本号为52.0 ,支持45.0到52.0的版本号,次版本为0,如果你的jdk不是这个版本,可以更改readAndCheckVersion()函数中的值。
5、类访问标志
版本号之后是常量池,常量池之后是类访问标志,是一个16位的“bitmask”指出class中定义的是class还是接口。
6、类和超类索引
类访问标志之后是两个u2的常量池索引分别给出类名和超类名,出Object.class对象的超类为0,其余类不能为0,必须为有效值
7、接口索引表
8、字段和方法表
定义member_info.go文件
- package classfile
- /*
- field_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
- method_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
- */
- type MemberInfo struct {
- cp ConstantPool
- accessFlags uint16
- nameIndex uint16
- descriptorIndex uint16
- attributes []AttributeInfo
- }
- // read field or method table
- func readMembers(reader *ClassReader, cp ConstantPool) []*MemberInfo {
- memberCount := reader.readUint16()
- members := make([]*MemberInfo, memberCount)
- for i := range members {
- members[i] = readMember(reader, cp)
- }
- return members
- }
- func readMember(reader *ClassReader, cp ConstantPool) *MemberInfo {
- return &MemberInfo{
- cp: cp,
- accessFlags: reader.readUint16(),
- nameIndex: reader.readUint16(),
- descriptorIndex: reader.readUint16(),
- attributes: readAttributes(reader, cp),
- }
- }
- func (self *MemberInfo) AccessFlags() uint16 {
- return self.accessFlags
- }
- func (self *MemberInfo) Name() string {
- return self.cp.getUtf8(self.nameIndex)
- }
- func (self *MemberInfo) Descriptor() string {
- return self.cp.getUtf8(self.descriptorIndex)
- }
MermberInfo结构体,cp字段保存常量池指针,readMembers()读取字段表或方法表,readMermber()读取字段或方法数据。Name()从常量池字段查找方法或字段名,Descriptor()从常量池查找字段或方法描述符。
三、解析常量池
1、ConstantPool
创建constant_pool.go文件
- package classfile
- import "fmt"
- type ConstantPool []ConstantInfo
- func readConstantPool(reader *ClassReader) ConstantPool {
- cpCount := int(reader.readUint16())
- cp := make([]ConstantInfo, cpCount)
- // The constant_pool table is indexed from 1 to constant_pool_count - 1.
- for i := 1; i < cpCount; i++ {
- cp[i] = readConstantInfo(reader, cp)
- // http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.5
- // All 8-byte constants take up two entries in the constant_pool table of the class file.
- // If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool
- // table at index n, then the next usable item in the pool is located at index n+2.
- // The constant_pool index n+1 must be valid but is considered unusable.
- switch cp[i].(type) {
- case *ConstantLongInfo, *ConstantDoubleInfo:
- i++
- }
- }
- return cp
- }
- func (self ConstantPool) getConstantInfo(index uint16) ConstantInfo {
- if cpInfo := self[index]; cpInfo != nil {
- return cpInfo
- }
- panic(fmt.Errorf("Invalid constant pool index: %v!", index))
- }
- func (self ConstantPool) getNameAndType(index uint16) (string, string) {
- ntInfo := self.getConstantInfo(index).(*ConstantNameAndTypeInfo)
- name := self.getUtf8(ntInfo.nameIndex)
- _type := self.getUtf8(ntInfo.descriptorIndex)
- return name, _type
- }
- func (self ConstantPool) getClassName(index uint16) string {
- classInfo := self.getConstantInfo(index).(*ConstantClassInfo)
- return self.getUtf8(classInfo.nameIndex)
- }
- func (self ConstantPool) getUtf8(index uint16) string {
- utf8Info := self.getConstantInfo(index).(*ConstantUtf8Info)
- return utf8Info.str
- }
常量池表头给出的大小比实际大1,假设是n,实际有n-1个,有效索引是1~n-1,CONSTANT_Long和CONSTANT_Double占用两个位置
readConstantPool()函数是常量池的读取,getConstantInfo()函数按索引查找常量,getNameAndType()从常量池查找字段或方法的名字和描述符,getClassName()从常量池查找类名,getUtf8()从常量池查找UTF-8字符串。
2、ConstantInfo接口
创建constant_info.go文件
- package classfile
- // Constant pool tags
- const (
- CONSTANT_Class = 7
- CONSTANT_Fieldref = 9
- CONSTANT_Methodref = 10
- CONSTANT_InterfaceMethodref = 11
- CONSTANT_String = 8
- CONSTANT_Integer = 3
- CONSTANT_Float = 4
- CONSTANT_Long = 5
- CONSTANT_Double = 6
- CONSTANT_NameAndType = 12
- CONSTANT_Utf8 = 1
- CONSTANT_MethodHandle = 15
- CONSTANT_MethodType = 16
- CONSTANT_InvokeDynamic = 18
- )
- /*
- cp_info {
- u1 tag;
- u1 info[];
- }
- */
- type ConstantInfo interface {
- readInfo(reader *ClassReader)
- }
- func readConstantInfo(reader *ClassReader, cp ConstantPool) ConstantInfo {
- tag := reader.readUint8()
- c := newConstantInfo(tag, cp)
- c.readInfo(reader)
- return c
- }
- // todo ugly code
- func newConstantInfo(tag uint8, cp ConstantPool) ConstantInfo {
- switch tag {
- case CONSTANT_Integer:
- return &ConstantIntegerInfo{}
- case CONSTANT_Float:
- return &ConstantFloatInfo{}
- case CONSTANT_Long:
- return &ConstantLongInfo{}
- case CONSTANT_Double:
- return &ConstantDoubleInfo{}
- case CONSTANT_Utf8:
- return &ConstantUtf8Info{}
- case CONSTANT_String:
- return &ConstantStringInfo{cp: cp}
- case CONSTANT_Class:
- return &ConstantClassInfo{cp: cp}
- case CONSTANT_Fieldref:
- return &ConstantFieldrefInfo{ConstantMemberrefInfo{cp: cp}}
- case CONSTANT_Methodref:
- return &ConstantMethodrefInfo{ConstantMemberrefInfo{cp: cp}}
- case CONSTANT_InterfaceMethodref:
- return &ConstantInterfaceMethodrefInfo{ConstantMemberrefInfo{cp: cp}}
- case CONSTANT_NameAndType:
- return &ConstantNameAndTypeInfo{}
- case CONSTANT_MethodType:
- return &ConstantMethodTypeInfo{}
- case CONSTANT_MethodHandle:
- return &ConstantMethodHandleInfo{}
- case CONSTANT_InvokeDynamic:
- return &ConstantInvokeDynamicInfo{}
- default:
- panic("java.lang.ClassFormatError: constant pool tag!")
- }
- }
- readInfo()读取常量信息,需要由具体的常量结构体实现,readConstantInfo()函数先读出tag值然后调用newConstantInfo()创造具体常量最后调用常量的readInfo()方法读出常量信息。
- 3、CONSTANT_Integer_info、CONSTANT_Float_info和CONSTANT_Double_info
创建cp_numeric.go文件
- package classfile
- import "math"
- /*
- CONSTANT_Integer_info {
- u1 tag;
- u4 bytes;
- }
- */
- type ConstantIntegerInfo struct {
- val int32
- }
- func (self *ConstantIntegerInfo) readInfo(reader *ClassReader) {
- bytes := reader.readUint32()
- self.val = int32(bytes)
- }
- func (self *ConstantIntegerInfo) Value() int32 {
- return self.val
- }
- /*
- CONSTANT_Float_info {
- u1 tag;
- u4 bytes;
- }
- */
- type ConstantFloatInfo struct {
- val float32
- }
- func (self *ConstantFloatInfo) readInfo(reader *ClassReader) {
- bytes := reader.readUint32()
- self.val = math.Float32frombits(bytes)
- }
- func (self *ConstantFloatInfo) Value() float32 {
- return self.val
- }
- /*
- CONSTANT_Long_info {
- u1 tag;
- u4 high_bytes;
- u4 low_bytes;
- }
- */
- type ConstantLongInfo struct {
- val int64
- }
- func (self *ConstantLongInfo) readInfo(reader *ClassReader) {
- bytes := reader.readUint64()
- self.val = int64(bytes)
- }
- func (self *ConstantLongInfo) Value() int64 {
- return self.val
- }
- /*
- CONSTANT_Double_info {
- u1 tag;
- u4 high_bytes;
- u4 low_bytes;
- }
- */
- type ConstantDoubleInfo struct {
- val float64
- }
- func (self *ConstantDoubleInfo) readInfo(reader *ClassReader) {
- bytes := reader.readUint64()
- self.val = math.Float64frombits(bytes)
- }
- func (self *ConstantDoubleInfo) Value() float64 {
- return self.val
- }
4、CONSTANT_Utf8_info
创建cp_utf8.go
- package classfile
- import "fmt"
- import "unicode/utf16"
- /*
- CONSTANT_Utf8_info {
- u1 tag;
- u2 length;
- u1 bytes[length];
- }
- */
- type ConstantUtf8Info struct {
- str string
- }
- func (self *ConstantUtf8Info) readInfo(reader *ClassReader) {
- length := uint32(reader.readUint16())
- bytes := reader.readBytes(length)
- self.str = decodeMUTF8(bytes)
- }
- func (self *ConstantUtf8Info) Str() string {
- return self.str
- }
- /*
- func decodeMUTF8(bytes []byte) string {
- return string(bytes) // not correct!
- }
- */
- // mutf8 -> utf16 -> utf32 -> string
- // see java.io.DataInputStream.readUTF(DataInput)
- func decodeMUTF8(bytearr []byte) string {
- utflen := len(bytearr)
- chararr := make([]uint16, utflen)
- var c, char2, char3 uint16
- count := 0
- chararr_count := 0
- for count < utflen {
- c = uint16(bytearr[count])
- if c > 127 {
- break
- }
- count++
- chararr[chararr_count] = c
- chararr_count++
- }
- for count < utflen {
- c = uint16(bytearr[count])
- switch c >> 4 {
- case 0, 1, 2, 3, 4, 5, 6, 7:
- /* 0xxxxxxx*/
- count++
- chararr[chararr_count] = c
- chararr_count++
- case 12, 13:
- /* 110x xxxx 10xx xxxx*/
- count += 2
- if count > utflen {
- panic("malformed input: partial character at end")
- }
- char2 = uint16(bytearr[count-1])
- if char2&0xC0 != 0x80 {
- panic(fmt.Errorf("malformed input around byte %v", count))
- }
- chararr[chararr_count] = c&0x1F<<6 | char2&0x3F
- chararr_count++
- case 14:
- /* 1110 xxxx 10xx xxxx 10xx xxxx*/
- count += 3
- if count > utflen {
- panic("malformed input: partial character at end")
- }
- char2 = uint16(bytearr[count-2])
- char3 = uint16(bytearr[count-1])
- if char2&0xC0 != 0x80 || char3&0xC0 != 0x80 {
- panic(fmt.Errorf("malformed input around byte %v", (count - 1)))
- }
- chararr[chararr_count] = c&0x0F<<12 | char2&0x3F<<6 | char3&0x3F<<0
- chararr_count++
- default:
- /* 10xx xxxx, 1111 xxxx */
- panic(fmt.Errorf("malformed input around byte %v", count))
- }
- }
- // The number of chars produced may be less than utflen
- chararr = chararr[0:chararr_count]
- runes := utf16.Decode(chararr)
- return string(runes)
- }
readInfo()方法先读出[]byte,然后调用decodeMUTF8()函数把他解析成go字符串。
5、CONSTANT_String_info
创建cp_string.go
- package classfile
- /*
- CONSTANT_String_info {
- u1 tag;
- u2 string_index;
- }
- */
- type ConstantStringInfo struct {
- cp ConstantPool
- stringIndex uint16
- }
- func (self *ConstantStringInfo) readInfo(reader *ClassReader) {
- self.stringIndex = reader.readUint16()
- }
- func (self *ConstantStringInfo) String() string {
- return self.cp.getUtf8(self.stringIndex)
- }
6、CONSTANT_Class_info
创建cp_class.go
- package classfile
- /*
- CONSTANT_Class_info {
- u1 tag;
- u2 name_index;
- }
- */
- type ConstantClassInfo struct {
- cp ConstantPool
- nameIndex uint16
- }
- func (self *ConstantClassInfo) readInfo(reader *ClassReader) {
- self.nameIndex = reader.readUint16()
- }
- func (self *ConstantClassInfo) Name() string {
- return self.cp.getUtf8(self.nameIndex)
- }
7、CONSTANT_NameAndType_info
- package classfile
- /*
- CONSTANT_NameAndType_info {
- u1 tag;
- u2 name_index;
- u2 descriptor_index;
- }
- */
- type ConstantNameAndTypeInfo struct {
- nameIndex uint16 //名称下标
- descriptorIndex uint16 //描述符下标
- }
- func (self *ConstantNameAndTypeInfo) readInfo(reader *ClassReader) {
- self.nameIndex = reader.readUint16()
- self.descriptorIndex = reader.readUint16()
- }
8、CONSTANT_Fieldref_info、CONSTANT_FMethodref_info和CONSTANT_Interfaceref_info
创建cp_member_ref.go文件
- package classfile
- /*
- CONSTANT_Fieldref_info {
- u1 tag;
- u2 class_index;
- u2 name_and_type_index;
- }
- CONSTANT_Methodref_info {
- u1 tag;
- u2 class_index;
- u2 name_and_type_index;
- }
- CONSTANT_InterfaceMethodref_info {
- u1 tag;
- u2 class_index;
- u2 name_and_type_index;
- }
- */
- type ConstantFieldrefInfo struct{ ConstantMemberrefInfo }
- type ConstantMethodrefInfo struct{ ConstantMemberrefInfo }
- type ConstantInterfaceMethodrefInfo struct{ ConstantMemberrefInfo }
- type ConstantMemberrefInfo struct {
- cp ConstantPool
- classIndex uint16
- nameAndTypeIndex uint16
- }
- func (self *ConstantMemberrefInfo) readInfo(reader *ClassReader) {
- self.classIndex = reader.readUint16()
- self.nameAndTypeIndex = reader.readUint16()
- }
- func (self *ConstantMemberrefInfo) ClassName() string {
- return self.cp.getClassName(self.classIndex)
- }
- func (self *ConstantMemberrefInfo) NameAndDescriptor() (string, string) {
- return self.cp.getNameAndType(self.nameAndTypeIndex)
- }
四、属性解析表
属性表集合:https://www.cnblogs.com/lrh-xl/p/5351182.html
1、AttributeInfo接口
创建attribute_info.go文件
- package classfile
- /*
- attribute_info {
- u2 attribute_name_index;
- u4 attribute_length;
- u1 info[attribute_length];
- }
- */
- type AttributeInfo interface {
- readInfo(reader *ClassReader)
- }
- func readAttributes(reader *ClassReader, cp ConstantPool) []AttributeInfo {
- attributesCount := reader.readUint16()
- attributes := make([]AttributeInfo, attributesCount)
- for i := range attributes {
- attributes[i] = readAttribute(reader, cp)
- }
- return attributes
- }
- func readAttribute(reader *ClassReader, cp ConstantPool) AttributeInfo {
- attrNameIndex := reader.readUint16()
- attrName := cp.getUtf8(attrNameIndex)
- attrLen := reader.readUint32()
- attrInfo := newAttributeInfo(attrName, attrLen, cp)
- attrInfo.readInfo(reader)
- return attrInfo
- }
- func newAttributeInfo(attrName string, attrLen uint32, cp ConstantPool) AttributeInfo {
- switch attrName {
- case "Code":
- return &CodeAttribute{cp: cp}
- case "ConstantValue":
- return &ConstantValueAttribute{}
- case "Deprecated":
- return &DeprecatedAttribute{}
- case "Exceptions":
- return &ExceptionsAttribute{}
- case "LineNumberTable":
- return &LineNumberTableAttribute{}
- case "LocalVariableTable":
- return &LocalVariableTableAttribute{}
- case "SourceFile":
- return &SourceFileAttribute{cp: cp}
- case "Synthetic":
- return &SyntheticAttribute{}
- default:
- return &UnparsedAttribute{attrName, attrLen, nil}
- }
- }
函数的作用和常量表的constant_pool_info中的函数功能相似,newAttributeInfo()函数创建属性实例
UnparsedAttribute结构体在attr_unparsed.go文件中
- package classfile
- /*
- attribute_info {
- u2 attribute_name_index;
- u4 attribute_length;
- u1 info[attribute_length];
- }
- */
- type UnparsedAttribute struct {
- name string
- length uint32
- info []byte
- }
- func (self *UnparsedAttribute) readInfo(reader *ClassReader) {
- self.info = reader.readBytes(self.length)
- }
- func (self *UnparsedAttribute) Info() []byte {
- return self.info
- }
2、Deprecated和Synthetic
都是标记用标签,创建attr_markers.go
- package classfile
- /*
- Deprecated_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- }
- */
- type DeprecatedAttribute struct {
- MarkerAttribute
- }
- /*
- Synthetic_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- }
- */
- type SyntheticAttribute struct {
- MarkerAttribute
- }
- type MarkerAttribute struct{}
- func (self *MarkerAttribute) readInfo(reader *ClassReader) {
- // read nothing
- }
由于没有数据,readInfo()函数都为空。
3、SourceFile属性
可选长属性,只出现在ClassFile结构,用于指出源文件名。创建attr_source_file.go文件
- package classfile
- /*
- SourceFile_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 sourcefile_index;
- }
- */
- type SourceFileAttribute struct {
- cp ConstantPool
- sourceFileIndex uint16
- }
- func (self *SourceFileAttribute) readInfo(reader *ClassReader) {
- self.sourceFileIndex = reader.readUint16()
- }
- func (self *SourceFileAttribute) FileName() string {
- return self.cp.getUtf8(self.sourceFileIndex)
- }
4、ConstantValue属性
定长属性,只会出现在field_info结构中,表示常量表达式。创建attr_constant_value.go
- package classfile
- /*
- ConstantValue_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 constantvalue_index;
- }
- */
- type ConstantValueAttribute struct {
- constantValueIndex uint16
- }
- func (self *ConstantValueAttribute) readInfo(reader *ClassReader) {
- self.constantValueIndex = reader.readUint16()
- }
- func (self *ConstantValueAttribute) ConstantValueIndex() uint16 {
- return self.constantValueIndex
- }
5、Code属性
创建attr_code.go文件
- package classfile
- /*
- 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;
- { u2 start_pc;
- u2 end_pc;
- u2 handler_pc;
- u2 catch_type;
- } exception_table[exception_table_length];
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
- */
- type CodeAttribute struct {
- cp ConstantPool
- maxStack uint16
- maxLocals uint16
- code []byte
- exceptionTable []*ExceptionTableEntry
- attributes []AttributeInfo
- }
- func (self *CodeAttribute) readInfo(reader *ClassReader) {
- self.maxStack = reader.readUint16()
- self.maxLocals = reader.readUint16()
- codeLength := reader.readUint32()
- self.code = reader.readBytes(codeLength)
- self.exceptionTable = readExceptionTable(reader)
- self.attributes = readAttributes(reader, self.cp)
- }
- func (self *CodeAttribute) MaxStack() uint {
- return uint(self.maxStack)
- }
- func (self *CodeAttribute) MaxLocals() uint {
- return uint(self.maxLocals)
- }
- func (self *CodeAttribute) Code() []byte {
- return self.code
- }
- func (self *CodeAttribute) ExceptionTable() []*ExceptionTableEntry {
- return self.exceptionTable
- }
- type ExceptionTableEntry struct {
- startPc uint16
- endPc uint16
- handlerPc uint16
- catchType uint16
- }
- func readExceptionTable(reader *ClassReader) []*ExceptionTableEntry {
- exceptionTableLength := reader.readUint16()
- exceptionTable := make([]*ExceptionTableEntry, exceptionTableLength)
- for i := range exceptionTable {
- exceptionTable[i] = &ExceptionTableEntry{
- startPc: reader.readUint16(),
- endPc: reader.readUint16(),
- handlerPc: reader.readUint16(),
- catchType: reader.readUint16(),
- }
- }
- return exceptionTable
- }
- func (self *ExceptionTableEntry) StartPc() uint16 {
- return self.startPc
- }
- func (self *ExceptionTableEntry) EndPc() uint16 {
- return self.endPc
- }
- func (self *ExceptionTableEntry) HandlerPc() uint16 {
- return self.handlerPc
- }
- func (self *ExceptionTableEntry) CatchType() uint16 {
- return self.catchType
- }
6、Exceptions属性
创建attr_exceptions.go文件
- package classfile
- /*
- Exceptions_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 number_of_exceptions;
- u2 exception_index_table[number_of_exceptions];
- }
- */
- type ExceptionsAttribute struct {
- exceptionIndexTable []uint16
- }
- func (self *ExceptionsAttribute) readInfo(reader *ClassReader) {
- self.exceptionIndexTable = reader.readUint16s()
- }
- func (self *ExceptionsAttribute) ExceptionIndexTable() []uint16 {
- return self.exceptionIndexTable
- }
7、LineNumberTable和LocalVariableTable属性
创建attr_line_number_table.go
- package classfile
- /*
- LineNumberTable_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 line_number_table_length;
- { u2 start_pc;
- u2 line_number;
- } line_number_table[line_number_table_length];
- }
- */
- type LineNumberTableAttribute struct {
- lineNumberTable []*LineNumberTableEntry
- }
- type LineNumberTableEntry struct {
- startPc uint16
- lineNumber uint16
- }
- func (self *LineNumberTableAttribute) readInfo(reader *ClassReader) {
- lineNumberTableLength := reader.readUint16()
- self.lineNumberTable = make([]*LineNumberTableEntry, lineNumberTableLength)
- for i := range self.lineNumberTable {
- self.lineNumberTable[i] = &LineNumberTableEntry{
- startPc: reader.readUint16(),
- lineNumber: reader.readUint16(),
- }
- }
- }
- func (self *LineNumberTableAttribute) GetLineNumber(pc int) int {
- for i := len(self.lineNumberTable) - 1; i >= 0; i-- {
- entry := self.lineNumberTable[i]
- if pc >= int(entry.startPc) {
- return int(entry.lineNumber)
- }
- }
- return -1
- }
创建attr_local_variable_table.go文件
- package classfile
- /*
- LocalVariableTable_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 local_variable_table_length;
- { u2 start_pc;
- u2 length;
- u2 name_index;
- u2 descriptor_index;
- u2 index;
- } local_variable_table[local_variable_table_length];
- }
- */
- type LocalVariableTableAttribute struct {
- localVariableTable []*LocalVariableTableEntry
- }
- type LocalVariableTableEntry struct {
- startPc uint16
- length uint16
- nameIndex uint16
- descriptorIndex uint16
- index uint16
- }
- func (self *LocalVariableTableAttribute) readInfo(reader *ClassReader) {
- localVariableTableLength := reader.readUint16()
- self.localVariableTable = make([]*LocalVariableTableEntry, localVariableTableLength)
- for i := range self.localVariableTable {
- self.localVariableTable[i] = &LocalVariableTableEntry{
- startPc: reader.readUint16(),
- length: reader.readUint16(),
- nameIndex: reader.readUint16(),
- descriptorIndex: reader.readUint16(),
- index: reader.readUint16(),
- }
- }
- }
其余文件可以从这里下载:https://github.com/zxh0/jvmgo-book
五、测试
打开main.go文件,修改import语句和startJVM()函数
import "jvmgo/classfile"
修改startJVM()函数
- func startJVM(cmd *Cmd) {
- cp := classpath.Parse(cmd.XjreOption, cmd.cpOption)
- className := strings.Replace(cmd.class, ".", "/", -1)
- cf := loadClass(className, cp)
- fmt.Println(cmd.class)
- printClassInfo(cf)
- }
添加loadClass()函数
- func loadClass(className string, cp *classpath.Classpath) *classfile.ClassFile {
- classData, _, err := cp.ReadClass(className)
- if err != nil {
- panic(err)
- }
- cf, err := classfile.Parse(classData)
- if err != nil {
- panic(err)
- }
- return cf
- }
添加printClassInfo()函数对class信息进行输出
- func printClassInfo(cf *classfile.ClassFile) {
- fmt.Printf("version: %v.%v\n", cf.MajorVersion(), cf.MinorVersion())
- fmt.Printf("constants count: %v\n", len(cf.ConstantPool()))
- fmt.Printf("access flags: 0x%x\n", cf.AccessFlags())
- fmt.Printf("this class: %v\n", cf.ClassName())
- fmt.Printf("super class: %v\n", cf.SuperClassName())
- fmt.Printf("interfaces: %v\n", cf.InterfaceNames())
- fmt.Printf("fields count: %v\n", len(cf.Fields()))
- for _, f := range cf.Fields() {
- fmt.Printf(" %s\n", f.Name())
- }
- fmt.Printf("methods count: %v\n", len(cf.Methods()))
- for _, m := range cf.Methods() {
- fmt.Printf(" %s\n", m.Name())
- }
- }
在命令行窗口输入go install jvmgo
在%GOPATH%\bin下命令行窗口运行jvmgo.exe文件,测试java.lang.String.class的信息。
- PS D:\Program_Files\go\bin> .\jvmgo -Xjre "D:\APP\java\java1.8\jdk1.8.0_171\jre" java.lang.String
- java.lang.String
- version: 52.0
- constants count: 540
- access flags: 0x31
- this class: java/lang/String
- super class: java/lang/Object
- interfaces: [java/io/Serializable java/lang/Comparable java/lang/CharSequence]
- fields count: 5
- value
- hash
- serialVersionUID
- serialPersistentFields
- CASE_INSENSITIVE_ORDER
- methods count: 94
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- checkBounds
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- <init>
- length
- isEmpty
- charAt
- codePointAt
- codePointBefore
- codePointCount
- offsetByCodePoints
- getChars
- getChars
- getBytes
- getBytes
- getBytes
- getBytes
- equals
- contentEquals
- nonSyncContentEquals
- contentEquals
- equalsIgnoreCase
- compareTo
- compareToIgnoreCase
- regionMatches
- regionMatches
- startsWith
- startsWith
- endsWith
- hashCode
- indexOf
- indexOf
- indexOfSupplementary
- lastIndexOf
- lastIndexOf
- lastIndexOfSupplementary
- indexOf
- indexOf
- indexOf
- indexOf
- lastIndexOf
- lastIndexOf
- lastIndexOf
- lastIndexOf
- substring
- substring
- subSequence
- concat
- replace
- matches
- contains
- replaceFirst
- replaceAll
- replace
- split
- split
- join
- join
- toLowerCase
- toLowerCase
- toUpperCase
- toUpperCase
- trim
- toString
- toCharArray
- format
- format
- valueOf
- valueOf
- valueOf
- copyValueOf
- copyValueOf
- valueOf
- valueOf
- valueOf
- valueOf
- valueOf
- valueOf
- intern
- compareTo
- <clinit>
三、解析class文件的更多相关文章
- 解析Xml文件的三种方式及其特点
解析Xml文件的三种方式 1.Sax解析(simple api for xml) 使用流式处理的方式,它并不记录所读内容的相关信息.它是一种以事件为驱动的XML API,解析速度快,占用内存少.使用 ...
- 解析Xml文件的三种方式
1.Sax解析(simple api for xml) 使用流式处理的方式,它并不记录所读内容的相关信息.它是一种以事件为驱动的XML API,解析速度快,占用内存少.使用回调函数来实现. clas ...
- CSharpGL(9)解析OBJ文件并用CSharpGL渲染
CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...
- JAVA中使用DOM解析XML文件
XML是一种方便快捷高效的数据保存传输的格式,在JSON广泛使用之前,XML是服务器和客户端之间数据传输的主要方式.因此,需要使用各种方式,解析服务器传送过来的信息,以供使用者查看. JAVA作为一种 ...
- java中采用dom4j解析xml文件
一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...
- java解析XML文件
dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...
- 命令行解析Crash文件
做了快两年的开发了,没有写过博客,最近公司app上架,程序崩溃被拒绝了,可是给的crash文件,又看不出哪里的问题,网上各种搜,终于找到了解决的办法,想想还是写个博客吧,希望给哪些也遇到这类问题的朋友 ...
- 命令行工具解析Crash文件,dSYM文件进行符号化
备份 文/爱掏蜂窝的熊(简书作者)原文链接:http://www.jianshu.com/p/0b6f5148dab8著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 序 在日常开发 ...
- Android pull解析xml文件
本文介绍android中使用pull来解析xml文件 先自己写一个xml文件,存一些天气信息 <?xml version="1.0" encoding="UTF-8 ...
随机推荐
- php7 新内容
1.use增强 以thinkphp5.0为例 namespace app\home\controller;use think\{Loader,Controller,Captcha,Request}; ...
- 阿里云OSS同城冗余存储正式商业化,提供云上同城容灾能力
近日,阿里云正式发布OSS同城冗余存储产品.这是国内目前提供同城多AZ冗余部署能力覆盖最广的云上对象存储产品,可以实现云存储的同城双活,满足企业级客户对于“发生机房级灾难事件时数据不丢失,业务不中断” ...
- 在laravel框架中使用ajax请求报错419
laravel框架中报419 419 unknown status 这个时候你需要将这个接口放到api路由上,这样可以跳过CSRF的检查
- jQuery 鼠标移入图片 显示大图并跟随鼠标移动
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 2016 Asia Jakarta Regional Contest A - Confusing Date Format UVALive 7711 【模拟题】
A - Confusing Date Format 题目大意:就是有六种日期格式,给你一个字符串,判断它能组成多少种可能的日期. 第一次WA是:1.没有判重,2.没有特判题目要求的数据,3.判断天数时 ...
- oracle函数 TO_CHAR(x[[,c2],C3])
[功能]将日期或数据转换为char数据类型 [参数] x是一个date或number数据类型. c2为格式参数 c3为NLS设置参数 如果x为日期nlsparm=NLS_DATE_LANGUAGE 控 ...
- Java练习 SDUT-1586_计算组合数
计算组合数 Time Limit: 1000 ms Memory Limit: 32768 KiB Problem Description 计算组合数.C(n,m),表示从n个数中选择m个的组合数. ...
- PHP中header头设置Cookie与内置setCookie的区别
首先声明,浏览的Cookie操作都是通过HTTP Header(俗称“Http头”) 来实现.所有的服务器与客户端之间Cookie数据传输都是通过Http请求头来操作. PHP中setCookie(函 ...
- Vue.js 第1章 Vue常用指令学习
今日目标 能够写出第一个vue应用程序 能够接受为什么需要学vue 能够使用指令 能够通过指定完成简单的业务(增加删除查询) 能够理解mvvm 为什么要学习vue 企业需要 可以提高开发效率 实现vu ...
- Hadoop应用程序示例