1
2
3
4
5
6
7
8
9 package gccgoimporter
10
11 import (
12 "debug/elf"
13 "fmt"
14 "go/types"
15 "io"
16 "os"
17 "path/filepath"
18 "strings"
19 )
20
21
22 type PackageInit struct {
23 Name string
24 InitFunc string
25 Priority int
26 }
27
28
29 type InitData struct {
30
31
32
33 Priority int
34
35
36
37
38 Inits []PackageInit
39 }
40
41
42
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
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 elfreader io.ReaderAt
96 switch string(magic[:]) {
97 case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
98
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
126
127
128
129
130
131
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
137
138
139
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
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231 default:
232 err = fmt.Errorf("unrecognized magic string: %q", magics)
233 }
234
235 return
236 }
237 }
238
239
240
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 }
251
View as plain text