mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
The new package "internal/unsafeheader" depends only on "unsafe", and provides declarations equivalent to reflect.StringHeader and reflect.SliceHeader but with Data fields of the proper unsafe.Pointer type (instead of uintptr). Unlike the types it replaces, the "internal/unsafeheader" package has a regression test to ensure that its header types remain equivalent to the declarations provided by the "reflect" package. Since "internal/unsafeheader" has almost no dependencies, it can be used in other low-level packages such as "syscall" and "reflect". This change is based on the corresponding x/sys change in CL 231177. Fixes #37805 Updates #19367 Change-Id: I7a6d93ef8dd6e235bcab94e7c47270aad047af31 Reviewed-on: https://go-review.googlesource.com/c/go/+/231223 Reviewed-by: Ian Lance Taylor <iant@golang.org>
664 lines
16 KiB
Go
664 lines
16 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package objfile reads Go object files for the Go linker, cmd/link.
|
|
//
|
|
// This package is similar to cmd/internal/objfile which also reads
|
|
// Go object files.
|
|
package objfile
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"cmd/internal/bio"
|
|
"cmd/internal/dwarf"
|
|
"cmd/internal/goobj2"
|
|
"cmd/internal/obj"
|
|
"cmd/internal/objabi"
|
|
"cmd/internal/sys"
|
|
"cmd/oldlink/internal/sym"
|
|
"fmt"
|
|
"internal/unsafeheader"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
startmagic = "\x00go114ld"
|
|
endmagic = "\xffgo114ld"
|
|
)
|
|
|
|
var emptyPkg = []byte(`"".`)
|
|
|
|
// objReader reads Go object files.
|
|
type objReader struct {
|
|
rd *bio.Reader
|
|
arch *sys.Arch
|
|
syms *sym.Symbols
|
|
lib *sym.Library
|
|
unit *sym.CompilationUnit
|
|
pn string
|
|
dupSym *sym.Symbol
|
|
localSymVersion int
|
|
flags int
|
|
strictDupMsgs int
|
|
dataSize int
|
|
|
|
// rdBuf is used by readString and readSymName as scratch for reading strings.
|
|
rdBuf []byte
|
|
|
|
// List of symbol references for the file being read.
|
|
refs []*sym.Symbol
|
|
data []byte
|
|
reloc []sym.Reloc
|
|
pcdata []sym.Pcdata
|
|
funcdata []*sym.Symbol
|
|
funcdataoff []int64
|
|
file []*sym.Symbol
|
|
pkgpref string // objabi.PathToPrefix(r.lib.Pkg) + "."
|
|
|
|
roObject []byte // from read-only mmap of object file (may be nil)
|
|
roOffset int64 // offset into readonly object data examined so far
|
|
|
|
dataReadOnly bool // whether data is backed by read-only memory
|
|
}
|
|
|
|
// Flags to enable optional behavior during object loading/reading.
|
|
|
|
const (
|
|
NoFlag int = iota
|
|
|
|
// Sanity-check duplicate symbol contents, issuing warning
|
|
// when duplicates have different lengths or contents.
|
|
StrictDupsWarnFlag
|
|
|
|
// Similar to StrictDupsWarnFlag, but issue fatal error.
|
|
StrictDupsErrFlag
|
|
)
|
|
|
|
// Load loads an object file f into library lib.
|
|
// The symbols loaded are added to syms.
|
|
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int {
|
|
start := f.Offset()
|
|
roObject := f.SliceRO(uint64(length))
|
|
if roObject != nil {
|
|
f.MustSeek(int64(-length), os.SEEK_CUR)
|
|
}
|
|
r := &objReader{
|
|
rd: f,
|
|
lib: lib,
|
|
unit: unit,
|
|
arch: arch,
|
|
syms: syms,
|
|
pn: pn,
|
|
dupSym: &sym.Symbol{Name: ".dup"},
|
|
localSymVersion: syms.IncVersion(),
|
|
flags: flags,
|
|
roObject: roObject,
|
|
pkgpref: objabi.PathToPrefix(lib.Pkg) + ".",
|
|
}
|
|
r.loadObjFile()
|
|
if roObject != nil {
|
|
if r.roOffset != length {
|
|
log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length)
|
|
}
|
|
r.rd.MustSeek(int64(length), os.SEEK_CUR)
|
|
} else if f.Offset() != start+length {
|
|
log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
|
|
}
|
|
return r.strictDupMsgs
|
|
}
|
|
|
|
func (r *objReader) loadObjFile() {
|
|
// Magic header
|
|
var buf [8]uint8
|
|
r.readFull(buf[:])
|
|
if string(buf[:]) != startmagic {
|
|
if string(buf[:]) == goobj2.Magic {
|
|
log.Fatalf("found object file %s in new format, but -go115newobj is false\nset -go115newobj consistently in all -gcflags, -asmflags, and -ldflags", r.pn)
|
|
}
|
|
log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
|
|
}
|
|
|
|
// Version
|
|
c, err := r.readByte()
|
|
if err != nil || c != 1 {
|
|
log.Fatalf("%s: invalid file version number %d", r.pn, c)
|
|
}
|
|
|
|
// Autolib
|
|
for {
|
|
lib := r.readString()
|
|
if lib == "" {
|
|
break
|
|
}
|
|
r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
|
|
}
|
|
|
|
// DWARF strings
|
|
count := r.readInt()
|
|
r.unit.DWARFFileTable = make([]string, count)
|
|
for i := 0; i < count; i++ {
|
|
// TODO: This should probably be a call to mkROString.
|
|
r.unit.DWARFFileTable[i] = r.readString()
|
|
}
|
|
|
|
// Symbol references
|
|
r.refs = []*sym.Symbol{nil} // zeroth ref is nil
|
|
for {
|
|
c, err := r.peek(1)
|
|
if err != nil {
|
|
log.Fatalf("%s: peeking: %v", r.pn, err)
|
|
}
|
|
if c[0] == 0xff {
|
|
r.readByte()
|
|
break
|
|
}
|
|
r.readRef()
|
|
}
|
|
|
|
// Lengths
|
|
r.readSlices()
|
|
|
|
// Data section
|
|
err = r.readDataSection()
|
|
if err != nil {
|
|
log.Fatalf("%s: error reading %s", r.pn, err)
|
|
}
|
|
|
|
// Defined symbols
|
|
for {
|
|
c, err := r.peek(1)
|
|
if err != nil {
|
|
log.Fatalf("%s: peeking: %v", r.pn, err)
|
|
}
|
|
if c[0] == 0xff {
|
|
break
|
|
}
|
|
r.readSym()
|
|
}
|
|
|
|
// Magic footer
|
|
buf = [8]uint8{}
|
|
r.readFull(buf[:])
|
|
if string(buf[:]) != endmagic {
|
|
log.Fatalf("%s: invalid file end", r.pn)
|
|
}
|
|
}
|
|
|
|
func (r *objReader) readSlices() {
|
|
r.dataSize = r.readInt()
|
|
n := r.readInt()
|
|
r.reloc = make([]sym.Reloc, n)
|
|
n = r.readInt()
|
|
r.pcdata = make([]sym.Pcdata, n)
|
|
_ = r.readInt() // TODO: remove on next object file rev (autom count)
|
|
n = r.readInt()
|
|
r.funcdata = make([]*sym.Symbol, n)
|
|
r.funcdataoff = make([]int64, n)
|
|
n = r.readInt()
|
|
r.file = make([]*sym.Symbol, n)
|
|
}
|
|
|
|
func (r *objReader) readDataSection() (err error) {
|
|
if r.roObject != nil {
|
|
r.data, r.dataReadOnly, err =
|
|
r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil
|
|
r.roOffset += int64(r.dataSize)
|
|
return
|
|
}
|
|
r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize))
|
|
return
|
|
}
|
|
|
|
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
|
const symPrefix = 0xfe
|
|
|
|
func (r *objReader) readSym() {
|
|
var c byte
|
|
var err error
|
|
if c, err = r.readByte(); c != symPrefix || err != nil {
|
|
log.Fatalln("readSym out of sync")
|
|
}
|
|
if c, err = r.readByte(); err != nil {
|
|
log.Fatalln("error reading input: ", err)
|
|
}
|
|
t := sym.AbiSymKindToSymKind[c]
|
|
s := r.readSymIndex()
|
|
flags := r.readInt()
|
|
dupok := flags&1 != 0
|
|
local := flags&2 != 0
|
|
makeTypelink := flags&4 != 0
|
|
size := r.readInt()
|
|
typ := r.readSymIndex()
|
|
data := r.readData()
|
|
nreloc := r.readInt()
|
|
isdup := false
|
|
|
|
var dup *sym.Symbol
|
|
if s.Type != 0 && s.Type != sym.SXREF {
|
|
if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
|
|
if s.Size < int64(size) {
|
|
s.Size = int64(size)
|
|
}
|
|
if typ != nil && s.Gotype == nil {
|
|
s.Gotype = typ
|
|
}
|
|
return
|
|
}
|
|
|
|
if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
|
|
goto overwrite
|
|
}
|
|
if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
|
|
log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
|
|
}
|
|
if len(s.P) > 0 {
|
|
dup = s
|
|
s = r.dupSym
|
|
isdup = true
|
|
}
|
|
}
|
|
|
|
overwrite:
|
|
s.File = r.pkgpref[:len(r.pkgpref)-1]
|
|
s.Unit = r.unit
|
|
if dupok {
|
|
s.Attr |= sym.AttrDuplicateOK
|
|
}
|
|
if t == sym.SXREF {
|
|
log.Fatalf("bad sxref")
|
|
}
|
|
if t == 0 {
|
|
log.Fatalf("missing type for %s in %s", s.Name, r.pn)
|
|
}
|
|
if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
|
|
t = s.Type
|
|
}
|
|
s.Type = t
|
|
if s.Size < int64(size) {
|
|
s.Size = int64(size)
|
|
}
|
|
s.Attr.Set(sym.AttrLocal, local)
|
|
s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
|
|
if typ != nil {
|
|
s.Gotype = typ
|
|
}
|
|
if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
|
|
dup.Gotype = typ
|
|
}
|
|
s.P = data
|
|
s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly)
|
|
if nreloc > 0 {
|
|
s.R = r.reloc[:nreloc:nreloc]
|
|
if !isdup {
|
|
r.reloc = r.reloc[nreloc:]
|
|
}
|
|
|
|
for i := 0; i < nreloc; i++ {
|
|
s.R[i] = sym.Reloc{
|
|
Off: r.readInt32(),
|
|
Siz: r.readUint8(),
|
|
Type: objabi.RelocType(r.readInt32()),
|
|
Add: r.readInt64(),
|
|
Sym: r.readSymIndex(),
|
|
}
|
|
}
|
|
}
|
|
|
|
if s.Type == sym.STEXT {
|
|
s.FuncInfo = new(sym.FuncInfo)
|
|
pc := s.FuncInfo
|
|
|
|
pc.Args = r.readInt32()
|
|
pc.Locals = r.readInt32()
|
|
s.Align = r.readInt32()
|
|
if r.readUint8() != 0 {
|
|
s.Attr |= sym.AttrNoSplit
|
|
}
|
|
flags := r.readInt()
|
|
if flags&(1<<2) != 0 {
|
|
s.Attr |= sym.AttrReflectMethod
|
|
}
|
|
if flags&(1<<3) != 0 {
|
|
s.Attr |= sym.AttrShared
|
|
}
|
|
if flags&(1<<4) != 0 {
|
|
s.Attr |= sym.AttrTopFrame
|
|
}
|
|
n := r.readInt()
|
|
if n != 0 {
|
|
log.Fatalf("stale object file: autom count nonzero")
|
|
}
|
|
|
|
pc.Pcsp.P = r.readData()
|
|
pc.Pcfile.P = r.readData()
|
|
pc.Pcline.P = r.readData()
|
|
pc.Pcinline.P = r.readData()
|
|
n = r.readInt()
|
|
pc.Pcdata = r.pcdata[:n:n]
|
|
if !isdup {
|
|
r.pcdata = r.pcdata[n:]
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
pc.Pcdata[i].P = r.readData()
|
|
}
|
|
n = r.readInt()
|
|
pc.Funcdata = r.funcdata[:n:n]
|
|
pc.Funcdataoff = r.funcdataoff[:n:n]
|
|
if !isdup {
|
|
r.funcdata = r.funcdata[n:]
|
|
r.funcdataoff = r.funcdataoff[n:]
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
pc.Funcdata[i] = r.readSymIndex()
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
pc.Funcdataoff[i] = r.readInt64()
|
|
}
|
|
n = r.readInt()
|
|
pc.File = r.file[:n:n]
|
|
if !isdup {
|
|
r.file = r.file[n:]
|
|
}
|
|
for i := 0; i < n; i++ {
|
|
pc.File[i] = r.readSymIndex()
|
|
}
|
|
n = r.readInt()
|
|
pc.InlTree = make([]sym.InlinedCall, n)
|
|
for i := 0; i < n; i++ {
|
|
pc.InlTree[i].Parent = r.readInt32()
|
|
pc.InlTree[i].File = r.readSymIndex()
|
|
pc.InlTree[i].Line = r.readInt32()
|
|
pc.InlTree[i].Func = r.readSymIndex().Name
|
|
pc.InlTree[i].ParentPC = r.readInt32()
|
|
}
|
|
|
|
if !dupok {
|
|
if s.Attr.OnList() {
|
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
|
}
|
|
s.Attr |= sym.AttrOnList
|
|
r.lib.Textp = append(r.lib.Textp, s)
|
|
} else {
|
|
// there may ba a dup in another package
|
|
// put into a temp list and add to text later
|
|
if !isdup {
|
|
r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
|
|
} else {
|
|
r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
|
|
}
|
|
}
|
|
}
|
|
if s.Type == sym.SDWARFINFO {
|
|
r.patchDWARFName(s)
|
|
}
|
|
|
|
if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
|
|
// Compare the just-read symbol with the previously read
|
|
// symbol of the same name, verifying that they have the same
|
|
// payload. If not, issue a warning and possibly an error.
|
|
if !bytes.Equal(s.P, dup.P) {
|
|
reason := "same length but different contents"
|
|
if len(s.P) != len(dup.P) {
|
|
reason = fmt.Sprintf("new length %d != old length %d",
|
|
len(data), len(dup.P))
|
|
}
|
|
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
|
|
|
|
// For the moment, whitelist DWARF subprogram DIEs for
|
|
// auto-generated wrapper functions. What seems to happen
|
|
// here is that we get different line numbers on formal
|
|
// params; I am guessing that the pos is being inherited
|
|
// from the spot where the wrapper is needed.
|
|
whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
|
|
strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
|
|
strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
|
|
strings.HasPrefix(dup.Name, "go.debuglines"))
|
|
if !whitelist {
|
|
r.strictDupMsgs++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *objReader) patchDWARFName(s *sym.Symbol) {
|
|
// This is kind of ugly. Really the package name should not
|
|
// even be included here.
|
|
if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
|
|
return
|
|
}
|
|
e := bytes.IndexByte(s.P, 0)
|
|
if e == -1 {
|
|
return
|
|
}
|
|
p := bytes.Index(s.P[:e], emptyPkg)
|
|
if p == -1 {
|
|
return
|
|
}
|
|
pkgprefix := []byte(r.pkgpref)
|
|
patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
|
|
|
|
s.P = append(patched, s.P[e:]...)
|
|
delta := int64(len(s.P)) - s.Size
|
|
s.Size = int64(len(s.P))
|
|
for i := range s.R {
|
|
r := &s.R[i]
|
|
if r.Off > int32(e) {
|
|
r.Off += int32(delta)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *objReader) readFull(b []byte) {
|
|
if r.roObject != nil {
|
|
copy(b, r.roObject[r.roOffset:])
|
|
r.roOffset += int64(len(b))
|
|
return
|
|
}
|
|
_, err := io.ReadFull(r.rd, b)
|
|
if err != nil {
|
|
log.Fatalf("%s: error reading %s", r.pn, err)
|
|
}
|
|
}
|
|
|
|
func (r *objReader) readByte() (byte, error) {
|
|
if r.roObject != nil {
|
|
b := r.roObject[r.roOffset]
|
|
r.roOffset++
|
|
return b, nil
|
|
}
|
|
return r.rd.ReadByte()
|
|
}
|
|
|
|
func (r *objReader) peek(n int) ([]byte, error) {
|
|
if r.roObject != nil {
|
|
return r.roObject[r.roOffset : r.roOffset+int64(n)], nil
|
|
}
|
|
return r.rd.Peek(n)
|
|
}
|
|
|
|
func (r *objReader) readRef() {
|
|
if c, err := r.readByte(); c != symPrefix || err != nil {
|
|
log.Fatalf("readSym out of sync")
|
|
}
|
|
name := r.readSymName()
|
|
var v int
|
|
if abi := r.readInt(); abi == -1 {
|
|
// Static
|
|
v = r.localSymVersion
|
|
} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
|
|
// Note that data symbols are "ABI0", which maps to version 0.
|
|
v = abiver
|
|
} else {
|
|
log.Fatalf("invalid symbol ABI for %q: %d", name, abi)
|
|
}
|
|
s := r.syms.Lookup(name, v)
|
|
r.refs = append(r.refs, s)
|
|
|
|
if s == nil || v == r.localSymVersion {
|
|
return
|
|
}
|
|
if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
|
|
x, err := strconv.ParseUint(s.Name[5:], 16, 64)
|
|
if err != nil {
|
|
log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
|
|
}
|
|
s.Type = sym.SRODATA
|
|
s.Attr |= sym.AttrLocal
|
|
switch s.Name[:5] {
|
|
case "$f32.":
|
|
if uint64(uint32(x)) != x {
|
|
log.Panicf("$-symbol %s too large: %d", s.Name, x)
|
|
}
|
|
s.AddUint32(r.arch, uint32(x))
|
|
case "$f64.", "$i64.":
|
|
s.AddUint64(r.arch, x)
|
|
default:
|
|
log.Panicf("unrecognized $-symbol: %s", s.Name)
|
|
}
|
|
s.Attr.Set(sym.AttrReachable, false)
|
|
}
|
|
if strings.HasPrefix(s.Name, "runtime.gcbits.") {
|
|
s.Attr |= sym.AttrLocal
|
|
}
|
|
}
|
|
|
|
func (r *objReader) readInt64() int64 {
|
|
uv := uint64(0)
|
|
for shift := uint(0); ; shift += 7 {
|
|
if shift >= 64 {
|
|
log.Fatalf("corrupt input")
|
|
}
|
|
c, err := r.readByte()
|
|
if err != nil {
|
|
log.Fatalln("error reading input: ", err)
|
|
}
|
|
uv |= uint64(c&0x7F) << shift
|
|
if c&0x80 == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return int64(uv>>1) ^ (int64(uv<<63) >> 63)
|
|
}
|
|
|
|
func (r *objReader) readInt() int {
|
|
n := r.readInt64()
|
|
if int64(int(n)) != n {
|
|
log.Panicf("%v out of range for int", n)
|
|
}
|
|
return int(n)
|
|
}
|
|
|
|
func (r *objReader) readInt32() int32 {
|
|
n := r.readInt64()
|
|
if int64(int32(n)) != n {
|
|
log.Panicf("%v out of range for int32", n)
|
|
}
|
|
return int32(n)
|
|
}
|
|
|
|
func (r *objReader) readInt16() int16 {
|
|
n := r.readInt64()
|
|
if int64(int16(n)) != n {
|
|
log.Panicf("%v out of range for int16", n)
|
|
}
|
|
return int16(n)
|
|
}
|
|
|
|
func (r *objReader) readUint8() uint8 {
|
|
n := r.readInt64()
|
|
if int64(uint8(n)) != n {
|
|
log.Panicf("%v out of range for uint8", n)
|
|
}
|
|
return uint8(n)
|
|
}
|
|
|
|
func (r *objReader) readString() string {
|
|
n := r.readInt()
|
|
if cap(r.rdBuf) < n {
|
|
r.rdBuf = make([]byte, 2*n)
|
|
}
|
|
r.readFull(r.rdBuf[:n])
|
|
return string(r.rdBuf[:n])
|
|
}
|
|
|
|
func (r *objReader) readData() []byte {
|
|
n := r.readInt()
|
|
p := r.data[:n:n]
|
|
r.data = r.data[n:]
|
|
return p
|
|
}
|
|
|
|
func mkROString(rodata []byte) string {
|
|
if len(rodata) == 0 {
|
|
return ""
|
|
}
|
|
|
|
var s string
|
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
|
hdr.Data = unsafe.Pointer(&rodata[0])
|
|
hdr.Len = len(rodata)
|
|
|
|
return s
|
|
}
|
|
|
|
// readSymName reads a symbol name, replacing all "". with pkg.
|
|
func (r *objReader) readSymName() string {
|
|
n := r.readInt()
|
|
if n == 0 {
|
|
r.readInt64()
|
|
return ""
|
|
}
|
|
if cap(r.rdBuf) < n {
|
|
r.rdBuf = make([]byte, 2*n)
|
|
}
|
|
sOffset := r.roOffset
|
|
origName, err := r.peek(n)
|
|
if err == bufio.ErrBufferFull {
|
|
// Long symbol names are rare but exist. One source is type
|
|
// symbols for types with long string forms. See #15104.
|
|
origName = make([]byte, n)
|
|
r.readFull(origName)
|
|
} else if err != nil {
|
|
log.Fatalf("%s: error reading symbol: %v", r.pn, err)
|
|
}
|
|
adjName := r.rdBuf[:0]
|
|
nPkgRefs := 0
|
|
for {
|
|
i := bytes.Index(origName, emptyPkg)
|
|
if i == -1 {
|
|
var s string
|
|
if r.roObject != nil && nPkgRefs == 0 {
|
|
s = mkROString(r.roObject[sOffset : sOffset+int64(n)])
|
|
} else {
|
|
s = string(append(adjName, origName...))
|
|
}
|
|
// Read past the peeked origName, now that we're done with it,
|
|
// using the rfBuf (also no longer used) as the scratch space.
|
|
// TODO: use bufio.Reader.Discard if available instead?
|
|
if err == nil {
|
|
r.readFull(r.rdBuf[:n])
|
|
}
|
|
r.rdBuf = adjName[:0] // in case 2*n wasn't enough
|
|
return s
|
|
}
|
|
nPkgRefs++
|
|
adjName = append(adjName, origName[:i]...)
|
|
adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...)
|
|
adjName = append(adjName, '.')
|
|
origName = origName[i+len(emptyPkg):]
|
|
}
|
|
}
|
|
|
|
// Reads the index of a symbol reference and resolves it to a symbol
|
|
func (r *objReader) readSymIndex() *sym.Symbol {
|
|
i := r.readInt()
|
|
return r.refs[i]
|
|
}
|