github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/gccgoexportdata/gccgoexportdata.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package gccgoexportdata provides functions for reading export data 6 // files containing type information produced by the gccgo compiler. 7 // 8 // This package is a stop-gap until such time as gccgo uses the same 9 // export data format as gc; see Go issue 17573. Once that occurs, this 10 // package will be deprecated and eventually deleted. 11 package gccgoexportdata 12 13 // TODO(adonovan): add Find, Write, Importer to the API, 14 // for symmetry with gcexportdata. 15 16 import ( 17 "bytes" 18 "debug/elf" 19 "fmt" 20 "go/token" 21 "go/types" 22 "io" 23 "io/ioutil" 24 "strconv" 25 "strings" 26 27 "github.com/powerman/golang-tools/go/internal/gccgoimporter" 28 ) 29 30 // CompilerInfo executes the specified gccgo compiler and returns 31 // information about it: its version (e.g. "4.8.0"), its target triple 32 // (e.g. "x86_64-unknown-linux-gnu"), and the list of directories it 33 // searches to find standard packages. The given arguments are passed 34 // directly to calls to the specified gccgo compiler. 35 func CompilerInfo(gccgo string, args ...string) (version, triple string, dirs []string, err error) { 36 var inst gccgoimporter.GccgoInstallation 37 err = inst.InitFromDriver(gccgo, args...) 38 if err == nil { 39 version = inst.GccVersion 40 triple = inst.TargetTriple 41 dirs = inst.SearchPaths() 42 } 43 return 44 } 45 46 // NewReader returns a reader for the export data section of an object 47 // (.o) or archive (.a) file read from r. 48 func NewReader(r io.Reader) (io.Reader, error) { 49 data, err := ioutil.ReadAll(r) 50 if err != nil { 51 return nil, err 52 } 53 54 // If the file is an archive, extract the first section. 55 const archiveMagic = "!<arch>\n" 56 if bytes.HasPrefix(data, []byte(archiveMagic)) { 57 section, err := firstSection(data[len(archiveMagic):]) 58 if err != nil { 59 return nil, err 60 } 61 data = section 62 } 63 64 // Data contains an ELF file with a .go_export section. 65 // ELF magic number is "\x7fELF". 66 ef, err := elf.NewFile(bytes.NewReader(data)) 67 if err != nil { 68 return nil, err 69 } 70 sec := ef.Section(".go_export") 71 if sec == nil { 72 return nil, fmt.Errorf("no .go_export section") 73 } 74 return sec.Open(), nil 75 } 76 77 // firstSection returns the contents of the first regular file in an ELF 78 // archive (http://www.sco.com/developers/devspecs/gabi41.pdf, ยง7.2). 79 func firstSection(a []byte) ([]byte, error) { 80 for len(a) >= 60 { 81 var hdr []byte 82 hdr, a = a[:60], a[60:] 83 84 name := strings.TrimSpace(string(hdr[:16])) 85 86 sizeStr := string(hdr[48:58]) 87 size, err := strconv.Atoi(strings.TrimSpace(sizeStr)) 88 if err != nil { 89 return nil, fmt.Errorf("invalid size: %q", sizeStr) 90 } 91 92 if len(a) < size { 93 return nil, fmt.Errorf("invalid section size: %d", size) 94 } 95 96 // The payload is padded to an even number of bytes. 97 var payload []byte 98 payload, a = a[:size], a[size+size&1:] 99 100 // Skip special files: 101 // "/" archive symbol table 102 // "/SYM64/" archive symbol table on e.g. s390x 103 // "//" archive string table (if any filename is >15 bytes) 104 if name == "/" || name == "/SYM64/" || name == "//" { 105 continue 106 } 107 108 return payload, nil 109 } 110 return nil, fmt.Errorf("archive has no regular sections") 111 } 112 113 // Read reads export data from in, decodes it, and returns type 114 // information for the package. 115 // The package name is specified by path. 116 // 117 // The FileSet parameter is currently unused but exists for symmetry 118 // with gcexportdata. 119 // 120 // Read may inspect and add to the imports map to ensure that references 121 // within the export data to other packages are consistent. The caller 122 // must ensure that imports[path] does not exist, or exists but is 123 // incomplete (see types.Package.Complete), and Read inserts the 124 // resulting package into this map entry. 125 // 126 // On return, the state of the reader is undefined. 127 func Read(in io.Reader, _ *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { 128 return gccgoimporter.Parse(in, imports, path) 129 }