• 三、解析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%srcjvmgoclassfile文件夹下创建以下文件

    1、读取数据

    创建class_reader.go

     1 package classfile
     2 
     3 import "encoding/binary"
     4 
     5 type ClassReader struct {
     6     data []byte
     7 }
     8 
     9 // u1
    10 func (self *ClassReader) readUint8() uint8 {
    11     val := self.data[0]
    12     self.data = self.data[1:]
    13     return val
    14 }
    15 
    16 // u2
    17 func (self *ClassReader) readUint16() uint16 {
    18     val := binary.BigEndian.Uint16(self.data)
    19     self.data = self.data[2:]
    20     return val
    21 }
    22 
    23 // u4
    24 func (self *ClassReader) readUint32() uint32 {
    25     val := binary.BigEndian.Uint32(self.data)
    26     self.data = self.data[4:]
    27     return val
    28 }
    29 
    30 func (self *ClassReader) readUint64() uint64 {
    31     val := binary.BigEndian.Uint64(self.data)
    32     self.data = self.data[8:]
    33     return val
    34 }
    35 
    36 func (self *ClassReader) readUint16s() []uint16 {
    37     n := self.readUint16()
    38     s := make([]uint16, n)
    39     for i := range s {
    40         s[i] = self.readUint16()
    41     }
    42     return s
    43 }
    44 
    45 func (self *ClassReader) readBytes(n uint32) []byte {
    46     bytes := self.data[:n]
    47     self.data = self.data[n:]
    48     return bytes
    49 }

    ClassReader结构是[]byte类型的包装,依据Go语言的reslice语法跳过已经读取的数据。readUint8()是读取u1类型数据,readUint16()是读取u2类型数据,encoding/binary中有一个变量BigEndian,可以从[]byte中读取多字节,readUint32()读取u4类型数据,readUint64()读取uint64类型数据。readUint16s()读取uint16表,表的大小由开头的uint16数据指出。最后一个是readBytes()读取指定数量的字节。

    2、整体结构

    创建class_file.go文件

      1 package classfile
      2 
      3 import "fmt"
      4 
      5 /*
      6 ClassFile {
      7     u4             magic;
      8     u2             minor_version;
      9     u2             major_version;
     10     u2             constant_pool_count;
     11     cp_info        constant_pool[constant_pool_count-1];
     12     u2             access_flags;
     13     u2             this_class;
     14     u2             super_class;
     15     u2             interfaces_count;
     16     u2             interfaces[interfaces_count];
     17     u2             fields_count;
     18     field_info     fields[fields_count];
     19     u2             methods_count;
     20     method_info    methods[methods_count];
     21     u2             attributes_count;
     22     attribute_info attributes[attributes_count];
     23 }
     24 */
     25 type ClassFile struct {
     26     //magic      uint32
     27     minorVersion uint16
     28     majorVersion uint16
     29     constantPool ConstantPool
     30     accessFlags  uint16
     31     thisClass    uint16
     32     superClass   uint16
     33     interfaces   []uint16
     34     fields       []*MemberInfo
     35     methods      []*MemberInfo
     36     attributes   []AttributeInfo
     37 }
     38 
     39 func Parse(classData []byte) (cf *ClassFile, err error) {
     40     defer func() {
     41         if r := recover(); r != nil {
     42             var ok bool
     43             err, ok = r.(error)
     44             if !ok {
     45                 err = fmt.Errorf("%v", r)
     46             }
     47         }
     48     }()
     49 
     50     cr := &ClassReader{classData}
     51     cf = &ClassFile{}
     52     cf.read(cr)
     53     return
     54 }
     55 
     56 func (self *ClassFile) read(reader *ClassReader) {
     57     self.readAndCheckMagic(reader)
     58     self.readAndCheckVersion(reader)
     59     self.constantPool = readConstantPool(reader)
     60     self.accessFlags = reader.readUint16()
     61     self.thisClass = reader.readUint16()
     62     self.superClass = reader.readUint16()
     63     self.interfaces = reader.readUint16s()
     64     self.fields = readMembers(reader, self.constantPool)
     65     self.methods = readMembers(reader, self.constantPool)
     66     self.attributes = readAttributes(reader, self.constantPool)
     67 }
     68 
     69 func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
     70     magic := reader.readUint32()
     71     if magic != 0xCAFEBABE {
     72         panic("java.lang.ClassFormatError: magic!")
     73     }
     74 }
     75 
     76 func (self *ClassFile) readAndCheckVersion(reader *ClassReader) {
     77     self.minorVersion = reader.readUint16()
     78     self.majorVersion = reader.readUint16()
     79     switch self.majorVersion {
     80     case 45:
     81         return
     82     case 46, 47, 48, 49, 50, 51, 52:
     83         if self.minorVersion == 0 {
     84             return
     85         }
     86     }
     87 
     88     panic("java.lang.UnsupportedClassVersionError!")
     89 }
     90 
     91 func (self *ClassFile) MinorVersion() uint16 {
     92     return self.minorVersion
     93 }
     94 func (self *ClassFile) MajorVersion() uint16 {
     95     return self.majorVersion
     96 }
     97 func (self *ClassFile) ConstantPool() ConstantPool {
     98     return self.constantPool
     99 }
    100 func (self *ClassFile) AccessFlags() uint16 {
    101     return self.accessFlags
    102 }
    103 func (self *ClassFile) Fields() []*MemberInfo {
    104     return self.fields
    105 }
    106 func (self *ClassFile) Methods() []*MemberInfo {
    107     return self.methods
    108 }
    109 
    110 func (self *ClassFile) ClassName() string {
    111     return self.constantPool.getClassName(self.thisClass)
    112 }
    113 
    114 func (self *ClassFile) SuperClassName() string {
    115     if self.superClass > 0 {
    116         return self.constantPool.getClassName(self.superClass)
    117     }
    118     return ""
    119 }
    120 
    121 func (self *ClassFile) InterfaceNames() []string {
    122     interfaceNames := make([]string, len(self.interfaces))
    123     for i, cpIndex := range self.interfaces {
    124         interfaceNames[i] = self.constantPool.getClassName(cpIndex)
    125     }
    126     return interfaceNames
    127 }

    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文件

     1 package classfile
     2 
     3 /*
     4 field_info {
     5     u2             access_flags;
     6     u2             name_index;
     7     u2             descriptor_index;
     8     u2             attributes_count;
     9     attribute_info attributes[attributes_count];
    10 }
    11 method_info {
    12     u2             access_flags;
    13     u2             name_index;
    14     u2             descriptor_index;
    15     u2             attributes_count;
    16     attribute_info attributes[attributes_count];
    17 }
    18 */
    19 
    20 type MemberInfo struct {
    21     cp              ConstantPool
    22     accessFlags     uint16
    23     nameIndex       uint16
    24     descriptorIndex uint16
    25     attributes      []AttributeInfo
    26 }
    27 
    28 // read field or method table
    29 func readMembers(reader *ClassReader, cp ConstantPool) []*MemberInfo {
    30     memberCount := reader.readUint16()
    31     members := make([]*MemberInfo, memberCount)
    32     for i := range members {
    33         members[i] = readMember(reader, cp)
    34     }
    35     return members
    36 }
    37 
    38 func readMember(reader *ClassReader, cp ConstantPool) *MemberInfo {
    39     return &MemberInfo{
    40         cp:              cp,
    41         accessFlags:     reader.readUint16(),
    42         nameIndex:       reader.readUint16(),
    43         descriptorIndex: reader.readUint16(),
    44         attributes:      readAttributes(reader, cp),
    45     }
    46 }
    47 
    48 func (self *MemberInfo) AccessFlags() uint16 {
    49     return self.accessFlags
    50 }
    51 func (self *MemberInfo) Name() string {
    52     return self.cp.getUtf8(self.nameIndex)
    53 }
    54 func (self *MemberInfo) Descriptor() string {
    55     return self.cp.getUtf8(self.descriptorIndex)
    56 }

    MermberInfo结构体,cp字段保存常量池指针,readMembers()读取字段表或方法表,readMermber()读取字段或方法数据。Name()从常量池字段查找方法或字段名,Descriptor()从常量池查找字段或方法描述符。

    三、解析常量池

    1、ConstantPool

    创建constant_pool.go文件

     1 package classfile
     2 
     3 import "fmt"
     4 
     5 type ConstantPool []ConstantInfo
     6 
     7 func readConstantPool(reader *ClassReader) ConstantPool {
     8     cpCount := int(reader.readUint16())
     9     cp := make([]ConstantInfo, cpCount)
    10 
    11     // The constant_pool table is indexed from 1 to constant_pool_count - 1.
    12     for i := 1; i < cpCount; i++ {
    13         cp[i] = readConstantInfo(reader, cp)
    14         // http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.5
    15         // All 8-byte constants take up two entries in the constant_pool table of the class file.
    16         // If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item in the constant_pool
    17         // table at index n, then the next usable item in the pool is located at index n+2.
    18         // The constant_pool index n+1 must be valid but is considered unusable.
    19         switch cp[i].(type) {
    20         case *ConstantLongInfo, *ConstantDoubleInfo:
    21             i++
    22         }
    23     }
    24 
    25     return cp
    26 }
    27 
    28 func (self ConstantPool) getConstantInfo(index uint16) ConstantInfo {
    29     if cpInfo := self[index]; cpInfo != nil {
    30         return cpInfo
    31     }
    32     panic(fmt.Errorf("Invalid constant pool index: %v!", index))
    33 }
    34 
    35 func (self ConstantPool) getNameAndType(index uint16) (string, string) {
    36     ntInfo := self.getConstantInfo(index).(*ConstantNameAndTypeInfo)
    37     name := self.getUtf8(ntInfo.nameIndex)
    38     _type := self.getUtf8(ntInfo.descriptorIndex)
    39     return name, _type
    40 }
    41 
    42 func (self ConstantPool) getClassName(index uint16) string {
    43     classInfo := self.getConstantInfo(index).(*ConstantClassInfo)
    44     return self.getUtf8(classInfo.nameIndex)
    45 }
    46 
    47 func (self ConstantPool) getUtf8(index uint16) string {
    48     utf8Info := self.getConstantInfo(index).(*ConstantUtf8Info)
    49     return utf8Info.str
    50 }

    常量池表头给出的大小比实际大1,假设是n,实际有n-1个,有效索引是1~n-1,CONSTANT_Long和CONSTANT_Double占用两个位置

    readConstantPool()函数是常量池的读取,getConstantInfo()函数按索引查找常量,getNameAndType()从常量池查找字段或方法的名字和描述符,getClassName()从常量池查找类名,getUtf8()从常量池查找UTF-8字符串。

    2、ConstantInfo接口

    创建constant_info.go文件

     1 package classfile
     2 
     3 // Constant pool tags
     4 const (
     5     CONSTANT_Class              = 7
     6     CONSTANT_Fieldref           = 9
     7     CONSTANT_Methodref          = 10
     8     CONSTANT_InterfaceMethodref = 11
     9     CONSTANT_String             = 8
    10     CONSTANT_Integer            = 3
    11     CONSTANT_Float              = 4
    12     CONSTANT_Long               = 5
    13     CONSTANT_Double             = 6
    14     CONSTANT_NameAndType        = 12
    15     CONSTANT_Utf8               = 1
    16     CONSTANT_MethodHandle       = 15
    17     CONSTANT_MethodType         = 16
    18     CONSTANT_InvokeDynamic      = 18
    19 )
    20 
    21 /*
    22 cp_info {
    23     u1 tag;
    24     u1 info[];
    25 }
    26 */
    27 type ConstantInfo interface {
    28     readInfo(reader *ClassReader)
    29 }
    30 
    31 func readConstantInfo(reader *ClassReader, cp ConstantPool) ConstantInfo {
    32     tag := reader.readUint8()
    33     c := newConstantInfo(tag, cp)
    34     c.readInfo(reader)
    35     return c
    36 }
    37 
    38 // todo ugly code
    39 func newConstantInfo(tag uint8, cp ConstantPool) ConstantInfo {
    40     switch tag {
    41     case CONSTANT_Integer:
    42         return &ConstantIntegerInfo{}
    43     case CONSTANT_Float:
    44         return &ConstantFloatInfo{}
    45     case CONSTANT_Long:
    46         return &ConstantLongInfo{}
    47     case CONSTANT_Double:
    48         return &ConstantDoubleInfo{}
    49     case CONSTANT_Utf8:
    50         return &ConstantUtf8Info{}
    51     case CONSTANT_String:
    52         return &ConstantStringInfo{cp: cp}
    53     case CONSTANT_Class:
    54         return &ConstantClassInfo{cp: cp}
    55     case CONSTANT_Fieldref:
    56         return &ConstantFieldrefInfo{ConstantMemberrefInfo{cp: cp}}
    57     case CONSTANT_Methodref:
    58         return &ConstantMethodrefInfo{ConstantMemberrefInfo{cp: cp}}
    59     case CONSTANT_InterfaceMethodref:
    60         return &ConstantInterfaceMethodrefInfo{ConstantMemberrefInfo{cp: cp}}
    61     case CONSTANT_NameAndType:
    62         return &ConstantNameAndTypeInfo{}
    63     case CONSTANT_MethodType:
    64         return &ConstantMethodTypeInfo{}
    65     case CONSTANT_MethodHandle:
    66         return &ConstantMethodHandleInfo{}
    67     case CONSTANT_InvokeDynamic:
    68         return &ConstantInvokeDynamicInfo{}
    69     default:
    70         panic("java.lang.ClassFormatError: constant pool tag!")
    71     }
    72 }
    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

     1 package classfile
     2 
     3 import "fmt"
     4 import "unicode/utf16"
     5 
     6 /*
     7 CONSTANT_Utf8_info {
     8     u1 tag;
     9     u2 length;
    10     u1 bytes[length];
    11 }
    12 */
    13 type ConstantUtf8Info struct {
    14     str string
    15 }
    16 
    17 func (self *ConstantUtf8Info) readInfo(reader *ClassReader) {
    18     length := uint32(reader.readUint16())
    19     bytes := reader.readBytes(length)
    20     self.str = decodeMUTF8(bytes)
    21 }
    22 
    23 func (self *ConstantUtf8Info) Str() string {
    24     return self.str
    25 }
    26 
    27 /*
    28 func decodeMUTF8(bytes []byte) string {
    29     return string(bytes) // not correct!
    30 }
    31 */
    32 
    33 // mutf8 -> utf16 -> utf32 -> string
    34 // see java.io.DataInputStream.readUTF(DataInput)
    35 func decodeMUTF8(bytearr []byte) string {
    36     utflen := len(bytearr)
    37     chararr := make([]uint16, utflen)
    38 
    39     var c, char2, char3 uint16
    40     count := 0
    41     chararr_count := 0
    42 
    43     for count < utflen {
    44         c = uint16(bytearr[count])
    45         if c > 127 {
    46             break
    47         }
    48         count++
    49         chararr[chararr_count] = c
    50         chararr_count++
    51     }
    52 
    53     for count < utflen {
    54         c = uint16(bytearr[count])
    55         switch c >> 4 {
    56         case 0, 1, 2, 3, 4, 5, 6, 7:
    57             /* 0xxxxxxx*/
    58             count++
    59             chararr[chararr_count] = c
    60             chararr_count++
    61         case 12, 13:
    62             /* 110x xxxx   10xx xxxx*/
    63             count += 2
    64             if count > utflen {
    65                 panic("malformed input: partial character at end")
    66             }
    67             char2 = uint16(bytearr[count-1])
    68             if char2&0xC0 != 0x80 {
    69                 panic(fmt.Errorf("malformed input around byte %v", count))
    70             }
    71             chararr[chararr_count] = c&0x1F<<6 | char2&0x3F
    72             chararr_count++
    73         case 14:
    74             /* 1110 xxxx  10xx xxxx  10xx xxxx*/
    75             count += 3
    76             if count > utflen {
    77                 panic("malformed input: partial character at end")
    78             }
    79             char2 = uint16(bytearr[count-2])
    80             char3 = uint16(bytearr[count-1])
    81             if char2&0xC0 != 0x80 || char3&0xC0 != 0x80 {
    82                 panic(fmt.Errorf("malformed input around byte %v", (count - 1)))
    83             }
    84             chararr[chararr_count] = c&0x0F<<12 | char2&0x3F<<6 | char3&0x3F<<0
    85             chararr_count++
    86         default:
    87             /* 10xx xxxx,  1111 xxxx */
    88             panic(fmt.Errorf("malformed input around byte %v", count))
    89         }
    90     }
    91     // The number of chars produced may be less than utflen
    92     chararr = chararr[0:chararr_count]
    93     runes := utf16.Decode(chararr)
    94     return string(runes)
    95 }

    readInfo()方法先读出[]byte,然后调用decodeMUTF8()函数把他解析成go字符串。

    5、CONSTANT_String_info

    创建cp_string.go

     1 package classfile
     2 
     3 /*
     4 CONSTANT_String_info {
     5     u1 tag;
     6     u2 string_index;
     7 }
     8 */
     9 type ConstantStringInfo struct {
    10     cp          ConstantPool
    11     stringIndex uint16
    12 }
    13 
    14 func (self *ConstantStringInfo) readInfo(reader *ClassReader) {
    15     self.stringIndex = reader.readUint16()
    16 }
    17 func (self *ConstantStringInfo) String() string {
    18     return self.cp.getUtf8(self.stringIndex)
    19 }

    6、CONSTANT_Class_info

    创建cp_class.go

     1 package classfile
     2 
     3 /*
     4 CONSTANT_Class_info {
     5     u1 tag;
     6     u2 name_index;
     7 }
     8 */
     9 type ConstantClassInfo struct {
    10     cp        ConstantPool
    11     nameIndex uint16
    12 }
    13 
    14 func (self *ConstantClassInfo) readInfo(reader *ClassReader) {
    15     self.nameIndex = reader.readUint16()
    16 }
    17 func (self *ConstantClassInfo) Name() string {
    18     return self.cp.getUtf8(self.nameIndex)
    19 }

    7、CONSTANT_NameAndType_info

     1 package classfile
     2 
     3 /*
     4 CONSTANT_NameAndType_info {
     5     u1 tag;
     6     u2 name_index;
     7     u2 descriptor_index;
     8 }
     9 */
    10 type ConstantNameAndTypeInfo struct {
    11     nameIndex       uint16  //名称下标
    12     descriptorIndex uint16  //描述符下标
    13 }
    14 
    15 func (self *ConstantNameAndTypeInfo) readInfo(reader *ClassReader) {
    16     self.nameIndex = reader.readUint16()
    17     self.descriptorIndex = reader.readUint16()
    18 }

    8、CONSTANT_Fieldref_info、CONSTANT_FMethodref_info和CONSTANT_Interfaceref_info

    创建cp_member_ref.go文件

     1 package classfile
     2 
     3 /*
     4 CONSTANT_Fieldref_info {
     5     u1 tag;
     6     u2 class_index;
     7     u2 name_and_type_index;
     8 }
     9 CONSTANT_Methodref_info {
    10     u1 tag;
    11     u2 class_index;
    12     u2 name_and_type_index;
    13 }
    14 CONSTANT_InterfaceMethodref_info {
    15     u1 tag;
    16     u2 class_index;
    17     u2 name_and_type_index;
    18 }
    19 */
    20 type ConstantFieldrefInfo struct{ ConstantMemberrefInfo }
    21 type ConstantMethodrefInfo struct{ ConstantMemberrefInfo }
    22 type ConstantInterfaceMethodrefInfo struct{ ConstantMemberrefInfo }
    23 
    24 type ConstantMemberrefInfo struct {
    25     cp               ConstantPool
    26     classIndex       uint16
    27     nameAndTypeIndex uint16
    28 }
    29 
    30 func (self *ConstantMemberrefInfo) readInfo(reader *ClassReader) {
    31     self.classIndex = reader.readUint16()
    32     self.nameAndTypeIndex = reader.readUint16()
    33 }
    34 
    35 func (self *ConstantMemberrefInfo) ClassName() string {
    36     return self.cp.getClassName(self.classIndex)
    37 }
    38 func (self *ConstantMemberrefInfo) NameAndDescriptor() (string, string) {
    39     return self.cp.getNameAndType(self.nameAndTypeIndex)
    40 }

    四、属性解析表

    属性表集合:https://www.cnblogs.com/lrh-xl/p/5351182.html

    1、AttributeInfo接口

    创建attribute_info.go文件

     1 package classfile
     2 
     3 /*
     4 attribute_info {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u1 info[attribute_length];
     8 }
     9 */
    10 type AttributeInfo interface {
    11     readInfo(reader *ClassReader)
    12 }
    13 
    14 func readAttributes(reader *ClassReader, cp ConstantPool) []AttributeInfo {
    15     attributesCount := reader.readUint16()
    16     attributes := make([]AttributeInfo, attributesCount)
    17     for i := range attributes {
    18         attributes[i] = readAttribute(reader, cp)
    19     }
    20     return attributes
    21 }
    22 
    23 func readAttribute(reader *ClassReader, cp ConstantPool) AttributeInfo {
    24     attrNameIndex := reader.readUint16()
    25     attrName := cp.getUtf8(attrNameIndex)
    26     attrLen := reader.readUint32()
    27     attrInfo := newAttributeInfo(attrName, attrLen, cp)
    28     attrInfo.readInfo(reader)
    29     return attrInfo
    30 }
    31 
    32 func newAttributeInfo(attrName string, attrLen uint32, cp ConstantPool) AttributeInfo {
    33     switch attrName {
    34     case "Code":
    35         return &CodeAttribute{cp: cp}
    36     case "ConstantValue":
    37         return &ConstantValueAttribute{}
    38     case "Deprecated":
    39         return &DeprecatedAttribute{}
    40     case "Exceptions":
    41         return &ExceptionsAttribute{}
    42     case "LineNumberTable":
    43         return &LineNumberTableAttribute{}
    44     case "LocalVariableTable":
    45         return &LocalVariableTableAttribute{}
    46     case "SourceFile":
    47         return &SourceFileAttribute{cp: cp}
    48     case "Synthetic":
    49         return &SyntheticAttribute{}
    50     default:
    51         return &UnparsedAttribute{attrName, attrLen, nil}
    52     }
    53 }

    函数的作用和常量表的constant_pool_info中的函数功能相似,newAttributeInfo()函数创建属性实例

    UnparsedAttribute结构体在attr_unparsed.go文件中

     1 package classfile
     2 
     3 /*
     4 attribute_info {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u1 info[attribute_length];
     8 }
     9 */
    10 type UnparsedAttribute struct {
    11     name   string
    12     length uint32
    13     info   []byte
    14 }
    15 
    16 func (self *UnparsedAttribute) readInfo(reader *ClassReader) {
    17     self.info = reader.readBytes(self.length)
    18 }
    19 
    20 func (self *UnparsedAttribute) Info() []byte {
    21     return self.info
    22 }

    2、Deprecated和Synthetic

    都是标记用标签,创建attr_markers.go

     1 package classfile
     2 
     3 /*
     4 Deprecated_attribute {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7 }
     8 */
     9 type DeprecatedAttribute struct {
    10     MarkerAttribute
    11 }
    12 
    13 /*
    14 Synthetic_attribute {
    15     u2 attribute_name_index;
    16     u4 attribute_length;
    17 }
    18 */
    19 type SyntheticAttribute struct {
    20     MarkerAttribute
    21 }
    22 
    23 type MarkerAttribute struct{}
    24 
    25 func (self *MarkerAttribute) readInfo(reader *ClassReader) {
    26     // read nothing
    27 }

    由于没有数据,readInfo()函数都为空。

    3、SourceFile属性

    可选长属性,只出现在ClassFile结构,用于指出源文件名。创建attr_source_file.go文件

     1 package classfile
     2 
     3 /*
     4 SourceFile_attribute {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u2 sourcefile_index;
     8 }
     9 */
    10 type SourceFileAttribute struct {
    11     cp              ConstantPool
    12     sourceFileIndex uint16
    13 }
    14 
    15 func (self *SourceFileAttribute) readInfo(reader *ClassReader) {
    16     self.sourceFileIndex = reader.readUint16()
    17 }
    18 
    19 func (self *SourceFileAttribute) FileName() string {
    20     return self.cp.getUtf8(self.sourceFileIndex)
    21 }

    4、ConstantValue属性

    定长属性,只会出现在field_info结构中,表示常量表达式。创建attr_constant_value.go

     1 package classfile
     2 
     3 /*
     4 ConstantValue_attribute {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u2 constantvalue_index;
     8 }
     9 */
    10 type ConstantValueAttribute struct {
    11     constantValueIndex uint16
    12 }
    13 
    14 func (self *ConstantValueAttribute) readInfo(reader *ClassReader) {
    15     self.constantValueIndex = reader.readUint16()
    16 }
    17 
    18 func (self *ConstantValueAttribute) ConstantValueIndex() uint16 {
    19     return self.constantValueIndex
    20 }

    5、Code属性

    创建attr_code.go文件

     1 package classfile
     2 
     3 /*
     4 Code_attribute {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u2 max_stack;
     8     u2 max_locals;
     9     u4 code_length;
    10     u1 code[code_length];
    11     u2 exception_table_length;
    12     {   u2 start_pc;
    13         u2 end_pc;
    14         u2 handler_pc;
    15         u2 catch_type;
    16     } exception_table[exception_table_length];
    17     u2 attributes_count;
    18     attribute_info attributes[attributes_count];
    19 }
    20 */
    21 type CodeAttribute struct {
    22     cp             ConstantPool
    23     maxStack       uint16
    24     maxLocals      uint16
    25     code           []byte
    26     exceptionTable []*ExceptionTableEntry
    27     attributes     []AttributeInfo
    28 }
    29 
    30 func (self *CodeAttribute) readInfo(reader *ClassReader) {
    31     self.maxStack = reader.readUint16()
    32     self.maxLocals = reader.readUint16()
    33     codeLength := reader.readUint32()
    34     self.code = reader.readBytes(codeLength)
    35     self.exceptionTable = readExceptionTable(reader)
    36     self.attributes = readAttributes(reader, self.cp)
    37 }
    38 
    39 func (self *CodeAttribute) MaxStack() uint {
    40     return uint(self.maxStack)
    41 }
    42 func (self *CodeAttribute) MaxLocals() uint {
    43     return uint(self.maxLocals)
    44 }
    45 func (self *CodeAttribute) Code() []byte {
    46     return self.code
    47 }
    48 func (self *CodeAttribute) ExceptionTable() []*ExceptionTableEntry {
    49     return self.exceptionTable
    50 }
    51 
    52 type ExceptionTableEntry struct {
    53     startPc   uint16
    54     endPc     uint16
    55     handlerPc uint16
    56     catchType uint16
    57 }
    58 
    59 func readExceptionTable(reader *ClassReader) []*ExceptionTableEntry {
    60     exceptionTableLength := reader.readUint16()
    61     exceptionTable := make([]*ExceptionTableEntry, exceptionTableLength)
    62     for i := range exceptionTable {
    63         exceptionTable[i] = &ExceptionTableEntry{
    64             startPc:   reader.readUint16(),
    65             endPc:     reader.readUint16(),
    66             handlerPc: reader.readUint16(),
    67             catchType: reader.readUint16(),
    68         }
    69     }
    70     return exceptionTable
    71 }
    72 
    73 func (self *ExceptionTableEntry) StartPc() uint16 {
    74     return self.startPc
    75 }
    76 func (self *ExceptionTableEntry) EndPc() uint16 {
    77     return self.endPc
    78 }
    79 func (self *ExceptionTableEntry) HandlerPc() uint16 {
    80     return self.handlerPc
    81 }
    82 func (self *ExceptionTableEntry) CatchType() uint16 {
    83     return self.catchType
    84 }

    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

     1 package classfile
     2 
     3 /*
     4 LineNumberTable_attribute {
     5     u2 attribute_name_index;
     6     u4 attribute_length;
     7     u2 line_number_table_length;
     8     {   u2 start_pc;
     9         u2 line_number;
    10     } line_number_table[line_number_table_length];
    11 }
    12 */
    13 type LineNumberTableAttribute struct {
    14     lineNumberTable []*LineNumberTableEntry
    15 }
    16 
    17 type LineNumberTableEntry struct {
    18     startPc    uint16
    19     lineNumber uint16
    20 }
    21 
    22 func (self *LineNumberTableAttribute) readInfo(reader *ClassReader) {
    23     lineNumberTableLength := reader.readUint16()
    24     self.lineNumberTable = make([]*LineNumberTableEntry, lineNumberTableLength)
    25     for i := range self.lineNumberTable {
    26         self.lineNumberTable[i] = &LineNumberTableEntry{
    27             startPc:    reader.readUint16(),
    28             lineNumber: reader.readUint16(),
    29         }
    30     }
    31 }
    32 
    33 func (self *LineNumberTableAttribute) GetLineNumber(pc int) int {
    34     for i := len(self.lineNumberTable) - 1; i >= 0; i-- {
    35         entry := self.lineNumberTable[i]
    36         if pc >= int(entry.startPc) {
    37             return int(entry.lineNumber)
    38         }
    39     }
    40     return -1
    41 }

    创建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
    ", cf.MajorVersion(), cf.MinorVersion())
        fmt.Printf("constants count: %v
    ", len(cf.ConstantPool()))
        fmt.Printf("access flags: 0x%x
    ", cf.AccessFlags())
        fmt.Printf("this class: %v
    ", cf.ClassName())
        fmt.Printf("super class: %v
    ", cf.SuperClassName())
        fmt.Printf("interfaces: %v
    ", cf.InterfaceNames())
        fmt.Printf("fields count: %v
    ", len(cf.Fields()))
        for _, f := range cf.Fields() {
            fmt.Printf("  %s
    ", f.Name())
        }
        fmt.Printf("methods count: %v
    ", len(cf.Methods()))
        for _, m := range cf.Methods() {
            fmt.Printf("  %s
    ", m.Name())
        }
    }

    在命令行窗口输入go install jvmgo

    在%GOPATH%in下命令行窗口运行jvmgo.exe文件,测试java.lang.String.class的信息。

    PS D:Program_Filesgoin> .jvmgo  -Xjre "D:APPjavajava1.8jdk1.8.0_171jre" 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>
  • 相关阅读:
    C# 以管理员身份运行程序
    C# 全局热键设置 与 窗体热键设置
    C# Math类详细说明
    WIN7命令工具大全
    jQuery Validation ,调用valid方法时,不验证remote
    Nopcommerce4.2解析——安装
    MVC授权不通过之后不执行任何自定义ActionFilter
    《将博客搬至CSDN》
    Unity开发者的C#内存管理(中篇)
    Unity开发者的C#内存管理(上篇)
  • 原文地址:https://www.cnblogs.com/pingxin/p/p00082.html
Copyright © 2020-2023  润新知