From 5e7fa1cbaac7c20ee61e6fafce3e778e0e854571 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 24 Oct 2016 17:33:01 -0400 Subject: [PATCH] go/gccgoexporter: an API for parsing gccgo export data This package is provided as a stop-gap until gccgo uses the same export data format as gc. Once that occurs, this package will be deprecated and eventually deleted. The API is similar to (a subset of) gcexportdata. Change-Id: I3398dbb8eab508a24d12036bbadaa60c2c1e77b3 Reviewed-on: https://go-review.googlesource.com/31822 Reviewed-by: Robert Griesemer --- go/gccgoexportdata/gccgoexportdata.go | 122 +++++++++++++++++++++ go/gccgoexportdata/gccgoexportdata_test.go | 36 ++++++ go/gccgoexportdata/testdata/errors.gox | Bin 0 -> 24632 bytes go/internal/gccgoimporter/backdoor.go | 28 +++++ 4 files changed, 186 insertions(+) create mode 100644 go/gccgoexportdata/gccgoexportdata.go create mode 100644 go/gccgoexportdata/gccgoexportdata_test.go create mode 100644 go/gccgoexportdata/testdata/errors.gox create mode 100644 go/internal/gccgoimporter/backdoor.go diff --git a/go/gccgoexportdata/gccgoexportdata.go b/go/gccgoexportdata/gccgoexportdata.go new file mode 100644 index 00000000..d850f15a --- /dev/null +++ b/go/gccgoexportdata/gccgoexportdata.go @@ -0,0 +1,122 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package gccgoexportdata provides functions for reading export data +// files containing type information produced by the gccgo compiler. +// +// This package is a stop-gap until gccgo uses the same export data +// format as gc. Once that occurs, this package will be deprecated and +// eventually deleted. +package gccgoexportdata + +// TODO(adonovan): add Find, Write, Importer to the API, +// for symmetry with gcexportdata. + +import ( + "bytes" + "debug/elf" + "fmt" + "go/token" + "go/types" + "io" + "io/ioutil" + "strconv" + "strings" + + "golang.org/x/tools/go/internal/gccgoimporter" +) + +// CompilerInfo executes the specified gccgo compiler and returns +// information about it: its version (e.g. "4.8.0"), its target triple +// (e.g. "x86_64-unknown-linux-gnu"), and the list of directories it +// searches to find standard packages. +func CompilerInfo(gccgo string) (version, triple string, dirs []string, err error) { + var inst gccgoimporter.GccgoInstallation + err = inst.InitFromDriver(gccgo) + if err == nil { + version = inst.GccVersion + triple = inst.TargetTriple + dirs = inst.SearchPaths() + } + return +} + +// NewReader returns a reader for the export data section of an object +// (.o) or archive (.a) file read from r. +func NewReader(r io.Reader) (io.Reader, error) { + data, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + // If the file is an archive, extract the first section. + const archiveMagic = "!\n" + if bytes.HasPrefix(data, []byte(archiveMagic)) { + section, err := firstSection(data[len(archiveMagic):]) + if err != nil { + return nil, err + } + data = section + } + + // Data contains an ELF file with a .go_export section. + // ELF magic number is "\x7fELF". + ef, err := elf.NewFile(bytes.NewReader(data)) + if err != nil { + return nil, err + } + sec := ef.Section(".go_export") + if sec == nil { + return nil, fmt.Errorf("no .go_export section") + } + return sec.Open(), nil +} + +// firstSection returns the contents of the first non-empty section of the archive file. +func firstSection(a []byte) ([]byte, error) { + for len(a) >= 60 { + var hdr []byte + hdr, a = a[:60], a[60:] + + modeStr := string(string(hdr[40:48])) + mode, err := strconv.Atoi(strings.TrimSpace(modeStr)) + if err != nil { + return nil, fmt.Errorf("invalid mode: %q", modeStr) + } + + sizeStr := string(hdr[48:58]) + size, err := strconv.Atoi(strings.TrimSpace(sizeStr)) + if err != nil { + return nil, fmt.Errorf("invalid size: %q", sizeStr) + } + + var payload []byte + payload, a = a[:size], a[size:] + + if mode == 0 { + continue // skip "/" + } + + return payload, nil + } + return nil, fmt.Errorf("archive has no non-empty sections") +} + +// Read reads export data from in, decodes it, and returns type +// information for the package. +// The package name is specified by path. +// +// The FileSet parameter is currently unused but exists for symmetry +// with gcexportdata. +// +// Read may inspect and add to the imports map to ensure that references +// within the export data to other packages are consistent. The caller +// must ensure that imports[path] does not exist, or exists but is +// incomplete (see types.Package.Complete), and Read inserts the +// resulting package into this map entry. +// +// On return, the state of the reader is undefined. +func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { + return gccgoimporter.Parse(in, imports, path) +} diff --git a/go/gccgoexportdata/gccgoexportdata_test.go b/go/gccgoexportdata/gccgoexportdata_test.go new file mode 100644 index 00000000..131f4135 --- /dev/null +++ b/go/gccgoexportdata/gccgoexportdata_test.go @@ -0,0 +1,36 @@ +package gccgoexportdata_test + +import ( + "go/types" + "os" + "testing" + + "golang.org/x/tools/go/gccgoexportdata" +) + +// Test ensures this package can read gccgo export data from the +// .go_export section of an ELF file. +func Test(t *testing.T) { + f, err := os.Open("testdata/errors.gox") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r, err := gccgoexportdata.NewReader(f) + if err != nil { + t.Fatal(err) + } + imports := make(map[string]*types.Package) + pkg, err := gccgoexportdata.Read(r, nil, imports, "errors") + if err != nil { + + t.Fatal(err) + } + + // Check type of errors.New. + got := pkg.Scope().Lookup("New").Type().String() + want := "func(text string) error" + if got != want { + t.Errorf("New.Type = %s, want %s", got, want) + } +} diff --git a/go/gccgoexportdata/testdata/errors.gox b/go/gccgoexportdata/testdata/errors.gox new file mode 100644 index 0000000000000000000000000000000000000000..c6ff16bcc1868a9344fa7890da752402f4be5d66 GIT binary patch literal 24632 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