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