Commit 38ad6f8a by Ian Lance Taylor

cmd/go: buildid support for AIX archives.

    
    Reviewed-on: https://go-review.googlesource.com/88935

From-SVN: r256971
parent f991f102
87525458bcd5ab4beb5b95e7d58e3dfdbc1bd478 3488a401e50835de5de5c4f153772ac2798d0e71
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -330,6 +330,43 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { ...@@ -330,6 +330,43 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
return sfile, nil 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. // buildID returns the build ID found in the given file.
// If no build ID is found, buildID returns the content hash of the file. // If no build ID is found, buildID returns the content hash of the file.
func (b *Builder) buildID(file string) string { func (b *Builder) buildID(file string) string {
......
...@@ -637,6 +637,16 @@ func (b *Builder) build(a *Action) (err error) { ...@@ -637,6 +637,16 @@ func (b *Builder) build(a *Action) (err error) {
return err return err
} }
objects = append(objects, ofiles...) 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...)
} }
} }
......
...@@ -7,6 +7,7 @@ package buildid ...@@ -7,6 +7,7 @@ package buildid
import ( import (
"bytes" "bytes"
"debug/elf" "debug/elf"
"debug/xcoff"
"fmt" "fmt"
"io" "io"
"os" "os"
...@@ -40,6 +41,9 @@ func ReadFile(name string) (id string, err error) { ...@@ -40,6 +41,9 @@ func ReadFile(name string) (id string, err error) {
return "", err return "", err
} }
if string(buf) != "!<arch>\n" { if string(buf) != "!<arch>\n" {
if string(buf) == "<bigaf>\n" {
return readGccgoBigArchive(name, f)
}
return readBinary(name, f) return readBinary(name, f)
} }
...@@ -157,6 +161,85 @@ func readGccgoArchive(name string, f *os.File) (string, error) { ...@@ -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 ( var (
goBuildPrefix = []byte("\xff Go build ID: \"") goBuildPrefix = []byte("\xff Go build ID: \"")
goBuildEnd = []byte("\"\n \xff") goBuildEnd = []byte("\"\n \xff")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment