cmd/go: buildid support for AIX archives.
Reviewed-on: https://go-review.googlesource.com/88935 From-SVN: r256971
This commit is contained in:
parent
f991f1022c
commit
38ad6f8a44
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) != "!<arch>\n" {
|
||||
if string(buf) == "<bigaf>\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")
|
||||
|
|
Loading…
Reference in New Issue