Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / internal / gccgoimporter / ar.go
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.
4
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.
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 // Magic strings for different archive file formats.
21 const (
22         armag  = "!<arch>\n"
23         armagt = "!<thin>\n"
24         armagb = "<bigaf>\n"
25 )
26
27 // Offsets and sizes for fields in a standard archive header.
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 // The contents of the fmag field of a standard archive header.
48 const arfmag = "`\n"
49
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 {
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 // standardArExportData returns export data form a standard archive.
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                         // Archive symbol table or extended name table,
99                         // which we don't care about.
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 // 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)
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 // 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 {
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 }