Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / internal / gccgoimporter / importer.go
1 // Copyright 2013 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 // Except for this comment and the import path, this file is a verbatim copy of the file
6 // with the same name in $GOROOT/src/go/internal/gccgoimporter.
7
8 // Package gccgoimporter implements Import for gccgo-generated object files.
9 package gccgoimporter // import "golang.org/x/tools/go/internal/gccgoimporter"
10
11 import (
12         "debug/elf"
13         "fmt"
14         "go/types"
15         "io"
16         "os"
17         "path/filepath"
18         "strings"
19 )
20
21 // A PackageInit describes an imported package that needs initialization.
22 type PackageInit struct {
23         Name     string // short package name
24         InitFunc string // name of init function
25         Priority int    // priority of init function, see InitData.Priority
26 }
27
28 // The gccgo-specific init data for a package.
29 type InitData struct {
30         // Initialization priority of this package relative to other packages.
31         // This is based on the maximum depth of the package's dependency graph;
32         // it is guaranteed to be greater than that of its dependencies.
33         Priority int
34
35         // The list of packages which this package depends on to be initialized,
36         // including itself if needed. This is the subset of the transitive closure of
37         // the package's dependencies that need initialization.
38         Inits []PackageInit
39 }
40
41 // Locate the file from which to read export data.
42 // This is intended to replicate the logic in gofrontend.
43 func findExportFile(searchpaths []string, pkgpath string) (string, error) {
44         for _, spath := range searchpaths {
45                 pkgfullpath := filepath.Join(spath, pkgpath)
46                 pkgdir, name := filepath.Split(pkgfullpath)
47
48                 for _, filepath := range [...]string{
49                         pkgfullpath,
50                         pkgfullpath + ".gox",
51                         pkgdir + "lib" + name + ".so",
52                         pkgdir + "lib" + name + ".a",
53                         pkgfullpath + ".o",
54                 } {
55                         fi, err := os.Stat(filepath)
56                         if err == nil && !fi.IsDir() {
57                                 return filepath, nil
58                         }
59                 }
60         }
61
62         return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
63 }
64
65 const (
66         gccgov1Magic    = "v1;\n"
67         gccgov2Magic    = "v2;\n"
68         gccgov3Magic    = "v3;\n"
69         goimporterMagic = "\n$$ "
70         archiveMagic    = "!<ar"
71 )
72
73 // Opens the export data file at the given path. If this is an ELF file,
74 // searches for and opens the .go_export section. If this is an archive,
75 // reads the export data from the first member, which is assumed to be an ELF file.
76 // This is intended to replicate the logic in gofrontend.
77 func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
78         f, err := os.Open(fpath)
79         if err != nil {
80                 return
81         }
82         closer = f
83         defer func() {
84                 if err != nil && closer != nil {
85                         f.Close()
86                 }
87         }()
88
89         var magic [4]byte
90         _, err = f.ReadAt(magic[:], 0)
91         if err != nil {
92                 return
93         }
94
95         var elfreader io.ReaderAt
96         switch string(magic[:]) {
97         case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
98                 // Raw export data.
99                 reader = f
100                 return
101
102         case archiveMagic:
103                 reader, err = arExportData(f)
104                 return
105
106         default:
107                 elfreader = f
108         }
109
110         ef, err := elf.NewFile(elfreader)
111         if err != nil {
112                 return
113         }
114
115         sec := ef.Section(".go_export")
116         if sec == nil {
117                 err = fmt.Errorf("%s: .go_export section not found", fpath)
118                 return
119         }
120
121         reader = sec.Open()
122         return
123 }
124
125 // An Importer resolves import paths to Packages. The imports map records
126 // packages already known, indexed by package path.
127 // An importer must determine the canonical package path and check imports
128 // to see if it is already present in the map. If so, the Importer can return
129 // the map entry. Otherwise, the importer must load the package data for the
130 // given path into a new *Package, record it in imports map, and return the
131 // package.
132 type Importer func(imports map[string]*types.Package, path, srcDir string, lookup func(string) (io.ReadCloser, error)) (*types.Package, error)
133
134 func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Importer {
135         return func(imports map[string]*types.Package, pkgpath, srcDir string, lookup func(string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
136                 // TODO(gri): Use srcDir.
137                 // Or not. It's possible that srcDir will fade in importance as
138                 // the go command and other tools provide a translation table
139                 // for relative imports (like ./foo or vendored imports).
140                 if pkgpath == "unsafe" {
141                         return types.Unsafe, nil
142                 }
143
144                 var reader io.ReadSeeker
145                 var fpath string
146                 var rc io.ReadCloser
147                 if lookup != nil {
148                         if p := imports[pkgpath]; p != nil && p.Complete() {
149                                 return p, nil
150                         }
151                         rc, err = lookup(pkgpath)
152                         if err != nil {
153                                 return nil, err
154                         }
155                 }
156                 if rc != nil {
157                         defer rc.Close()
158                         rs, ok := rc.(io.ReadSeeker)
159                         if !ok {
160                                 return nil, fmt.Errorf("gccgo importer requires lookup to return an io.ReadSeeker, have %T", rc)
161                         }
162                         reader = rs
163                         fpath = "<lookup " + pkgpath + ">"
164                         // Take name from Name method (like on os.File) if present.
165                         if n, ok := rc.(interface{ Name() string }); ok {
166                                 fpath = n.Name()
167                         }
168                 } else {
169                         fpath, err = findExportFile(searchpaths, pkgpath)
170                         if err != nil {
171                                 return nil, err
172                         }
173
174                         r, closer, err := openExportFile(fpath)
175                         if err != nil {
176                                 return nil, err
177                         }
178                         if closer != nil {
179                                 defer closer.Close()
180                         }
181                         reader = r
182                 }
183
184                 var magics string
185                 magics, err = readMagic(reader)
186                 if err != nil {
187                         return
188                 }
189
190                 if magics == archiveMagic {
191                         reader, err = arExportData(reader)
192                         if err != nil {
193                                 return
194                         }
195                         magics, err = readMagic(reader)
196                         if err != nil {
197                                 return
198                         }
199                 }
200
201                 switch magics {
202                 case gccgov1Magic, gccgov2Magic, gccgov3Magic:
203                         var p parser
204                         p.init(fpath, reader, imports)
205                         pkg = p.parsePackage()
206                         if initmap != nil {
207                                 initmap[pkg] = p.initdata
208                         }
209
210                 // Excluded for now: Standard gccgo doesn't support this import format currently.
211                 // case goimporterMagic:
212                 //      var data []byte
213                 //      data, err = ioutil.ReadAll(reader)
214                 //      if err != nil {
215                 //              return
216                 //      }
217                 //      var n int
218                 //      n, pkg, err = importer.ImportData(imports, data)
219                 //      if err != nil {
220                 //              return
221                 //      }
222
223                 //      if initmap != nil {
224                 //              suffixreader := bytes.NewReader(data[n:])
225                 //              var p parser
226                 //              p.init(fpath, suffixreader, nil)
227                 //              p.parseInitData()
228                 //              initmap[pkg] = p.initdata
229                 //      }
230
231                 default:
232                         err = fmt.Errorf("unrecognized magic string: %q", magics)
233                 }
234
235                 return
236         }
237 }
238
239 // readMagic reads the four bytes at the start of a ReadSeeker and
240 // returns them as a string.
241 func readMagic(reader io.ReadSeeker) (string, error) {
242         var magic [4]byte
243         if _, err := reader.Read(magic[:]); err != nil {
244                 return "", err
245         }
246         if _, err := reader.Seek(0, io.SeekStart); err != nil {
247                 return "", err
248         }
249         return string(magic[:]), nil
250 }