Filippo Valsorda 608cdcaede all: replace usages of whitelist/blacklist and master/slave
There's been plenty of discussion on the usage of these terms in tech.
I'm not trying to have yet another debate. It's clear that there are
people who are hurt by them and who are made to feel unwelcome by their
use due not to technical reasons but to their historical and social
context. That's simply enough reason to replace them.

Anyway, allowlist and blocklist are more self-explanatory than whitelist
and blacklist, so this change has negative cost.

Didn't change vendored, bundled, and minified files. Nearly all changes
are tests or comments, with a couple renames in cmd/link and cmd/oldlink
which are extremely safe. This should be fine to land during the freeze
without even asking for an exception.

Change-Id: I8fc54a3c8f9cc1973b710bbb9558a9e45810b896
Reviewed-on: https://go-review.googlesource.com/c/go/+/236857
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Khosrow Moossavi <khos2ow@gmail.com>
Reviewed-by: Leigh McCulloch <leighmcc@gmail.com>
Reviewed-by: Urban Ishimwe <urbainishimwe@gmail.com>
2020-06-08 01:03:14 +00:00

665 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, allowlist 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.
allowlist := (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 !allowlist {
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]
}