golang.org/x/tools@v0.21.0/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 "strconv" 24 "strings" 25 26 "golang.org/x/tools/go/internal/gccgoimporter" 27 ) 28 29 // CompilerInfo executes the specified gccgo compiler and returns 30 // information about it: its version (e.g. "4.8.0"), its target triple 31 // (e.g. "x86_64-unknown-linux-gnu"), and the list of directories it 32 // searches to find standard packages. The given arguments are passed 33 // directly to calls to the specified gccgo compiler. 34 func CompilerInfo(gccgo string, args ...string) (version, triple string, dirs []string, err error) { 35 var inst gccgoimporter.GccgoInstallation 36 err = inst.InitFromDriver(gccgo, args...) 37 if err == nil { 38 version = inst.GccVersion 39 triple = inst.TargetTriple 40 dirs = inst.SearchPaths() 41 } 42 return 43 } 44 45 // NewReader returns a reader for the export data section of an object 46 // (.o) or archive (.a) file read from r. 47 func NewReader(r io.Reader) (io.Reader, error) { 48 data, err := io.ReadAll(r) 49 if err != nil { 50 return nil, err 51 } 52 53 // If the file is an archive, extract the first section. 54 const archiveMagic = "!<arch>\n" 55 if bytes.HasPrefix(data, []byte(archiveMagic)) { 56 section, err := firstSection(data[len(archiveMagic):]) 57 if err != nil { 58 return nil, err 59 } 60 data = section 61 } 62 63 // Data contains an ELF file with a .go_export section. 64 // ELF magic number is "\x7fELF". 65 ef, err := elf.NewFile(bytes.NewReader(data)) 66 if err != nil { 67 return nil, err 68 } 69 sec := ef.Section(".go_export") 70 if sec == nil { 71 return nil, fmt.Errorf("no .go_export section") 72 } 73 return sec.Open(), nil 74 } 75 76 // firstSection returns the contents of the first regular file in an ELF 77 // archive (http://www.sco.com/developers/devspecs/gabi41.pdf, ยง7.2). 78 func firstSection(a []byte) ([]byte, error) { 79 for len(a) >= 60 { 80 var hdr []byte 81 hdr, a = a[:60], a[60:] 82 83 name := strings.TrimSpace(string(hdr[:16])) 84 85 sizeStr := string(hdr[48:58]) 86 size, err := strconv.Atoi(strings.TrimSpace(sizeStr)) 87 if err != nil { 88 return nil, fmt.Errorf("invalid size: %q", sizeStr) 89 } 90 91 if len(a) < size { 92 return nil, fmt.Errorf("invalid section size: %d", size) 93 } 94 95 // The payload is padded to an even number of bytes. 96 var payload []byte 97 payload, a = a[:size], a[size+size&1:] 98 99 // Skip special files: 100 // "/" archive symbol table 101 // "/SYM64/" archive symbol table on e.g. s390x 102 // "//" archive string table (if any filename is >15 bytes) 103 if name == "/" || name == "/SYM64/" || name == "//" { 104 continue 105 } 106 107 return payload, nil 108 } 109 return nil, fmt.Errorf("archive has no regular sections") 110 } 111 112 // Read reads export data from in, decodes it, and returns type 113 // information for the package. 114 // The package name is specified by path. 115 // 116 // The FileSet parameter is currently unused but exists for symmetry 117 // with gcexportdata. 118 // 119 // Read may inspect and add to the imports map to ensure that references 120 // within the export data to other packages are consistent. The caller 121 // must ensure that imports[path] does not exist, or exists but is 122 // incomplete (see types.Package.Complete), and Read inserts the 123 // resulting package into this map entry. 124 // 125 // On return, the state of the reader is undefined. 126 func Read(in io.Reader, _ *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { 127 return gccgoimporter.Parse(in, imports, path) 128 }