Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use correct byte order #86

Merged
merged 5 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading