一、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

  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. }
  1. readInfo()读取常量信息,需要由具体的常量结构体实现,readConstantInfo()函数先读出tag值然后调用newConstantInfo()创造具体常量最后调用常量的readInfo()方法读出常量信息。
  2.  
  3. 3CONSTANT_Integer_infoCONSTANT_Float_infoCONSTANT_Double_info
    创建cp_numeric.go文件
  1. package classfile
  2.  
  3. import "math"
  4.  
  5. /*
  6. CONSTANT_Integer_info {
  7. u1 tag;
  8. u4 bytes;
  9. }
  10. */
  11. type ConstantIntegerInfo struct {
  12. val int32
  13. }
  14.  
  15. func (self *ConstantIntegerInfo) readInfo(reader *ClassReader) {
  16. bytes := reader.readUint32()
  17. self.val = int32(bytes)
  18. }
  19. func (self *ConstantIntegerInfo) Value() int32 {
  20. return self.val
  21. }
  22.  
  23. /*
  24. CONSTANT_Float_info {
  25. u1 tag;
  26. u4 bytes;
  27. }
  28. */
  29. type ConstantFloatInfo struct {
  30. val float32
  31. }
  32.  
  33. func (self *ConstantFloatInfo) readInfo(reader *ClassReader) {
  34. bytes := reader.readUint32()
  35. self.val = math.Float32frombits(bytes)
  36. }
  37. func (self *ConstantFloatInfo) Value() float32 {
  38. return self.val
  39. }
  40.  
  41. /*
  42. CONSTANT_Long_info {
  43. u1 tag;
  44. u4 high_bytes;
  45. u4 low_bytes;
  46. }
  47. */
  48. type ConstantLongInfo struct {
  49. val int64
  50. }
  51.  
  52. func (self *ConstantLongInfo) readInfo(reader *ClassReader) {
  53. bytes := reader.readUint64()
  54. self.val = int64(bytes)
  55. }
  56. func (self *ConstantLongInfo) Value() int64 {
  57. return self.val
  58. }
  59.  
  60. /*
  61. CONSTANT_Double_info {
  62. u1 tag;
  63. u4 high_bytes;
  64. u4 low_bytes;
  65. }
  66. */
  67. type ConstantDoubleInfo struct {
  68. val float64
  69. }
  70.  
  71. func (self *ConstantDoubleInfo) readInfo(reader *ClassReader) {
  72. bytes := reader.readUint64()
  73. self.val = math.Float64frombits(bytes)
  74. }
  75. func (self *ConstantDoubleInfo) Value() float64 {
  76. return self.val
  77. }

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

  1. package classfile
  2.  
  3. /*
  4. Exceptions_attribute {
  5. u2 attribute_name_index;
  6. u4 attribute_length;
  7. u2 number_of_exceptions;
  8. u2 exception_index_table[number_of_exceptions];
  9. }
  10. */
  11. type ExceptionsAttribute struct {
  12. exceptionIndexTable []uint16
  13. }
  14.  
  15. func (self *ExceptionsAttribute) readInfo(reader *ClassReader) {
  16. self.exceptionIndexTable = reader.readUint16s()
  17. }
  18.  
  19. func (self *ExceptionsAttribute) ExceptionIndexTable() []uint16 {
  20. return self.exceptionIndexTable
  21. }

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

  1. package classfile
  2.  
  3. /*
  4. LocalVariableTable_attribute {
  5. u2 attribute_name_index;
  6. u4 attribute_length;
  7. u2 local_variable_table_length;
  8. { u2 start_pc;
  9. u2 length;
  10. u2 name_index;
  11. u2 descriptor_index;
  12. u2 index;
  13. } local_variable_table[local_variable_table_length];
  14. }
  15. */
  16. type LocalVariableTableAttribute struct {
  17. localVariableTable []*LocalVariableTableEntry
  18. }
  19.  
  20. type LocalVariableTableEntry struct {
  21. startPc uint16
  22. length uint16
  23. nameIndex uint16
  24. descriptorIndex uint16
  25. index uint16
  26. }
  27.  
  28. func (self *LocalVariableTableAttribute) readInfo(reader *ClassReader) {
  29. localVariableTableLength := reader.readUint16()
  30. self.localVariableTable = make([]*LocalVariableTableEntry, localVariableTableLength)
  31. for i := range self.localVariableTable {
  32. self.localVariableTable[i] = &LocalVariableTableEntry{
  33. startPc: reader.readUint16(),
  34. length: reader.readUint16(),
  35. nameIndex: reader.readUint16(),
  36. descriptorIndex: reader.readUint16(),
  37. index: reader.readUint16(),
  38. }
  39. }
  40. }

其余文件可以从这里下载:https://github.com/zxh0/jvmgo-book

五、测试

打开main.go文件,修改import语句和startJVM()函数

import "jvmgo/classfile"

修改startJVM()函数

  1. func startJVM(cmd *Cmd) {
  2. cp := classpath.Parse(cmd.XjreOption, cmd.cpOption)
  3. className := strings.Replace(cmd.class, ".", "/", -1)
  4. cf := loadClass(className, cp)
  5. fmt.Println(cmd.class)
  6. printClassInfo(cf)
  7. }

添加loadClass()函数

  1. func loadClass(className string, cp *classpath.Classpath) *classfile.ClassFile {
  2. classData, _, err := cp.ReadClass(className)
  3. if err != nil {
  4. panic(err)
  5. }
  6.  
  7. cf, err := classfile.Parse(classData)
  8. if err != nil {
  9. panic(err)
  10. }
  11.  
  12. return cf
  13. }

添加printClassInfo()函数对class信息进行输出

  1. func printClassInfo(cf *classfile.ClassFile) {
  2. fmt.Printf("version: %v.%v\n", cf.MajorVersion(), cf.MinorVersion())
  3. fmt.Printf("constants count: %v\n", len(cf.ConstantPool()))
  4. fmt.Printf("access flags: 0x%x\n", cf.AccessFlags())
  5. fmt.Printf("this class: %v\n", cf.ClassName())
  6. fmt.Printf("super class: %v\n", cf.SuperClassName())
  7. fmt.Printf("interfaces: %v\n", cf.InterfaceNames())
  8. fmt.Printf("fields count: %v\n", len(cf.Fields()))
  9. for _, f := range cf.Fields() {
  10. fmt.Printf(" %s\n", f.Name())
  11. }
  12. fmt.Printf("methods count: %v\n", len(cf.Methods()))
  13. for _, m := range cf.Methods() {
  14. fmt.Printf(" %s\n", m.Name())
  15. }
  16. }

在命令行窗口输入go install jvmgo

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

  1. PS D:\Program_Files\go\bin> .\jvmgo -Xjre "D:\APP\java\java1.8\jdk1.8.0_171\jre" java.lang.String
  2. java.lang.String
  3. version: 52.0
  4. constants count: 540
  5. access flags: 0x31
  6. this class: java/lang/String
  7. super class: java/lang/Object
  8. interfaces: [java/io/Serializable java/lang/Comparable java/lang/CharSequence]
  9. fields count: 5
  10. value
  11. hash
  12. serialVersionUID
  13. serialPersistentFields
  14. CASE_INSENSITIVE_ORDER
  15. methods count: 94
  16. <init>
  17. <init>
  18. <init>
  19. <init>
  20. <init>
  21. <init>
  22. <init>
  23. checkBounds
  24. <init>
  25. <init>
  26. <init>
  27. <init>
  28. <init>
  29. <init>
  30. <init>
  31. <init>
  32. <init>
  33. length
  34. isEmpty
  35. charAt
  36. codePointAt
  37. codePointBefore
  38. codePointCount
  39. offsetByCodePoints
  40. getChars
  41. getChars
  42. getBytes
  43. getBytes
  44. getBytes
  45. getBytes
  46. equals
  47. contentEquals
  48. nonSyncContentEquals
  49. contentEquals
  50. equalsIgnoreCase
  51. compareTo
  52. compareToIgnoreCase
  53. regionMatches
  54. regionMatches
  55. startsWith
  56. startsWith
  57. endsWith
  58. hashCode
  59. indexOf
  60. indexOf
  61. indexOfSupplementary
  62. lastIndexOf
  63. lastIndexOf
  64. lastIndexOfSupplementary
  65. indexOf
  66. indexOf
  67. indexOf
  68. indexOf
  69. lastIndexOf
  70. lastIndexOf
  71. lastIndexOf
  72. lastIndexOf
  73. substring
  74. substring
  75. subSequence
  76. concat
  77. replace
  78. matches
  79. contains
  80. replaceFirst
  81. replaceAll
  82. replace
  83. split
  84. split
  85. join
  86. join
  87. toLowerCase
  88. toLowerCase
  89. toUpperCase
  90. toUpperCase
  91. trim
  92. toString
  93. toCharArray
  94. format
  95. format
  96. valueOf
  97. valueOf
  98. valueOf
  99. copyValueOf
  100. copyValueOf
  101. valueOf
  102. valueOf
  103. valueOf
  104. valueOf
  105. valueOf
  106. valueOf
  107. intern
  108. compareTo
  109. <clinit>

三、解析class文件的更多相关文章

  1. 解析Xml文件的三种方式及其特点

    解析Xml文件的三种方式 1.Sax解析(simple api  for xml) 使用流式处理的方式,它并不记录所读内容的相关信息.它是一种以事件为驱动的XML API,解析速度快,占用内存少.使用 ...

  2. 解析Xml文件的三种方式

    1.Sax解析(simple api  for xml) 使用流式处理的方式,它并不记录所读内容的相关信息.它是一种以事件为驱动的XML API,解析速度快,占用内存少.使用回调函数来实现. clas ...

  3. CSharpGL(9)解析OBJ文件并用CSharpGL渲染

    CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...

  4. JAVA中使用DOM解析XML文件

    XML是一种方便快捷高效的数据保存传输的格式,在JSON广泛使用之前,XML是服务器和客户端之间数据传输的主要方式.因此,需要使用各种方式,解析服务器传送过来的信息,以供使用者查看. JAVA作为一种 ...

  5. java中采用dom4j解析xml文件

    一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...

  6. java解析XML文件

    dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...

  7. 命令行解析Crash文件

    做了快两年的开发了,没有写过博客,最近公司app上架,程序崩溃被拒绝了,可是给的crash文件,又看不出哪里的问题,网上各种搜,终于找到了解决的办法,想想还是写个博客吧,希望给哪些也遇到这类问题的朋友 ...

  8. 命令行工具解析Crash文件,dSYM文件进行符号化

    备份   文/爱掏蜂窝的熊(简书作者)原文链接:http://www.jianshu.com/p/0b6f5148dab8著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 序 在日常开发 ...

  9. Android pull解析xml文件

    本文介绍android中使用pull来解析xml文件 先自己写一个xml文件,存一些天气信息 <?xml version="1.0" encoding="UTF-8 ...

随机推荐

  1. php7 新内容

    1.use增强 以thinkphp5.0为例 namespace app\home\controller;use think\{Loader,Controller,Captcha,Request}; ...

  2. 阿里云OSS同城冗余存储正式商业化,提供云上同城容灾能力

    近日,阿里云正式发布OSS同城冗余存储产品.这是国内目前提供同城多AZ冗余部署能力覆盖最广的云上对象存储产品,可以实现云存储的同城双活,满足企业级客户对于“发生机房级灾难事件时数据不丢失,业务不中断” ...

  3. 在laravel框架中使用ajax请求报错419

    laravel框架中报419 419 unknown status 这个时候你需要将这个接口放到api路由上,这样可以跳过CSRF的检查

  4. jQuery 鼠标移入图片 显示大图并跟随鼠标移动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 2016 Asia Jakarta Regional Contest A - Confusing Date Format UVALive 7711 【模拟题】

    A - Confusing Date Format 题目大意:就是有六种日期格式,给你一个字符串,判断它能组成多少种可能的日期. 第一次WA是:1.没有判重,2.没有特判题目要求的数据,3.判断天数时 ...

  6. oracle函数 TO_CHAR(x[[,c2],C3])

    [功能]将日期或数据转换为char数据类型 [参数] x是一个date或number数据类型. c2为格式参数 c3为NLS设置参数 如果x为日期nlsparm=NLS_DATE_LANGUAGE 控 ...

  7. Java练习 SDUT-1586_计算组合数

    计算组合数 Time Limit: 1000 ms Memory Limit: 32768 KiB Problem Description 计算组合数.C(n,m),表示从n个数中选择m个的组合数. ...

  8. PHP中header头设置Cookie与内置setCookie的区别

    首先声明,浏览的Cookie操作都是通过HTTP Header(俗称“Http头”) 来实现.所有的服务器与客户端之间Cookie数据传输都是通过Http请求头来操作. PHP中setCookie(函 ...

  9. Vue.js 第1章 Vue常用指令学习

    今日目标 能够写出第一个vue应用程序 能够接受为什么需要学vue 能够使用指令 能够通过指定完成简单的业务(增加删除查询) 能够理解mvvm 为什么要学习vue 企业需要 可以提高开发效率 实现vu ...

  10. Hadoop应用程序示例