GoPLS Viewer

Home|gopls/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
8package gccgoimporter
9
10import (
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.
21const (
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.
28const (
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.
48const 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.
55func arExportData(archive io.ReadSeeker) (io.ReadSeekererror) {
56    if _err := archive.Seek(0io.SeekStart); err != nil {
57        return nilerr
58    }
59
60    var buf [len(armag)]byte
61    if _err := archive.Read(buf[:]); err != nil {
62        return nilerr
63    }
64
65    switch string(buf[:]) {
66    case armag:
67        return standardArExportData(archive)
68    case armagt:
69        return nilerrors.New("unsupported thin archive")
70    case armagb:
71        return nilerrors.New("unsupported AIX big archive")
72    default:
73        return nilfmt.Errorf("unrecognized archive file format %q"buf[:])
74    }
75}
76
77// standardArExportData returns export data form a standard archive.
78func standardArExportData(archive io.ReadSeeker) (io.ReadSeekererror) {
79    off := int64(len(armag))
80    for {
81        var hdrBuf [arHdrSize]byte
82        if _err := archive.Read(hdrBuf[:]); err != nil {
83            return nilerr
84        }
85        off += arHdrSize
86
87        if !bytes.Equal(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) {
88            return nilfmt.Errorf("archive header format header (%q)"hdrBuf[:])
89        }
90
91        sizeerr := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 1064)
92        if err != nil {
93            return nilfmt.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            reterr := elfFromAr(io.NewSectionReader(archiveAtoffsize))
103            if ret != nil || err != nil {
104                return reterr
105            }
106        }
107
108        if size&1 != 0 {
109            size++
110        }
111        off += size
112        if _err := archive.Seek(offio.SeekStart); err != nil {
113            return nilerr
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.
120func elfFromAr(member *io.SectionReader) (io.ReadSeekererror) {
121    eferr := elf.NewFile(member)
122    if err != nil {
123        return nilerr
124    }
125    sec := ef.Section(".go_export")
126    if sec == nil {
127        return nilnil
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.
135func readerAtFromSeeker(rs io.ReadSeekerio.ReaderAt {
136    if retok := rs.(io.ReaderAt); ok {
137        return ret
138    }
139    return seekerReadAt{rs}
140}
141
142type seekerReadAt struct {
143    seeker io.ReadSeeker
144}
145
146func (sra seekerReadAtReadAt(p []byteoff int64) (interror) {
147    if _err := sra.seeker.Seek(offio.SeekStart); err != nil {
148        return 0err
149    }
150    return sra.seeker.Read(p)
151}
152
MembersX
arExportData.err
standardArExportData.BlockStmt.err
standardArExportData.BlockStmt.size
seekerReadAt.ReadAt.sra
arDateSize
arModeSize
arExportData
arUIDSize
arFmagSize
standardArExportData.BlockStmt.BlockStmt.archiveAt
standardArExportData.BlockStmt.BlockStmt.err
elfFromAr.member
strconv
strings
arNameSize
readerAtFromSeeker.rs
seekerReadAt.seeker
seekerReadAt.ReadAt
armagt
standardArExportData
standardArExportData.archive
seekerReadAt.ReadAt._
seekerReadAt.ReadAt.err
errors
elfFromAr.err
seekerReadAt.ReadAt.p
arGIDSize
arSizeSize
arfmag
standardArExportData.BlockStmt.hdrBuf
standardArExportData.BlockStmt._
bytes
elf
armag
seekerReadAt
standardArExportData.BlockStmt.BlockStmt.ret
elfFromAr
elfFromAr.ef
elfFromAr.sec
readerAtFromSeeker
arExportData.archive
arExportData.buf
standardArExportData.off
seekerReadAt.ReadAt.off
fmt
io
arExportData._
armagb
arNameOff
Members
X