Skip to content

Commit 2b85042

Browse files
committed
Support parsing the 'importmap' directive in an importcfg file.
Also change Parse to take in a function instead of a map to give the caller additional flexibility. Fixes #13 and #17.
1 parent d867f0b commit 2b85042

File tree

1 file changed

+40
-26
lines changed

1 file changed

+40
-26
lines changed

goobj2/file.go

+40-26
Original file line numberDiff line numberDiff line change
@@ -194,24 +194,29 @@ const (
194194
SLIBFUZZER_EXTRA_COUNTER
195195
)
196196

197-
type ImportCfg map[string]ExportInfo
197+
type ImportCfg struct {
198+
ImportMap map[string]string
199+
Packages map[string]ExportInfo
200+
}
198201

199202
type ExportInfo struct {
200203
Path string
201204
IsSharedLib bool
202205
}
203206

204-
func ParseImportCfg(path string) (ImportCfg, error) {
207+
func ParseImportCfg(path string) (importCfg ImportCfg, err error) {
205208
data, err := ioutil.ReadFile(path)
206209
if err != nil {
207-
return nil, fmt.Errorf("error reading importcfg: %v", err)
210+
return importCfg, fmt.Errorf("error reading importcfg: %v", err)
208211
}
209212

210213
lines := bytes.Count(data, []byte("\n"))
211214
if lines == -1 {
212-
return nil, errors.New("error parsing importcfg: could not find any newlines")
215+
return importCfg, errors.New("error parsing importcfg: could not find any newlines")
213216
}
214-
importMap := make(ImportCfg, lines)
217+
218+
importCfg.ImportMap = make(map[string]string)
219+
importCfg.Packages = make(map[string]ExportInfo, lines)
215220

216221
for lineNum, line := range strings.Split(string(data), "\n") {
217222
lineNum++ // 1-based
@@ -235,21 +240,26 @@ func ParseImportCfg(path string) (ImportCfg, error) {
235240
}
236241
switch verb {
237242
default:
238-
return nil, fmt.Errorf("error parsing importcfg: %s:%d: unknown directive %q", path, lineNum, verb)
243+
return importCfg, fmt.Errorf("error parsing importcfg: %s:%d: unknown directive %q", path, lineNum, verb)
244+
case "importmap":
245+
if before == "" || after == "" {
246+
return importCfg, fmt.Errorf(`error parsing importcfg: %s:%d: invalid importmap: syntax is "importmap path=path"`, path, lineNum)
247+
}
248+
importCfg.ImportMap[before] = after
239249
case "packagefile":
240250
if before == "" || after == "" {
241-
return nil, fmt.Errorf(`error parsing importcfg: %s:%d: invalid packagefile: syntax is "packagefile path=filename"`, path, lineNum)
251+
return importCfg, fmt.Errorf(`error parsing importcfg: %s:%d: invalid packagefile: syntax is "packagefile path=filename"`, path, lineNum)
242252
}
243-
importMap[before] = ExportInfo{after, false}
253+
importCfg.Packages[before] = ExportInfo{after, false}
244254
case "packageshlib":
245255
if before == "" || after == "" {
246-
return nil, fmt.Errorf(`error parsing importcfg: %s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, path, lineNum)
256+
return importCfg, fmt.Errorf(`error parsing importcfg: %s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, path, lineNum)
247257
}
248-
importMap[before] = ExportInfo{after, true}
258+
importCfg.Packages[before] = ExportInfo{after, true}
249259
}
250260
}
251261

252-
return importMap, nil
262+
return importCfg, nil
253263
}
254264

255265
var (
@@ -416,22 +426,27 @@ func (r *objReader) skip(n int64) {
416426
}
417427
}
418428

419-
// Parse parses an object file or archive from f, assuming that its
420-
// import path is pkgpath. An import configuration file that would
421-
// be passed into the linker can optionally be passed in as importCfg
429+
// ImportMap is a function that returns the path of a Go object
430+
// from a given import path. If the import path is not known,
431+
// an empty string should be returned.
432+
type ImportMap = func(importPath string) (objectPath string)
433+
434+
// Parse parses an object file or archive from objPath, assuming that
435+
// its import path is pkgpath. A function that returns paths of object
436+
// files from import paths can optionally be passed in as importMap
422437
// to optimize looking up paths to dependencies' object files.
423-
func Parse(objPath, pkgPath string, importCfg ImportCfg) (*Package, error) {
438+
func Parse(objPath, pkgPath string, importMap ImportMap) (*Package, error) {
424439
p := new(Package)
425440
p.ImportPath = pkgPath
426441

427-
if _, err := parse(objPath, p, importCfg, false); err != nil {
442+
if _, err := parse(objPath, p, importMap, false); err != nil {
428443
return nil, err
429444
}
430445

431446
return p, nil
432447
}
433448

434-
func parse(objPath string, p *Package, importCfg ImportCfg, returnReader bool) (rr *goobj2.Reader, err error) {
449+
func parse(objPath string, p *Package, importMap ImportMap, returnReader bool) (rr *goobj2.Reader, err error) {
435450
f, openErr := os.Open(objPath)
436451
if err != nil {
437452
return nil, openErr
@@ -457,13 +472,13 @@ func parse(objPath string, p *Package, importCfg ImportCfg, returnReader bool) (
457472
default:
458473
return nil, errNotObject
459474
case bytes.Equal(rd.tmp[:8], archiveHeader):
460-
rr, err = rd.parseArchive(importCfg, returnReader)
475+
rr, err = rd.parseArchive(importMap, returnReader)
461476
if err != nil {
462477
return nil, err
463478
}
464479
case bytes.Equal(rd.tmp[:8], goobjHeader):
465480
var am *ArchiveMember
466-
rr, am, _, err = rd.parseObject(goobjHeader, importCfg, returnReader)
481+
rr, am, _, err = rd.parseObject(goobjHeader, importMap, returnReader)
467482
if err != nil {
468483
return nil, err
469484
}
@@ -480,7 +495,7 @@ func trimSpace(b []byte) string {
480495
}
481496

482497
// parseArchive parses a Unix archive of Go object files.
483-
func (r *objReader) parseArchive(importCfg ImportCfg, returnReader bool) (*goobj2.Reader, error) {
498+
func (r *objReader) parseArchive(importMap ImportMap, returnReader bool) (*goobj2.Reader, error) {
484499
for r.offset < r.limit {
485500
if err := r.readFull(r.tmp[:archiveHeaderLen]); err != nil {
486501
return nil, err
@@ -551,7 +566,7 @@ func (r *objReader) parseArchive(importCfg ImportCfg, returnReader bool) (*goobj
551566
}
552567
if bytes.Equal(p, goobjHeader) {
553568
var rr *goobj2.Reader
554-
rr, am, data, err = r.parseObject(nil, importCfg, returnReader)
569+
rr, am, data, err = r.parseObject(nil, importMap, returnReader)
555570
if err != nil {
556571
return nil, fmt.Errorf("parsing archive member %q: %v", ar.Name, err)
557572
}
@@ -593,7 +608,7 @@ func (r *objReader) parseArchive(importCfg ImportCfg, returnReader bool) (*goobj
593608
// and then the part we want to parse begins.
594609
// The format of that part is defined in a comment at the top
595610
// of src/liblink/objfile.c.
596-
func (r *objReader) parseObject(prefix []byte, importMap ImportCfg, returnReader bool) (*goobj2.Reader, *ArchiveMember, []byte, error) {
611+
func (r *objReader) parseObject(prefix []byte, importMap ImportMap, returnReader bool) (*goobj2.Reader, *ArchiveMember, []byte, error) {
597612
h := make([]byte, 0, 256)
598613
h = append(h, prefix...)
599614
var c1, c2, c3 byte
@@ -887,12 +902,11 @@ func (r *objReader) parseObject(prefix []byte, importMap ImportCfg, returnReader
887902
return nil, &am, h, nil
888903
}
889904

890-
func getArchivePath(pkg string, importMap ImportCfg) (s string, err error) {
905+
func getArchivePath(pkg string, importMap ImportMap) (s string, err error) {
891906
// try to get the archive path from the importMap first
892907
if importMap != nil {
893-
path, ok := importMap[pkg]
894-
if ok {
895-
return path.Path, nil
908+
if path := importMap(pkg); path != "" {
909+
return path, nil
896910
}
897911
}
898912

0 commit comments

Comments
 (0)