Skip to content

Commit

Permalink
Merge pull request #86 from Zxilly/order
Browse files Browse the repository at this point in the history
use correct byte order
  • Loading branch information
TcM1911 authored Feb 12, 2024
2 parents d54afa1 + f39cc7d commit 8f57369
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 111 deletions.
8 changes: 7 additions & 1 deletion file.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,13 @@ func (f *GoFile) GetTypes() ([]*GoType, error) {
if err != nil {
return nil, err
}
t, err := getTypes(f.FileInfo, f.fh)
err = f.initModuleData()
if err != nil {
return nil, err
}
md := f.moduledata

t, err := getTypes(f.FileInfo, f.fh, md)
if err != nil {
return nil, err
}
Expand Down
41 changes: 22 additions & 19 deletions modinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ func TestBuildInfo(t *testing.T) {
t.Run("extracting build info for "+test, func(t *testing.T) {
r := require.New(t)

// TODO: Remove this check when arm support has been added.
if strings.Contains(test, "arm64") {
t.Skip("ARM currently not supported")
}

fp, err := getTestResourcePath("gold/" + test)
r.NoError(err, "Failed to get path to resource")

Expand All @@ -62,23 +57,31 @@ func TestBuildInfo(t *testing.T) {
// Version with build info.
r.NotNil(f.BuildInfo)
r.NotNil(f.BuildInfo.Compiler)
if GoVersionCompare(ver.Name, "go1.16") >= 0 {
// The mod info is not always available in Go versions earlier than 1.16.

if GoVersionCompare(ver.Name, "go1.19beta1") >= 0 {
r.Equal("github.com/goretk/gore/gold", f.BuildInfo.ModInfo.Path)
} else {
r.Equal("command-line-arguments", f.BuildInfo.ModInfo.Path)
}
if GoVersionCompare(ver.Name, "go1.16") < 0 {
t.Skip("No mod info available for Go versions earlier than 1.16")
}

switch {
case GoVersionCompare(ver.Name, "go1.19beta1") >= 0:
r.Equal("github.com/goretk/gore/gold", f.BuildInfo.ModInfo.Path)
case GoVersionCompare(ver.Name, "go1.16.0") >= 0 && strings.Contains(test, "darwin-arm64"):
r.Equal("github.com/goretk/gore/gold", f.BuildInfo.ModInfo.Path)
default:
r.Equal("command-line-arguments", f.BuildInfo.ModInfo.Path)
}

if GoVersionCompare(ver.Name, "go1.19beta1") >= 0 {
r.Equal("(devel)", f.BuildInfo.ModInfo.Main.Version)
} else if GoVersionCompare(ver.Name, "go1.18beta1") >= 0 {
r.Equal("", f.BuildInfo.ModInfo.Main.Version)
} else {
r.Equal("(devel)", f.BuildInfo.ModInfo.Main.Version)
}
switch {
case GoVersionCompare(ver.Name, "go1.19beta1") >= 0:
r.Equal("(devel)", f.BuildInfo.ModInfo.Main.Version)
case GoVersionCompare(ver.Name, "go1.18beta1") >= 0 && strings.Contains(test, "darwin-arm64"):
r.Equal("(devel)", f.BuildInfo.ModInfo.Main.Version)
case GoVersionCompare(ver.Name, "go1.18beta1") >= 0:
r.Equal("", f.BuildInfo.ModInfo.Main.Version)
default:
r.Equal("(devel)", f.BuildInfo.ModInfo.Main.Version)
}

}
})
}
Expand Down
32 changes: 20 additions & 12 deletions moduledata.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ type Moduledata interface {
// ITabLinks returns the itablinks section.
ITabLinks() ModuleDataSection
// TypeLink returns the typelink section.
TypeLink() ([]int32, error)
TypeLink() ModuleDataSection
// TypeLinkData returns the typelink section data.
TypeLinkData() ([]int32, error)
// GoFuncValue returns the value of the 'go:func.*' symbol.
GoFuncValue() uint64
}
Expand Down Expand Up @@ -156,7 +158,16 @@ func (m moduledata) ITabLinks() ModuleDataSection {
}

// TypeLink returns the typelink section.
func (m moduledata) TypeLink() ([]int32, error) {
func (m moduledata) TypeLink() ModuleDataSection {
return ModuleDataSection{
Address: m.TypelinkAddr,
Length: m.TypelinkLen,
fh: m.fh,
}
}

// TypeLinkData returns the typelink section.
func (m moduledata) TypeLinkData() ([]int32, error) {
base, data, err := m.fh.getSectionDataFromOffset(m.TypelinkAddr)
if err != nil {
return nil, fmt.Errorf("failed to get the typelink data section: %w", err)
Expand Down Expand Up @@ -211,16 +222,13 @@ func (m ModuleDataSection) Data() ([]byte, error) {
return buf, nil
}

func buildPclnTabAddrBinary(addr uint64) ([]byte, error) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, &addr)
if err != nil {
return nil, err
}
return buf.Bytes()[:intSize32], nil
func buildPclnTabAddrBinary(order binary.ByteOrder, addr uint64) ([]byte, error) {
buf := make([]byte, intSize32)
order.PutUint32(buf, uint32(addr))
return buf, nil
}

func pickVersionedModuleData(info FileInfo) (modulable, error) {
func pickVersionedModuleData(info *FileInfo) (modulable, error) {
var bits int
if info.WordSize == intSize32 {
bits = 32
Expand All @@ -244,7 +252,7 @@ func pickVersionedModuleData(info FileInfo) (modulable, error) {
}

func extractModuledata(fileInfo *FileInfo, f fileHandler) (moduledata, error) {
vmd, err := pickVersionedModuleData(*fileInfo)
vmd, err := pickVersionedModuleData(fileInfo)
if err != nil {
return moduledata{}, err
}
Expand All @@ -260,7 +268,7 @@ func extractModuledata(fileInfo *FileInfo, f fileHandler) (moduledata, error) {
return moduledata{}, err
}

magic, err := buildPclnTabAddrBinary(tabAddr)
magic, err := buildPclnTabAddrBinary(fileInfo.ByteOrder, tabAddr)
if err != nil {
return moduledata{}, err
}
Expand Down
17 changes: 4 additions & 13 deletions type.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,17 @@ const (
ChanBoth = ChanRecv | ChanSend
)

func getTypes(fileInfo *FileInfo, f fileHandler) (map[uint64]*GoType, error) {
func getTypes(fileInfo *FileInfo, f fileHandler, md moduledata) (map[uint64]*GoType, error) {
if GoVersionCompare(fileInfo.goversion.Name, "go1.7beta1") < 0 {
return getLegacyTypes(fileInfo, f)
}

md, err := extractModuledata(fileInfo, f)
if err != nil {
return nil, fmt.Errorf("failed to parse the module data: %w", err)
return getLegacyTypes(fileInfo, f, md)
}

types, err := md.Types().Data()
if err != nil {
return nil, fmt.Errorf("failed to get types data section: %w", err)
}

typeLink, err := md.TypeLink()
typeLink, err := md.TypeLinkData()
if err != nil {
return nil, fmt.Errorf("failed to get type link data: %w", err)
}
Expand All @@ -86,11 +81,7 @@ func getTypes(fileInfo *FileInfo, f fileHandler) (map[uint64]*GoType, error) {
return parser.parsedTypes(), nil
}

func getLegacyTypes(fileInfo *FileInfo, f fileHandler) (map[uint64]*GoType, error) {
md, err := extractModuledata(fileInfo, f)
if err != nil {
return nil, err
}
func getLegacyTypes(fileInfo *FileInfo, f fileHandler, md moduledata) (map[uint64]*GoType, error) {
typelinkAddr, typelinkData, err := f.getSectionDataFromOffset(md.TypelinkAddr)
if err != nil {
return nil, fmt.Errorf("no typelink section found: %w", err)
Expand Down
126 changes: 60 additions & 66 deletions type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"os"
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -36,126 +35,121 @@ func TestGetTypes(t *testing.T) {
}
for _, test := range goldFiles {
t.Run("get_types_"+test, func(t *testing.T) {
require := require.New(t)
assert := assert.New(t)

// TODO: Remove this check when arm support has been added.
if strings.Contains(test, "arm64") {
t.Skip("ARM currently not supported")
}
r := require.New(t)
a := assert.New(t)

fp, err := getTestResourcePath("gold/" + test)
require.NoError(err, "Failed to get path to resource")
r.NoError(err, "Failed to get path to resource")
if _, err = os.Stat(fp); os.IsNotExist(err) {
// Skip this file because it doesn't exist
// t.Skip will cause the parent test to be skipped.
fmt.Printf("[SKIPPING TEST] golden fille %s does not exist\n", test)
return
}
f, err := Open(fp)
require.NoError(err, "Failed to get path to the file")
r.NoError(err, "Failed to get path to the file")
defer f.Close()

typs, err := f.GetTypes()
require.NoError(err, "Should parse with no error")
r.NoError(err, "Should parse with no error")

var simpleStructTested bool
var complexStructTested bool
var stringerInterfaceTested bool
for _, typ := range typs {
if typ.Name == "fmt.Stringer" && typ.PackagePath == "fmt" &&
GoVersionCompare(f.FileInfo.goversion.Name, "go1.7beta1") >= 0 {
assert.Equal(reflect.Interface, typ.Kind, "Stringer should be an interface")
assert.Len(typ.Methods, 1, "Stringer should have 1 function defined")
assert.Equal("String", typ.Methods[0].Name, "Stringer's function should have the name of String")
a.Equal(reflect.Interface, typ.Kind, "Stringer should be an interface")
a.Len(typ.Methods, 1, "Stringer should have 1 function defined")
a.Equal("String", typ.Methods[0].Name, "Stringer's function should have the name of String")

stringerInterfaceTested = true
}
if typ.Name == "main.simpleStruct" && typ.PackagePath == "main" {
assert.Equal(reflect.Struct, typ.Kind, "simpleStruct parsed as wrong type")
assert.Len(typ.Fields, 2, "simpleStruct should have 2 fields")
a.Equal(reflect.Struct, typ.Kind, "simpleStruct parsed as wrong type")
a.Len(typ.Fields, 2, "simpleStruct should have 2 fields")

// Checking fields first should be a string and second an int
assert.Equal(reflect.String, typ.Fields[0].Kind, "First field is the wrong kind.")
assert.Equal("name", typ.Fields[0].FieldName, "First field has the wrong name.")
a.Equal(reflect.String, typ.Fields[0].Kind, "First field is the wrong kind.")
a.Equal("name", typ.Fields[0].FieldName, "First field has the wrong name.")

assert.Equal(reflect.Int, typ.Fields[1].Kind, "Second field is the wrong kind.")
assert.Equal("age", typ.Fields[1].FieldName, "Second field has the wrong name.")
a.Equal(reflect.Int, typ.Fields[1].Kind, "Second field is the wrong kind.")
a.Equal("age", typ.Fields[1].FieldName, "Second field has the wrong name.")

simpleStructTested = true
}

if typ.Name == "main.myComplexStruct" && typ.PackagePath == "main" &&
GoVersionCompare(f.FileInfo.goversion.Name, "go1.7beta1") >= 0 {
assert.Equal(reflect.Struct, typ.Kind, "myComplexStruct parsed as wrong type")
assert.Len(typ.Fields, 8, "myComplexStruct should have 7 fields")
a.Equal(reflect.Struct, typ.Kind, "myComplexStruct parsed as wrong type")
a.Len(typ.Fields, 8, "myComplexStruct should have 7 fields")

// Checking fields first should be a string and second an int
assert.Equal(reflect.String, typ.Fields[0].Kind, "First field is the wrong kind.")
assert.Equal("MyString", typ.Fields[0].FieldName, "First field has the wrong name.")
assert.Equal(`json:"String"`, typ.Fields[0].FieldTag, "Field tag incorrectly parsed")
a.Equal(reflect.String, typ.Fields[0].Kind, "First field is the wrong kind.")
a.Equal("MyString", typ.Fields[0].FieldName, "First field has the wrong name.")
a.Equal(`json:"String"`, typ.Fields[0].FieldTag, "Field tag incorrectly parsed")

assert.Equal(reflect.Ptr, typ.Fields[1].Kind, "Second field is the wrong kind.")
assert.Equal("person", typ.Fields[1].FieldName, "Second field has the wrong name.")
assert.Equal(reflect.Struct, typ.Fields[1].Element.Kind, "Second field resolves to the wrong kind.")
a.Equal(reflect.Ptr, typ.Fields[1].Kind, "Second field is the wrong kind.")
a.Equal("person", typ.Fields[1].FieldName, "Second field has the wrong name.")
a.Equal(reflect.Struct, typ.Fields[1].Element.Kind, "Second field resolves to the wrong kind.")

assert.Len(typ.Fields[1].Element.Fields, 2, "simpleStruct should have 2 fields")
assert.Equal(reflect.String, typ.Fields[1].Element.Fields[0].Kind, "First resolved field is the wrong kind.")
assert.Equal("name", typ.Fields[1].Element.Fields[0].FieldName, "First resolved field has the wrong name.")
a.Len(typ.Fields[1].Element.Fields, 2, "simpleStruct should have 2 fields")
a.Equal(reflect.String, typ.Fields[1].Element.Fields[0].Kind, "First resolved field is the wrong kind.")
a.Equal("name", typ.Fields[1].Element.Fields[0].FieldName, "First resolved field has the wrong name.")

assert.Equal(reflect.Int, typ.Fields[1].Element.Fields[1].Kind, "Second resolved field is the wrong kind.")
assert.Equal("age", typ.Fields[1].Element.Fields[1].FieldName, "Second resolved field has the wrong name.")
a.Equal(reflect.Int, typ.Fields[1].Element.Fields[1].Kind, "Second resolved field is the wrong kind.")
a.Equal("age", typ.Fields[1].Element.Fields[1].FieldName, "Second resolved field has the wrong name.")

// Methods on simpleStruct
assert.Len(typ.Fields[1].Methods, 1, "simpleStruct should have 1 method")
assert.Equal("String", typ.Fields[1].Methods[0].Name, "Wrong method name")
a.Len(typ.Fields[1].Methods, 1, "simpleStruct should have 1 method")
a.Equal("String", typ.Fields[1].Methods[0].Name, "Wrong method name")

// Checking other types
assert.Equal(reflect.Array, typ.Fields[2].Kind, "Third field is the wrong kind.")
assert.Equal("myArray", typ.Fields[2].FieldName, "Third field has the wrong name.")
assert.Equal(2, typ.Fields[2].Length, "Array length is wrong")
assert.Equal(reflect.Int, typ.Fields[2].Element.Kind, "Array element is wrong")

assert.Equal(reflect.Slice, typ.Fields[3].Kind, "4th field is the wrong kind.")
assert.Equal("mySlice", typ.Fields[3].FieldName, "4th field has the wrong name.")
assert.Equal(reflect.Uint, typ.Fields[3].Element.Kind, "Slice element is wrong")

assert.Equal(reflect.Chan, typ.Fields[4].Kind, "5th field is the wrong kind.")
assert.Equal("myChan", typ.Fields[4].FieldName, "5th field has the wrong name.")
assert.Equal(reflect.Struct, typ.Fields[4].Element.Kind, "Chan element is wrong")
assert.Equal(ChanBoth, typ.Fields[4].ChanDir, "Chan direction is wrong")

assert.Equal(reflect.Map, typ.Fields[5].Kind, "6th field is the wrong kind.")
assert.Equal("myMap", typ.Fields[5].FieldName, "6th field has the wrong name.")
assert.Equal(reflect.String, typ.Fields[5].Key.Kind, "Map key is wrong")
assert.Equal(reflect.Int, typ.Fields[5].Element.Kind, "Map element is wrong")

assert.Equal(reflect.Func, typ.Fields[6].Kind, "7th field is the wrong kind.")
assert.Equal("myFunc", typ.Fields[6].FieldName, "7th field has the wrong name.")
assert.Equal(reflect.String, typ.Fields[6].FuncArgs[0].Kind, "Function argument kind is wrong.")
assert.Equal(reflect.Int, typ.Fields[6].FuncArgs[1].Kind, "Function argument kind is wrong.")
assert.Equal(reflect.Uint, typ.Fields[6].FuncReturnVals[0].Kind, "Function return kind is wrong.")
a.Equal(reflect.Array, typ.Fields[2].Kind, "Third field is the wrong kind.")
a.Equal("myArray", typ.Fields[2].FieldName, "Third field has the wrong name.")
a.Equal(2, typ.Fields[2].Length, "Array length is wrong")
a.Equal(reflect.Int, typ.Fields[2].Element.Kind, "Array element is wrong")

a.Equal(reflect.Slice, typ.Fields[3].Kind, "4th field is the wrong kind.")
a.Equal("mySlice", typ.Fields[3].FieldName, "4th field has the wrong name.")
a.Equal(reflect.Uint, typ.Fields[3].Element.Kind, "Slice element is wrong")

a.Equal(reflect.Chan, typ.Fields[4].Kind, "5th field is the wrong kind.")
a.Equal("myChan", typ.Fields[4].FieldName, "5th field has the wrong name.")
a.Equal(reflect.Struct, typ.Fields[4].Element.Kind, "Chan element is wrong")
a.Equal(ChanBoth, typ.Fields[4].ChanDir, "Chan direction is wrong")

a.Equal(reflect.Map, typ.Fields[5].Kind, "6th field is the wrong kind.")
a.Equal("myMap", typ.Fields[5].FieldName, "6th field has the wrong name.")
a.Equal(reflect.String, typ.Fields[5].Key.Kind, "Map key is wrong")
a.Equal(reflect.Int, typ.Fields[5].Element.Kind, "Map element is wrong")

a.Equal(reflect.Func, typ.Fields[6].Kind, "7th field is the wrong kind.")
a.Equal("myFunc", typ.Fields[6].FieldName, "7th field has the wrong name.")
a.Equal(reflect.String, typ.Fields[6].FuncArgs[0].Kind, "Function argument kind is wrong.")
a.Equal(reflect.Int, typ.Fields[6].FuncArgs[1].Kind, "Function argument kind is wrong.")
a.Equal(reflect.Uint, typ.Fields[6].FuncReturnVals[0].Kind, "Function return kind is wrong.")

// Embedded struct
assert.True(typ.Fields[7].FieldAnon, "Last field should be an anonymous struct")
assert.Equal(reflect.Struct, typ.Fields[7].Kind, "Last field should be an anonymous struct")
assert.Equal("val", typ.Fields[7].Fields[0].FieldName, "Last field's field should be called val")
a.True(typ.Fields[7].FieldAnon, "Last field should be an anonymous struct")
a.Equal(reflect.Struct, typ.Fields[7].Kind, "Last field should be an anonymous struct")
a.Equal("val", typ.Fields[7].Fields[0].FieldName, "Last field's field should be called val")

complexStructTested = true
}

if typ.Name == "cpu.option" && typ.PackagePath == "" &&
GoVersionCompare(f.FileInfo.goversion.Name, "go1.7beta1") >= 0 {
for _, field := range typ.Fields {
assert.Equal("", field.FieldTag, "Field Tag should be empty")
a.Equal("", field.FieldTag, "Field Tag should be empty")
}
}
}
if GoVersionCompare(f.FileInfo.goversion.Name, "go1.7beta1") >= 0 {
assert.True(complexStructTested, "myComplexStruct was not found")
assert.True(stringerInterfaceTested, "fmt.Stringer was not found")
a.True(complexStructTested, "myComplexStruct was not found")
a.True(stringerInterfaceTested, "fmt.Stringer was not found")
}
assert.True(simpleStructTested, "simpleStruct was not found")
a.True(simpleStructTested, "simpleStruct was not found")
})
}
}
Expand Down

0 comments on commit 8f57369

Please sign in to comment.