1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Except for this comment, this file is a verbatim copy of the file
6 // with the same name in $GOROOT/src/go/internal/gccgoimporter.
20 // Magic strings for different archive file formats.
27 // Offsets and sizes for fields in a standard archive header.
31 arDateOff = arNameOff + arNameSize
33 arUIDOff = arDateOff + arDateSize
35 arGIDOff = arUIDOff + arUIDSize
37 arModeOff = arGIDOff + arGIDSize
39 arSizeOff = arModeOff + arModeSize
41 arFmagOff = arSizeOff + arSizeSize
44 arHdrSize = arFmagOff + arFmagSize
47 // The contents of the fmag field of a standard archive header.
50 // arExportData takes an archive file and returns a ReadSeeker for the
51 // export data in that file. This assumes that there is only one
52 // object in the archive containing export data, which is not quite
53 // what gccgo does; gccgo concatenates together all the export data
54 // for all the objects in the file. In practice that case does not arise.
55 func arExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
56 if _, err := archive.Seek(0, io.SeekStart); err != nil {
60 var buf [len(armag)]byte
61 if _, err := archive.Read(buf[:]); err != nil {
65 switch string(buf[:]) {
67 return standardArExportData(archive)
69 return nil, errors.New("unsupported thin archive")
71 return nil, errors.New("unsupported AIX big archive")
73 return nil, fmt.Errorf("unrecognized archive file format %q", buf[:])
77 // standardArExportData returns export data form a standard archive.
78 func standardArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
79 off := int64(len(armag))
81 var hdrBuf [arHdrSize]byte
82 if _, err := archive.Read(hdrBuf[:]); err != nil {
87 if !bytes.Equal(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) {
88 return nil, fmt.Errorf("archive header format header (%q)", hdrBuf[:])
91 size, err := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 10, 64)
93 return nil, fmt.Errorf("error parsing size in archive header (%q): %v", hdrBuf[:], err)
96 fn := hdrBuf[arNameOff : arNameOff+arNameSize]
97 if fn[0] == '/' && (fn[1] == ' ' || fn[1] == '/' || bytes.Equal(fn[:8], []byte("/SYM64/ "))) {
98 // Archive symbol table or extended name table,
99 // which we don't care about.
101 archiveAt := readerAtFromSeeker(archive)
102 ret, err := elfFromAr(io.NewSectionReader(archiveAt, off, size))
103 if ret != nil || err != nil {
112 if _, err := archive.Seek(off, io.SeekStart); err != nil {
118 // elfFromAr tries to get export data from an archive member as an ELF file.
119 // If there is no export data, this returns nil, nil.
120 func elfFromAr(member *io.SectionReader) (io.ReadSeeker, error) {
121 ef, err := elf.NewFile(member)
125 sec := ef.Section(".go_export")
129 return sec.Open(), nil
132 // readerAtFromSeeker turns an io.ReadSeeker into an io.ReaderAt.
133 // This is only safe because there won't be any concurrent seeks
134 // while this code is executing.
135 func readerAtFromSeeker(rs io.ReadSeeker) io.ReaderAt {
136 if ret, ok := rs.(io.ReaderAt); ok {
139 return seekerReadAt{rs}
142 type seekerReadAt struct {
146 func (sra seekerReadAt) ReadAt(p []byte, off int64) (int, error) {
147 if _, err := sra.seeker.Seek(off, io.SeekStart); err != nil {
150 return sra.seeker.Read(p)