diff --git a/class/annotation.go b/class/annotation.go deleted file mode 100644 index e0232ed..0000000 --- a/class/annotation.go +++ /dev/null @@ -1,47 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type Annotation struct { - TypeIndex uint16 - ElementValuePairs []*ElementValuePair -} - -type ElementValuePair struct { - ElementNameIndex uint16 - Value *ElementValue -} - -func NewAnnotation(stream *commons.Stream) (*Annotation, error) { - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read Annotation failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs[2:]) - a := &Annotation{ - TypeIndex: binary.BigEndian.Uint16(bs[:2]), - } - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read Annotation ElementValuePair[%d] failed, no enough data in the stream", i) - } - - pair := &ElementValuePair{ - ElementNameIndex: binary.BigEndian.Uint16(bs), - } - pair.Value, err = NewElementValue(stream) - if err != nil { - return nil, fmt.Errorf("read Annotation ElementValuePair[%d] failed, caused by: %v", i, err) - } - - a.ElementValuePairs = append(a.ElementValuePairs, pair) - } - - return a, nil -} diff --git a/class/attr_annotation_default.go b/class/attr_annotation_default.go deleted file mode 100644 index 9b9d3c8..0000000 --- a/class/attr_annotation_default.go +++ /dev/null @@ -1,22 +0,0 @@ -package class - -import ( - "fmt" - "github.com/phith0n/zkar/commons" -) - -type AttrAnnotationDefault struct { - *AttributeBase - - DefaultValue *ElementValue -} - -func (a *AttrAnnotationDefault) readInfo(stream *commons.Stream) error { - value, err := NewElementValue(stream) - if err != nil { - return fmt.Errorf("read AttrAnnotationDefault failed, caused by: %v", err) - } - - a.DefaultValue = value - return nil -} diff --git a/class/attr_bootstrap_methods.go b/class/attr_bootstrap_methods.go deleted file mode 100644 index 64c195e..0000000 --- a/class/attr_bootstrap_methods.go +++ /dev/null @@ -1,64 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrBootstrapMethods https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.23 -type AttrBootstrapMethods struct { - *AttributeBase - - BootstrapMethods []*BootstrapMethod -} - -type BootstrapMethod struct { - // The value of the bootstrap_method_ref item must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_MethodHandle_info structure. - BootstrapMethodRef uint16 - - // Each entry in the bootstrap_arguments array must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be loadable. - BoostrapArguments []uint16 -} - -func (a *AttrBootstrapMethods) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrBootstrapMethods failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - method, err := a.readBootstrapMethod(stream) - if err != nil { - return err - } - - a.BootstrapMethods = append(a.BootstrapMethods, method) - } - - return nil -} - -func (a *AttrBootstrapMethods) readBootstrapMethod(stream *commons.Stream) (*BootstrapMethod, error) { - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read AttrBootstrapMethods BootstrapMethod failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs[2:]) - method := &BootstrapMethod{ - BootstrapMethodRef: binary.BigEndian.Uint16(bs[:2]), - } - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrBootstrapMethods BootstrapMethod argument[%d] failed, no enough data in the stream", i) - } - - method.BoostrapArguments = append(method.BoostrapArguments, binary.BigEndian.Uint16(bs)) - } - - return method, nil -} diff --git a/class/attr_code.go b/class/attr_code.go deleted file mode 100644 index a47fa20..0000000 --- a/class/attr_code.go +++ /dev/null @@ -1,100 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrCode attribute of Method -// https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.3 -type AttrCode struct { - *AttributeBase - - // Maximum depth of the operand stack of this method at any point during execution of the method. - MaxStack uint16 - - // The number of local variables in the local variable array allocated upon invocation of this method, - // including the local variables used to pass parameters to the method on its invocation. - MaxLocals uint16 - - // Actual bytes of Java Virtual Machine code that implement the method - // If the method is either native or abstract, and is not a class or interface initialization method, - // then its Method structure must not have a Code attribute in its attributes table. - // Otherwise, its Method structure must have exactly one Code attribute in its attributes table. - Code []byte - - // Each entry in the ExceptionTable array describes one exception handler in the code array. - // The order of the handlers in the ExceptionTable array is significant - ExceptionTable []*Exception - - // Attributes related to AttrCode - Attributes []Attribute -} - -type Exception struct { - // The values of the two items StartPC and EndPC indicate the ranges - // in the code array at which the exception handler is active. - StartPC uint16 - EndPC uint16 - - // The value of the HandlerPC item indicates the start of the exception handler. - HandlerPC uint16 - - // If the value of the CatchType item is nonzero, it must be a valid index into the constant pool table. - // If the value of the CatchType item is zero, this exception handler is called for all exceptions. - CatchType uint16 -} - -func (a *AttrCode) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(8) - if err != nil { - return fmt.Errorf("read AttrCode attribute failed, no enough data in the stream") - } - - a.MaxStack = binary.BigEndian.Uint16(bs[:2]) - a.MaxLocals = binary.BigEndian.Uint16(bs[2:4]) - length4 := binary.BigEndian.Uint32(bs[4:]) - - a.Code, err = stream.ReadN(int(length4)) - if err != nil { - return fmt.Errorf("read AttrCode code failed, no enough data in the stream") - } - - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrCode exception length failed, no enough data in the stream") - } - - length2 := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length2; i++ { - bs, err = stream.ReadN(8) - if err != nil { - return fmt.Errorf("read AttrCode exception failed, no enough data in the stream") - } - - exception := &Exception{ - StartPC: binary.BigEndian.Uint16(bs[:2]), - EndPC: binary.BigEndian.Uint16(bs[2:4]), - HandlerPC: binary.BigEndian.Uint16(bs[4:6]), - CatchType: binary.BigEndian.Uint16(bs[6:]), - } - a.ExceptionTable = append(a.ExceptionTable, exception) - } - - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrCode attributes length failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - attr, err := a.class.readAttribute(stream) - if err != nil { - return fmt.Errorf("read AttrCode attribute failed, no enough data in the stream") - } - - a.Attributes = append(a.Attributes, attr) - } - - return nil -} diff --git a/class/attr_const_value.go b/class/attr_const_value.go deleted file mode 100644 index c1d9c18..0000000 --- a/class/attr_const_value.go +++ /dev/null @@ -1,27 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrConstValue attribute of Field -// https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.2 -type AttrConstValue struct { - *AttributeBase - - // indicate the index of the constant value - // one of ConstantInteger, ConstantFloat, ConstantDouble, ConstantString, ConstantLong - ConstantValueIndex uint16 -} - -func (a *AttrConstValue) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrSourceFile attribute failed, no enough data in the stream") - } - - a.ConstantValueIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/attr_deprecated.go b/class/attr_deprecated.go deleted file mode 100644 index 7e16570..0000000 --- a/class/attr_deprecated.go +++ /dev/null @@ -1,12 +0,0 @@ -package class - -import "github.com/phith0n/zkar/commons" - -// AttrDeprecated https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.15 -type AttrDeprecated struct { - *AttributeBase -} - -func (a *AttrDeprecated) readInfo(stream *commons.Stream) error { - return nil -} diff --git a/class/attr_enclosing_method.go b/class/attr_enclosing_method.go deleted file mode 100644 index 1a3be95..0000000 --- a/class/attr_enclosing_method.go +++ /dev/null @@ -1,29 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrEnclosingMethod https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.7 -type AttrEnclosingMethod struct { - *AttributeBase - - // The value of the class_index item must be a valid index into the constant_pool table. - ClassIndex uint16 - - // The value of the method_index item must be a valid index into the constant_pool table - MethodIndex uint16 -} - -func (a *AttrEnclosingMethod) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(4) - if err != nil { - return fmt.Errorf("read AttrEnclosingMethod failed, no enough data in the stream") - } - - a.ClassIndex = binary.BigEndian.Uint16(bs[:2]) - a.MethodIndex = binary.BigEndian.Uint16(bs[2:]) - return nil -} diff --git a/class/attr_exceptions.go b/class/attr_exceptions.go deleted file mode 100644 index 190f8c1..0000000 --- a/class/attr_exceptions.go +++ /dev/null @@ -1,36 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrExceptions https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.5 -type AttrExceptions struct { - *AttributeBase - - // Each value in the exception_index_table array must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Class_info structure (§4.4.1) representing - // a class type that this method is declared to throw. - ExceptionIndexes []uint16 -} - -func (a *AttrExceptions) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrExceptions exception length failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrExceptions exception failed, no enough data in the stream") - } - - a.ExceptionIndexes = append(a.ExceptionIndexes, binary.BigEndian.Uint16(bs)) - } - - return nil -} diff --git a/class/attr_innerclasses.go b/class/attr_innerclasses.go deleted file mode 100644 index c49f031..0000000 --- a/class/attr_innerclasses.go +++ /dev/null @@ -1,66 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrInnerClasses https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.6 -type AttrInnerClasses struct { - *AttributeBase - - InnerClasses []*InnerClass -} - -type InnerClass struct { - // The value of the InnerClassInfo item must be a valid index into the constant_pool table. - InnerClassInfo uint16 - - // The value of the InnerClassIndex item must be a valid index into the constant_pool table - OuterClassInfo uint16 - - // The value of the InnerClassIndex item must be a valid index into the constant_pool table - InnerClassIndex uint16 - - // The value of the InnerClassAccessFlags item is a mask of flags used to denote access permissions to - // and properties of class or interface C as declared in the source code from which this class file was compiled. - InnerClassAccessFlags ClassAccessFlag -} - -func (a *AttrInnerClasses) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrInnerClasses failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - c, err := a.readInnerClass(stream) - if err != nil { - return err - } - - a.InnerClasses = append(a.InnerClasses, c) - } - - return nil -} - -func (a *AttrInnerClasses) readInnerClass(stream *commons.Stream) (*InnerClass, error) { - bs, err := stream.ReadN(8) - if err != nil { - return nil, fmt.Errorf("read AttrInnerClasses InnerClass failed, no enough data in the stream") - } - - c := &InnerClass{ - InnerClassInfo: binary.BigEndian.Uint16(bs[:2]), - OuterClassInfo: binary.BigEndian.Uint16(bs[2:4]), - InnerClassIndex: binary.BigEndian.Uint16(bs[4:6]), - InnerClassAccessFlags: ClassAccessFlag(binary.BigEndian.Uint16(bs[6:])), - } - return c, nil -} - -func (ic *InnerClass) HasFlag(flag ClassAccessFlag) bool { - return ic.InnerClassAccessFlags.HasAccessFlag(flag) -} diff --git a/class/attr_linenumber_table.go b/class/attr_linenumber_table.go deleted file mode 100644 index 0d31d15..0000000 --- a/class/attr_linenumber_table.go +++ /dev/null @@ -1,45 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrLineNumberTable https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.12 -type AttrLineNumberTable struct { - *AttributeBase - - Tables []*LineNumberTable -} - -type LineNumberTable struct { - // The value of the StartPC item must be a valid index into the code array of this AttrCode attribute. - StartPC uint16 - - // The value of the LineNumber item gives the corresponding line number in the original source file. - LineNumber uint16 -} - -func (a *AttrLineNumberTable) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrLineNumberTable failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(4) - if err != nil { - return fmt.Errorf("read AttrLineNumberTable line numbers failed, no enough data in the stream") - } - - table := &LineNumberTable{ - StartPC: binary.BigEndian.Uint16(bs[:2]), - LineNumber: binary.BigEndian.Uint16(bs[2:]), - } - a.Tables = append(a.Tables, table) - } - - return nil -} diff --git a/class/attr_localvartable.go b/class/attr_localvartable.go deleted file mode 100644 index ecbb237..0000000 --- a/class/attr_localvartable.go +++ /dev/null @@ -1,47 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type AttrLocalVariableTable struct { - *AttributeBase - - Tables []*LocalVariableTable -} - -type LocalVariableTable struct { - StartPC uint16 - Length uint16 - NameIndex uint16 - DescriptorIndex uint16 - Index uint16 -} - -func (a *AttrLocalVariableTable) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrLocalVariableTable failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(10) - if err != nil { - return fmt.Errorf("read AttrLocalVariableTable tables failed, no enough data in the stream") - } - - table := &LocalVariableTable{ - StartPC: binary.BigEndian.Uint16(bs[:2]), - Length: binary.BigEndian.Uint16(bs[2:4]), - NameIndex: binary.BigEndian.Uint16(bs[4:6]), - DescriptorIndex: binary.BigEndian.Uint16(bs[6:8]), - Index: binary.BigEndian.Uint16(bs[8:]), - } - a.Tables = append(a.Tables, table) - } - - return nil -} diff --git a/class/attr_localvartypetable.go b/class/attr_localvartypetable.go deleted file mode 100644 index 3df0623..0000000 --- a/class/attr_localvartypetable.go +++ /dev/null @@ -1,48 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrLocalVariableTypeTable https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.14 -type AttrLocalVariableTypeTable struct { - *AttributeBase - - Tables []*LocalVariableTypeTable -} - -type LocalVariableTypeTable struct { - StartPC uint16 - Length uint16 - NameIndex uint16 - SignatureIndex uint16 - Index uint16 -} - -func (a *AttrLocalVariableTypeTable) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrLocalVariableTypeTable failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(10) - if err != nil { - return fmt.Errorf("read AttrLocalVariableTypeTable tables failed, no enough data in the stream") - } - - table := &LocalVariableTypeTable{ - StartPC: binary.BigEndian.Uint16(bs[:2]), - Length: binary.BigEndian.Uint16(bs[2:4]), - NameIndex: binary.BigEndian.Uint16(bs[4:6]), - SignatureIndex: binary.BigEndian.Uint16(bs[6:8]), - Index: binary.BigEndian.Uint16(bs[8:]), - } - a.Tables = append(a.Tables, table) - } - - return nil -} diff --git a/class/attr_method_parameters.go b/class/attr_method_parameters.go deleted file mode 100644 index 2e4dd06..0000000 --- a/class/attr_method_parameters.go +++ /dev/null @@ -1,40 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrMethodParameters https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.24 -type AttrMethodParameters struct { - *AttributeBase - - Parameters []*MethodParameter -} - -type MethodParameter struct { - NameIndex uint16 - AccessFlags ParameterAccessFlag -} - -func (a *AttrMethodParameters) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(1) - if err != nil { - return fmt.Errorf("read AttrMethodParameters NameIndex failed, no enough data in the stream") - } - - length := bs[0] - for i := uint8(0); i < length; i++ { - bs, err = stream.ReadN(4) - if err != nil { - return fmt.Errorf("read AttrMethodParameters NameIndex and AccessFlag failed, no enough data in the stream") - } - - a.Parameters = append(a.Parameters, &MethodParameter{ - NameIndex: binary.BigEndian.Uint16(bs[:2]), - AccessFlags: ParameterAccessFlag(binary.BigEndian.Uint16(bs[2:])), - }) - } - return nil -} diff --git a/class/attr_module.go b/class/attr_module.go deleted file mode 100644 index feff4fe..0000000 --- a/class/attr_module.go +++ /dev/null @@ -1,210 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrModule https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.25 -type AttrModule struct { - *AttributeBase - - ModuleName uint16 - ModuleFlags uint16 - ModuleVersionIndex uint16 - - Requires []*ModuleRequires - Exports []*ModuleExports - Opens []*ModuleOpens - UsesIndex []uint16 - Provides []*ModuleProvides -} - -func (a *AttrModule) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(6) - if err != nil { - return fmt.Errorf("read AttrModule failed, no enough data in the stream") - } - - a.ModuleName = binary.BigEndian.Uint16(bs[:2]) - a.ModuleFlags = binary.BigEndian.Uint16(bs[2:4]) - a.ModuleVersionIndex = binary.BigEndian.Uint16(bs[4:]) - - a.Requires, err = a.readRequires(stream) - if err != nil { - return err - } - - a.Exports, err = a.readExports(stream) - if err != nil { - return err - } - - a.Opens, err = a.readOpens(stream) - if err != nil { - return err - } - - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrModule UsesIndex failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - data, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrModule UsesIndex[%d] failed, no enough data in the stream", i) - } - - a.UsesIndex = append(a.UsesIndex, binary.BigEndian.Uint16(data)) - } - - a.Provides, err = a.readProvides(stream) - if err != nil { - return err - } - - return nil -} - -type ModuleRequires struct { - RequiresIndex uint16 - RequiresFlags uint16 - RequiresVersionIndex uint16 -} - -func (a *AttrModule) readRequires(stream *commons.Stream) ([]*ModuleRequires, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Requires failed, no enough data in the stream") - } - - var requires []*ModuleRequires - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(6) - if err != nil { - return nil, fmt.Errorf("read AttrModule Requires[%d] failed, no enough data in the stream", i) - } - - requires = append(requires, &ModuleRequires{ - RequiresIndex: binary.BigEndian.Uint16(bs[:2]), - RequiresFlags: binary.BigEndian.Uint16(bs[2:4]), - RequiresVersionIndex: binary.BigEndian.Uint16(bs[4:]), - }) - } - return requires, nil -} - -type ModuleExports struct { - ExportsIndex uint16 - ExportsFlags uint16 - ExportsToIndex []uint16 -} - -func (a *AttrModule) readExports(stream *commons.Stream) ([]*ModuleExports, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Exports failed, no enough data in the stream") - } - - var exports []*ModuleExports - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(6) - if err != nil { - return nil, fmt.Errorf("read AttrModule Exports[%d] failed, no enough data in the stream", i) - } - - export := &ModuleExports{ - ExportsIndex: binary.BigEndian.Uint16(bs[:2]), - ExportsFlags: binary.BigEndian.Uint16(bs[2:4]), - } - - for j := uint16(0); j < binary.BigEndian.Uint16(bs[4:]); j++ { - data, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Exports[%d] ExportsToIndex[%d] failed, no enough data in the stream", i, j) - } - - export.ExportsToIndex = append(export.ExportsToIndex, binary.BigEndian.Uint16(data)) - } - exports = append(exports, export) - } - return exports, nil -} - -type ModuleOpens struct { - OpensIndex uint16 - OpensFlags uint16 - OpensToIndex []uint16 -} - -func (a *AttrModule) readOpens(stream *commons.Stream) ([]*ModuleOpens, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Opens failed, no enough data in the stream") - } - - var opens []*ModuleOpens - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(6) - if err != nil { - return nil, fmt.Errorf("read AttrModule Opens[%d] failed, no enough data in the stream", i) - } - - open := &ModuleOpens{ - OpensIndex: binary.BigEndian.Uint16(bs[:2]), - OpensFlags: binary.BigEndian.Uint16(bs[2:4]), - } - for j := uint16(0); j < binary.BigEndian.Uint16(bs[4:]); j++ { - data, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Opens[%d] OpensToIndex[%d] failed, no enough data in the stream", i, j) - } - - open.OpensToIndex = append(open.OpensToIndex, binary.BigEndian.Uint16(data)) - } - opens = append(opens, open) - } - - return opens, nil -} - -type ModuleProvides struct { - ProvidesIndex uint16 - ProvidesWithIndex []uint16 -} - -func (a *AttrModule) readProvides(stream *commons.Stream) ([]*ModuleProvides, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Provides failed, no enough data in the stream") - } - - var provides []*ModuleProvides - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read AttrModule Provides[%d] failed, no enough data in the stream", i) - } - - provide := &ModuleProvides{ - ProvidesIndex: binary.BigEndian.Uint16(bs[:2]), - } - - for j := uint16(0); j < binary.BigEndian.Uint16(bs[2:]); j++ { - data, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrModule Opens[%d] OpensToIndex[%d] failed, no enough data in the stream", i, j) - } - - provide.ProvidesWithIndex = append(provide.ProvidesWithIndex, binary.BigEndian.Uint16(data)) - } - provides = append(provides, provide) - } - return provides, nil -} diff --git a/class/attr_module_main_class.go b/class/attr_module_main_class.go deleted file mode 100644 index 87ac1bd..0000000 --- a/class/attr_module_main_class.go +++ /dev/null @@ -1,24 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrModuleMainClass https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.27 -type AttrModuleMainClass struct { - *AttributeBase - - MainClassIndex uint16 -} - -func (a *AttrModuleMainClass) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrModuleMainClass failed, no enough data in the stream") - } - - a.MainClassIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/attr_module_packages.go b/class/attr_module_packages.go deleted file mode 100644 index 4a6eff5..0000000 --- a/class/attr_module_packages.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrModulePackages https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.26 -type AttrModulePackages struct { - *AttributeBase - - PackageIndex []uint16 -} - -func (a *AttrModulePackages) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrModulePackages failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrModulePackages[%d] failed, no enough data in the stream", i) - } - - a.PackageIndex = append(a.PackageIndex, binary.BigEndian.Uint16(bs)) - } - - return nil -} diff --git a/class/attr_nest_host.go b/class/attr_nest_host.go deleted file mode 100644 index 744f13b..0000000 --- a/class/attr_nest_host.go +++ /dev/null @@ -1,26 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrNestHost https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.28 -type AttrNestHost struct { - *AttributeBase - - // The value of the host_class_index item must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Class_info structure (§4.4.1) representing a class or interface which is the nest host for the current class or interface. - HostClassIndex uint16 -} - -func (a *AttrNestHost) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrNestHost failed, no enough data in the stream") - } - - a.HostClassIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/attr_nest_members.go b/class/attr_nest_members.go deleted file mode 100644 index 85ffe7b..0000000 --- a/class/attr_nest_members.go +++ /dev/null @@ -1,35 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrNestMembers https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.29 -type AttrNestMembers struct { - *AttributeBase - - // Each value in the classes array must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Class_info structure representing a class or interface which is a member of the nest hosted by the current class or interface. - classes []uint16 -} - -func (a *AttrNestMembers) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrNestMembers failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrNestMembers class[%d] failed, no enough data in the stream", i) - } - - a.classes = append(a.classes, binary.BigEndian.Uint16(bs)) - } - - return nil -} diff --git a/class/attr_permitted_subclasses.go b/class/attr_permitted_subclasses.go deleted file mode 100644 index 454899c..0000000 --- a/class/attr_permitted_subclasses.go +++ /dev/null @@ -1,35 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrPermittedSubclasses https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.31 -type AttrPermittedSubclasses struct { - *AttributeBase - - // Each value in the classes array must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Class_info structure (§4.4.1) representing a class or interface which is authorized to directly extend or implement the current class or interface. - classes []uint16 -} - -func (a *AttrPermittedSubclasses) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrPermittedSubclasses failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrPermittedSubclasses class[%d] failed, no enough data in the stream", i) - } - - a.classes = append(a.classes, binary.BigEndian.Uint16(bs)) - } - - return nil -} diff --git a/class/attr_record.go b/class/attr_record.go deleted file mode 100644 index 5e4c502..0000000 --- a/class/attr_record.go +++ /dev/null @@ -1,65 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRecord https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.3 -type AttrRecord struct { - *AttributeBase - - Components []*RecordComponentInfo -} - -type RecordComponentInfo struct { - // The value of the name_index item must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing a valid unqualified name denoting the record component (§4.2.2). - NameIndex uint16 - - // The value of the descriptor_index item must be a valid index into the constant_pool table. - // The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) representing a field descriptor which encodes the type of the record component (§4.3.2). - DescriptorIndex uint16 - - // Each value of the attributes table must be an attribute_info structure (§4.7). - Attributes []Attribute -} - -func (a *AttrRecord) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrRecord failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - component, err := a.readComponent(stream) - if err != nil { - return err - } - - a.Components = append(a.Components, component) - } - - return nil -} - -func (a *AttrRecord) readComponent(stream *commons.Stream) (*RecordComponentInfo, error) { - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read AttrRecord Component failed, no enough data in the stream") - } - - component := &RecordComponentInfo{ - NameIndex: binary.BigEndian.Uint16(bs[:2]), - DescriptorIndex: binary.BigEndian.Uint16(bs[2:]), - } - - attr, err := a.class.readAttribute(stream) - if err != nil { - return nil, fmt.Errorf("read AttrCode attribute failed, no enough data in the stream") - } - - component.Attributes = append(component.Attributes, attr) - return component, nil -} diff --git a/class/attr_runtime_invisible_annotations.go b/class/attr_runtime_invisible_annotations.go deleted file mode 100644 index e8a6803..0000000 --- a/class/attr_runtime_invisible_annotations.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeInvisibleAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.17 -type AttrRuntimeInvisibleAnnotations struct { - *AttributeBase - - Annotations []*Annotation -} - -func (a *AttrRuntimeInvisibleAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrRuntimeInvisibleAnnotations failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - annotation, err := NewAnnotation(stream) - if err != nil { - return fmt.Errorf("read AttrRuntimeInvisibleAnnotations failed, caused by: %v", err) - } - - a.Annotations = append(a.Annotations, annotation) - } - - return nil -} diff --git a/class/attr_runtime_invisible_parameter_annotations.go b/class/attr_runtime_invisible_parameter_annotations.go deleted file mode 100644 index c6bd723..0000000 --- a/class/attr_runtime_invisible_parameter_annotations.go +++ /dev/null @@ -1,51 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeInvisibleParameterAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.19 -type AttrRuntimeInvisibleParameterAnnotations struct { - *AttributeBase - - Parameters []*ParameterAnnotation -} - -func (a *AttrRuntimeInvisibleParameterAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(1) - if err != nil { - return fmt.Errorf("read AttrRuntimeInvisibleParameterAnnotations failed, no enough data in the stream") - } - - for i := uint8(0); i < bs[0]; i++ { - p, err := a.readParameter(stream) - if err != nil { - return err - } - - a.Parameters = append(a.Parameters, p) - } - - return nil -} - -func (a *AttrRuntimeInvisibleParameterAnnotations) readParameter(stream *commons.Stream) (*ParameterAnnotation, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrRuntimeInvisibleParameterAnnotations ParameterAnnotation failed, no enough data in the stream") - } - - parameter := &ParameterAnnotation{} - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - annotation, err := NewAnnotation(stream) - if err != nil { - return nil, fmt.Errorf("read AttrRuntimeInvisibleParameterAnnotations ParameterAnnotation failed, caused by: %v", err) - } - - parameter.Annotations = append(parameter.Annotations, annotation) - } - - return parameter, nil -} diff --git a/class/attr_runtime_invisible_type_annotation.go b/class/attr_runtime_invisible_type_annotation.go deleted file mode 100644 index c6b0424..0000000 --- a/class/attr_runtime_invisible_type_annotation.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeInvisibleTypeAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.21 -type AttrRuntimeInvisibleTypeAnnotations struct { - *AttributeBase - - Annotations []*TypeAnnotation -} - -func (a *AttrRuntimeInvisibleTypeAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrRuntimeInvisibleTypeAnnotations failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - var annotation *TypeAnnotation - annotation, err = NewTypeAnnotation(stream) - if err != nil { - return fmt.Errorf("read AttrRuntimeInvisibleTypeAnnotations TypeAnnotation[%d] failed, caused by: %v", i, err) - } - - a.Annotations = append(a.Annotations, annotation) - } - - return nil -} diff --git a/class/attr_runtime_visible_annotations.go b/class/attr_runtime_visible_annotations.go deleted file mode 100644 index 92aa561..0000000 --- a/class/attr_runtime_visible_annotations.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeVisibleAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.16 -type AttrRuntimeVisibleAnnotations struct { - *AttributeBase - - Annotations []*Annotation -} - -func (a *AttrRuntimeVisibleAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrRuntimeVisibleAnnotations failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - annotation, err := NewAnnotation(stream) - if err != nil { - return fmt.Errorf("read AttrRuntimeVisibleAnnotations Annotation[%d] failed, no enough data in the stream", i) - } - - a.Annotations = append(a.Annotations, annotation) - } - - return nil -} diff --git a/class/attr_runtime_visible_parameter_annotations.go b/class/attr_runtime_visible_parameter_annotations.go deleted file mode 100644 index 5fc0412..0000000 --- a/class/attr_runtime_visible_parameter_annotations.go +++ /dev/null @@ -1,55 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeVisibleParameterAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.18 -type AttrRuntimeVisibleParameterAnnotations struct { - *AttributeBase - - Parameters []*ParameterAnnotation -} - -type ParameterAnnotation struct { - Annotations []*Annotation -} - -func (a *AttrRuntimeVisibleParameterAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(1) - if err != nil { - return fmt.Errorf("read AttrRuntimeVisibleParameterAnnotations failed, no enough data in the stream") - } - - for i := uint8(0); i < bs[0]; i++ { - p, err := a.readParameter(stream) - if err != nil { - return err - } - - a.Parameters = append(a.Parameters, p) - } - - return nil -} - -func (a *AttrRuntimeVisibleParameterAnnotations) readParameter(stream *commons.Stream) (*ParameterAnnotation, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read AttrRuntimeVisibleParameterAnnotations ParameterAnnotation failed, no enough data in the stream") - } - - parameter := &ParameterAnnotation{} - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - annotation, err := NewAnnotation(stream) - if err != nil { - return nil, fmt.Errorf("read AttrRuntimeVisibleParameterAnnotations ParameterAnnotation failed, caused by: %v", err) - } - - parameter.Annotations = append(parameter.Annotations, annotation) - } - - return parameter, nil -} diff --git a/class/attr_runtime_visible_type_annotation.go b/class/attr_runtime_visible_type_annotation.go deleted file mode 100644 index fc5cde6..0000000 --- a/class/attr_runtime_visible_type_annotation.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrRuntimeVisibleTypeAnnotations https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.20 -type AttrRuntimeVisibleTypeAnnotations struct { - *AttributeBase - - Annotations []*TypeAnnotation -} - -func (a *AttrRuntimeVisibleTypeAnnotations) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrRuntimeVisibleTypeAnnotations failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - var annotation *TypeAnnotation - annotation, err = NewTypeAnnotation(stream) - if err != nil { - return fmt.Errorf("read AttrRuntimeVisibleTypeAnnotations TypeAnnotation[%d] failed, caused by: %v", i, err) - } - - a.Annotations = append(a.Annotations, annotation) - } - - return nil -} diff --git a/class/attr_signature.go b/class/attr_signature.go deleted file mode 100644 index 07d874e..0000000 --- a/class/attr_signature.go +++ /dev/null @@ -1,25 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrSignature https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.9 -type AttrSignature struct { - *AttributeBase - - // The value of the SignatureIndex item must be a valid index into the constant_pool table. - SignatureIndex uint16 -} - -func (a *AttrSignature) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrSignature failed, no enough data in the stream") - } - - a.SignatureIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/attr_source_debug_extension.go b/class/attr_source_debug_extension.go deleted file mode 100644 index 988ccb7..0000000 --- a/class/attr_source_debug_extension.go +++ /dev/null @@ -1,24 +0,0 @@ -package class - -import ( - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrSourceDebugExtension https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.11 -type AttrSourceDebugExtension struct { - *AttributeBase - - // The DebugExtension array holds extended debugging information which has no semantic effect on the Java Virtual Machine. - DebugExtension []byte -} - -func (a *AttrSourceDebugExtension) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(int(a.AttributeLength)) - if err != nil { - return fmt.Errorf("read AttrSourceDebugExtension failed, no enough data in the stream") - } - - a.DebugExtension = bs - return nil -} diff --git a/class/attr_source_file.go b/class/attr_source_file.go deleted file mode 100644 index ba27905..0000000 --- a/class/attr_source_file.go +++ /dev/null @@ -1,24 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// AttrSourceFile attribute of ClassFile -// https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.10 -type AttrSourceFile struct { - *AttributeBase - SourceFileIndex uint16 // indicate the name of the source file of the class -} - -func (a *AttrSourceFile) readInfo(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read AttrSourceFile attribute failed, no enough data in the stream") - } - - a.SourceFileIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/attr_stackmap.go b/class/attr_stackmap.go deleted file mode 100644 index 4c2bc75..0000000 --- a/class/attr_stackmap.go +++ /dev/null @@ -1,26 +0,0 @@ -package class - -import ( - "fmt" - "github.com/phith0n/zkar/commons" -) - -// The AttrStackMapTable attribute is a variable-length attribute in the attributes table of a Code attribute. -// A AttrStackMapTable attribute is used during the process of verification by type checking. -type AttrStackMapTable struct { - *AttributeBase - - Data []byte -} - -// readInfo not implement -// TODO: read detail information of AttrStackMapTable -func (a *AttrStackMapTable) readInfo(stream *commons.Stream) error { - var err error - a.Data, err = stream.ReadN(int(a.AttributeLength)) - if err != nil { - return fmt.Errorf("read AttrStackMapTable failed, no enough data in the stream") - } - - return nil -} diff --git a/class/attr_synthetic.go b/class/attr_synthetic.go deleted file mode 100644 index 38e15b1..0000000 --- a/class/attr_synthetic.go +++ /dev/null @@ -1,13 +0,0 @@ -package class - -import "github.com/phith0n/zkar/commons" - -// AttrSynthetic https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.8 -type AttrSynthetic struct { - *AttributeBase -} - -func (a *AttrSynthetic) readInfo(stream *commons.Stream) error { - // read nothing - return nil -} diff --git a/class/attribute.go b/class/attribute.go deleted file mode 100644 index 86d356b..0000000 --- a/class/attribute.go +++ /dev/null @@ -1,55 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type Attribute interface { - readInfo(stream *commons.Stream) error -} - -type AttributeBase struct { - class *ClassFile - - AttributeNameIndex uint16 - AttributeLength uint32 -} - -func newAttributeBase(class *ClassFile, nameIndex uint16, length uint32) *AttributeBase { - return &AttributeBase{ - class: class, - AttributeNameIndex: nameIndex, - AttributeLength: length, - } -} - -func (cf *ClassFile) readAttribute(stream *commons.Stream) (Attribute, error) { - bs, err := stream.ReadN(6) - if err != nil { - return nil, fmt.Errorf("read attribute failed, no enough data in the stream") - } - - nameIndex := binary.BigEndian.Uint16(bs[:2]) - length := binary.BigEndian.Uint32(bs[2:]) - - var utf8 *ConstantUTF8 - var ok bool - if utf8, ok = cf.ConstantPool[nameIndex].(*ConstantUTF8); !ok { - return nil, fmt.Errorf("attribute name index must be a ConstantUTF8 reference") - } - - var attr Attribute - switch utf8.Data { - case "SourceFile": - attr = &AttrSourceFile{AttributeBase: newAttributeBase(cf, nameIndex, length)} - } - - err = attr.readInfo(stream) - if err != nil { - return nil, err - } - - return attr, nil -} diff --git a/class/attribute_access.go b/class/attribute_access.go deleted file mode 100644 index 6977c4e..0000000 --- a/class/attribute_access.go +++ /dev/null @@ -1,22 +0,0 @@ -package class - -type AttrAccessFlag uint16 - -const ( - AttrAccPublic AttrAccessFlag = 0x0001 // Declared public; may be accessed from outside its package. - AttrAccPrivate AttrAccessFlag = 0x0002 // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). - AttrAccProtected AttrAccessFlag = 0x0004 // Declared protected; may be accessed within subclasses. - AttrAccStatic AttrAccessFlag = 0x0008 // Declared static. - AttrAccFinal AttrAccessFlag = 0x0010 // Declared final; must not be overridden (§5.4.5). - AttrAccSynchronized AttrAccessFlag = 0x0020 // Declared synchronized; invocation is wrapped by a monitor use. - AttrAccBridge AttrAccessFlag = 0x0040 // A bridge method, generated by the compiler. - AttrAccVarargs AttrAccessFlag = 0x0080 // Declared with variable number of arguments. - AttrAccNative AttrAccessFlag = 0x0100 // Declared native; implemented in a language other than the Java programming language. - AttrAccAbstract AttrAccessFlag = 0x0400 // Declared abstract; no implementation is provided. - AttrAccStrict AttrAccessFlag = 0x0800 // In a class file whose major version number is at least 46 and at most 60: Declared strictfp. - AttrAccSynthetic AttrAccessFlag = 0x1000 // Declared synthetic; not present in the source code. -) - -func (aaf AttrAccessFlag) HasAccessFlag(flag AttrAccessFlag) bool { - return (flag & aaf) == flag -} diff --git a/class/class_access.go b/class/class_access.go deleted file mode 100644 index d727163..0000000 --- a/class/class_access.go +++ /dev/null @@ -1,50 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ClassAccessFlag uint16 - -const ( - ClassAccPublic ClassAccessFlag = 0x0001 // Declared public; may be accessed from outside its package. - ClassAccPrivate ClassAccessFlag = 0x0002 // Marked private in source. - ClassAccProtected ClassAccessFlag = 0x0004 // Marked protected in source. - ClassAccStatic ClassAccessFlag = 0x0008 // Marked or implicitly static in source. - ClassAccFinal ClassAccessFlag = 0x0010 // Declared final; no subclasses allowed. - ClassAccSuper ClassAccessFlag = 0x0020 // Treat superclass methods specially when invoked by the invokespecial instruction. - ClassAccInterface ClassAccessFlag = 0x0200 // Is an interface, not a class. - ClassAccAbstract ClassAccessFlag = 0x0400 // Declared abstract; must not be instantiated. - ClassAccSynthetic ClassAccessFlag = 0x1000 // Declared synthetic; not present in the source code. - ClassAccAnnotation ClassAccessFlag = 0x2000 // Declared as an annotation type. - ClassAccEnum ClassAccessFlag = 0x4000 // Declared as an enum type. - ClassAccModule ClassAccessFlag = 0x8000 // Is a module, not a class or interface. -) - -func (caf ClassAccessFlag) HasAccessFlag(flag ClassAccessFlag) bool { - return (flag & caf) == flag -} - -func (cf *ClassFile) readAccessFlag(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read access flag failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint16(bs) - cf.AccessFlag = ClassAccessFlag(i) - - // check access flag valid - if cf.AccessFlag.HasAccessFlag(ClassAccFinal) && cf.AccessFlag.HasAccessFlag(ClassAccAbstract) { - return fmt.Errorf("ACC_FINAL and ACC_ABSTRACT are not able to set at the same time") - } - - if cf.AccessFlag.HasAccessFlag(ClassAccAnnotation) && !cf.AccessFlag.HasAccessFlag(ClassAccInterface) { - return fmt.Errorf("if ACC_ANNOTATION is set, ACC_ANNOTATION must also be set") - } - - // TODO: maybe need more check - return nil -} diff --git a/class/classfile.go b/class/classfile.go deleted file mode 100644 index e8563b3..0000000 --- a/class/classfile.go +++ /dev/null @@ -1,59 +0,0 @@ -package class - -import ( - "bytes" - "encoding/binary" - "encoding/hex" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ClassFile struct { - MagicNumber []byte - MinorVersion uint16 - MajorVersion uint16 - ConstantPool []Constant - AccessFlag ClassAccessFlag - ThisClassIndex uint16 - SuperClassIndex uint16 - InterfaceIndexArray []uint16 - Fields []*Field - Methods []*Method - Attributes []*Attribute -} - -func (cf *ClassFile) readHeader(stream *commons.Stream) error { - bs, err := stream.ReadN(4) - if err != nil { - return fmt.Errorf("read magic number failed, no enough data in the stream") - } - - if !bytes.Equal(bs, []byte("\xCA\xFE\xBA\xBE")) { - return fmt.Errorf("magic number %v is not equal to 0xCAFEBABE", hex.EncodeToString(bs)) - } - - cf.MagicNumber = bs - bs, err = stream.ReadN(4) - if err != nil { - return fmt.Errorf("read minor and major version failed, no enough data in the stream") - } - - cf.MinorVersion = binary.BigEndian.Uint16(bs[:2]) - cf.MajorVersion = binary.BigEndian.Uint16(bs[2:]) - return nil -} - -func (cf *ClassFile) readClass(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read this class failed, no enough data in the stream") - } - cf.ThisClassIndex = binary.BigEndian.Uint16(bs) - - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read super class failed, no enough data in the stream") - } - cf.SuperClassIndex = binary.BigEndian.Uint16(bs) - return nil -} diff --git a/class/constant.go b/class/constant.go deleted file mode 100644 index d45b4d6..0000000 --- a/class/constant.go +++ /dev/null @@ -1,104 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -const ( - ConstantUtf8Info = 1 - ConstantIntegerInfo = 3 - ConstantFloatInfo = 4 - ConstantLongInfo = 5 - ConstantDoubleInfo = 6 - ConstantClassInfo = 7 - ConstantStringInfo = 8 - ConstantFieldRefInfo = 9 - ConstantMethodRefInfo = 10 - ConstantInterfaceMethodRefInfo = 11 - ConstantNameAndTypeInfo = 12 - ConstantMethodHandleInfo = 15 - ConstantMethodTypeInfo = 16 - ConstantDynamicInfo = 17 - ConstantInvokeDynamicInfo = 18 - ConstantModuleInfo = 19 - ConstantPackageInfo = 20 -) - -type Constant interface { - ToBytes() []byte -} - -func (cf *ClassFile) readConstantPool(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read constant pool size failed, no enough data in the stream") - } - - var size = binary.BigEndian.Uint16(bs) - - // Note: Constant Pool index is start from 1, not 0 - for i := uint16(1); i < size; i++ { - err = cf.readConstant(stream) - if err != nil { - return err - } - } - - return nil -} - -func (cf *ClassFile) readConstant(stream *commons.Stream) error { - bs, err := stream.PeekN(1) - if err != nil { - return fmt.Errorf("read constant type failed, no enough data in the stream") - } - - var obj Constant - switch bs[0] { - case ConstantUtf8Info: - obj, err = cf.readConstantUTF8(stream) - case ConstantIntegerInfo: - obj, err = cf.readConstantInteger(stream) - case ConstantFloatInfo: - obj, err = cf.readConstantFloat(stream) - case ConstantLongInfo: - obj, err = cf.readConstantLong(stream) - case ConstantDoubleInfo: - obj, err = cf.readConstantDouble(stream) - case ConstantClassInfo: - obj, err = cf.readConstantClass(stream) - case ConstantStringInfo: - obj, err = cf.readConstantString(stream) - case ConstantFieldRefInfo: - obj, err = cf.readConstantFieldRef(stream) - case ConstantMethodRefInfo: - obj, err = cf.readConstantMethodRef(stream) - case ConstantInterfaceMethodRefInfo: - obj, err = cf.readConstantInterfaceMethodRef(stream) - case ConstantNameAndTypeInfo: - obj, err = cf.readConstantNameAndType(stream) - case ConstantMethodHandleInfo: - obj, err = cf.readConstantMethodHandle(stream) - case ConstantMethodTypeInfo: - obj, err = cf.readConstantMethodType(stream) - case ConstantDynamicInfo: - obj, err = cf.readConstantDynamic(stream) - case ConstantInvokeDynamicInfo: - obj, err = cf.readConstantInvokeDynamic(stream) - case ConstantModuleInfo: - obj, err = cf.readConstantModule(stream) - case ConstantPackageInfo: - obj, err = cf.readConstantPackage(stream) - default: - err = fmt.Errorf("constant type %v doesn't exists", bs) - } - - if err != nil { - return err - } - - cf.ConstantPool = append(cf.ConstantPool, obj) - return nil -} diff --git a/class/constant_class.go b/class/constant_class.go deleted file mode 100644 index 120cf1a..0000000 --- a/class/constant_class.go +++ /dev/null @@ -1,30 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantClass struct { - NameIndex uint16 -} - -func (c *ConstantClass) ToBytes() []byte { - var bs = []byte{ConstantClassInfo} - bs = append(bs, commons.NumberToBytes(c.NameIndex)...) - return bs -} - -func (cf *ClassFile) readConstantClass(stream *commons.Stream) (*ConstantClass, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant class failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint16(bs) - return &ConstantClass{ - NameIndex: i, - }, nil -} diff --git a/class/constant_double.go b/class/constant_double.go deleted file mode 100644 index 3e1f4ed..0000000 --- a/class/constant_double.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" - "math" -) - -type ConstantDouble struct { - Double float64 -} - -func (c *ConstantDouble) ToBytes() []byte { - var bs = []byte{ConstantDoubleInfo} - bs = append(bs, commons.NumberToBytes(c.Double)...) - return bs -} - -func (cf *ClassFile) readConstantDouble(stream *commons.Stream) (*ConstantDouble, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(8) - if err != nil { - return nil, fmt.Errorf("read constant double failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint64(bs) - var c = &ConstantDouble{ - Double: math.Float64frombits(i), - } - - return c, nil -} diff --git a/class/constant_dynamic.go b/class/constant_dynamic.go deleted file mode 100644 index 4253d31..0000000 --- a/class/constant_dynamic.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantDynamic struct { - BootstrapMethodIndex uint16 // a reference to the BootstrapMethod in ClassFile.Attributes - NameAndTypeIndex uint16 -} - -func (c *ConstantDynamic) ToBytes() []byte { - var bs = []byte{ConstantDynamicInfo} - bs = append(bs, commons.NumberToBytes(c.BootstrapMethodIndex)...) - bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) - return bs -} - -func (cf *ClassFile) readConstantDynamic(stream *commons.Stream) (*ConstantDynamic, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant dynamic failed, no enough data in the stream") - } - - var c = &ConstantDynamic{} - c.BootstrapMethodIndex = binary.BigEndian.Uint16(bs[:2]) - c.NameAndTypeIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_fieldref.go b/class/constant_fieldref.go deleted file mode 100644 index 119cc15..0000000 --- a/class/constant_fieldref.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantFieldRef struct { - ClassIndex uint16 - NameAndTypeIndex uint16 -} - -func (c *ConstantFieldRef) ToBytes() []byte { - var bs = []byte{ConstantFieldRefInfo} - bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) - bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) - return bs -} - -func (cf *ClassFile) readConstantFieldRef(stream *commons.Stream) (*ConstantFieldRef, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant field ref failed, no enough data in the stream") - } - - var c = &ConstantFieldRef{} - c.ClassIndex = binary.BigEndian.Uint16(bs[:2]) - c.NameAndTypeIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_float.go b/class/constant_float.go deleted file mode 100644 index b552465..0000000 --- a/class/constant_float.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" - "math" -) - -type ConstantFloat struct { - Float float32 -} - -func (c *ConstantFloat) ToBytes() []byte { - var bs = []byte{ConstantFloatInfo} - bs = append(bs, commons.NumberToBytes(c.Float)...) - return bs -} - -func (cf *ClassFile) readConstantFloat(stream *commons.Stream) (*ConstantFloat, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant float failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint32(bs) - var c = &ConstantFloat{ - Float: math.Float32frombits(i), - } - - return c, nil -} diff --git a/class/constant_integer.go b/class/constant_integer.go deleted file mode 100644 index 16aa533..0000000 --- a/class/constant_integer.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantInteger struct { - Integer int32 -} - -func (c *ConstantInteger) ToBytes() []byte { - var bs = []byte{ConstantIntegerInfo} - bs = append(bs, commons.NumberToBytes(c.Integer)...) - return bs -} - -func (cf *ClassFile) readConstantInteger(stream *commons.Stream) (*ConstantInteger, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant integer failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint32(bs) - var c = &ConstantInteger{ - Integer: int32(i), - } - - return c, nil -} diff --git a/class/constant_interface_methodref.go b/class/constant_interface_methodref.go deleted file mode 100644 index 6b01ab4..0000000 --- a/class/constant_interface_methodref.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantInterfaceMethodRef struct { - ClassIndex uint16 - NameAndTypeIndex uint16 -} - -func (c *ConstantInterfaceMethodRef) ToBytes() []byte { - var bs = []byte{ConstantInterfaceMethodRefInfo} - bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) - bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) - return bs -} - -func (cf *ClassFile) readConstantInterfaceMethodRef(stream *commons.Stream) (*ConstantInterfaceMethodRef, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant interface method ref failed, no enough data in the stream") - } - - var c = &ConstantInterfaceMethodRef{} - c.ClassIndex = binary.BigEndian.Uint16(bs[:2]) - c.NameAndTypeIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_invoke_dynamic.go b/class/constant_invoke_dynamic.go deleted file mode 100644 index 27b8861..0000000 --- a/class/constant_invoke_dynamic.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantInvokeDynamic struct { - BootstrapMethodIndex uint16 // a reference to the BootstrapMethod in ClassFile.Attributes - NameAndTypeIndex uint16 -} - -func (c *ConstantInvokeDynamic) ToBytes() []byte { - var bs = []byte{ConstantInvokeDynamicInfo} - bs = append(bs, commons.NumberToBytes(c.BootstrapMethodIndex)...) - bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) - return bs -} - -func (cf *ClassFile) readConstantInvokeDynamic(stream *commons.Stream) (*ConstantInvokeDynamic, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant invoke dynamic failed, no enough data in the stream") - } - - var c = &ConstantInvokeDynamic{} - c.BootstrapMethodIndex = binary.BigEndian.Uint16(bs[:2]) - c.NameAndTypeIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_long.go b/class/constant_long.go deleted file mode 100644 index 503cd2a..0000000 --- a/class/constant_long.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantLong struct { - Long int64 -} - -func (c *ConstantLong) ToBytes() []byte { - var bs = []byte{ConstantLongInfo} - bs = append(bs, commons.NumberToBytes(c.Long)...) - return bs -} - -func (cf *ClassFile) readConstantLong(stream *commons.Stream) (*ConstantLong, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(8) - if err != nil { - return nil, fmt.Errorf("read constant long failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint64(bs) - var c = &ConstantLong{ - Long: int64(i), - } - - return c, nil -} diff --git a/class/constant_method_handle.go b/class/constant_method_handle.go deleted file mode 100644 index 01cdf7c..0000000 --- a/class/constant_method_handle.go +++ /dev/null @@ -1,32 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantMethodHandle struct { - ReferenceKind byte - ReferenceIndex uint16 -} - -func (c *ConstantMethodHandle) ToBytes() []byte { - var bs = []byte{ConstantMethodHandleInfo} - bs = append(bs, c.ReferenceKind) - bs = append(bs, commons.NumberToBytes(c.ReferenceIndex)...) - return bs -} - -func (cf *ClassFile) readConstantMethodHandle(stream *commons.Stream) (*ConstantMethodHandle, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(3) - if err != nil { - return nil, fmt.Errorf("read constant method handle failed, no enough data in the stream") - } - - return &ConstantMethodHandle{ - ReferenceKind: bs[0], - ReferenceIndex: binary.BigEndian.Uint16(bs[1:]), - }, nil -} diff --git a/class/constant_method_type.go b/class/constant_method_type.go deleted file mode 100644 index a4c5825..0000000 --- a/class/constant_method_type.go +++ /dev/null @@ -1,29 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantMethodType struct { - DescriptorIndex uint16 -} - -func (c *ConstantMethodType) ToBytes() []byte { - var bs = []byte{ConstantMethodTypeInfo} - bs = append(bs, commons.NumberToBytes(c.DescriptorIndex)...) - return bs -} - -func (cf *ClassFile) readConstantMethodType(stream *commons.Stream) (*ConstantMethodType, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant method type failed, no enough data in the stream") - } - - return &ConstantMethodType{ - DescriptorIndex: binary.BigEndian.Uint16(bs), - }, nil -} diff --git a/class/constant_methodref.go b/class/constant_methodref.go deleted file mode 100644 index f5c7e74..0000000 --- a/class/constant_methodref.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantMethodRef struct { - ClassIndex uint16 - NameAndTypeIndex uint16 -} - -func (c *ConstantMethodRef) ToBytes() []byte { - var bs = []byte{ConstantMethodRefInfo} - bs = append(bs, commons.NumberToBytes(c.ClassIndex)...) - bs = append(bs, commons.NumberToBytes(c.NameAndTypeIndex)...) - return bs -} - -func (cf *ClassFile) readConstantMethodRef(stream *commons.Stream) (*ConstantMethodRef, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant method ref failed, no enough data in the stream") - } - - var c = &ConstantMethodRef{} - c.ClassIndex = binary.BigEndian.Uint16(bs[:2]) - c.NameAndTypeIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_module.go b/class/constant_module.go deleted file mode 100644 index af19436..0000000 --- a/class/constant_module.go +++ /dev/null @@ -1,29 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantModule struct { - NameIndex uint16 -} - -func (c *ConstantModule) ToBytes() []byte { - var bs = []byte{ConstantModuleInfo} - bs = append(bs, commons.NumberToBytes(c.NameIndex)...) - return bs -} - -func (cf *ClassFile) readConstantModule(stream *commons.Stream) (*ConstantModule, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant module failed, no enough data in the stream") - } - - return &ConstantModule{ - NameIndex: binary.BigEndian.Uint16(bs), - }, nil -} diff --git a/class/constant_nametype.go b/class/constant_nametype.go deleted file mode 100644 index a5d90cc..0000000 --- a/class/constant_nametype.go +++ /dev/null @@ -1,33 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantNameAndType struct { - NameIndex uint16 - DescriptorIndex uint16 -} - -func (c *ConstantNameAndType) ToBytes() []byte { - var bs = []byte{ConstantNameAndTypeInfo} - bs = append(bs, commons.NumberToBytes(c.NameIndex)...) - bs = append(bs, commons.NumberToBytes(c.DescriptorIndex)...) - return bs -} - -func (cf *ClassFile) readConstantNameAndType(stream *commons.Stream) (*ConstantNameAndType, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read constant name and type failed, no enough data in the stream") - } - - var c = &ConstantNameAndType{} - c.NameIndex = binary.BigEndian.Uint16(bs[:2]) - c.DescriptorIndex = binary.BigEndian.Uint16(bs[2:]) - - return c, nil -} diff --git a/class/constant_package.go b/class/constant_package.go deleted file mode 100644 index ecdf900..0000000 --- a/class/constant_package.go +++ /dev/null @@ -1,29 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantPackage struct { - NameIndex uint16 -} - -func (c *ConstantPackage) ToBytes() []byte { - var bs = []byte{ConstantPackageInfo} - bs = append(bs, commons.NumberToBytes(c.NameIndex)...) - return bs -} - -func (cf *ClassFile) readConstantPackage(stream *commons.Stream) (*ConstantPackage, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant package failed, no enough data in the stream") - } - - return &ConstantPackage{ - NameIndex: binary.BigEndian.Uint16(bs), - }, nil -} diff --git a/class/constant_str.go b/class/constant_str.go deleted file mode 100644 index 68cb7dd..0000000 --- a/class/constant_str.go +++ /dev/null @@ -1,30 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantString struct { - StringIndex uint16 -} - -func (c *ConstantString) ToBytes() []byte { - var bs = []byte{ConstantStringInfo} - bs = append(bs, commons.NumberToBytes(c.StringIndex)...) - return bs -} - -func (cf *ClassFile) readConstantString(stream *commons.Stream) (*ConstantString, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant string failed, no enough data in the stream") - } - - var i = binary.BigEndian.Uint16(bs) - return &ConstantString{ - StringIndex: i, - }, nil -} diff --git a/class/constant_utf8.go b/class/constant_utf8.go deleted file mode 100644 index 6bd4db9..0000000 --- a/class/constant_utf8.go +++ /dev/null @@ -1,39 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type ConstantUTF8 struct { - Data string -} - -func (c *ConstantUTF8) ToBytes() []byte { - var bs = []byte{ConstantUtf8Info} - - // integer overflow - bs = append(bs, commons.NumberToBytes(uint16(len(c.Data)))...) - bs = append(bs, []byte(c.Data)...) - return bs -} - -func (cf *ClassFile) readConstantUTF8(stream *commons.Stream) (*ConstantUTF8, error) { - _, _ = stream.ReadN(1) - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read constant utf8 size failed, no enough data in the stream") - } - - length := binary.BigEndian.Uint16(bs) - data, err := stream.ReadN(int(length)) - if err != nil { - return nil, fmt.Errorf("read constant utf8 failed, no enough data in the stream") - } - - c := &ConstantUTF8{ - Data: string(data), - } - return c, nil -} diff --git a/class/element_value.go b/class/element_value.go deleted file mode 100644 index 6347546..0000000 --- a/class/element_value.go +++ /dev/null @@ -1,86 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// ElementValue https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.16.1 -type ElementValue struct { - Tag byte - - ConstValueIndex uint16 - EnumConstValue *EnumConstValue - ClassInfoIndex uint16 - AnnotationValue *Annotation - ArrayValue []*ElementValue -} - -type EnumConstValue struct { - TypeNameIndex uint16 - ConstNameIndex uint16 -} - -func NewElementValue(stream *commons.Stream) (*ElementValue, error) { - bs, err := stream.ReadN(1) - if err != nil { - return nil, fmt.Errorf("read ElementValue tag failed, no enough data in the stream") - } - - element := &ElementValue{ - Tag: bs[0], - } - - switch element.Tag { - case 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 's': - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read ElementValue ConstValueIndex failed, no enough data in the stream") - } - - element.ConstValueIndex = binary.BigEndian.Uint16(bs) - case 'e': - bs, err = stream.ReadN(4) - if err != nil { - return nil, fmt.Errorf("read ElementValue EnumConstValue failed, no enough data in the stream") - } - - element.EnumConstValue = &EnumConstValue{ - TypeNameIndex: binary.BigEndian.Uint16(bs[:2]), - ConstNameIndex: binary.BigEndian.Uint16(bs[2:]), - } - case 'c': - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read ElementValue ClassInfoIndex failed, no enough data in the stream") - } - - element.ClassInfoIndex = binary.BigEndian.Uint16(bs) - case '@': - annotation, err := NewAnnotation(stream) - if err != nil { - return nil, fmt.Errorf("read ElementValue AnnotationValue failed, caused by: %v", err) - } - - element.AnnotationValue = annotation - case '[': - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read ElementValue ArrayValue failed, no enough data in the stream") - } - - for i := uint16(0); i < binary.BigEndian.Uint16(bs); i++ { - subElement, err := NewElementValue(stream) - if err != nil { - return nil, fmt.Errorf("read ElementValue ArrayValue failed, caused by: %v", err) - } - - element.ArrayValue = append(element.ArrayValue, subElement) - } - default: - return nil, fmt.Errorf("read ElementValue tag failed, tag %v not supported", element.Tag) - } - - return element, nil -} diff --git a/class/field.go b/class/field.go deleted file mode 100644 index 2185b87..0000000 --- a/class/field.go +++ /dev/null @@ -1,55 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -type Field struct { - AccessFlag AttrAccessFlag - NameIndex uint16 - DescriptorIndex uint16 - Attributes []Attribute -} - -func (cf *ClassFile) readFields(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read fields count failed, no enough data in the stream") - } - - var size = binary.BigEndian.Uint16(bs) - for i := uint16(0); i < size; i++ { - field, err := cf.readField(stream) - if err != nil { - return err - } - - cf.Fields = append(cf.Fields, field) - } - - return nil -} - -func (cf *ClassFile) readField(stream *commons.Stream) (*Field, error) { - var field = new(Field) - bs, err := stream.ReadN(8) - if err != nil { - return nil, fmt.Errorf("read field access flag failed, no enough data in the stream") - } - field.AccessFlag = AttrAccessFlag(binary.BigEndian.Uint16(bs[:2])) - field.NameIndex = binary.BigEndian.Uint16(bs[2:4]) - field.DescriptorIndex = binary.BigEndian.Uint16(bs[4:6]) - var size = binary.BigEndian.Uint16(bs[6:]) - for i := uint16(0); i < size; i++ { - attr, err := cf.readAttribute(stream) - if err != nil { - return nil, err - } - - field.Attributes = append(field.Attributes, attr) - } - - return field, nil -} diff --git a/class/interface.go b/class/interface.go deleted file mode 100644 index f7ed1b1..0000000 --- a/class/interface.go +++ /dev/null @@ -1,26 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -func (cf *ClassFile) readInterfaces(stream *commons.Stream) error { - bs, err := stream.ReadN(2) - if err != nil { - return fmt.Errorf("read interface count failed, no enough data in the stream") - } - - var size = binary.BigEndian.Uint16(bs) - for i := uint16(0); i < size; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return fmt.Errorf("read interface array failed, no enough data in the stream") - } - - cf.InterfaceIndexArray = append(cf.InterfaceIndexArray, binary.BigEndian.Uint16(bs)) - } - - return nil -} diff --git a/class/method.go b/class/method.go deleted file mode 100644 index 99f72b0..0000000 --- a/class/method.go +++ /dev/null @@ -1,4 +0,0 @@ -package class - -type Method struct { -} diff --git a/class/parameter_access.go b/class/parameter_access.go deleted file mode 100644 index 8b3e1ff..0000000 --- a/class/parameter_access.go +++ /dev/null @@ -1,13 +0,0 @@ -package class - -type ParameterAccessFlag uint16 - -const ( - ParameterAccFinal ParameterAccessFlag = 0x0010 - ParameterAccSynthetic ParameterAccessFlag = 0x1000 - ParameterAccMandated ParameterAccessFlag = 0x8000 -) - -func (caf ParameterAccessFlag) HasAccessFlag(flag ParameterAccessFlag) bool { - return (flag & caf) == flag -} diff --git a/class/parser.go b/class/parser.go deleted file mode 100644 index 1ab96b3..0000000 --- a/class/parser.go +++ /dev/null @@ -1,39 +0,0 @@ -package class - -import "github.com/phith0n/zkar/commons" - -func ParseClass(data []byte) (*ClassFile, error) { - stream := commons.NewStream(data) - classFile := new(ClassFile) - err := classFile.readHeader(stream) - if err != nil { - return nil, err - } - - err = classFile.readConstantPool(stream) - if err != nil { - return nil, err - } - - err = classFile.readAccessFlag(stream) - if err != nil { - return nil, err - } - - err = classFile.readClass(stream) - if err != nil { - return nil, err - } - - err = classFile.readInterfaces(stream) - if err != nil { - return nil, err - } - - err = classFile.readFields(stream) - if err != nil { - return nil, err - } - - return classFile, nil -} diff --git a/class/parser_test.go b/class/parser_test.go deleted file mode 100644 index d028861..0000000 --- a/class/parser_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package class - -import ( - "github.com/phith0n/litter" - "github.com/stretchr/testify/require" - "io/ioutil" - "testing" -) - -func TestParseClass(t *testing.T) { - t.SkipNow() - - data, err := ioutil.ReadFile("../testcases/classfile/TrainPrint.class") - require.Nil(t, err) - - classFile, err := ParseClass(data) - require.Nil(t, err) - - litter.Dump(classFile) -} diff --git a/class/type_annotation.go b/class/type_annotation.go deleted file mode 100644 index 30598df..0000000 --- a/class/type_annotation.go +++ /dev/null @@ -1,80 +0,0 @@ -package class - -import ( - "fmt" - "github.com/phith0n/zkar/commons" -) - -// TypeAnnotation https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.20 -type TypeAnnotation struct { - TargetType uint8 - TypeParameterTarget *TypeParameterTarget - SuperTypeTarget *SuperTypeTarget - TypeParameterBoundTarget *TypeParameterBoundTarget - EmptyTarget *EmptyTarget - FormalParameterTarget *FormalParameterTarget - ThrowsTarget *ThrowsTarget - LocalVarTarget *LocalVarTarget - CatchTarget *CatchTarget - OffsetTarget *OffsetTarget - TypeArgumentTarget *TypeArgumentTarget - - TargetPath *TypePath - - // same as Annotation - TypeIndex uint16 - ElementValuePairs []*ElementValuePair -} - -func NewTypeAnnotation(stream *commons.Stream) (*TypeAnnotation, error) { - bs, err := stream.ReadN(1) - if err != nil { - return nil, fmt.Errorf("read TypeAnnotation TargetType failed, no enough data in the stream") - } - - ta := &TypeAnnotation{ - TargetType: bs[0], - } - switch ta.TargetType { - case 0x00, 0x01: - ta.TypeParameterTarget, err = NewTypeParameterTarget(stream) - case 0x10: - ta.SuperTypeTarget, err = NewSuperTypeTarget(stream) - case 0x11, 0x12: - ta.TypeParameterBoundTarget, err = NewTypeParameterBoundTarget(stream) - case 0x13, 0x14, 0x15: - ta.EmptyTarget = &EmptyTarget{} - case 0x16: - ta.FormalParameterTarget, err = NewFormalParameterTarget(stream) - case 0x17: - ta.ThrowsTarget, err = NewThrowsTarget(stream) - case 0x40, 0x41: - ta.LocalVarTarget, err = NewLocalVarTarget(stream) - case 0x42: - ta.CatchTarget, err = NewCatchTarget(stream) - case 0x43, 0x44, 0x45, 0x46: - ta.OffsetTarget, err = NewOffsetTarget(stream) - case 0x47, 0x48, 0x49, 0x4A, 0x4B: - ta.TypeArgumentTarget, err = NewTypeArgumentTarget(stream) - default: - return nil, fmt.Errorf("read TypeAnnotation failed, TargetType %v not found", ta.TargetType) - } - - if err != nil { - return nil, fmt.Errorf("read TypeAnnotation TargetInfo failed, caused by: %v", err) - } - - ta.TargetPath, err = NewTypePath(stream) - if err != nil { - return nil, fmt.Errorf("read TypeAnnotation TargetPath failed, caused by: %v", err) - } - - annotation, err := NewAnnotation(stream) - if err != nil { - return nil, fmt.Errorf("read TypeAnnotation Annotation failed, caused by: %v", err) - } - - ta.TypeIndex = annotation.TypeIndex - ta.ElementValuePairs = annotation.ElementValuePairs - return ta, nil -} diff --git a/class/type_annotation_target.go b/class/type_annotation_target.go deleted file mode 100644 index 8213a0a..0000000 --- a/class/type_annotation_target.go +++ /dev/null @@ -1,154 +0,0 @@ -package class - -import ( - "encoding/binary" - "fmt" - "github.com/phith0n/zkar/commons" -) - -// TypeParameterTarget https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.20.1 -type TypeParameterTarget struct { - TypeParameterIndex uint8 -} - -func NewTypeParameterTarget(stream *commons.Stream) (*TypeParameterTarget, error) { - bs, err := stream.ReadN(1) - if err != nil { - return nil, fmt.Errorf("read TypeParameterTarget failed, no enough data in the stream") - } - - return &TypeParameterTarget{TypeParameterIndex: bs[0]}, nil -} - -type SuperTypeTarget struct { - SuperTypeIndex uint16 -} - -func NewSuperTypeTarget(stream *commons.Stream) (*SuperTypeTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read SuperTypeTarget failed, no enough data in the stream") - } - - return &SuperTypeTarget{SuperTypeIndex: binary.BigEndian.Uint16(bs)}, nil -} - -type TypeParameterBoundTarget struct { - TypeParameterIndex uint8 - BoundIndex uint8 -} - -func NewTypeParameterBoundTarget(stream *commons.Stream) (*TypeParameterBoundTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read TypeParameterBoundTarget failed, no enough data in the stream") - } - - return &TypeParameterBoundTarget{TypeParameterIndex: bs[0], BoundIndex: bs[1]}, nil -} - -type EmptyTarget struct { -} - -type FormalParameterTarget struct { - FormalParameterIndex uint8 -} - -func NewFormalParameterTarget(stream *commons.Stream) (*FormalParameterTarget, error) { - bs, err := stream.ReadN(1) - if err != nil { - return nil, fmt.Errorf("read FormalParameterTarget failed, no enough data in the stream") - } - - return &FormalParameterTarget{FormalParameterIndex: bs[0]}, nil -} - -type ThrowsTarget struct { - ThrowsTypeIndex uint16 -} - -func NewThrowsTarget(stream *commons.Stream) (*ThrowsTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read ThrowsTarget failed, no enough data in the stream") - } - - return &ThrowsTarget{ThrowsTypeIndex: binary.BigEndian.Uint16(bs)}, nil -} - -type LocalVarTarget struct { - Table []*LocalVarTargetTable -} - -type LocalVarTargetTable struct { - StartPC uint16 - Length uint16 - Index uint16 -} - -func NewLocalVarTarget(stream *commons.Stream) (*LocalVarTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read LocalVarTarget failed, no enough data in the stream") - } - - target := &LocalVarTarget{} - length := binary.BigEndian.Uint16(bs) - for i := uint16(0); i < length; i++ { - bs, err = stream.ReadN(6) - if err != nil { - return nil, fmt.Errorf("read LocalVarTarget Table[%d] failed, no enough data in the stream", i) - } - - target.Table = append(target.Table, &LocalVarTargetTable{ - StartPC: binary.BigEndian.Uint16(bs[:2]), - Length: binary.BigEndian.Uint16(bs[2:4]), - Index: binary.BigEndian.Uint16(bs[4:]), - }) - } - - return target, nil -} - -type CatchTarget struct { - ExceptionTableIndex uint16 -} - -func NewCatchTarget(stream *commons.Stream) (*CatchTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read CatchTarget failed, no enough data in the stream") - } - - return &CatchTarget{ExceptionTableIndex: binary.BigEndian.Uint16(bs)}, nil -} - -type OffsetTarget struct { - Offset uint16 -} - -func NewOffsetTarget(stream *commons.Stream) (*OffsetTarget, error) { - bs, err := stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read OffsetTarget failed, no enough data in the stream") - } - - return &OffsetTarget{Offset: binary.BigEndian.Uint16(bs)}, nil -} - -type TypeArgumentTarget struct { - Offset uint16 - TypeArgumentIndex uint8 -} - -func NewTypeArgumentTarget(stream *commons.Stream) (*TypeArgumentTarget, error) { - bs, err := stream.ReadN(3) - if err != nil { - return nil, fmt.Errorf("read TypeArgumentTarget failed, no enough data in the stream") - } - - return &TypeArgumentTarget{ - Offset: binary.BigEndian.Uint16(bs[:2]), - TypeArgumentIndex: bs[2], - }, nil -} diff --git a/class/type_path.go b/class/type_path.go deleted file mode 100644 index c559f1e..0000000 --- a/class/type_path.go +++ /dev/null @@ -1,38 +0,0 @@ -package class - -import ( - "fmt" - "github.com/phith0n/zkar/commons" -) - -type TypePath struct { - Path []*TypePathNode -} - -type TypePathNode struct { - TypePathKind uint8 - TypeArgumentIndex uint8 -} - -func NewTypePath(stream *commons.Stream) (*TypePath, error) { - bs, err := stream.ReadN(1) - if err != nil { - return nil, fmt.Errorf("read TypePath failed, no enough data in the stream") - } - - tp := &TypePath{} - length := bs[0] - for i := uint8(0); i < length; i++ { - bs, err = stream.ReadN(2) - if err != nil { - return nil, fmt.Errorf("read TypePath Node failed, no enough data in the stream") - } - - tp.Path = append(tp.Path, &TypePathNode{ - TypePathKind: bs[0], - TypeArgumentIndex: bs[1], - }) - } - - return tp, nil -} diff --git a/classfile/attr_bootstrap_methods.go b/classfile/attr_bootstrap_methods.go new file mode 100644 index 0000000..45afe18 --- /dev/null +++ b/classfile/attr_bootstrap_methods.go @@ -0,0 +1,33 @@ +package classfile + +/* +BootstrapMethods_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 num_bootstrap_methods; + { u2 bootstrap_method_ref; + u2 num_bootstrap_arguments; + u2 bootstrap_arguments[num_bootstrap_arguments]; + } bootstrap_methods[num_bootstrap_methods]; +} +*/ + +type BootstrapMethodsAttribute struct { + bootstrapMethods []*BootstrapMethod +} + +func (c *BootstrapMethodsAttribute) readInfo(reader *ClassReader) { + numBootstrapMethods := reader.readUint16() + c.bootstrapMethods = make([]*BootstrapMethod, numBootstrapMethods) + for i := range c.bootstrapMethods { + c.bootstrapMethods[i] = &BootstrapMethod{ + bootstrapMethodRef: reader.readUint16(), + bootstrapArguments: reader.readUint16s(), + } + } +} + +type BootstrapMethod struct { + bootstrapMethodRef uint16 + bootstrapArguments []uint16 +} diff --git a/classfile/attr_code.go b/classfile/attr_code.go new file mode 100644 index 0000000..c105c08 --- /dev/null +++ b/classfile/attr_code.go @@ -0,0 +1,91 @@ +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 (c *CodeAttribute) readInfo(reader *ClassReader) { + c.maxStack = reader.readUint16() + c.maxLocals = reader.readUint16() + codeLength := reader.readUint32() + c.code = reader.readBytes(codeLength) + c.exceptionTable = readExceptionTable(reader) + c.attributes = readAttributes(reader, c.cp) +} + +func (c *CodeAttribute) MaxStack() uint { + return uint(c.maxStack) +} + +func (c *CodeAttribute) MaxLocals() uint { + return uint(c.maxLocals) +} + +func (c *CodeAttribute) Code() []byte { + return c.code +} + +func (c *CodeAttribute) ExceptionTable() []*ExceptionTableEntry { + return c.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 (c *ExceptionTableEntry) StartPc() uint16 { + return c.startPc +} + +func (c *ExceptionTableEntry) EndPc() uint16 { + return c.endPc +} + +func (c *ExceptionTableEntry) HandlerPc() uint16 { + return c.handlerPc +} + +func (c *ExceptionTableEntry) CatchType() uint16 { + return c.catchType +} diff --git a/classfile/attr_constant_value.go b/classfile/attr_constant_value.go new file mode 100644 index 0000000..943c10a --- /dev/null +++ b/classfile/attr_constant_value.go @@ -0,0 +1,21 @@ +package classfile + +/* +ConstantValue_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 constantvalue_index; +} +*/ + +type ConstantValueAttribute struct { + constantValueIndex uint16 +} + +func (c *ConstantValueAttribute) readInfo(reader *ClassReader) { + c.constantValueIndex = reader.readUint16() +} + +func (c *ConstantValueAttribute) ConstantValueIndex() uint16 { + return c.constantValueIndex +} diff --git a/classfile/attr_deprecate.go b/classfile/attr_deprecate.go new file mode 100644 index 0000000..8e9fd6e --- /dev/null +++ b/classfile/attr_deprecate.go @@ -0,0 +1,12 @@ +package classfile + +/* +Deprecated_attribute { + u2 attribute_name_index; + u4 attribute_length; +} +*/ + +type DeprecatedAttribute struct { + MarkerAttribute +} diff --git a/classfile/attr_enclosing_method.go b/classfile/attr_enclosing_method.go new file mode 100644 index 0000000..87b827d --- /dev/null +++ b/classfile/attr_enclosing_method.go @@ -0,0 +1,33 @@ +package classfile + +/* +EnclosingMethod_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 class_index; + u2 method_index; +} +*/ + +type EnclosingMethodAttribute struct { + cp ConstantPool + classIndex uint16 + methodIndex uint16 +} + +func (c *EnclosingMethodAttribute) readInfo(reader *ClassReader) { + c.classIndex = reader.readUint16() + c.methodIndex = reader.readUint16() +} + +func (c *EnclosingMethodAttribute) ClassName() string { + return c.cp.GetClassName(c.classIndex) +} + +func (c *EnclosingMethodAttribute) MethodNameAndDescriptor() (string, string) { + if c.methodIndex > 0 { + return c.cp.GetNameAndType(c.methodIndex) + } else { + return "", "" + } +} diff --git a/classfile/attr_exceptions.go b/classfile/attr_exceptions.go new file mode 100644 index 0000000..795e471 --- /dev/null +++ b/classfile/attr_exceptions.go @@ -0,0 +1,22 @@ +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 (c *ExceptionsAttribute) readInfo(reader *ClassReader) { + c.exceptionIndexTable = reader.readUint16s() +} + +func (c *ExceptionsAttribute) ExceptionIndexTable() []uint16 { + return c.exceptionIndexTable +} diff --git a/classfile/attr_inner_classes.go b/classfile/attr_inner_classes.go new file mode 100644 index 0000000..0beb36e --- /dev/null +++ b/classfile/attr_inner_classes.go @@ -0,0 +1,38 @@ +package classfile + +/* +InnerClasses_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 number_of_classes; + { u2 inner_class_info_index; + u2 outer_class_info_index; + u2 inner_name_index; + u2 inner_class_access_flags; + } classes[number_of_classes]; +} +*/ + +type InnerClassesAttribute struct { + classes []*InnerClassInfo +} + +type InnerClassInfo struct { + innerClassInfoIndex uint16 + outerClassInfoIndex uint16 + innerNameIndex uint16 + innerClassAccessFlags uint16 +} + +func (c *InnerClassesAttribute) readInfo(reader *ClassReader) { + numberOfClasses := reader.readUint16() + c.classes = make([]*InnerClassInfo, numberOfClasses) + for i := range c.classes { + c.classes[i] = &InnerClassInfo{ + innerClassInfoIndex: reader.readUint16(), + outerClassInfoIndex: reader.readUint16(), + innerNameIndex: reader.readUint16(), + innerClassAccessFlags: reader.readUint16(), + } + } +} diff --git a/classfile/attr_line_number_table.go b/classfile/attr_line_number_table.go new file mode 100644 index 0000000..84f78d6 --- /dev/null +++ b/classfile/attr_line_number_table.go @@ -0,0 +1,42 @@ +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 (c *LineNumberTableAttribute) readInfo(reader *ClassReader) { + lineNumberTableLength := reader.readUint16() + c.lineNumberTable = make([]*LineNumberTableEntry, lineNumberTableLength) + for i := range c.lineNumberTable { + c.lineNumberTable[i] = &LineNumberTableEntry{ + startPc: reader.readUint16(), + lineNumber: reader.readUint16(), + } + } +} + +func (c *LineNumberTableAttribute) GetLineNumber(pc int) int { + for i := len(c.lineNumberTable) - 1; i >= 0; i-- { + entry := c.lineNumberTable[i] + if pc >= int(entry.startPc) { + return int(entry.lineNumber) + } + } + return -1 +} diff --git a/classfile/attr_local_variable_table.go b/classfile/attr_local_variable_table.go new file mode 100644 index 0000000..8bce872 --- /dev/null +++ b/classfile/attr_local_variable_table.go @@ -0,0 +1,41 @@ +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 (c *LocalVariableTableAttribute) readInfo(reader *ClassReader) { + localVariableTableLength := reader.readUint16() + c.localVariableTable = make([]*LocalVariableTableEntry, localVariableTableLength) + for i := range c.localVariableTable { + c.localVariableTable[i] = &LocalVariableTableEntry{ + startPc: reader.readUint16(), + length: reader.readUint16(), + nameIndex: reader.readUint16(), + descriptorIndex: reader.readUint16(), + index: reader.readUint16(), + } + } +} diff --git a/classfile/attr_local_variable_type_table.go b/classfile/attr_local_variable_type_table.go new file mode 100644 index 0000000..efd4315 --- /dev/null +++ b/classfile/attr_local_variable_type_table.go @@ -0,0 +1,41 @@ +package classfile + +/* +LocalVariableTypeTable_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 local_variable_type_table_length; + { u2 start_pc; + u2 length; + u2 name_index; + u2 signature_index; + u2 index; + } local_variable_type_table[local_variable_type_table_length]; +} +*/ + +type LocalVariableTypeTableAttribute struct { + localVariableTypeTable []*LocalVariableTypeTableEntry +} + +type LocalVariableTypeTableEntry struct { + startPc uint16 + length uint16 + nameIndex uint16 + signatureIndex uint16 + index uint16 +} + +func (c *LocalVariableTypeTableAttribute) readInfo(reader *ClassReader) { + localVariableTypeTableLength := reader.readUint16() + c.localVariableTypeTable = make([]*LocalVariableTypeTableEntry, localVariableTypeTableLength) + for i := range c.localVariableTypeTable { + c.localVariableTypeTable[i] = &LocalVariableTypeTableEntry{ + startPc: reader.readUint16(), + length: reader.readUint16(), + nameIndex: reader.readUint16(), + signatureIndex: reader.readUint16(), + index: reader.readUint16(), + } + } +} diff --git a/classfile/attr_markers.go b/classfile/attr_markers.go new file mode 100644 index 0000000..b19514e --- /dev/null +++ b/classfile/attr_markers.go @@ -0,0 +1,6 @@ +package classfile + +type MarkerAttribute struct{} + +func (c *MarkerAttribute) readInfo(_ *ClassReader) { +} diff --git a/classfile/attr_signature.go b/classfile/attr_signature.go new file mode 100644 index 0000000..548f629 --- /dev/null +++ b/classfile/attr_signature.go @@ -0,0 +1,22 @@ +package classfile + +/* +Signature_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 signature_index; +} +*/ + +type SignatureAttribute struct { + cp ConstantPool + signatureIndex uint16 +} + +func (c *SignatureAttribute) readInfo(reader *ClassReader) { + c.signatureIndex = reader.readUint16() +} + +func (c *SignatureAttribute) Signature() string { + return c.cp.GetUtf8(c.signatureIndex) +} diff --git a/classfile/attr_source_file.go b/classfile/attr_source_file.go new file mode 100644 index 0000000..1fb4ccd --- /dev/null +++ b/classfile/attr_source_file.go @@ -0,0 +1,22 @@ +package classfile + +/* +SourceFile_attribute { + u2 attribute_name_index; + u4 attribute_length; + u2 sourcefile_index; +} +*/ + +type SourceFileAttribute struct { + cp ConstantPool + sourceFileIndex uint16 +} + +func (c *SourceFileAttribute) readInfo(reader *ClassReader) { + c.sourceFileIndex = reader.readUint16() +} + +func (c *SourceFileAttribute) FileName() string { + return c.cp.GetUtf8(c.sourceFileIndex) +} diff --git a/classfile/attr_synthetic.go b/classfile/attr_synthetic.go new file mode 100644 index 0000000..1a82e20 --- /dev/null +++ b/classfile/attr_synthetic.go @@ -0,0 +1,12 @@ +package classfile + +/* +Synthetic_attribute { + u2 attribute_name_index; + u4 attribute_length; +} +*/ + +type SyntheticAttribute struct { + MarkerAttribute +} diff --git a/classfile/attr_unparsed.go b/classfile/attr_unparsed.go new file mode 100644 index 0000000..8771b6b --- /dev/null +++ b/classfile/attr_unparsed.go @@ -0,0 +1,23 @@ +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 (c *UnparsedAttribute) readInfo(reader *ClassReader) { + c.info = reader.readBytes(c.length) +} + +func (c *UnparsedAttribute) Info() []byte { + return c.info +} diff --git a/classfile/attribute_info.go b/classfile/attribute_info.go new file mode 100644 index 0000000..3bd124c --- /dev/null +++ b/classfile/attribute_info.go @@ -0,0 +1,54 @@ +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} + } +} diff --git a/classfile/class_file.go b/classfile/class_file.go new file mode 100644 index 0000000..e96c57c --- /dev/null +++ b/classfile/class_file.go @@ -0,0 +1,134 @@ +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 (c *ClassFile) read(reader *ClassReader) { + c.readAndCheckMagic(reader) + c.readAndCheckVersion(reader) + c.constantPool = readConstantPool(reader) + c.accessFlags = reader.readUint16() + c.thisClass = reader.readUint16() + c.superClass = reader.readUint16() + c.interfaces = reader.readUint16s() + c.fields = readMembers(reader, c.constantPool) + c.methods = readMembers(reader, c.constantPool) + c.attributes = readAttributes(reader, c.constantPool) +} + +func (c *ClassFile) readAndCheckMagic(reader *ClassReader) { + magic := reader.readUint32() + if magic != 0xCAFEBABE { + panic("java.lang.ClassFormatError: magic!") + } + c.magic = magic +} + +func (c *ClassFile) readAndCheckVersion(reader *ClassReader) { + c.minorVersion = reader.readUint16() + c.majorVersion = reader.readUint16() + switch c.majorVersion { + case 45: + // JDK 1.0.2 + return + case 46, 47, 48, 49, 50, 51, 52: + // JDK 1.2 - JDK 1.8 + if c.minorVersion == 0 { + return + } + } + panic("java.lang.UnsupportedClassVersionError!") +} + +func (c *ClassFile) MinorVersion() uint16 { + return c.minorVersion +} + +func (c *ClassFile) MajorVersion() uint16 { + return c.majorVersion +} + +func (c *ClassFile) ConstantPool() ConstantPool { + return c.constantPool +} + +func (c *ClassFile) AccessFlags() uint16 { + return c.accessFlags +} + +func (c *ClassFile) Fields() []*MemberInfo { + return c.fields +} + +func (c *ClassFile) Methods() []*MemberInfo { + return c.methods +} + +func (c *ClassFile) ClassName() string { + return c.constantPool.GetClassName(c.thisClass) +} + +func (c *ClassFile) SuperClassName() string { + if c.superClass > 0 { + return c.constantPool.GetClassName(c.superClass) + } + return "" +} + +func (c *ClassFile) InterfaceNames() []string { + interfaceNames := make([]string, len(c.interfaces)) + for i, cpIndex := range c.interfaces { + interfaceNames[i] = c.constantPool.GetClassName(cpIndex) + } + return interfaceNames +} diff --git a/classfile/class_reader.go b/classfile/class_reader.go new file mode 100644 index 0000000..71104ec --- /dev/null +++ b/classfile/class_reader.go @@ -0,0 +1,50 @@ +package classfile + +import "encoding/binary" + +type ClassReader struct { + data []byte +} + +// u1 +func (c *ClassReader) readUint8() uint8 { + val := c.data[0] + c.data = c.data[1:] + return val +} + +// u2 +func (c *ClassReader) readUint16() uint16 { + val := binary.BigEndian.Uint16(c.data) + c.data = c.data[2:] + return val +} + +// u4 +func (c *ClassReader) readUint32() uint32 { + val := binary.BigEndian.Uint32(c.data) + c.data = c.data[4:] + return val +} + +func (c *ClassReader) readUint64() uint64 { + val := binary.BigEndian.Uint64(c.data) + c.data = c.data[8:] + return val +} + +// uint16 table +func (c *ClassReader) readUint16s() []uint16 { + n := c.readUint16() + s := make([]uint16, n) + for i := range s { + s[i] = c.readUint16() + } + return s +} + +func (c *ClassReader) readBytes(n uint32) []byte { + bytes := c.data[:n] + c.data = c.data[n:] + return bytes +} diff --git a/classfile/constant_info.go b/classfile/constant_info.go new file mode 100644 index 0000000..cfd1c21 --- /dev/null +++ b/classfile/constant_info.go @@ -0,0 +1,71 @@ +package classfile + +const ( + ConstantClass = 7 + ConstantFieldRef = 9 + ConstantMethodRef = 10 + ConstantInterfaceMethodRef = 11 + ConstantString = 8 + ConstantInteger = 3 + ConstantFloat = 4 + ConstantLong = 5 + ConstantDouble = 6 + ConstantNameAndType = 12 + ConstantUtf8 = 1 + ConstantMethodHandle = 15 + ConstantMethodType = 16 + ConstantInvokeDynamic = 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 +} + +func newConstantInfo(tag uint8, cp ConstantPool) ConstantInfo { + switch tag { + case ConstantInteger: + return &ConstantIntegerInfo{} + case ConstantFloat: + return &ConstantFloatInfo{} + case ConstantLong: + return &ConstantLongInfo{} + case ConstantDouble: + return &ConstantDoubleInfo{} + case ConstantUtf8: + return &ConstantUtf8Info{} + case ConstantString: + return &ConstantStringInfo{cp: cp} + case ConstantClass: + return &ConstantClassInfo{cp: cp} + case ConstantFieldRef: + return &ConstantFieldRefInfo{ConstantMemberRefInfo{cp: cp}} + case ConstantMethodRef: + return &ConstantMethodRefInfo{ConstantMemberRefInfo{cp: cp}} + case ConstantInterfaceMethodRef: + return &ConstantInterfaceMethodRefInfo{ConstantMemberRefInfo{cp: cp}} + case ConstantNameAndType: + return &ConstantNameAndTypeInfo{} + case ConstantMethodType: + return &ConstantMethodTypeInfo{} + case ConstantMethodHandle: + return &ConstantMethodHandleInfo{} + case ConstantInvokeDynamic: + return &ConstantInvokeDynamicInfo{} + default: + panic("java.lang.ClassFormatError: constant pool tag!") + } +} diff --git a/classfile/constant_pool.go b/classfile/constant_pool.go new file mode 100644 index 0000000..40e1a7b --- /dev/null +++ b/classfile/constant_pool.go @@ -0,0 +1,42 @@ +package classfile + +import "fmt" + +type ConstantPool []ConstantInfo + +func readConstantPool(reader *ClassReader) ConstantPool { + cpCount := int(reader.readUint16()) + cp := make([]ConstantInfo, cpCount) + for i := 1; i < cpCount; i++ { + cp[i] = readConstantInfo(reader, cp) + switch cp[i].(type) { + case *ConstantLongInfo, *ConstantDoubleInfo: + i++ + } + } + return cp +} + +func (c ConstantPool) GetConstantInfo(index uint16) ConstantInfo { + if cpInfo := c[index]; cpInfo != nil { + return cpInfo + } + panic(fmt.Errorf("invalid constant pool index: %v", index)) +} + +func (c ConstantPool) GetNameAndType(index uint16) (string, string) { + ntInfo := c.GetConstantInfo(index).(*ConstantNameAndTypeInfo) + name := c.GetUtf8(ntInfo.nameIndex) + _type := c.GetUtf8(ntInfo.descriptorIndex) + return name, _type +} + +func (c ConstantPool) GetClassName(index uint16) string { + classInfo := c.GetConstantInfo(index).(*ConstantClassInfo) + return c.GetUtf8(classInfo.nameIndex) +} + +func (c ConstantPool) GetUtf8(index uint16) string { + utf8Info := c.GetConstantInfo(index).(*ConstantUtf8Info) + return utf8Info.str +} diff --git a/classfile/cp_class.go b/classfile/cp_class.go new file mode 100644 index 0000000..596eca1 --- /dev/null +++ b/classfile/cp_class.go @@ -0,0 +1,20 @@ +package classfile + +/* +CONSTANT_Class_info { + u1 tag; + u2 name_index; +} +*/ + +type ConstantClassInfo struct { + cp ConstantPool + nameIndex uint16 +} + +func (c *ConstantClassInfo) readInfo(reader *ClassReader) { + c.nameIndex = reader.readUint16() +} +func (c *ConstantClassInfo) Name() string { + return c.cp.GetUtf8(c.nameIndex) +} diff --git a/classfile/cp_double.go b/classfile/cp_double.go new file mode 100644 index 0000000..9a58abc --- /dev/null +++ b/classfile/cp_double.go @@ -0,0 +1,23 @@ +package classfile + +import "math" + +/* +CONSTANT_Double_info { + u1 tag; + u4 high_bytes; + u4 low_bytes; +} +*/ + +type ConstantDoubleInfo struct { + val float64 +} + +func (c *ConstantDoubleInfo) readInfo(reader *ClassReader) { + bytes := reader.readUint64() + c.val = math.Float64frombits(bytes) +} +func (c *ConstantDoubleInfo) Value() float64 { + return c.val +} diff --git a/classfile/cp_field_ref.go b/classfile/cp_field_ref.go new file mode 100644 index 0000000..4acd3d1 --- /dev/null +++ b/classfile/cp_field_ref.go @@ -0,0 +1,11 @@ +package classfile + +/* +CONSTANT_Fieldref_info { + u1 tag; + u2 class_index; + u2 name_and_type_index; +} +*/ + +type ConstantFieldRefInfo struct{ ConstantMemberRefInfo } diff --git a/classfile/cp_float.go b/classfile/cp_float.go new file mode 100644 index 0000000..a32c0bb --- /dev/null +++ b/classfile/cp_float.go @@ -0,0 +1,22 @@ +package classfile + +import "math" + +/* +CONSTANT_Float_info { + u1 tag; + u4 bytes; +} +*/ + +type ConstantFloatInfo struct { + val float32 +} + +func (c *ConstantFloatInfo) readInfo(reader *ClassReader) { + bytes := reader.readUint32() + c.val = math.Float32frombits(bytes) +} +func (c *ConstantFloatInfo) Value() float32 { + return c.val +} diff --git a/classfile/cp_integer.go b/classfile/cp_integer.go new file mode 100644 index 0000000..ecb12ca --- /dev/null +++ b/classfile/cp_integer.go @@ -0,0 +1,21 @@ +package classfile + +/* +CONSTANT_Integer_info { + u1 tag; + u4 bytes; +} +*/ + +type ConstantIntegerInfo struct { + val int32 +} + +func (c *ConstantIntegerInfo) readInfo(reader *ClassReader) { + bytes := reader.readUint32() + c.val = int32(bytes) +} + +func (c *ConstantIntegerInfo) Value() int32 { + return c.val +} diff --git a/classfile/cp_interface_method_ref.go b/classfile/cp_interface_method_ref.go new file mode 100644 index 0000000..b548273 --- /dev/null +++ b/classfile/cp_interface_method_ref.go @@ -0,0 +1,11 @@ +package classfile + +/* +CONSTANT_InterfaceMethodref_info { + u1 tag; + u2 class_index; + u2 name_and_type_index; +} +*/ + +type ConstantInterfaceMethodRefInfo struct{ ConstantMemberRefInfo } diff --git a/classfile/cp_invoke_dynamic.go b/classfile/cp_invoke_dynamic.go new file mode 100644 index 0000000..e3ae9dd --- /dev/null +++ b/classfile/cp_invoke_dynamic.go @@ -0,0 +1,19 @@ +package classfile + +/* +CONSTANT_InvokeDynamic_info { + u1 tag; + u2 bootstrap_method_attr_index; + u2 name_and_type_index; +} +*/ + +type ConstantInvokeDynamicInfo struct { + bootstrapMethodAttrIndex uint16 + nameAndTypeIndex uint16 +} + +func (c *ConstantInvokeDynamicInfo) readInfo(reader *ClassReader) { + c.bootstrapMethodAttrIndex = reader.readUint16() + c.nameAndTypeIndex = reader.readUint16() +} diff --git a/classfile/cp_long.go b/classfile/cp_long.go new file mode 100644 index 0000000..311ce94 --- /dev/null +++ b/classfile/cp_long.go @@ -0,0 +1,21 @@ +package classfile + +/* +CONSTANT_Long_info { + u1 tag; + u4 high_bytes; + u4 low_bytes; +} +*/ + +type ConstantLongInfo struct { + val int64 +} + +func (c *ConstantLongInfo) readInfo(reader *ClassReader) { + bytes := reader.readUint64() + c.val = int64(bytes) +} +func (c *ConstantLongInfo) Value() int64 { + return c.val +} diff --git a/classfile/cp_member_ref.go b/classfile/cp_member_ref.go new file mode 100644 index 0000000..b79d5f8 --- /dev/null +++ b/classfile/cp_member_ref.go @@ -0,0 +1,19 @@ +package classfile + +type ConstantMemberRefInfo struct { + cp ConstantPool + classIndex uint16 + nameAndTypeIndex uint16 +} + +func (c *ConstantMemberRefInfo) readInfo(reader *ClassReader) { + c.classIndex = reader.readUint16() + c.nameAndTypeIndex = reader.readUint16() +} + +func (c *ConstantMemberRefInfo) ClassName() string { + return c.cp.GetClassName(c.classIndex) +} +func (c *ConstantMemberRefInfo) NameAndDescriptor() (string, string) { + return c.cp.GetNameAndType(c.nameAndTypeIndex) +} diff --git a/classfile/cp_method_handle.go b/classfile/cp_method_handle.go new file mode 100644 index 0000000..997ccdd --- /dev/null +++ b/classfile/cp_method_handle.go @@ -0,0 +1,19 @@ +package classfile + +/* +CONSTANT_MethodHandle_info { + u1 tag; + u1 reference_kind; + u2 reference_index; +} +*/ + +type ConstantMethodHandleInfo struct { + referenceKind uint8 + referenceIndex uint16 +} + +func (c *ConstantMethodHandleInfo) readInfo(reader *ClassReader) { + c.referenceKind = reader.readUint8() + c.referenceIndex = reader.readUint16() +} diff --git a/classfile/cp_method_ref.go b/classfile/cp_method_ref.go new file mode 100644 index 0000000..f9d5580 --- /dev/null +++ b/classfile/cp_method_ref.go @@ -0,0 +1,11 @@ +package classfile + +/* +CONSTANT_Methodref_info { + u1 tag; + u2 class_index; + u2 name_and_type_index; +} +*/ + +type ConstantMethodRefInfo struct{ ConstantMemberRefInfo } diff --git a/classfile/cp_method_type.go b/classfile/cp_method_type.go new file mode 100644 index 0000000..d068c60 --- /dev/null +++ b/classfile/cp_method_type.go @@ -0,0 +1,16 @@ +package classfile + +/* +CONSTANT_MethodType_info { + u1 tag; + u2 descriptor_index; +} +*/ + +type ConstantMethodTypeInfo struct { + descriptorIndex uint16 +} + +func (c *ConstantMethodTypeInfo) readInfo(reader *ClassReader) { + c.descriptorIndex = reader.readUint16() +} diff --git a/classfile/cp_name_and_type.go b/classfile/cp_name_and_type.go new file mode 100644 index 0000000..4df87a6 --- /dev/null +++ b/classfile/cp_name_and_type.go @@ -0,0 +1,19 @@ +package classfile + +/* +CONSTANT_NameAndType_info { + u1 tag; + u2 name_index; + u2 descriptor_index; +} +*/ + +type ConstantNameAndTypeInfo struct { + nameIndex uint16 + descriptorIndex uint16 +} + +func (c *ConstantNameAndTypeInfo) readInfo(reader *ClassReader) { + c.nameIndex = reader.readUint16() + c.descriptorIndex = reader.readUint16() +} diff --git a/classfile/cp_string.go b/classfile/cp_string.go new file mode 100644 index 0000000..c42a08a --- /dev/null +++ b/classfile/cp_string.go @@ -0,0 +1,20 @@ +package classfile + +/* +CONSTANT_String_info { + u1 tag; + u2 string_index; +} +*/ + +type ConstantStringInfo struct { + cp ConstantPool + stringIndex uint16 +} + +func (c *ConstantStringInfo) readInfo(reader *ClassReader) { + c.stringIndex = reader.readUint16() +} +func (c *ConstantStringInfo) String() string { + return c.cp.GetUtf8(c.stringIndex) +} diff --git a/classfile/cp_utf8.go b/classfile/cp_utf8.go new file mode 100644 index 0000000..be34199 --- /dev/null +++ b/classfile/cp_utf8.go @@ -0,0 +1,82 @@ +package classfile + +import ( + "fmt" + "unicode/utf16" +) + +/* +CONSTANT_Utf8_info { + u1 tag; + u2 length; + u1 bytes[length]; +} +*/ + +type ConstantUtf8Info struct { + str string +} + +func (c *ConstantUtf8Info) readInfo(reader *ClassReader) { + length := uint32(reader.readUint16()) + bytes := reader.readBytes(length) + c.str = decodeMUTF8(bytes) +} + +func (c *ConstantUtf8Info) Str() string { + return c.str +} + +func decodeMUTF8(byteArr []byte) string { + utfLen := len(byteArr) + charArr := make([]uint16, utfLen) + var c, char2, char3 uint16 + count := 0 + charArrCount := 0 + for count < utfLen { + c = uint16(byteArr[count]) + if c > 127 { + break + } + count++ + charArr[charArrCount] = c + charArrCount++ + } + for count < utfLen { + c = uint16(byteArr[count]) + switch c >> 4 { + case 0, 1, 2, 3, 4, 5, 6, 7: + count++ + charArr[charArrCount] = c + charArrCount++ + case 12, 13: + 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[charArrCount] = c&0x1F<<6 | char2&0x3F + charArrCount++ + case 14: + 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[charArrCount] = c&0x0F<<12 | char2&0x3F<<6 | char3&0x3F<<0 + charArrCount++ + default: + panic(fmt.Errorf("malformed input around byte %v", count)) + } + } + charArr = charArr[0:charArrCount] + runes := utf16.Decode(charArr) + return string(runes) +} diff --git a/classfile/field_info.go b/classfile/field_info.go new file mode 100644 index 0000000..002320c --- /dev/null +++ b/classfile/field_info.go @@ -0,0 +1,15 @@ +package classfile + +/* +field_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; +} +*/ + +type FieldInfo struct { + MemberInfo +} diff --git a/classfile/member_info.go b/classfile/member_info.go new file mode 100644 index 0000000..96bb064 --- /dev/null +++ b/classfile/member_info.go @@ -0,0 +1,58 @@ +package classfile + +type MemberInfo struct { + cp ConstantPool + accessFlags uint16 + nameIndex uint16 + descriptorIndex uint16 + attributes []AttributeInfo +} + +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) +} + +func (self *MemberInfo) CodeAttribute() *CodeAttribute { + for _, attrInfo := range self.attributes { + switch attrInfo.(type) { + case *CodeAttribute: + return attrInfo.(*CodeAttribute) + } + } + return nil +} + +func (self *MemberInfo) ConstantValueAttribute() *ConstantValueAttribute { + for _, attrInfo := range self.attributes { + switch attrInfo.(type) { + case *ConstantValueAttribute: + return attrInfo.(*ConstantValueAttribute) + } + } + return nil +} diff --git a/classfile/method_info.go b/classfile/method_info.go new file mode 100644 index 0000000..a892a07 --- /dev/null +++ b/classfile/method_info.go @@ -0,0 +1,15 @@ +package classfile + +/* +method_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + attribute_info attributes[attributes_count]; +} +*/ + +type MethodInfo struct { + MemberInfo +} diff --git a/core/add.go b/core/add.go new file mode 100644 index 0000000..7257528 --- /dev/null +++ b/core/add.go @@ -0,0 +1,9 @@ +package core + +type DADD struct{ NoOperandsInstruction } + +type FADD struct{ NoOperandsInstruction } + +type IADD struct{ NoOperandsInstruction } + +type LADD struct{ NoOperandsInstruction } diff --git a/core/aload.go b/core/aload.go new file mode 100644 index 0000000..fa34231 --- /dev/null +++ b/core/aload.go @@ -0,0 +1,11 @@ +package core + +type ALOAD struct{ Index8Instruction } + +type ALOAD_0 struct{ NoOperandsInstruction } + +type ALOAD_1 struct{ NoOperandsInstruction } + +type ALOAD_2 struct{ NoOperandsInstruction } + +type ALOAD_3 struct{ NoOperandsInstruction } diff --git a/core/and.go b/core/and.go new file mode 100644 index 0000000..9741836 --- /dev/null +++ b/core/and.go @@ -0,0 +1,5 @@ +package core + +type IAND struct{ NoOperandsInstruction } + +type LAND struct{ NoOperandsInstruction } diff --git a/core/anewarray.go b/core/anewarray.go new file mode 100644 index 0000000..21c4542 --- /dev/null +++ b/core/anewarray.go @@ -0,0 +1,3 @@ +package core + +type ANEW_ARRAY struct{ Index16Instruction } diff --git a/core/arraylength.go b/core/arraylength.go new file mode 100644 index 0000000..bf13248 --- /dev/null +++ b/core/arraylength.go @@ -0,0 +1,3 @@ +package core + +type ARRAY_LENGTH struct{ NoOperandsInstruction } diff --git a/core/astore.go b/core/astore.go new file mode 100644 index 0000000..c88721d --- /dev/null +++ b/core/astore.go @@ -0,0 +1,11 @@ +package core + +type ASTORE struct{ Index8Instruction } + +type ASTORE_0 struct{ NoOperandsInstruction } + +type ASTORE_1 struct{ NoOperandsInstruction } + +type ASTORE_2 struct{ NoOperandsInstruction } + +type ASTORE_3 struct{ NoOperandsInstruction } diff --git a/core/athrow.go b/core/athrow.go new file mode 100644 index 0000000..5f2fd05 --- /dev/null +++ b/core/athrow.go @@ -0,0 +1,3 @@ +package core + +type ATHROW struct{ NoOperandsInstruction } diff --git a/core/base.go b/core/base.go new file mode 100644 index 0000000..41e45ff --- /dev/null +++ b/core/base.go @@ -0,0 +1,7 @@ +package core + +const ( + NotSupport = "[not support]" + MethodType = "*classfile.ConstantMethodRefInfo" + InterfaceMethodType = "*classfile.ConstantInterfaceMethodRefInfo" +) diff --git a/core/bytecode_reader.go b/core/bytecode_reader.go new file mode 100644 index 0000000..2b03563 --- /dev/null +++ b/core/bytecode_reader.go @@ -0,0 +1,57 @@ +package core + +type BytecodeReader struct { + code []byte + pc int +} + +func (self *BytecodeReader) Reset(code []byte, pc int) { + self.code = code + self.pc = pc +} + +func (self *BytecodeReader) PC() int { + return self.pc +} + +func (self *BytecodeReader) ReadInt8() int8 { + return int8(self.ReadUint8()) +} + +func (self *BytecodeReader) ReadUint8() uint8 { + i := self.code[self.pc] + self.pc++ + return i +} + +func (self *BytecodeReader) ReadInt16() int16 { + return int16(self.ReadUint16()) +} + +func (self *BytecodeReader) ReadUint16() uint16 { + byte1 := uint16(self.ReadUint8()) + byte2 := uint16(self.ReadUint8()) + return (byte1 << 8) | byte2 +} + +func (self *BytecodeReader) ReadInt32() int32 { + byte1 := int32(self.ReadUint8()) + byte2 := int32(self.ReadUint8()) + byte3 := int32(self.ReadUint8()) + byte4 := int32(self.ReadUint8()) + return (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4 +} + +func (self *BytecodeReader) ReadInt32s(n int32) []int32 { + ints := make([]int32, n) + for i := range ints { + ints[i] = self.ReadInt32() + } + return ints +} + +func (self *BytecodeReader) SkipPadding() { + for self.pc%4 != 0 { + self.ReadUint8() + } +} diff --git a/core/checkcast.go b/core/checkcast.go new file mode 100644 index 0000000..3fa11fa --- /dev/null +++ b/core/checkcast.go @@ -0,0 +1,3 @@ +package core + +type CHECK_CAST struct{ Index16Instruction } diff --git a/core/const.go b/core/const.go new file mode 100644 index 0000000..4494cd7 --- /dev/null +++ b/core/const.go @@ -0,0 +1,31 @@ +package core + +type ACONST_NULL struct{ NoOperandsInstruction } + +type DCONST_0 struct{ NoOperandsInstruction } + +type DCONST_1 struct{ NoOperandsInstruction } + +type FCONST_0 struct{ NoOperandsInstruction } + +type FCONST_1 struct{ NoOperandsInstruction } + +type FCONST_2 struct{ NoOperandsInstruction } + +type ICONST_M1 struct{ NoOperandsInstruction } + +type ICONST_0 struct{ NoOperandsInstruction } + +type ICONST_1 struct{ NoOperandsInstruction } + +type ICONST_2 struct{ NoOperandsInstruction } + +type ICONST_3 struct{ NoOperandsInstruction } + +type ICONST_4 struct{ NoOperandsInstruction } + +type ICONST_5 struct{ NoOperandsInstruction } + +type LCONST_0 struct{ NoOperandsInstruction } + +type LCONST_1 struct{ NoOperandsInstruction } diff --git a/core/d2x.go b/core/d2x.go new file mode 100644 index 0000000..7ae53ec --- /dev/null +++ b/core/d2x.go @@ -0,0 +1,7 @@ +package core + +type D2F struct{ NoOperandsInstruction } + +type D2I struct{ NoOperandsInstruction } + +type D2L struct{ NoOperandsInstruction } diff --git a/core/dcmp.go b/core/dcmp.go new file mode 100644 index 0000000..6445b97 --- /dev/null +++ b/core/dcmp.go @@ -0,0 +1,5 @@ +package core + +type DCMPG struct{ NoOperandsInstruction } + +type DCMPL struct{ NoOperandsInstruction } diff --git a/core/div.go b/core/div.go new file mode 100644 index 0000000..d73118f --- /dev/null +++ b/core/div.go @@ -0,0 +1,9 @@ +package core + +type DDIV struct{ NoOperandsInstruction } + +type FDIV struct{ NoOperandsInstruction } + +type IDIV struct{ NoOperandsInstruction } + +type LDIV struct{ NoOperandsInstruction } diff --git a/core/dload.go b/core/dload.go new file mode 100644 index 0000000..6275284 --- /dev/null +++ b/core/dload.go @@ -0,0 +1,11 @@ +package core + +type DLOAD struct{ Index8Instruction } + +type DLOAD_0 struct{ NoOperandsInstruction } + +type DLOAD_1 struct{ NoOperandsInstruction } + +type DLOAD_2 struct{ NoOperandsInstruction } + +type DLOAD_3 struct{ NoOperandsInstruction } diff --git a/core/dstore.go b/core/dstore.go new file mode 100644 index 0000000..f77a3f9 --- /dev/null +++ b/core/dstore.go @@ -0,0 +1,11 @@ +package core + +type DSTORE struct{ Index8Instruction } + +type DSTORE_0 struct{ NoOperandsInstruction } + +type DSTORE_1 struct{ NoOperandsInstruction } + +type DSTORE_2 struct{ NoOperandsInstruction } + +type DSTORE_3 struct{ NoOperandsInstruction } diff --git a/core/dup.go b/core/dup.go new file mode 100644 index 0000000..057d728 --- /dev/null +++ b/core/dup.go @@ -0,0 +1,13 @@ +package core + +type DUP struct{ NoOperandsInstruction } + +type DUP_X1 struct{ NoOperandsInstruction } + +type DUP_X2 struct{ NoOperandsInstruction } + +type DUP2 struct{ NoOperandsInstruction } + +type DUP2_X1 struct{ NoOperandsInstruction } + +type DUP2_X2 struct{ NoOperandsInstruction } diff --git a/core/f2x.go b/core/f2x.go new file mode 100644 index 0000000..bc1d07c --- /dev/null +++ b/core/f2x.go @@ -0,0 +1,7 @@ +package core + +type F2D struct{ NoOperandsInstruction } + +type F2I struct{ NoOperandsInstruction } + +type F2L struct{ NoOperandsInstruction } diff --git a/core/factory.go b/core/factory.go new file mode 100644 index 0000000..567b1dc --- /dev/null +++ b/core/factory.go @@ -0,0 +1,573 @@ +package core + +import ( + "fmt" +) + +var ( + nop = &NOP{} + aconst_null = &ACONST_NULL{} + iconst_m1 = &ICONST_M1{} + iconst_0 = &ICONST_0{} + iconst_1 = &ICONST_1{} + iconst_2 = &ICONST_2{} + iconst_3 = &ICONST_3{} + iconst_4 = &ICONST_4{} + iconst_5 = &ICONST_5{} + lconst_0 = &LCONST_0{} + lconst_1 = &LCONST_1{} + fconst_0 = &FCONST_0{} + fconst_1 = &FCONST_1{} + fconst_2 = &FCONST_2{} + dconst_0 = &DCONST_0{} + dconst_1 = &DCONST_1{} + iload_0 = &ILOAD_0{} + iload_1 = &ILOAD_1{} + iload_2 = &ILOAD_2{} + iload_3 = &ILOAD_3{} + lload_0 = &LLOAD_0{} + lload_1 = &LLOAD_1{} + lload_2 = &LLOAD_2{} + lload_3 = &LLOAD_3{} + fload_0 = &FLOAD_0{} + fload_1 = &FLOAD_1{} + fload_2 = &FLOAD_2{} + fload_3 = &FLOAD_3{} + dload_0 = &DLOAD_0{} + dload_1 = &DLOAD_1{} + dload_2 = &DLOAD_2{} + dload_3 = &DLOAD_3{} + aload_0 = &ALOAD_0{} + aload_1 = &ALOAD_1{} + aload_2 = &ALOAD_2{} + aload_3 = &ALOAD_3{} + iaload = &IALOAD{} + laload = &LALOAD{} + faload = &FALOAD{} + daload = &DALOAD{} + aaload = &AALOAD{} + baload = &BALOAD{} + caload = &CALOAD{} + saload = &SALOAD{} + istore_0 = &ISTORE_0{} + istore_1 = &ISTORE_1{} + istore_2 = &ISTORE_2{} + istore_3 = &ISTORE_3{} + lstore_0 = &LSTORE_0{} + lstore_1 = &LSTORE_1{} + lstore_2 = &LSTORE_2{} + lstore_3 = &LSTORE_3{} + fstore_0 = &FSTORE_0{} + fstore_1 = &FSTORE_1{} + fstore_2 = &FSTORE_2{} + fstore_3 = &FSTORE_3{} + dstore_0 = &DSTORE_0{} + dstore_1 = &DSTORE_1{} + dstore_2 = &DSTORE_2{} + dstore_3 = &DSTORE_3{} + astore_0 = &ASTORE_0{} + astore_1 = &ASTORE_1{} + astore_2 = &ASTORE_2{} + astore_3 = &ASTORE_3{} + iastore = &IASTORE{} + lastore = &LASTORE{} + fastore = &FASTORE{} + dastore = &DASTORE{} + aastore = &AASTORE{} + bastore = &BASTORE{} + castore = &CASTORE{} + sastore = &SASTORE{} + pop = &POP{} + pop2 = &POP2{} + dup = &DUP{} + dup_x1 = &DUP_X1{} + dup_x2 = &DUP_X2{} + dup2 = &DUP2{} + dup2_x1 = &DUP2_X1{} + dup2_x2 = &DUP2_X2{} + swap = &SWAP{} + iadd = &IADD{} + ladd = &LADD{} + fadd = &FADD{} + dadd = &DADD{} + isub = &ISUB{} + lsub = &LSUB{} + fsub = &FSUB{} + dsub = &DSUB{} + imul = &IMUL{} + lmul = &LMUL{} + fmul = &FMUL{} + dmul = &DMUL{} + idiv = &IDIV{} + ldiv = &LDIV{} + fdiv = &FDIV{} + ddiv = &DDIV{} + irem = &IREM{} + lrem = &LREM{} + frem = &FREM{} + drem = &DREM{} + ineg = &INEG{} + lneg = &LNEG{} + fneg = &FNEG{} + dneg = &DNEG{} + ishl = &ISHL{} + lshl = &LSHL{} + ishr = &ISHR{} + lshr = &LSHR{} + iushr = &IUSHR{} + lushr = &LUSHR{} + iand = &IAND{} + land = &LAND{} + ior = &IOR{} + lor = &LOR{} + ixor = &IXOR{} + lxor = &LXOR{} + i2l = &I2L{} + i2f = &I2F{} + i2d = &I2D{} + l2i = &L2I{} + l2f = &L2F{} + l2d = &L2D{} + f2i = &F2I{} + f2l = &F2L{} + f2d = &F2D{} + d2i = &D2I{} + d2l = &D2L{} + d2f = &D2F{} + i2b = &I2B{} + i2c = &I2C{} + i2s = &I2S{} + lcmp = &LCMP{} + fcmpl = &FCMPL{} + fcmpg = &FCMPG{} + dcmpl = &DCMPL{} + dcmpg = &DCMPG{} + ireturn = &IRETURN{} + lreturn = &LRETURN{} + freturn = &FRETURN{} + dreturn = &DRETURN{} + areturn = &ARETURN{} + _return = &RETURN{} + arraylength = &ARRAY_LENGTH{} + athrow = &ATHROW{} + monitorenter = &MONITORENTER{} + monitorexit = &MONITOREXIT{} + invoke_native = &INVOKENATIVE{} +) + +func NewInstruction(opcode byte) Instruction { + switch opcode { + case 0x00: + return nop + case 0x01: + return aconst_null + case 0x02: + return iconst_m1 + case 0x03: + return iconst_0 + case 0x04: + return iconst_1 + case 0x05: + return iconst_2 + case 0x06: + return iconst_3 + case 0x07: + return iconst_4 + case 0x08: + return iconst_5 + case 0x09: + return lconst_0 + case 0x0a: + return lconst_1 + case 0x0b: + return fconst_0 + case 0x0c: + return fconst_1 + case 0x0d: + return fconst_2 + case 0x0e: + return dconst_0 + case 0x0f: + return dconst_1 + case 0x10: + return &BIPUSH{} + case 0x11: + return &SIPUSH{} + case 0x12: + return &LDC{} + case 0x13: + return &LDC_W{} + case 0x14: + return &LDC2_W{} + case 0x15: + return &ILOAD{} + case 0x16: + return &LLOAD{} + case 0x17: + return &FLOAD{} + case 0x18: + return &DLOAD{} + case 0x19: + return &ALOAD{} + case 0x1a: + return iload_0 + case 0x1b: + return iload_1 + case 0x1c: + return iload_2 + case 0x1d: + return iload_3 + case 0x1e: + return lload_0 + case 0x1f: + return lload_1 + case 0x20: + return lload_2 + case 0x21: + return lload_3 + case 0x22: + return fload_0 + case 0x23: + return fload_1 + case 0x24: + return fload_2 + case 0x25: + return fload_3 + case 0x26: + return dload_0 + case 0x27: + return dload_1 + case 0x28: + return dload_2 + case 0x29: + return dload_3 + case 0x2a: + return aload_0 + case 0x2b: + return aload_1 + case 0x2c: + return aload_2 + case 0x2d: + return aload_3 + case 0x2e: + return iaload + case 0x2f: + return laload + case 0x30: + return faload + case 0x31: + return daload + case 0x32: + return aaload + case 0x33: + return baload + case 0x34: + return caload + case 0x35: + return saload + case 0x36: + return &ISTORE{} + case 0x37: + return &LSTORE{} + case 0x38: + return &FSTORE{} + case 0x39: + return &DSTORE{} + case 0x3a: + return &ASTORE{} + case 0x3b: + return istore_0 + case 0x3c: + return istore_1 + case 0x3d: + return istore_2 + case 0x3e: + return istore_3 + case 0x3f: + return lstore_0 + case 0x40: + return lstore_1 + case 0x41: + return lstore_2 + case 0x42: + return lstore_3 + case 0x43: + return fstore_0 + case 0x44: + return fstore_1 + case 0x45: + return fstore_2 + case 0x46: + return fstore_3 + case 0x47: + return dstore_0 + case 0x48: + return dstore_1 + case 0x49: + return dstore_2 + case 0x4a: + return dstore_3 + case 0x4b: + return astore_0 + case 0x4c: + return astore_1 + case 0x4d: + return astore_2 + case 0x4e: + return astore_3 + case 0x4f: + return iastore + case 0x50: + return lastore + case 0x51: + return fastore + case 0x52: + return dastore + case 0x53: + return aastore + case 0x54: + return bastore + case 0x55: + return castore + case 0x56: + return sastore + case 0x57: + return pop + case 0x58: + return pop2 + case 0x59: + return dup + case 0x5a: + return dup_x1 + case 0x5b: + return dup_x2 + case 0x5c: + return dup2 + case 0x5d: + return dup2_x1 + case 0x5e: + return dup2_x2 + case 0x5f: + return swap + case 0x60: + return iadd + case 0x61: + return ladd + case 0x62: + return fadd + case 0x63: + return dadd + case 0x64: + return isub + case 0x65: + return lsub + case 0x66: + return fsub + case 0x67: + return dsub + case 0x68: + return imul + case 0x69: + return lmul + case 0x6a: + return fmul + case 0x6b: + return dmul + case 0x6c: + return idiv + case 0x6d: + return ldiv + case 0x6e: + return fdiv + case 0x6f: + return ddiv + case 0x70: + return irem + case 0x71: + return lrem + case 0x72: + return frem + case 0x73: + return drem + case 0x74: + return ineg + case 0x75: + return lneg + case 0x76: + return fneg + case 0x77: + return dneg + case 0x78: + return ishl + case 0x79: + return lshl + case 0x7a: + return ishr + case 0x7b: + return lshr + case 0x7c: + return iushr + case 0x7d: + return lushr + case 0x7e: + return iand + case 0x7f: + return land + case 0x80: + return ior + case 0x81: + return lor + case 0x82: + return ixor + case 0x83: + return lxor + case 0x84: + return &IINC{} + case 0x85: + return i2l + case 0x86: + return i2f + case 0x87: + return i2d + case 0x88: + return l2i + case 0x89: + return l2f + case 0x8a: + return l2d + case 0x8b: + return f2i + case 0x8c: + return f2l + case 0x8d: + return f2d + case 0x8e: + return d2i + case 0x8f: + return d2l + case 0x90: + return d2f + case 0x91: + return i2b + case 0x92: + return i2c + case 0x93: + return i2s + case 0x94: + return lcmp + case 0x95: + return fcmpl + case 0x96: + return fcmpg + case 0x97: + return dcmpl + case 0x98: + return dcmpg + case 0x99: + return &IFEQ{} + case 0x9a: + return &IFNE{} + case 0x9b: + return &IFLT{} + case 0x9c: + return &IFGE{} + case 0x9d: + return &IFGT{} + case 0x9e: + return &IFLE{} + case 0x9f: + return &IF_ICMPEQ{} + case 0xa0: + return &IF_ICMPNE{} + case 0xa1: + return &IF_ICMPLT{} + case 0xa2: + return &IF_ICMPGE{} + case 0xa3: + return &IF_ICMPGT{} + case 0xa4: + return &IF_ICMPLE{} + case 0xa5: + return &IF_ACMPEQ{} + case 0xa6: + return &IF_ACMPNE{} + case 0xa7: + return &GOTO{} + case 0xa8: + return &JSR{} + case 0xa9: + return &RET{} + case 0xaa: + return &TABLESWITCH{} + case 0xab: + return &LOOKUPSWITCH{} + case 0xac: + return ireturn + case 0xad: + return lreturn + case 0xae: + return freturn + case 0xaf: + return dreturn + case 0xb0: + return areturn + case 0xb1: + return _return + case 0xb2: + return &GET_STATIC{} + case 0xb3: + return &PUTSTATIC{} + case 0xb4: + return &GET_FIELD{} + case 0xb5: + return &PUTFIELD{} + case 0xb6: + return &INVOKEVIRTUAL{} + case 0xb7: + return &INVOKESPECIAL{} + case 0xb8: + return &INVOKESTATIC{} + case 0xb9: + return &INVOKEINTERFACE{} + case 0xba: + return &INVOKEDYNAMIC{} + case 0xbb: + return &NEW{} + case 0xbc: + return &NEWARRAY{} + case 0xbd: + return &ANEW_ARRAY{} + case 0xbe: + return arraylength + case 0xbf: + return athrow + case 0xc0: + return &CHECK_CAST{} + case 0xc1: + return &INSTANCEOF{} + case 0xc2: + return monitorenter + case 0xc3: + return monitorexit + case 0xc4: + return &WIDE{} + case 0xc5: + return &MULTIANEWARRAY{} + case 0xc6: + return &IFNULL{} + case 0xc7: + return &IFNONNULL{} + case 0xc8: + return &GOTO_W{} + case 0xc9: + return &JSR_W{} + case 0xca: + panic("reserved opcodes: breakpoint") + case 0xfe: + return invoke_native + case 0xff: + panic("reserved opcodes: impdep2") + default: + panic(fmt.Errorf("unsupported opcode: 0x%x", opcode)) + } +} diff --git a/core/fcmp.go b/core/fcmp.go new file mode 100644 index 0000000..f3f5f46 --- /dev/null +++ b/core/fcmp.go @@ -0,0 +1,5 @@ +package core + +type FCMPG struct{ NoOperandsInstruction } + +type FCMPL struct{ NoOperandsInstruction } diff --git a/core/fload.go b/core/fload.go new file mode 100644 index 0000000..cdc748d --- /dev/null +++ b/core/fload.go @@ -0,0 +1,11 @@ +package core + +type FLOAD struct{ Index8Instruction } + +type FLOAD_0 struct{ NoOperandsInstruction } + +type FLOAD_1 struct{ NoOperandsInstruction } + +type FLOAD_2 struct{ NoOperandsInstruction } + +type FLOAD_3 struct{ NoOperandsInstruction } diff --git a/core/fstore.go b/core/fstore.go new file mode 100644 index 0000000..0812b13 --- /dev/null +++ b/core/fstore.go @@ -0,0 +1,11 @@ +package core + +type FSTORE struct{ Index8Instruction } + +type FSTORE_0 struct{ NoOperandsInstruction } + +type FSTORE_1 struct{ NoOperandsInstruction } + +type FSTORE_2 struct{ NoOperandsInstruction } + +type FSTORE_3 struct{ NoOperandsInstruction } diff --git a/core/getfield.go b/core/getfield.go new file mode 100644 index 0000000..6d5e204 --- /dev/null +++ b/core/getfield.go @@ -0,0 +1,3 @@ +package core + +type GET_FIELD struct{ Index16Instruction } diff --git a/core/getstatic.go b/core/getstatic.go new file mode 100644 index 0000000..3ea16c0 --- /dev/null +++ b/core/getstatic.go @@ -0,0 +1,3 @@ +package core + +type GET_STATIC struct{ Index16Instruction } diff --git a/core/goto.go b/core/goto.go new file mode 100644 index 0000000..de53be3 --- /dev/null +++ b/core/goto.go @@ -0,0 +1,3 @@ +package core + +type GOTO struct{ BranchInstruction } diff --git a/core/goto_w.go b/core/goto_w.go new file mode 100644 index 0000000..195ab27 --- /dev/null +++ b/core/goto_w.go @@ -0,0 +1,15 @@ +package core + +type GOTO_W struct { + offset int +} + +func (self *GOTO_W) FetchOperands(reader *BytecodeReader) { + self.offset = int(reader.ReadInt32()) +} + +func (self *GOTO_W) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/i2x.go b/core/i2x.go new file mode 100644 index 0000000..c619b0b --- /dev/null +++ b/core/i2x.go @@ -0,0 +1,13 @@ +package core + +type I2B struct{ NoOperandsInstruction } + +type I2C struct{ NoOperandsInstruction } + +type I2S struct{ NoOperandsInstruction } + +type I2L struct{ NoOperandsInstruction } + +type I2F struct{ NoOperandsInstruction } + +type I2D struct{ NoOperandsInstruction } diff --git a/core/if_acmp.go b/core/if_acmp.go new file mode 100644 index 0000000..9657950 --- /dev/null +++ b/core/if_acmp.go @@ -0,0 +1,5 @@ +package core + +type IF_ACMPEQ struct{ BranchInstruction } + +type IF_ACMPNE struct{ BranchInstruction } diff --git a/core/if_icmp.go b/core/if_icmp.go new file mode 100644 index 0000000..311a81e --- /dev/null +++ b/core/if_icmp.go @@ -0,0 +1,13 @@ +package core + +type IF_ICMPEQ struct{ BranchInstruction } + +type IF_ICMPNE struct{ BranchInstruction } + +type IF_ICMPLT struct{ BranchInstruction } + +type IF_ICMPLE struct{ BranchInstruction } + +type IF_ICMPGT struct{ BranchInstruction } + +type IF_ICMPGE struct{ BranchInstruction } diff --git a/core/ifcond.go b/core/ifcond.go new file mode 100644 index 0000000..50a770d --- /dev/null +++ b/core/ifcond.go @@ -0,0 +1,13 @@ +package core + +type IFEQ struct{ BranchInstruction } + +type IFNE struct{ BranchInstruction } + +type IFLT struct{ BranchInstruction } + +type IFLE struct{ BranchInstruction } + +type IFGT struct{ BranchInstruction } + +type IFGE struct{ BranchInstruction } diff --git a/core/ifnull.go b/core/ifnull.go new file mode 100644 index 0000000..dd34afe --- /dev/null +++ b/core/ifnull.go @@ -0,0 +1,5 @@ +package core + +type IFNULL struct{ BranchInstruction } + +type IFNONNULL struct{ BranchInstruction } diff --git a/core/iinc.go b/core/iinc.go new file mode 100644 index 0000000..06794a5 --- /dev/null +++ b/core/iinc.go @@ -0,0 +1,20 @@ +package core + +import "strconv" + +type IINC struct { + Index uint + Const int32 +} + +func (self *IINC) FetchOperands(reader *BytecodeReader) { + self.Index = uint(reader.ReadUint8()) + self.Const = int32(reader.ReadInt8()) +} + +func (self *IINC) GetOperands() []string { + ret := make([]string, 2) + ret[0] = strconv.Itoa(int(self.Index)) + ret[1] = strconv.Itoa(int(self.Const)) + return ret +} diff --git a/core/iload.go b/core/iload.go new file mode 100644 index 0000000..5613042 --- /dev/null +++ b/core/iload.go @@ -0,0 +1,11 @@ +package core + +type ILOAD struct{ Index8Instruction } + +type ILOAD_0 struct{ NoOperandsInstruction } + +type ILOAD_1 struct{ NoOperandsInstruction } + +type ILOAD_2 struct{ NoOperandsInstruction } + +type ILOAD_3 struct{ NoOperandsInstruction } diff --git a/core/insn_set.go b/core/insn_set.go new file mode 100644 index 0000000..477f44b --- /dev/null +++ b/core/insn_set.go @@ -0,0 +1,13 @@ +package core + +type InstructionSet struct { + ClassName string + MethodName string + Desc string + InstArray []InstructionEntry +} + +type InstructionEntry struct { + Instrument string + Operands []string +} diff --git a/core/instanceof.go b/core/instanceof.go new file mode 100644 index 0000000..4398cd6 --- /dev/null +++ b/core/instanceof.go @@ -0,0 +1,3 @@ +package core + +type INSTANCEOF struct{ Index16Instruction } diff --git a/core/instruction.go b/core/instruction.go new file mode 100644 index 0000000..1f1dc10 --- /dev/null +++ b/core/instruction.go @@ -0,0 +1,62 @@ +package core + +import ( + "strconv" +) + +type Instruction interface { + FetchOperands(reader *BytecodeReader) + GetOperands() []string +} + +type NoOperandsInstruction struct { +} + +func (self *NoOperandsInstruction) FetchOperands(_ *BytecodeReader) { +} + +func (self *NoOperandsInstruction) GetOperands() []string { + return make([]string, 0) +} + +type BranchInstruction struct { + Offset int +} + +func (self *BranchInstruction) FetchOperands(reader *BytecodeReader) { + self.Offset = int(reader.ReadInt16()) +} + +func (self *BranchInstruction) GetOperands() []string { + ret := make([]string, 1) + ret[0] = strconv.Itoa(self.Offset) + return ret +} + +type Index8Instruction struct { + Index uint +} + +func (self *Index8Instruction) FetchOperands(reader *BytecodeReader) { + self.Index = uint(reader.ReadUint8()) +} + +func (self *Index8Instruction) GetOperands() []string { + ret := make([]string, 1) + ret[0] = strconv.Itoa(int(self.Index)) + return ret +} + +type Index16Instruction struct { + Index uint +} + +func (self *Index16Instruction) FetchOperands(reader *BytecodeReader) { + self.Index = uint(reader.ReadUint16()) +} + +func (self *Index16Instruction) GetOperands() []string { + ret := make([]string, 1) + ret[0] = strconv.Itoa(int(self.Index)) + return ret +} diff --git a/core/invokedynamic.go b/core/invokedynamic.go new file mode 100644 index 0000000..46d8d5e --- /dev/null +++ b/core/invokedynamic.go @@ -0,0 +1,17 @@ +package core + +type INVOKEDYNAMIC struct { +} + +func (self INVOKEDYNAMIC) FetchOperands(reader *BytecodeReader) { + reader.ReadInt8() + reader.ReadInt8() + reader.ReadInt8() + reader.ReadInt8() +} + +func (self *INVOKEDYNAMIC) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/invokeinterface.go b/core/invokeinterface.go new file mode 100644 index 0000000..d274349 --- /dev/null +++ b/core/invokeinterface.go @@ -0,0 +1,46 @@ +package core + +import ( + "fmt" + "reflect" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/global" +) + +type INVOKEINTERFACE struct { + index uint +} + +func (self *INVOKEINTERFACE) FetchOperands(reader *BytecodeReader) { + self.index = uint(reader.ReadUint16()) + reader.ReadUint8() + reader.ReadUint8() +} + +func (self *INVOKEINTERFACE) GetOperands() []string { + name := global.CP.GetConstantInfo(uint16(self.index)) + typeName := reflect.TypeOf(name).String() + + var ( + className string + methodName string + desc string + ) + + switch typeName { + case InterfaceMethodType: + className = name.(*classfile.ConstantInterfaceMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantInterfaceMethodRefInfo).NameAndDescriptor() + case MethodType: + className = name.(*classfile.ConstantMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantMethodRefInfo).NameAndDescriptor() + default: + panic("error") + } + + ret := make([]string, 1) + out := fmt.Sprintf("%s.%s %s", className, methodName, desc) + ret[0] = out + return ret +} diff --git a/core/invokenative.go b/core/invokenative.go new file mode 100644 index 0000000..1131ef3 --- /dev/null +++ b/core/invokenative.go @@ -0,0 +1,3 @@ +package core + +type INVOKENATIVE struct{ NoOperandsInstruction } diff --git a/core/invokespecial.go b/core/invokespecial.go new file mode 100644 index 0000000..a39f127 --- /dev/null +++ b/core/invokespecial.go @@ -0,0 +1,38 @@ +package core + +import ( + "fmt" + "reflect" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/global" +) + +type INVOKESPECIAL struct{ Index16Instruction } + +func (self *INVOKESPECIAL) GetOperands() []string { + name := global.CP.GetConstantInfo(uint16(self.Index)) + typeName := reflect.TypeOf(name).String() + + var ( + className string + methodName string + desc string + ) + + switch typeName { + case InterfaceMethodType: + className = name.(*classfile.ConstantInterfaceMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantInterfaceMethodRefInfo).NameAndDescriptor() + case MethodType: + className = name.(*classfile.ConstantMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantMethodRefInfo).NameAndDescriptor() + default: + panic("error") + } + + ret := make([]string, 1) + out := fmt.Sprintf("%s.%s %s", className, methodName, desc) + ret[0] = out + return ret +} diff --git a/core/invokestatic.go b/core/invokestatic.go new file mode 100644 index 0000000..eed3fe5 --- /dev/null +++ b/core/invokestatic.go @@ -0,0 +1,38 @@ +package core + +import ( + "fmt" + "reflect" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/global" +) + +type INVOKESTATIC struct{ Index16Instruction } + +func (self *INVOKESTATIC) GetOperands() []string { + name := global.CP.GetConstantInfo(uint16(self.Index)) + typeName := reflect.TypeOf(name).String() + + var ( + className string + methodName string + desc string + ) + + switch typeName { + case InterfaceMethodType: + className = name.(*classfile.ConstantInterfaceMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantInterfaceMethodRefInfo).NameAndDescriptor() + case MethodType: + className = name.(*classfile.ConstantMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantMethodRefInfo).NameAndDescriptor() + default: + panic("error") + } + + ret := make([]string, 1) + out := fmt.Sprintf("%s.%s %s", className, methodName, desc) + ret[0] = out + return ret +} diff --git a/core/invokevirtual.go b/core/invokevirtual.go new file mode 100644 index 0000000..0d2af04 --- /dev/null +++ b/core/invokevirtual.go @@ -0,0 +1,38 @@ +package core + +import ( + "fmt" + "reflect" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/global" +) + +type INVOKEVIRTUAL struct{ Index16Instruction } + +func (self *INVOKEVIRTUAL) GetOperands() []string { + name := global.CP.GetConstantInfo(uint16(self.Index)) + typeName := reflect.TypeOf(name).String() + + var ( + className string + methodName string + desc string + ) + + switch typeName { + case InterfaceMethodType: + className = name.(*classfile.ConstantInterfaceMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantInterfaceMethodRefInfo).NameAndDescriptor() + case MethodType: + className = name.(*classfile.ConstantMethodRefInfo).ClassName() + methodName, desc = name.(*classfile.ConstantMethodRefInfo).NameAndDescriptor() + default: + panic("error") + } + + ret := make([]string, 1) + out := fmt.Sprintf("%s.%s %s", className, methodName, desc) + ret[0] = out + return ret +} diff --git a/core/ipush.go b/core/ipush.go new file mode 100644 index 0000000..18fef67 --- /dev/null +++ b/core/ipush.go @@ -0,0 +1,31 @@ +package core + +import "strconv" + +type BIPUSH struct { + val int8 +} + +func (self *BIPUSH) FetchOperands(reader *BytecodeReader) { + self.val = reader.ReadInt8() +} + +func (self *BIPUSH) GetOperands() []string { + ret := make([]string, 1) + ret[0] = strconv.Itoa(int(self.val)) + return ret +} + +type SIPUSH struct { + val int16 +} + +func (self *SIPUSH) FetchOperands(reader *BytecodeReader) { + self.val = reader.ReadInt16() +} + +func (self *SIPUSH) GetOperands() []string { + ret := make([]string, 1) + ret[0] = strconv.Itoa(int(self.val)) + return ret +} diff --git a/core/istore.go b/core/istore.go new file mode 100644 index 0000000..78e0b56 --- /dev/null +++ b/core/istore.go @@ -0,0 +1,11 @@ +package core + +type ISTORE struct{ Index8Instruction } + +type ISTORE_0 struct{ NoOperandsInstruction } + +type ISTORE_1 struct{ NoOperandsInstruction } + +type ISTORE_2 struct{ NoOperandsInstruction } + +type ISTORE_3 struct{ NoOperandsInstruction } diff --git a/core/jsr.go b/core/jsr.go new file mode 100644 index 0000000..adf2920 --- /dev/null +++ b/core/jsr.go @@ -0,0 +1,19 @@ +package core + +type JSR struct{ Index16Instruction } + +type JSR_W struct { +} + +func (J JSR_W) FetchOperands(reader *BytecodeReader) { + reader.ReadUint8() + reader.ReadUint8() + reader.ReadUint8() + reader.ReadUint8() +} + +func (self *JSR_W) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/l2x.go b/core/l2x.go new file mode 100644 index 0000000..033f3cd --- /dev/null +++ b/core/l2x.go @@ -0,0 +1,7 @@ +package core + +type L2D struct{ NoOperandsInstruction } + +type L2F struct{ NoOperandsInstruction } + +type L2I struct{ NoOperandsInstruction } diff --git a/core/lcmp.go b/core/lcmp.go new file mode 100644 index 0000000..55ca9d7 --- /dev/null +++ b/core/lcmp.go @@ -0,0 +1,3 @@ +package core + +type LCMP struct{ NoOperandsInstruction } diff --git a/core/ldc.go b/core/ldc.go new file mode 100644 index 0000000..a2ab802 --- /dev/null +++ b/core/ldc.go @@ -0,0 +1,33 @@ +package core + +import ( + "reflect" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/global" +) + +type LDC struct{ Index8Instruction } + +func (self *LDC) GetOperands() []string { + name := global.CP.GetConstantInfo(uint16(self.Index)) + typeName := reflect.TypeOf(name).String() + + var constString string + + switch typeName { + case "*classfile.ConstantStringInfo": + constString = name.(*classfile.ConstantStringInfo).String() + default: + panic("error") + } + + ret := make([]string, 1) + out := constString + ret[0] = out + return ret +} + +type LDC_W struct{ Index16Instruction } + +type LDC2_W struct{ Index16Instruction } diff --git a/core/lload.go b/core/lload.go new file mode 100644 index 0000000..a0dafa8 --- /dev/null +++ b/core/lload.go @@ -0,0 +1,11 @@ +package core + +type LLOAD struct{ Index8Instruction } + +type LLOAD_0 struct{ NoOperandsInstruction } + +type LLOAD_1 struct{ NoOperandsInstruction } + +type LLOAD_2 struct{ NoOperandsInstruction } + +type LLOAD_3 struct{ NoOperandsInstruction } diff --git a/core/lookupswitch.go b/core/lookupswitch.go new file mode 100644 index 0000000..b570292 --- /dev/null +++ b/core/lookupswitch.go @@ -0,0 +1,20 @@ +package core + +type LOOKUPSWITCH struct { + defaultOffset int32 + npairs int32 + matchOffsets []int32 +} + +func (self *LOOKUPSWITCH) FetchOperands(reader *BytecodeReader) { + reader.SkipPadding() + self.defaultOffset = reader.ReadInt32() + self.npairs = reader.ReadInt32() + self.matchOffsets = reader.ReadInt32s(self.npairs * 2) +} + +func (self *LOOKUPSWITCH) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/lstore.go b/core/lstore.go new file mode 100644 index 0000000..90419e4 --- /dev/null +++ b/core/lstore.go @@ -0,0 +1,11 @@ +package core + +type LSTORE struct{ Index8Instruction } + +type LSTORE_0 struct{ NoOperandsInstruction } + +type LSTORE_1 struct{ NoOperandsInstruction } + +type LSTORE_2 struct{ NoOperandsInstruction } + +type LSTORE_3 struct{ NoOperandsInstruction } diff --git a/core/monitor.go b/core/monitor.go new file mode 100644 index 0000000..b76aeb7 --- /dev/null +++ b/core/monitor.go @@ -0,0 +1,5 @@ +package core + +type MONITORENTER struct{ NoOperandsInstruction } + +type MONITOREXIT struct{ NoOperandsInstruction } diff --git a/core/mul.go b/core/mul.go new file mode 100644 index 0000000..3882a99 --- /dev/null +++ b/core/mul.go @@ -0,0 +1,9 @@ +package core + +type DMUL struct{ NoOperandsInstruction } + +type FMUL struct{ NoOperandsInstruction } + +type IMUL struct{ NoOperandsInstruction } + +type LMUL struct{ NoOperandsInstruction } diff --git a/core/multianewarray.go b/core/multianewarray.go new file mode 100644 index 0000000..83f553c --- /dev/null +++ b/core/multianewarray.go @@ -0,0 +1,17 @@ +package core + +type MULTIANEWARRAY struct { + index uint16 + dimensions uint8 +} + +func (self *MULTIANEWARRAY) FetchOperands(reader *BytecodeReader) { + self.index = reader.ReadUint16() + self.dimensions = reader.ReadUint8() +} + +func (self *MULTIANEWARRAY) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/neg.go b/core/neg.go new file mode 100644 index 0000000..e6a5ce9 --- /dev/null +++ b/core/neg.go @@ -0,0 +1,9 @@ +package core + +type DNEG struct{ NoOperandsInstruction } + +type FNEG struct{ NoOperandsInstruction } + +type INEG struct{ NoOperandsInstruction } + +type LNEG struct{ NoOperandsInstruction } diff --git a/core/new.go b/core/new.go new file mode 100644 index 0000000..677565c --- /dev/null +++ b/core/new.go @@ -0,0 +1,3 @@ +package core + +type NEW struct{ Index16Instruction } diff --git a/core/newarray.go b/core/newarray.go new file mode 100644 index 0000000..0035db9 --- /dev/null +++ b/core/newarray.go @@ -0,0 +1,26 @@ +package core + +/* +T_BOOLEAN 4 +T_CHAR 5 +T_FLOAT 6 +T_DOUBLE 7 +T_BYTE 8 +T_SHORT 9 +T_INT 10 +T_LONG 11 +*/ + +type NEWARRAY struct { + arrayType uint8 +} + +func (self *NEWARRAY) FetchOperands(reader *BytecodeReader) { + self.arrayType = reader.ReadUint8() +} + +func (self *NEWARRAY) GetOperands() []string { + ret := make([]string, 1) + ret[0] = string(self.arrayType) + return ret +} diff --git a/core/nop.go b/core/nop.go new file mode 100644 index 0000000..473b2d4 --- /dev/null +++ b/core/nop.go @@ -0,0 +1,3 @@ +package core + +type NOP struct{ NoOperandsInstruction } diff --git a/core/or.go b/core/or.go new file mode 100644 index 0000000..40ff07a --- /dev/null +++ b/core/or.go @@ -0,0 +1,5 @@ +package core + +type IOR struct{ NoOperandsInstruction } + +type LOR struct{ NoOperandsInstruction } diff --git a/core/pop.go b/core/pop.go new file mode 100644 index 0000000..adac54b --- /dev/null +++ b/core/pop.go @@ -0,0 +1,5 @@ +package core + +type POP struct{ NoOperandsInstruction } + +type POP2 struct{ NoOperandsInstruction } diff --git a/core/putfield.go b/core/putfield.go new file mode 100644 index 0000000..1c5a204 --- /dev/null +++ b/core/putfield.go @@ -0,0 +1,3 @@ +package core + +type PUTFIELD struct{ Index16Instruction } diff --git a/core/putstatic.go b/core/putstatic.go new file mode 100644 index 0000000..65c69a7 --- /dev/null +++ b/core/putstatic.go @@ -0,0 +1,3 @@ +package core + +type PUTSTATIC struct{ Index16Instruction } diff --git a/core/rem.go b/core/rem.go new file mode 100644 index 0000000..f0840fc --- /dev/null +++ b/core/rem.go @@ -0,0 +1,9 @@ +package core + +type DREM struct{ NoOperandsInstruction } + +type FREM struct{ NoOperandsInstruction } + +type IREM struct{ NoOperandsInstruction } + +type LREM struct{ NoOperandsInstruction } diff --git a/core/ret.go b/core/ret.go new file mode 100644 index 0000000..939f6af --- /dev/null +++ b/core/ret.go @@ -0,0 +1,3 @@ +package core + +type RET struct{ Index8Instruction } diff --git a/core/return.go b/core/return.go new file mode 100644 index 0000000..7ce43f0 --- /dev/null +++ b/core/return.go @@ -0,0 +1,13 @@ +package core + +type RETURN struct{ NoOperandsInstruction } + +type ARETURN struct{ NoOperandsInstruction } + +type DRETURN struct{ NoOperandsInstruction } + +type FRETURN struct{ NoOperandsInstruction } + +type IRETURN struct{ NoOperandsInstruction } + +type LRETURN struct{ NoOperandsInstruction } diff --git a/core/sh.go b/core/sh.go new file mode 100644 index 0000000..6957a2c --- /dev/null +++ b/core/sh.go @@ -0,0 +1,13 @@ +package core + +type ISHL struct{ NoOperandsInstruction } + +type ISHR struct{ NoOperandsInstruction } + +type IUSHR struct{ NoOperandsInstruction } + +type LSHL struct{ NoOperandsInstruction } + +type LSHR struct{ NoOperandsInstruction } + +type LUSHR struct{ NoOperandsInstruction } diff --git a/core/sub.go b/core/sub.go new file mode 100644 index 0000000..6b887ae --- /dev/null +++ b/core/sub.go @@ -0,0 +1,9 @@ +package core + +type DSUB struct{ NoOperandsInstruction } + +type FSUB struct{ NoOperandsInstruction } + +type ISUB struct{ NoOperandsInstruction } + +type LSUB struct{ NoOperandsInstruction } diff --git a/core/swap.go b/core/swap.go new file mode 100644 index 0000000..bf88f92 --- /dev/null +++ b/core/swap.go @@ -0,0 +1,3 @@ +package core + +type SWAP struct{ NoOperandsInstruction } diff --git a/core/tableswitch.go b/core/tableswitch.go new file mode 100644 index 0000000..11b0f59 --- /dev/null +++ b/core/tableswitch.go @@ -0,0 +1,23 @@ +package core + +type TABLESWITCH struct { + defaultOffset int32 + low int32 + high int32 + jumpOffsets []int32 +} + +func (self *TABLESWITCH) FetchOperands(reader *BytecodeReader) { + reader.SkipPadding() + self.defaultOffset = reader.ReadInt32() + self.low = reader.ReadInt32() + self.high = reader.ReadInt32() + jumpOffsetsCount := self.high - self.low + 1 + self.jumpOffsets = reader.ReadInt32s(jumpOffsetsCount) +} + +func (self *TABLESWITCH) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/thread.go b/core/thread.go new file mode 100644 index 0000000..fc15761 --- /dev/null +++ b/core/thread.go @@ -0,0 +1,16 @@ +package core + +type Thread struct { + pc int +} + +func NewThread() *Thread { + return &Thread{pc: 0} +} + +func (self *Thread) PC() int { + return self.pc +} +func (self *Thread) SetPC(pc int) { + self.pc = pc +} diff --git a/core/wide.go b/core/wide.go new file mode 100644 index 0000000..d329ab7 --- /dev/null +++ b/core/wide.go @@ -0,0 +1,64 @@ +package core + +type WIDE struct { + modifiedInstruction Instruction +} + +func (self *WIDE) FetchOperands(reader *BytecodeReader) { + opcode := reader.ReadUint8() + switch opcode { + case 0x15: + inst := &ILOAD{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x16: + inst := &LLOAD{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x17: + inst := &FLOAD{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x18: + inst := &DLOAD{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x19: + inst := &ALOAD{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x36: + inst := &ISTORE{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x37: + inst := &LSTORE{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x38: + inst := &FSTORE{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x39: + inst := &DSTORE{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x3a: + inst := &ASTORE{} + inst.Index = uint(reader.ReadUint16()) + self.modifiedInstruction = inst + case 0x84: + inst := &IINC{} + inst.Index = uint(reader.ReadUint16()) + inst.Const = int32(reader.ReadInt16()) + self.modifiedInstruction = inst + case 0xa9: + panic("unsupported opcode: 0xa9") + } +} + +func (self *WIDE) GetOperands() []string { + ret := make([]string, 1) + ret[0] = NotSupport + return ret +} diff --git a/core/xaload.go b/core/xaload.go new file mode 100644 index 0000000..292b671 --- /dev/null +++ b/core/xaload.go @@ -0,0 +1,17 @@ +package core + +type AALOAD struct{ NoOperandsInstruction } + +type BALOAD struct{ NoOperandsInstruction } + +type CALOAD struct{ NoOperandsInstruction } + +type DALOAD struct{ NoOperandsInstruction } + +type FALOAD struct{ NoOperandsInstruction } + +type IALOAD struct{ NoOperandsInstruction } + +type LALOAD struct{ NoOperandsInstruction } + +type SALOAD struct{ NoOperandsInstruction } diff --git a/core/xastore.go b/core/xastore.go new file mode 100644 index 0000000..837d0cf --- /dev/null +++ b/core/xastore.go @@ -0,0 +1,17 @@ +package core + +type AASTORE struct{ NoOperandsInstruction } + +type BASTORE struct{ NoOperandsInstruction } + +type CASTORE struct{ NoOperandsInstruction } + +type DASTORE struct{ NoOperandsInstruction } + +type FASTORE struct{ NoOperandsInstruction } + +type IASTORE struct{ NoOperandsInstruction } + +type LASTORE struct{ NoOperandsInstruction } + +type SASTORE struct{ NoOperandsInstruction } diff --git a/core/xor.go b/core/xor.go new file mode 100644 index 0000000..d84a098 --- /dev/null +++ b/core/xor.go @@ -0,0 +1,5 @@ +package core + +type IXOR struct{ NoOperandsInstruction } + +type LXOR struct{ NoOperandsInstruction } diff --git a/global/global.go b/global/global.go new file mode 100644 index 0000000..0270eae --- /dev/null +++ b/global/global.go @@ -0,0 +1,5 @@ +package global + +import "github.com/phith0n/zkar/classfile" + +var CP classfile.ConstantPool diff --git a/main.go b/main.go index ee64160..569b1ca 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,19 @@ package main import ( "encoding/base64" + "encoding/hex" "fmt" - "github.com/phith0n/zkar/serz" - "github.com/urfave/cli/v2" "io/ioutil" "log" "os" + "strings" + + "github.com/urfave/cli/v2" + + "github.com/phith0n/zkar/classfile" + "github.com/phith0n/zkar/core" + "github.com/phith0n/zkar/global" + "github.com/phith0n/zkar/serz" ) func main() { @@ -39,6 +46,148 @@ func main() { return fmt.Errorf("payloads generation feature is working in progress") }, }, + { + Name: "export", + Usage: "export java class file", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "file", + Aliases: []string{"f"}, + Usage: "serz data filepath", + Required: false, + }, + &cli.StringFlag{ + Name: "base64", + Aliases: []string{"B"}, + Usage: "serz data as Base64 format string", + Required: false, + }, + &cli.BoolFlag{ + Name: "only-class", + Usage: "only export class file", + Required: false, + }, + }, + Action: func(context *cli.Context) error { + var filename = context.String("file") + var b64data = context.String("base64") + var data []byte + var err error + if (filename == "" && b64data == "") || (filename != "" && b64data != "") { + return fmt.Errorf("one \"file\" or \"base64\" flag must be specified, and not both") + } + + if filename != "" { + data, err = ioutil.ReadFile(filename) + } else { + data, err = base64.StdEncoding.DecodeString(b64data) + } + + if err != nil { + return err + } + + var obj *serz.Serialization + obj, err = serz.FromBytes(data) + + var bytesCodes [][]byte + err = obj.Walk(func(object serz.Object) error { + v, ok := object.(*serz.TCArray) + if ok { + if len(v.ArrayData) > 0 { + if v.ArrayData[0].TypeCode == "B" { + var temp []byte + for _, code := range v.ArrayData { + temp = append(temp, code.Byte) + } + if len(temp) > 4 && + // CHECK CAFE + hex.EncodeToString(temp[:8]) != "CAFEBABE" { + bytesCodes = append(bytesCodes, temp) + } + } + } + } + return nil + }) + if err != nil { + return err + } + + if len(bytesCodes) > 0 { + + for _, v := range bytesCodes { + classData, err := classfile.Parse(v) + if err != nil { + continue + } + global.CP = classData.ConstantPool() + name := classData.ClassName() + classTemp := strings.Split(name, "/") + class := classTemp[len(classTemp)-1] + ".class" + if context.Bool("only-class") { + err = os.WriteFile(class, v, 0644) + fmt.Println("[*] write class: " + class) + if err != nil { + fmt.Println("[!] write file error: " + err.Error()) + } + continue + } + fmt.Println("[*] find java class: " + name) + for _, m := range classData.Methods() { + methodName := m.Name() + if methodName == "" { + methodName = name + " {}" + } + if methodName == "" { + methodName = "static {}" + } + fmt.Println("[*] method: " + methodName) + bytecode := m.CodeAttribute().Code() + // virtual thread + thread := core.Thread{} + reader := &core.BytecodeReader{} + // save all instructions to struct + instSet := core.InstructionSet{} + instSet.ClassName = name + instSet.MethodName = methodName + instSet.Desc = m.Descriptor() + for { + // read finish + if thread.PC() >= len(bytecode) { + break + } + // offset + reader.Reset(bytecode, thread.PC()) + // read instruction + opcode := reader.ReadUint8() + inst := core.NewInstruction(opcode) + // read operands of the instruction + inst.FetchOperands(reader) + ops := inst.GetOperands() + instEntry := core.InstructionEntry{ + Instrument: getInstructionName(inst), + Operands: ops, + } + var out string + out += instEntry.Instrument + out += "\t" + for _, op := range instEntry.Operands { + out += op + out += " " + } + fmt.Println("\033[32m" + out + "\033[0m") + instSet.InstArray = append(instSet.InstArray, instEntry) + // offset++ + thread.SetPC(reader.PC()) + } + } + } + } + + return nil + }, + }, { Name: "dump", Usage: "parse the Java serz streams and dump the struct", @@ -116,3 +265,9 @@ func main() { fmt.Fprintf(os.Stderr, "[error] %v\n", err.Error()) } } + +func getInstructionName(instruction core.Instruction) string { + // type name -> instruction name + i := fmt.Sprintf("%T", instruction) + return strings.Split(i, ".")[1] +}