一、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文件的更多相关文章

  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. python 语法错误

  2. 【错误收集】JDK的安装 2016-02-03 14:35 725人阅读 评论(23) 收藏

    自己的jdk是根据视频的指示来安装的,首先打开网址www.java.sun.com,然后找到java se的下载,根据自己的机器系统来下载安装包,如下图: 将安装包下载好之后,双击进行安装,根据提示进 ...

  3. 阿里开源!轻量级深度学习端侧推理引擎 MNN

    阿里妹导读:近日,阿里正式开源轻量级深度学习端侧推理引擎“MNN”. AI科学家贾扬清如此评价道:“与 Tensorflow.Caffe2 等同时覆盖训练和推理的通用框架相比,MNN 更注重在推理时的 ...

  4. 微信小程序之购物车demo

    这篇小demo主要使用了一下几个技术点 1.全局变量的使用 在这里定义的变量 任何一个页面和组件都可以访问到 在使用到的页面 const app = getApp(); 声明一个实例 然后 app.g ...

  5. SecureCRT 7.1.1和SecureFx key 亲测可用

    CRT:Name: ygeRCompany: TEAM ZWTSerialNumber: 03-77-119256License Key: ABH2MJ 9YVAC5 Z17QF7 4ZAS7Z AB ...

  6. SPOJ 8073 The area of the union of circles (圆并入门)

    Sphere Online Judge (SPOJ) - Problem CIRU [求圆并的若干种算法,圆并扩展算法]_AekdyCoin的空间_百度空间 参考AekdyCoin的圆并算法解释,根据 ...

  7. oracle 和 mysql 遍历当前月份每一天

    获取当前月份的每一天的数据 oracle SELECT TO_DATE(TO_CHAR(SYSDATE, 'YYYYMM'), 'YYYYMM') + (ROWNUM - 1) DAY_ID FROM ...

  8. IP应用加速技术详解:如何提升动静混合站点的访问速率?

    全站加速(DCDN)-IPA是阿里云自主研发四层加速产品,它基于TCP/UDP的私有协议提供加速服务,包括解决跨运营商网络不稳定.单线源站.突发流量.网络拥塞等诸多因素导致的延迟高.服务不稳定的问题, ...

  9. 容器安全拾遗 - Rootless Container初探

    摘要: Docker和Kubernetes已经成为企业IT架构的基础设施,安全容器运行时越来越被关注.近期Docker 19.03中发布了一个重要的特性 “Rootless Container”,在提 ...

  10. @NOI模拟2017.07.02 - T1@ Attack

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 『新的风暴已经出现,怎么能够停滞不前』--你决定去攻击小怪兽的巢 ...