1
2
3
4
5
6 package gccgoimporter
7
8 import (
9 "bytes"
10 "debug/elf"
11 "fmt"
12 "go/types"
13 "internal/xcoff"
14 "io"
15 "os"
16 "path/filepath"
17 "strings"
18 )
19
20
21 type PackageInit struct {
22 Name string
23 InitFunc string
24 Priority int
25 }
26
27
28 type InitData struct {
29
30
31
32 Priority int
33
34
35
36
37 Inits []PackageInit
38 }
39
40
41
42 func findExportFile(searchpaths []string, pkgpath string) (string, error) {
43 for _, spath := range searchpaths {
44 pkgfullpath := filepath.Join(spath, pkgpath)
45 pkgdir, name := filepath.Split(pkgfullpath)
46
47 for _, filepath := range [...]string{
48 pkgfullpath,
49 pkgfullpath + ".gox",
50 pkgdir + "lib" + name + ".so",
51 pkgdir + "lib" + name + ".a",
52 pkgfullpath + ".o",
53 } {
54 fi, err := os.Stat(filepath)
55 if err == nil && !fi.IsDir() {
56 return filepath, nil
57 }
58 }
59 }
60
61 return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
62 }
63
64 const (
65 gccgov1Magic = "v1;\n"
66 gccgov2Magic = "v2;\n"
67 gccgov3Magic = "v3;\n"
68 goimporterMagic = "\n$$ "
69 archiveMagic = "!<ar"
70 aixbigafMagic = "<big"
71 )
72
73
74
75
76
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 objreader io.ReaderAt
96 switch string(magic[:]) {
97 case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
98
99 reader = f
100 return
101
102 case archiveMagic, aixbigafMagic:
103 reader, err = arExportData(f)
104 return
105
106 default:
107 objreader = f
108 }
109
110 ef, err := elf.NewFile(objreader)
111 if err == nil {
112 sec := ef.Section(".go_export")
113 if sec == nil {
114 err = fmt.Errorf("%s: .go_export section not found", fpath)
115 return
116 }
117 reader = sec.Open()
118 return
119 }
120
121 xf, err := xcoff.NewFile(objreader)
122 if err == nil {
123 sdat := xf.CSect(".go_export")
124 if sdat == nil {
125 err = fmt.Errorf("%s: .go_export section not found", fpath)
126 return
127 }
128 reader = bytes.NewReader(sdat)
129 return
130 }
131
132 err = fmt.Errorf("%s: unrecognized file format", fpath)
133 return
134 }
135
136
137
138
139
140
141
142
143 type Importer func(imports map[string]*types.Package, path, srcDir string, lookup func(string) (io.ReadCloser, error)) (*types.Package, error)
144
145 func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Importer {
146 return func(imports map[string]*types.Package, pkgpath, srcDir string, lookup func(string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
147
148
149
150
151 if pkgpath == "unsafe" {
152 return types.Unsafe, nil
153 }
154
155 var reader io.ReadSeeker
156 var fpath string
157 var rc io.ReadCloser
158 if lookup != nil {
159 if p := imports[pkgpath]; p != nil && p.Complete() {
160 return p, nil
161 }
162 rc, err = lookup(pkgpath)
163 if err != nil {
164 return nil, err
165 }
166 }
167 if rc != nil {
168 defer rc.Close()
169 rs, ok := rc.(io.ReadSeeker)
170 if !ok {
171 return nil, fmt.Errorf("gccgo importer requires lookup to return an io.ReadSeeker, have %T", rc)
172 }
173 reader = rs
174 fpath = "<lookup " + pkgpath + ">"
175
176 if n, ok := rc.(interface{ Name() string }); ok {
177 fpath = n.Name()
178 }
179 } else {
180 fpath, err = findExportFile(searchpaths, pkgpath)
181 if err != nil {
182 return nil, err
183 }
184
185 r, closer, err := openExportFile(fpath)
186 if err != nil {
187 return nil, err
188 }
189 if closer != nil {
190 defer closer.Close()
191 }
192 reader = r
193 }
194
195 var magics string
196 magics, err = readMagic(reader)
197 if err != nil {
198 return
199 }
200
201 if magics == archiveMagic || magics == aixbigafMagic {
202 reader, err = arExportData(reader)
203 if err != nil {
204 return
205 }
206 magics, err = readMagic(reader)
207 if err != nil {
208 return
209 }
210 }
211
212 switch magics {
213 case gccgov1Magic, gccgov2Magic, gccgov3Magic:
214 var p parser
215 p.init(fpath, reader, imports)
216 pkg = p.parsePackage()
217 if initmap != nil {
218 initmap[pkg] = p.initdata
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 default:
243 err = fmt.Errorf("unrecognized magic string: %q", magics)
244 }
245
246 return
247 }
248 }
249
250
251
252 func readMagic(reader io.ReadSeeker) (string, error) {
253 var magic [4]byte
254 if _, err := reader.Read(magic[:]); err != nil {
255 return "", err
256 }
257 if _, err := reader.Seek(0, io.SeekStart); err != nil {
258 return "", err
259 }
260 return string(magic[:]), nil
261 }
262
View as plain text