1
2
3
4
5 package gccgoimporter
6
7 import (
8 "bytes"
9 "debug/elf"
10 "errors"
11 "fmt"
12 "internal/xcoff"
13 "io"
14 "strconv"
15 "strings"
16 )
17
18
19 const (
20 armag = "!<arch>\n"
21 armagt = "!<thin>\n"
22 armagb = "<bigaf>\n"
23 )
24
25
26 const (
27 arNameOff = 0
28 arNameSize = 16
29 arDateOff = arNameOff + arNameSize
30 arDateSize = 12
31 arUIDOff = arDateOff + arDateSize
32 arUIDSize = 6
33 arGIDOff = arUIDOff + arUIDSize
34 arGIDSize = 6
35 arModeOff = arGIDOff + arGIDSize
36 arModeSize = 8
37 arSizeOff = arModeOff + arModeSize
38 arSizeSize = 10
39 arFmagOff = arSizeOff + arSizeSize
40 arFmagSize = 2
41
42 arHdrSize = arFmagOff + arFmagSize
43 )
44
45
46 const arfmag = "`\n"
47
48
49
50
51
52
53 func arExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
54 if _, err := archive.Seek(0, io.SeekStart); err != nil {
55 return nil, err
56 }
57
58 var buf [len(armag)]byte
59 if _, err := archive.Read(buf[:]); err != nil {
60 return nil, err
61 }
62
63 switch string(buf[:]) {
64 case armag:
65 return standardArExportData(archive)
66 case armagt:
67 return nil, errors.New("unsupported thin archive")
68 case armagb:
69 return aixBigArExportData(archive)
70 default:
71 return nil, fmt.Errorf("unrecognized archive file format %q", buf[:])
72 }
73 }
74
75
76 func standardArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
77 off := int64(len(armag))
78 for {
79 var hdrBuf [arHdrSize]byte
80 if _, err := archive.Read(hdrBuf[:]); err != nil {
81 return nil, err
82 }
83 off += arHdrSize
84
85 if bytes.Compare(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) != 0 {
86 return nil, fmt.Errorf("archive header format header (%q)", hdrBuf[:])
87 }
88
89 size, err := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 10, 64)
90 if err != nil {
91 return nil, fmt.Errorf("error parsing size in archive header (%q): %v", hdrBuf[:], err)
92 }
93
94 fn := hdrBuf[arNameOff : arNameOff+arNameSize]
95 if fn[0] == '/' && (fn[1] == ' ' || fn[1] == '/' || bytes.Compare(fn[:8], []byte("/SYM64/ ")) == 0) {
96
97
98 } else {
99 archiveAt := readerAtFromSeeker(archive)
100 ret, err := elfFromAr(io.NewSectionReader(archiveAt, off, size))
101 if ret != nil || err != nil {
102 return ret, err
103 }
104 }
105
106 if size&1 != 0 {
107 size++
108 }
109 off += size
110 if _, err := archive.Seek(off, io.SeekStart); err != nil {
111 return nil, err
112 }
113 }
114 }
115
116
117
118 func elfFromAr(member *io.SectionReader) (io.ReadSeeker, error) {
119 ef, err := elf.NewFile(member)
120 if err != nil {
121 return nil, err
122 }
123 sec := ef.Section(".go_export")
124 if sec == nil {
125 return nil, nil
126 }
127 return sec.Open(), nil
128 }
129
130
131 func aixBigArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
132 archiveAt := readerAtFromSeeker(archive)
133 arch, err := xcoff.NewArchive(archiveAt)
134 if err != nil {
135 return nil, err
136 }
137
138 for _, mem := range arch.Members {
139 f, err := arch.GetFile(mem.Name)
140 if err != nil {
141 return nil, err
142 }
143 sdat := f.CSect(".go_export")
144 if sdat != nil {
145 return bytes.NewReader(sdat), nil
146 }
147 }
148
149 return nil, fmt.Errorf(".go_export not found in this archive")
150 }
151
152
153
154
155 func readerAtFromSeeker(rs io.ReadSeeker) io.ReaderAt {
156 if ret, ok := rs.(io.ReaderAt); ok {
157 return ret
158 }
159 return seekerReadAt{rs}
160 }
161
162 type seekerReadAt struct {
163 seeker io.ReadSeeker
164 }
165
166 func (sra seekerReadAt) ReadAt(p []byte, off int64) (int, error) {
167 if _, err := sra.seeker.Seek(off, io.SeekStart); err != nil {
168 return 0, err
169 }
170 return sra.seeker.Read(p)
171 }
172
View as plain text