Skip to content

Commit

Permalink
Merge pull request #77 from Zxilly/develop
Browse files Browse the repository at this point in the history
refactor: use code generate for moduledata
  • Loading branch information
TcM1911 authored Feb 9, 2024
2 parents b4737e6 + e2fa922 commit 7b68ef2
Show file tree
Hide file tree
Showing 26 changed files with 3,739 additions and 1,686 deletions.
14 changes: 9 additions & 5 deletions elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ type elfFile struct {
osFile *os.File
}

func (e *elfFile) GetParsedFile() any {
func (e *elfFile) getParsedFile() any {
return e.file
}

func (e *elfFile) GetFile() *os.File {
func (e *elfFile) getFile() *os.File {
return e.osFile
}

Expand Down Expand Up @@ -88,12 +88,16 @@ func (e *elfFile) getRData() ([]byte, error) {
return section.Data()
}

func (e *elfFile) getCodeSection() ([]byte, error) {
func (e *elfFile) getCodeSection() (uint64, []byte, error) {
section := e.file.Section(".text")
if section == nil {
return nil, ErrSectionDoesNotExist
return 0, nil, ErrSectionDoesNotExist
}
return section.Data()
data, err := section.Data()
if err != nil {
return 0, nil, fmt.Errorf("error when getting the code section: %w", err)
}
return section.Addr, data, nil
}

func (e *elfFile) getPCLNTABData() (uint64, []byte, error) {
Expand Down
148 changes: 101 additions & 47 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func Open(filePath string) (*GoFile, error) {

buf := make([]byte, maxMagicBufLen)
n, err := f.Read(buf)
f.Close()
_ = f.Close()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -94,8 +94,9 @@ func Open(filePath string) (*GoFile, error) {

// Try to extract build information.
if bi, err := gofile.extractBuildInfo(); err == nil {
// This error is a minor failure, it just means we don't have
// this information. So if fails we just ignores it.
// This error is a minor failure; it just means we don't have
// this information.
// So if fails, we just ignore it.
gofile.BuildInfo = bi
if bi.Compiler != nil {
gofile.FileInfo.goversion = bi.Compiler
Expand All @@ -107,40 +108,72 @@ func Open(filePath string) (*GoFile, error) {

// GoFile is a structure representing a go binary file.
type GoFile struct {
// BuildInfo holds the data from the buildinf structure. This can be nil
// because it's not always available.
// BuildInfo holds the data from the buildinfo structure.
// This can be a nil because it's not always available.
BuildInfo *BuildInfo
// FileInfo holds information about the file.
FileInfo *FileInfo
// BuildID is the Go build ID hash extracted from the binary.
BuildID string
fh fileHandler
stdPkgs []*Package
generated []*Package
pkgs []*Package
vendors []*Package
unknown []*Package
pclntab *gosym.Table
initPackages sync.Once
BuildID string

fh fileHandler

stdPkgs []*Package
generated []*Package
pkgs []*Package
vendors []*Package
unknown []*Package

pclntab *gosym.Table

initPackagesOnce sync.Once
initPackagesError error

moduledata moduledata

versionError error

initModuleDataOnce sync.Once
initModuleDataError error
}

func (f *GoFile) init() error {
var returnVal error
f.initPackages.Do(func() {
func (f *GoFile) initModuleData() error {
f.initModuleDataOnce.Do(func() {
err := f.ensureCompilerVersion()
if err != nil {
f.initModuleDataError = err
return
}
f.moduledata, f.initModuleDataError = extractModuledata(f.FileInfo, f.fh)
})
return f.initModuleDataError
}

// Moduledata extracts the file's moduledata.
func (f *GoFile) Moduledata() (Moduledata, error) {
err := f.initModuleData()
if err != nil {
return moduledata{}, err
}
return f.moduledata, nil
}

func (f *GoFile) initPackages() error {
f.initPackagesOnce.Do(func() {
tab, err := f.PCLNTab()
if err != nil {
returnVal = err
f.initPackagesError = err
return
}
f.pclntab = tab
returnVal = f.enumPackages()
f.initPackagesError = f.enumPackages()
})
return returnVal
return f.initPackagesError
}

// GetFile returns the raw file opened by the library.
func (f *GoFile) GetFile() *os.File {
return f.fh.GetFile()
return f.fh.getFile()
}

// GetParsedFile returns the parsed file, should be cast based on the file type.
Expand All @@ -151,13 +184,38 @@ func (f *GoFile) GetFile() *os.File {
//
// all from the debug package.
func (f *GoFile) GetParsedFile() any {
return f.fh.GetParsedFile()
return f.fh.getParsedFile()
}

// GetCompilerVersion returns the Go compiler version of the compiler
// that was used to compile the binary.
func (f *GoFile) GetCompilerVersion() (*GoVersion, error) {
return findGoCompilerVersion(f)
err := f.ensureCompilerVersion()
if err != nil {
return nil, err
}
return f.FileInfo.goversion, nil
}

func (f *GoFile) ensureCompilerVersion() error {
if f.FileInfo.goversion == nil {
f.tryExtractCompilerVersion()
}
return f.versionError
}

// tryExtractCompilerVersion tries to extract the compiler version from the binary.
// should only be called if FileInfo.goversion is nil.
func (f *GoFile) tryExtractCompilerVersion() {
if f.FileInfo.goversion != nil {
return
}
v, err := findGoCompilerVersion(f)
if err != nil {
f.versionError = err
} else {
f.FileInfo.goversion = v
}
}

// SourceInfo returns the source code filename, starting line number
Expand All @@ -168,10 +226,9 @@ func (f *GoFile) SourceInfo(fn *Function) (string, int, int) {
return srcFile, start, end
}

// GetGoRoot returns the Go Root path
// that was used to compile the binary.
// GetGoRoot returns the Go Root path used to compile the binary.
func (f *GoFile) GetGoRoot() (string, error) {
err := f.init()
err := f.initPackages()
if err != nil {
return "", err
}
Expand All @@ -181,7 +238,7 @@ func (f *GoFile) GetGoRoot() (string, error) {
// SetGoVersion sets the assumed compiler version that was used. This
// can be used to force a version if gore is not able to determine the
// compiler version used. The version string must match one of the strings
// normally extracted from the binary. For example to set the version to
// normally extracted from the binary. For example, to set the version to
// go 1.12.0, use "go1.12". For 1.7.2, use "go1.7.2".
// If an incorrect version string or version not known to the library,
// ErrInvalidGoVersion is returned.
Expand All @@ -194,35 +251,35 @@ func (f *GoFile) SetGoVersion(version string) error {
return nil
}

// GetPackages returns the go packages that has been classified as part of the main
// GetPackages returns the go packages that have been classified as part of the main
// project.
func (f *GoFile) GetPackages() ([]*Package, error) {
err := f.init()
err := f.initPackages()
return f.pkgs, err
}

// GetVendors returns the 3rd party packages used by the binary.
// GetVendors returns the third party packages used by the binary.
func (f *GoFile) GetVendors() ([]*Package, error) {
err := f.init()
err := f.initPackages()
return f.vendors, err
}

// GetSTDLib returns the standard library packages used by the binary.
func (f *GoFile) GetSTDLib() ([]*Package, error) {
err := f.init()
err := f.initPackages()
return f.stdPkgs, err
}

// GetGeneratedPackages returns the compiler generated packages used by the binary.
func (f *GoFile) GetGeneratedPackages() ([]*Package, error) {
err := f.init()
err := f.initPackages()
return f.generated, err
}

// GetUnknown returns unclassified packages used by the binary. This is a catch all
// category when the classification could not be determined.
// GetUnknown returns unclassified packages used by the binary.
// This is a catch-all category when the classification could not be determined.
func (f *GoFile) GetUnknown() ([]*Package, error) {
err := f.init()
err := f.initPackages()
return f.unknown, err
}

Expand Down Expand Up @@ -325,24 +382,21 @@ func (f *GoFile) PCLNTab() (*gosym.Table, error) {

// GetTypes returns a map of all types found in the binary file.
func (f *GoFile) GetTypes() ([]*GoType, error) {
if f.FileInfo.goversion == nil {
ver, err := f.GetCompilerVersion()
if err != nil {
return nil, err
}
f.FileInfo.goversion = ver
err := f.ensureCompilerVersion()
if err != nil {
return nil, err
}
t, err := getTypes(f.FileInfo, f.fh)
if err != nil {
return nil, err
}
if err = f.init(); err != nil {
if err = f.initPackages(); err != nil {
return nil, err
}
return sortTypes(t), nil
}

// Bytes returns a slice of raw bytes with the length in the file from the address.
// Bytes return a slice of raw bytes with the length in the file from the address.
func (f *GoFile) Bytes(address uint64, length uint64) ([]byte, error) {
base, section, err := f.fh.getSectionDataFromOffset(address)
if err != nil {
Expand Down Expand Up @@ -377,15 +431,15 @@ type fileHandler interface {
io.Closer
getPCLNTab() (*gosym.Table, error)
getRData() ([]byte, error)
getCodeSection() ([]byte, error)
getCodeSection() (uint64, []byte, error)
getSectionDataFromOffset(uint64) (uint64, []byte, error)
getSectionData(string) (uint64, []byte, error)
getFileInfo() *FileInfo
getPCLNTABData() (uint64, []byte, error)
moduledataSection() string
getBuildID() (string, error)
GetFile() *os.File
GetParsedFile() any
getFile() *os.File
getParsedFile() any
}

func fileMagicMatch(buf, magic []byte) bool {
Expand Down
11 changes: 5 additions & 6 deletions file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ func TestGoldFiles(t *testing.T) {
// Get info from filename gold-os-arch-goversion
fileInfo := strings.Split(file, "-")

// If patch level is 0, it is dropped. For example. 10.0.0 is 10.0.
// This was changed in 1.21 so if the version is 1.21 or greater, we take
// the whole string.
// If the patch level is 0, it is dropped. For example. 10.0.0 is 10.0
// Up until 1.21.0, if patch level is 0, it is dropped. For example. 10.0.0 is 10.0
var actualVersion string
verArr := strings.Split(fileInfo[3], ".")
if len(verArr) == 3 && verArr[2] == "0" && mustParse(strconv.Atoi(verArr[1])) < 21 {
Expand Down Expand Up @@ -175,11 +174,11 @@ type mockFileHandler struct {
mGetSectionDataFromOffset func(uint64) (uint64, []byte, error)
}

func (m *mockFileHandler) GetFile() *os.File {
func (m *mockFileHandler) getFile() *os.File {
panic("not implemented")
}

func (m *mockFileHandler) GetParsedFile() any {
func (m *mockFileHandler) getParsedFile() any {
panic("not implemented")
}

Expand All @@ -195,7 +194,7 @@ func (m *mockFileHandler) getRData() ([]byte, error) {
panic("not implemented")
}

func (m *mockFileHandler) getCodeSection() ([]byte, error) {
func (m *mockFileHandler) getCodeSection() (uint64, []byte, error) {
panic("not implemented")
}

Expand Down
Loading

0 comments on commit 7b68ef2

Please sign in to comment.