From: Ian Lance Taylor Date: Tue, 23 Jan 2018 04:44:12 +0000 (+0000) Subject: cmd/go: buildid support for AIX archives. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=38ad6f8a440f7594b9cea5fb999078035ee36a57;p=gcc.git cmd/go: buildid support for AIX archives. Reviewed-on: https://go-review.googlesource.com/88935 From-SVN: r256971 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index a66fe24dfe2..a100cab84fe 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -87525458bcd5ab4beb5b95e7d58e3dfdbc1bd478 +3488a401e50835de5de5c4f153772ac2798d0e71 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go index 39ca20ee4f0..e2ae85083d8 100644 --- a/libgo/go/cmd/go/internal/work/buildid.go +++ b/libgo/go/cmd/go/internal/work/buildid.go @@ -330,6 +330,43 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { return sfile, nil } +// gccgoBuildIDXCOFFFile creates an assembler file that records the +// action's build ID in a CSECT (AIX linker deletes CSECTs that are +// not referenced in the output file). +func (b *Builder) gccgoBuildIDXCOFFFile(a *Action) (string, error) { + sfile := a.Objdir + "_buildid.s" + + var buf bytes.Buffer + fmt.Fprintf(&buf, "\t.csect .go.buildid[XO]\n") + fmt.Fprintf(&buf, "\t.byte ") + for i := 0; i < len(a.buildID); i++ { + if i > 0 { + if i%8 == 0 { + fmt.Fprintf(&buf, "\n\t.byte ") + } else { + fmt.Fprintf(&buf, ",") + } + } + fmt.Fprintf(&buf, "%#02x", a.buildID[i]) + } + fmt.Fprintf(&buf, "\n") + + if cfg.BuildN || cfg.BuildX { + for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { + b.Showcmd("", "echo '%s' >> %s", line, sfile) + } + if cfg.BuildN { + return sfile, nil + } + } + + if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil { + return "", err + } + + return sfile, nil +} + // buildID returns the build ID found in the given file. // If no build ID is found, buildID returns the content hash of the file. func (b *Builder) buildID(file string) string { diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go index c2704c4335e..edd2694b086 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -637,6 +637,16 @@ func (b *Builder) build(a *Action) (err error) { return err } objects = append(objects, ofiles...) + case "aix": + asmfile, err := b.gccgoBuildIDXCOFFFile(a) + if err != nil { + return err + } + ofiles, err := BuildToolchain.asm(b, a, []string{asmfile}) + if err != nil { + return err + } + objects = append(objects, ofiles...) } } diff --git a/libgo/go/cmd/internal/buildid/buildid.go b/libgo/go/cmd/internal/buildid/buildid.go index fa3d7f37ec6..41e6c773e1b 100644 --- a/libgo/go/cmd/internal/buildid/buildid.go +++ b/libgo/go/cmd/internal/buildid/buildid.go @@ -7,6 +7,7 @@ package buildid import ( "bytes" "debug/elf" + "debug/xcoff" "fmt" "io" "os" @@ -40,6 +41,9 @@ func ReadFile(name string) (id string, err error) { return "", err } if string(buf) != "!\n" { + if string(buf) == "\n" { + return readGccgoBigArchive(name, f) + } return readBinary(name, f) } @@ -157,6 +161,85 @@ func readGccgoArchive(name string, f *os.File) (string, error) { } } +// readGccgoBigArchive tries to parse the archive as an AIX big +// archive file, and fetch the build ID from the _buildid.o entry. +// The _buildid.o entry is written by (*Builder).gccgoBuildIDXCOFFFile +// in cmd/go/internal/work/exec.go. +func readGccgoBigArchive(name string, f *os.File) (string, error) { + bad := func() (string, error) { + return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed} + } + + // Read fixed-length header. + if _, err := f.Seek(0, io.SeekStart); err != nil { + return "", err + } + var flhdr [128]byte + if _, err := io.ReadFull(f, flhdr[:]); err != nil { + return "", err + } + // Read first member offset. + offStr := strings.TrimSpace(string(flhdr[68:88])) + off, err := strconv.ParseInt(offStr, 10, 64) + if err != nil { + return bad() + } + for { + if off == 0 { + // No more entries, no build ID. + return "", nil + } + if _, err := f.Seek(off, io.SeekStart); err != nil { + return "", err + } + // Read member header. + var hdr [112]byte + if _, err := io.ReadFull(f, hdr[:]); err != nil { + return "", err + } + // Read member name length. + namLenStr := strings.TrimSpace(string(hdr[108:112])) + namLen, err := strconv.ParseInt(namLenStr, 10, 32) + if err != nil { + return bad() + } + if namLen == 10 { + var nam [10]byte + if _, err := io.ReadFull(f, nam[:]); err != nil { + return "", err + } + if string(nam[:]) == "_buildid.o" { + sizeStr := strings.TrimSpace(string(hdr[0:20])) + size, err := strconv.ParseInt(sizeStr, 10, 64) + if err != nil { + return bad() + } + off += int64(len(hdr)) + namLen + 2 + if off&1 != 0 { + off++ + } + sr := io.NewSectionReader(f, off, size) + x, err := xcoff.NewFile(sr) + if err != nil { + return bad() + } + data := x.CSect(".go.buildid") + if data == nil { + return bad() + } + return string(data), nil + } + } + + // Read next member offset. + offStr = strings.TrimSpace(string(hdr[20:40])) + off, err = strconv.ParseInt(offStr, 10, 64) + if err != nil { + return bad() + } + } +} + var ( goBuildPrefix = []byte("\xff Go build ID: \"") goBuildEnd = []byte("\"\n \xff")