aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-12-22 16:54:51 -0500
committerRuss Cox <rsc@golang.org>2020-12-22 16:55:15 -0500
commitec741b04470cda8df5902f1d8d84ab15cb2c8b8b (patch)
tree06682f85c7951b2a94423c01ea6008af4d558053 /src
parentacc32ea124957ad4b097186fb2f6da8122a9a5d1 (diff)
parentc9fb4eb0a22131cc9922fa96afba01d4e21d4fd4 (diff)
downloadgo-ec741b04470cda8df5902f1d8d84ab15cb2c8b8b.tar.xz
[dev.regabi] all: merge master (c9fb4eb) into dev.regabi
Merge List: * 2020-12-22 c9fb4eb0a2 cmd/link: handle grouped resource sections * 2020-12-22 c06a354bcc test: trigger SIGSEGV instead of SIGTRAP in issue11656.go * 2020-12-22 0aa9b4709a cmd/pack: r command create output file if not exist * 2020-12-22 4d27c4c223 runtime: correct error handling in several FreeBSD syscall wrappers * 2020-12-22 9b6147120a cmd/pack: treat compiler's -linkobj output as "compiler object" * 2020-12-21 bc7e4d9257 syscall: don't generate ptrace on iOS * 2020-12-21 6cff874c47 runtime/metrics: add Read examples * 2020-12-21 8438a5779b runtime: use _exit on darwin * 2020-12-21 cb95819cf6 runtime: detect netbsd netpoll overrun in sysmon * 2020-12-21 53c984d976 runtime: skip wakep call in wakeNetPoller on Plan 9 * 2020-12-21 9abbe27710 test: skip issue11656.go on mips/mips64/ppc64 Change-Id: Ibb235fbf6a86ebcf50c686dc11f7c02d1865f845
Diffstat (limited to 'src')
-rw-r--r--src/cmd/link/internal/ld/lib.go2
-rw-r--r--src/cmd/link/internal/ld/pe.go60
-rw-r--r--src/cmd/link/internal/loadpe/ldpe.go49
-rw-r--r--src/cmd/link/link_test.go19
-rw-r--r--src/cmd/link/testdata/testPErsrc-complex/main.go43
-rw-r--r--src/cmd/link/testdata/testPErsrc-complex/rsrc.sysobin0 -> 352 bytes
-rw-r--r--src/cmd/pack/pack.go38
-rw-r--r--src/cmd/pack/pack_test.go89
-rw-r--r--src/runtime/defs_freebsd_386.go9
-rw-r--r--src/runtime/defs_freebsd_amd64.go9
-rw-r--r--src/runtime/defs_freebsd_arm.go9
-rw-r--r--src/runtime/defs_freebsd_arm64.go9
-rw-r--r--src/runtime/metrics/example_test.go96
-rw-r--r--src/runtime/os_freebsd.go3
-rw-r--r--src/runtime/proc.go24
-rw-r--r--src/runtime/sys_darwin.go2
-rw-r--r--src/runtime/sys_freebsd_386.s6
-rw-r--r--src/runtime/sys_freebsd_amd64.s6
-rw-r--r--src/runtime/sys_freebsd_arm.s3
-rw-r--r--src/runtime/sys_freebsd_arm64.s6
-rwxr-xr-xsrc/syscall/mksyscall.pl2
-rw-r--r--src/syscall/ptrace_darwin.go14
-rw-r--r--src/syscall/ptrace_ios.go12
-rw-r--r--src/syscall/syscall_darwin_amd64.go2
-rw-r--r--src/syscall/syscall_darwin_arm64.go2
-rw-r--r--src/syscall/zsyscall_darwin_amd64.go2
-rw-r--r--src/syscall/zsyscall_darwin_arm64.go2
27 files changed, 429 insertions, 89 deletions
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 833b3eb9db..bf95745d8d 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1820,7 +1820,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
Errorf(nil, "%v", err)
return
}
- if rsrc != 0 {
+ if len(rsrc) != 0 {
setpersrc(ctxt, rsrc)
}
ctxt.Textp = append(ctxt.Textp, textp...)
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index adbf516d5c..5edaf54dd2 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -253,7 +253,7 @@ type Dll struct {
}
var (
- rsrcsym loader.Sym
+ rsrcsyms []loader.Sym
PESECTHEADR int32
PEFILEHEADR int32
pe64 int
@@ -1508,46 +1508,56 @@ func (ctxt *Link) dope() {
initdynexport(ctxt)
}
-func setpersrc(ctxt *Link, sym loader.Sym) {
- if rsrcsym != 0 {
+func setpersrc(ctxt *Link, syms []loader.Sym) {
+ if len(rsrcsyms) != 0 {
Errorf(nil, "too many .rsrc sections")
}
-
- rsrcsym = sym
+ rsrcsyms = syms
}
func addpersrc(ctxt *Link) {
- if rsrcsym == 0 {
+ if len(rsrcsyms) == 0 {
return
}
- data := ctxt.loader.Data(rsrcsym)
- size := len(data)
- h := pefile.addSection(".rsrc", size, size)
+ var size int64
+ for _, rsrcsym := range rsrcsyms {
+ size += ctxt.loader.SymSize(rsrcsym)
+ }
+ h := pefile.addSection(".rsrc", int(size), int(size))
h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
h.checkOffset(ctxt.Out.Offset())
- // relocation
- relocs := ctxt.loader.Relocs(rsrcsym)
- for i := 0; i < relocs.Count(); i++ {
- r := relocs.At(i)
- p := data[r.Off():]
- val := uint32(int64(h.virtualAddress) + r.Add())
-
- // 32-bit little-endian
- p[0] = byte(val)
-
- p[1] = byte(val >> 8)
- p[2] = byte(val >> 16)
- p[3] = byte(val >> 24)
+ for _, rsrcsym := range rsrcsyms {
+ // A split resource happens when the actual resource data and its relocations are
+ // split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc
+ // section name.
+ splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
+ relocs := ctxt.loader.Relocs(rsrcsym)
+ data := ctxt.loader.Data(rsrcsym)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At(ri)
+ p := data[r.Off():]
+ val := uint32(int64(h.virtualAddress) + r.Add())
+ if splitResources {
+ // If we're a split resource section, and that section has relocation
+ // symbols, then the data that it points to doesn't actually begin at
+ // the virtual address listed in this current section, but rather
+ // begins at the section immediately after this one. So, in order to
+ // calculate the proper virtual address of the data it's pointing to,
+ // we have to add the length of this section to the virtual address.
+ // This works because .rsrc sections are divided into two (but not more)
+ // of these sections.
+ val += uint32(len(data))
+ }
+ binary.LittleEndian.PutUint32(p, val)
+ }
+ ctxt.Out.Write(data)
}
-
- ctxt.Out.Write(data)
h.pad(ctxt.Out, uint32(size))
// update data directory
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
-
pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
}
diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go
index 1e6f978531..a5c025de8f 100644
--- a/src/cmd/link/internal/loadpe/ldpe.go
+++ b/src/cmd/link/internal/loadpe/ldpe.go
@@ -157,8 +157,9 @@ func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loa
// Load loads the PE file pn from input.
// Symbols are written into syms, and a slice of the text symbols is returned.
-// If an .rsrc section is found, its symbol is returned as rsrc.
-func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc loader.Sym, err error) {
+// If an .rsrc section or set of .rsrc$xx sections is found, its symbols are
+// returned as rsrc.
+func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc []loader.Sym, err error) {
lookup := func(name string, version int) (*loader.SymbolBuilder, loader.Sym) {
s := l.LookupOrCreateSym(name, version)
sb := l.MakeSymbolUpdater(s)
@@ -176,7 +177,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
// TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
f, err := pe.NewFile(sr)
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
defer f.Close()
@@ -211,21 +212,21 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
bld.SetType(sym.STEXT)
default:
- return nil, 0, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
+ return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
}
if bld.Type() != sym.SNOPTRBSS {
data, err := sect.Data()
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
sectdata[sect] = data
bld.SetData(data)
}
bld.SetSize(int64(sect.Size))
sectsyms[sect] = s
- if sect.Name == ".rsrc" {
- rsrc = s
+ if sect.Name == ".rsrc" || strings.HasPrefix(sect.Name, ".rsrc$") {
+ rsrc = append(rsrc, s)
}
}
@@ -246,22 +247,23 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
continue
}
+ splitResources := strings.HasPrefix(rsect.Name, ".rsrc$")
sb := l.MakeSymbolUpdater(sectsyms[rsect])
for j, r := range rsect.Relocs {
if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
- return nil, 0, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
+ return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
}
pesym := &f.COFFSymbols[r.SymbolTableIndex]
_, gosym, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
if gosym == 0 {
name, err := pesym.FullName(f.StringTable)
if err != nil {
name = string(pesym.Name[:])
}
- return nil, 0, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
+ return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
}
rSym := gosym
@@ -271,11 +273,11 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
var rType objabi.RelocType
switch arch.Family {
default:
- return nil, 0, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
+ return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
case sys.I386, sys.AMD64:
switch r.Type {
default:
- return nil, 0, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
+ return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
@@ -302,7 +304,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
case sys.ARM:
switch r.Type {
default:
- return nil, 0, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
+ return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_ARM_SECREL:
rType = objabi.R_PCREL
@@ -323,8 +325,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
// ld -r could generate multiple section symbols for the
// same section but with different values, we have to take
- // that into account
- if issect(pesym) {
+ // that into account, or in the case of split resources,
+ // the section and its symbols are split into two sections.
+ if issect(pesym) || splitResources {
rAdd += int64(pesym.Value)
}
@@ -346,7 +349,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
name, err := pesym.FullName(f.StringTable)
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
if name == "" {
continue
@@ -384,7 +387,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
bld, s, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion)
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
if pesym.SectionNumber == 0 { // extern
@@ -402,14 +405,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
} else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
sect = f.Sections[pesym.SectionNumber-1]
if _, found := sectsyms[sect]; !found {
- return nil, 0, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
+ return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s)
}
} else {
- return nil, 0, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
+ return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s)
}
if sect == nil {
- return nil, 0, nil
+ return nil, nil, nil
}
if l.OuterSym(s) != 0 {
@@ -418,7 +421,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
}
outerName := l.SymName(l.OuterSym(s))
sectName := l.SymName(sectsyms[sect])
- return nil, 0, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName)
+ return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName)
}
bld = makeUpdater(l, bld, s)
@@ -429,7 +432,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
bld.SetSize(4)
if l.SymType(sectsym) == sym.STEXT {
if bld.External() && !bld.DuplicateOK() {
- return nil, 0, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s))
+ return nil, nil, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s))
}
bld.SetExternal(true)
}
@@ -446,7 +449,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
if l.SymType(s) == sym.STEXT {
for ; s != 0; s = l.SubSym(s) {
if l.AttrOnList(s) {
- return nil, 0, fmt.Errorf("symbol %s listed multiple times", l.SymName(s))
+ return nil, nil, fmt.Errorf("symbol %s listed multiple times", l.SymName(s))
}
l.SetAttrOnList(s, true)
textp = append(textp, s)
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 4eb02c9e8a..7eeb7ef568 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -786,6 +786,25 @@ func TestPErsrc(t *testing.T) {
if !bytes.Contains(b, []byte("Hello Gophers!")) {
t.Fatalf("binary does not contain expected content")
}
+
+ pkgdir = filepath.Join("testdata", "testPErsrc-complex")
+ exe = filepath.Join(tmpdir, "a.exe")
+ cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+ cmd.Dir = pkgdir
+ // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("building failed: %v, output:\n%s", err, out)
+ }
+
+ // Check that the binary contains the rsrc data
+ b, err = ioutil.ReadFile(exe)
+ if err != nil {
+ t.Fatalf("reading output failed: %v", err)
+ }
+ if !bytes.Contains(b, []byte("resname RCDATA a.rc")) {
+ t.Fatalf("binary does not contain expected content")
+ }
}
func TestContentAddressableSymbols(t *testing.T) {
diff --git a/src/cmd/link/testdata/testPErsrc-complex/main.go b/src/cmd/link/testdata/testPErsrc-complex/main.go
new file mode 100644
index 0000000000..affd6eada2
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc-complex/main.go
@@ -0,0 +1,43 @@
+// Copyright 2020 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.
+
+// Test that a PE rsrc section is handled correctly, when the object files
+// have been created by llvm-rc or msvc's rc.exe, which means there's the
+// @feat.00 symbol as well as split .rsrc$00 and .rsrc$01 section to deal with.
+//
+// rsrc.syso is created with:
+// windres -i a.rc -o rsrc.syso -O coff
+// where this windres calls into llvm-rc and llvm-cvtres. The source file,
+// a.rc, simply contains a reference to its own bytes:
+//
+// resname RCDATA a.rc
+//
+// Object dumping the resultant rsrc.syso, we can see the split sections and
+// the @feat.00 SEH symbol:
+//
+// rsrc.syso: file format coff-x86-64
+//
+// architecture: x86_64
+// start address: 0x0000000000000000
+//
+// Export Table:
+// Sections:
+// Idx Name Size VMA Type
+// 0 .rsrc$01 00000068 0000000000000000 DATA
+// 1 .rsrc$02 00000018 0000000000000000 DATA
+//
+// SYMBOL TABLE:
+// [ 0](sec -1)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x00000011 @feat.00
+// [ 1](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rsrc$01
+// AUX scnlen 0x68 nreloc 1 nlnno 0 checksum 0x0 assoc 0 comdat 0
+// [ 3](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rsrc$02
+// AUX scnlen 0x18 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
+// [ 5](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 0) 0x00000000 $R000000
+// RELOCATION RECORDS FOR [.rsrc$01]:
+// OFFSET TYPE VALUE
+// 0000000000000048 IMAGE_REL_AMD64_ADDR32NB $R000000
+
+package main
+
+func main() {}
diff --git a/src/cmd/link/testdata/testPErsrc-complex/rsrc.syso b/src/cmd/link/testdata/testPErsrc-complex/rsrc.syso
new file mode 100644
index 0000000000..eff630b8a2
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc-complex/rsrc.syso
Binary files differ
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index 82546ea7dc..412ea36d60 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -43,7 +43,7 @@ func main() {
ar = openArchive(os.Args[2], os.O_RDONLY, os.Args[3:])
ar.scan(ar.printContents)
case 'r':
- ar = openArchive(os.Args[2], os.O_RDWR, os.Args[3:])
+ ar = openArchive(os.Args[2], os.O_RDWR|os.O_CREATE, os.Args[3:])
ar.addFiles()
case 'c':
ar = openArchive(os.Args[2], os.O_RDWR|os.O_TRUNC|os.O_CREATE, os.Args[3:])
@@ -124,10 +124,13 @@ func openArchive(name string, mode int, files []string) *Archive {
log.Fatal(err)
}
var a *archive.Archive
- if mode&os.O_CREATE != 0 { // the c command
+ if mode&os.O_TRUNC != 0 { // the c command
a, err = archive.New(f)
} else {
a, err = archive.Parse(f, verbose)
+ if err != nil && mode&os.O_CREATE != 0 { // the r command
+ a, err = archive.New(f)
+ }
}
if err != nil {
log.Fatal(err)
@@ -315,20 +318,25 @@ func (ar *Archive) extractContents1(e *archive.Entry, out io.Writer) {
}
// isGoCompilerObjFile reports whether file is an object file created
-// by the Go compiler, which is an archive file with exactly two entries:
-// __.PKGDEF and _go_.o.
+// by the Go compiler, which is an archive file with exactly one entry
+// of __.PKGDEF, or _go_.o, or both entries.
func isGoCompilerObjFile(a *archive.Archive) bool {
- if len(a.Entries) != 2 {
- return false
- }
- var foundPkgDef, foundGo bool
- for _, e := range a.Entries {
- if e.Type == archive.EntryPkgDef && e.Name == "__.PKGDEF" {
- foundPkgDef = true
- }
- if e.Type == archive.EntryGoObj && e.Name == "_go_.o" {
- foundGo = true
+ switch len(a.Entries) {
+ case 1:
+ return (a.Entries[0].Type == archive.EntryGoObj && a.Entries[0].Name == "_go_.o") ||
+ (a.Entries[0].Type == archive.EntryPkgDef && a.Entries[0].Name == "__.PKGDEF")
+ case 2:
+ var foundPkgDef, foundGo bool
+ for _, e := range a.Entries {
+ if e.Type == archive.EntryPkgDef && e.Name == "__.PKGDEF" {
+ foundPkgDef = true
+ }
+ if e.Type == archive.EntryGoObj && e.Name == "_go_.o" {
+ foundGo = true
+ }
}
+ return foundPkgDef && foundGo
+ default:
+ return false
}
- return foundPkgDef && foundGo
}
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index 218c7acda6..118376f9df 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -302,6 +302,95 @@ func TestIssue21703(t *testing.T) {
run(goBin, "tool", "compile", "-I", ".", "b.go")
}
+// Test the "c" command can "see through" the archive generated by the compiler.
+// This is peculiar. (See issue #43271)
+func TestCreateWithCompilerObj(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ src := filepath.Join(dir, "p.go")
+ prog := "package p; var X = 42\n"
+ err := os.WriteFile(src, []byte(prog), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ run := func(args ...string) string {
+ return doRun(t, dir, args...)
+ }
+
+ goBin := testenv.GoToolPath(t)
+ run(goBin, "build", "cmd/pack") // writes pack binary to dir
+ run(goBin, "tool", "compile", "-pack", "-o", "p.a", "p.go")
+ run("./pack", "c", "packed.a", "p.a")
+ fi, err := os.Stat(filepath.Join(dir, "p.a"))
+ if err != nil {
+ t.Fatalf("stat p.a failed: %v", err)
+ }
+ fi2, err := os.Stat(filepath.Join(dir, "packed.a"))
+ if err != nil {
+ t.Fatalf("stat packed.a failed: %v", err)
+ }
+ // For compiler-generated object file, the "c" command is
+ // expected to get (essentially) the same file back, instead
+ // of packing it into a new archive with a single entry.
+ if want, got := fi.Size(), fi2.Size(); want != got {
+ t.Errorf("packed file with different size: want %d, got %d", want, got)
+ }
+
+ // Test -linkobj flag as well.
+ run(goBin, "tool", "compile", "-linkobj", "p2.a", "-o", "p.x", "p.go")
+ run("./pack", "c", "packed2.a", "p2.a")
+ fi, err = os.Stat(filepath.Join(dir, "p2.a"))
+ if err != nil {
+ t.Fatalf("stat p2.a failed: %v", err)
+ }
+ fi2, err = os.Stat(filepath.Join(dir, "packed2.a"))
+ if err != nil {
+ t.Fatalf("stat packed2.a failed: %v", err)
+ }
+ if want, got := fi.Size(), fi2.Size(); want != got {
+ t.Errorf("packed file with different size: want %d, got %d", want, got)
+ }
+
+ run("./pack", "c", "packed3.a", "p.x")
+ fi, err = os.Stat(filepath.Join(dir, "p.x"))
+ if err != nil {
+ t.Fatalf("stat p.x failed: %v", err)
+ }
+ fi2, err = os.Stat(filepath.Join(dir, "packed3.a"))
+ if err != nil {
+ t.Fatalf("stat packed3.a failed: %v", err)
+ }
+ if want, got := fi.Size(), fi2.Size(); want != got {
+ t.Errorf("packed file with different size: want %d, got %d", want, got)
+ }
+}
+
+// Test the "r" command creates the output file if it does not exist.
+func TestRWithNonexistentFile(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ dir := tmpDir(t)
+ defer os.RemoveAll(dir)
+ src := filepath.Join(dir, "p.go")
+ prog := "package p; var X = 42\n"
+ err := os.WriteFile(src, []byte(prog), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ run := func(args ...string) string {
+ return doRun(t, dir, args...)
+ }
+
+ goBin := testenv.GoToolPath(t)
+ run(goBin, "build", "cmd/pack") // writes pack binary to dir
+ run(goBin, "tool", "compile", "-o", "p.o", "p.go")
+ run("./pack", "r", "p.a", "p.o") // should succeed
+}
+
// doRun runs a program in a directory and returns the output.
func doRun(t *testing.T, dir string, args ...string) string {
cmd := exec.Command(args[0], args[1:]...)
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
index 767755425c..f822934d58 100644
--- a/src/runtime/defs_freebsd_386.go
+++ b/src/runtime/defs_freebsd_386.go
@@ -13,10 +13,11 @@ const (
)
const (
- _EINTR = 0x4
- _EFAULT = 0xe
- _EAGAIN = 0x23
- _ENOSYS = 0x4e
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EAGAIN = 0x23
+ _ENOSYS = 0x4e
+ _ETIMEDOUT = 0x3c
_O_NONBLOCK = 0x4
_O_CLOEXEC = 0x100000
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
index 5a833426fd..0b696cf227 100644
--- a/src/runtime/defs_freebsd_amd64.go
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -13,10 +13,11 @@ const (
)
const (
- _EINTR = 0x4
- _EFAULT = 0xe
- _EAGAIN = 0x23
- _ENOSYS = 0x4e
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EAGAIN = 0x23
+ _ENOSYS = 0x4e
+ _ETIMEDOUT = 0x3c
_O_NONBLOCK = 0x4
_O_CLOEXEC = 0x100000
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
index b55dfd88cf..b6f3e790cf 100644
--- a/src/runtime/defs_freebsd_arm.go
+++ b/src/runtime/defs_freebsd_arm.go
@@ -13,10 +13,11 @@ const (
)
const (
- _EINTR = 0x4
- _EFAULT = 0xe
- _EAGAIN = 0x23
- _ENOSYS = 0x4e
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EAGAIN = 0x23
+ _ENOSYS = 0x4e
+ _ETIMEDOUT = 0x3c
_O_NONBLOCK = 0x4
_O_CLOEXEC = 0x100000
diff --git a/src/runtime/defs_freebsd_arm64.go b/src/runtime/defs_freebsd_arm64.go
index 5b9d504ba6..0759a1238f 100644
--- a/src/runtime/defs_freebsd_arm64.go
+++ b/src/runtime/defs_freebsd_arm64.go
@@ -13,10 +13,11 @@ const (
)
const (
- _EINTR = 0x4
- _EFAULT = 0xe
- _EAGAIN = 0x23
- _ENOSYS = 0x4e
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _EAGAIN = 0x23
+ _ENOSYS = 0x4e
+ _ETIMEDOUT = 0x3c
_O_NONBLOCK = 0x4
_O_CLOEXEC = 0x100000
diff --git a/src/runtime/metrics/example_test.go b/src/runtime/metrics/example_test.go
new file mode 100644
index 0000000000..cade0c38bf
--- /dev/null
+++ b/src/runtime/metrics/example_test.go
@@ -0,0 +1,96 @@
+// Copyright 2020 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 metrics_test
+
+import (
+ "fmt"
+ "runtime/metrics"
+)
+
+func ExampleRead_readingOneMetric() {
+ // Name of the metric we want to read.
+ const myMetric = "/memory/classes/heap/free:bytes"
+
+ // Create a sample for the metric.
+ sample := make([]metrics.Sample, 1)
+ sample[0].Name = myMetric
+
+ // Sample the metric.
+ metrics.Read(sample)
+
+ // Check if the metric is actually supported.
+ // If it's not, the resulting value will always have
+ // kind KindBad.
+ if sample[0].Value.Kind() == metrics.KindBad {
+ panic(fmt.Sprintf("metric %q no longer supported", myMetric))
+ }
+
+ // Handle the result.
+ //
+ // It's OK to assume a particular Kind for a metric;
+ // they're guaranteed not to change.
+ freeBytes := sample[0].Value.Uint64()
+
+ fmt.Printf("free but not released memory: %d\n", freeBytes)
+}
+
+func ExampleRead_readingAllMetrics() {
+ // Get descriptions for all supported metrics.
+ descs := metrics.All()
+
+ // Create a sample for each metric.
+ samples := make([]metrics.Sample, len(descs))
+ for i := range samples {
+ samples[i].Name = descs[i].Name
+ }
+
+ // Sample the metrics. Re-use the samples slice if you can!
+ metrics.Read(samples)
+
+ // Iterate over all results.
+ for _, sample := range samples {
+ // Pull out the name and value.
+ name, value := sample.Name, sample.Value
+
+ // Handle each sample.
+ switch value.Kind() {
+ case metrics.KindUint64:
+ fmt.Printf("%s: %d\n", name, value.Uint64())
+ case metrics.KindFloat64:
+ fmt.Printf("%s: %f\n", name, value.Float64())
+ case metrics.KindFloat64Histogram:
+ // The histogram may be quite large, so let's just pull out
+ // a crude estimate for the median for the sake of this example.
+ fmt.Printf("%s: %f\n", name, medianBucket(value.Float64Histogram()))
+ case metrics.KindBad:
+ // This should never happen because all metrics are supported
+ // by construction.
+ panic("bug in runtime/metrics package!")
+ default:
+ // This may happen as new metrics get added.
+ //
+ // The safest thing to do here is to simply log it somewhere
+ // as something to look into, but ignore it for now.
+ // In the worst case, you might temporarily miss out on a new metric.
+ fmt.Printf("%s: unexpected metric Kind: %v\n", name, value.Kind())
+ }
+ }
+}
+
+func medianBucket(h *metrics.Float64Histogram) float64 {
+ total := uint64(0)
+ for _, count := range h.Counts {
+ total += count
+ }
+ thresh := total / 2
+ total = 0
+ for i, count := range h.Counts {
+ total += count
+ if total > thresh {
+ return h.Buckets[i]
+ }
+ }
+ panic("should not happen")
+}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 730973a202..1c60ee2a57 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -166,7 +166,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) {
utp = &ut
}
ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
- if ret >= 0 || ret == -_EINTR {
+ if ret >= 0 || ret == -_EINTR || ret == -_ETIMEDOUT {
return
}
print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
@@ -208,7 +208,6 @@ func newosproc(mp *m) {
var oset sigset
sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
- // TODO: Check for error.
ret := thr_new(&param, int32(unsafe.Sizeof(param)))
sigprocmask(_SIG_SETMASK, &oset, nil)
if ret < 0 {
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 64e102fb0a..5adcbf07dc 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -2882,7 +2882,9 @@ func wakeNetPoller(when int64) {
} else {
// There are no threads in the network poller, try to get
// one there so it can handle new timers.
- wakep()
+ if GOOS != "plan9" { // Temporary workaround - see issue #42303.
+ wakep()
+ }
}
}
@@ -5128,6 +5130,26 @@ func sysmon() {
}
}
mDoFixup()
+ if GOOS == "netbsd" {
+ // netpoll is responsible for waiting for timer
+ // expiration, so we typically don't have to worry
+ // about starting an M to service timers. (Note that
+ // sleep for timeSleepUntil above simply ensures sysmon
+ // starts running again when that timer expiration may
+ // cause Go code to run again).
+ //
+ // However, netbsd has a kernel bug that sometimes
+ // misses netpollBreak wake-ups, which can lead to
+ // unbounded delays servicing timers. If we detect this
+ // overrun, then startm to get something to handle the
+ // timer.
+ //
+ // See issue 42515 and
+ // https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50094.
+ if next, _ := timeSleepUntil(); next < now {
+ startm(nil, false)
+ }
+ }
if atomic.Load(&scavenge.sysmonWake) != 0 {
// Kick the scavenger awake if someone requested it.
wakeScavenger()
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index c89ce78012..55845bf2e5 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -467,7 +467,7 @@ func setNonblock(fd int32) {
//go:cgo_import_dynamic libc_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_self pthread_self "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_kill pthread_kill "/usr/lib/libSystem.B.dylib"
-//go:cgo_import_dynamic libc_exit exit "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_exit _exit "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_raise raise "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_open open "/usr/lib/libSystem.B.dylib"
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index c346e719e1..97e6d9ab36 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -13,12 +13,16 @@
TEXT runtime·sys_umtx_op(SB),NOSPLIT,$-4
MOVL $454, AX
INT $0x80
+ JAE 2(PC)
+ NEGL AX
MOVL AX, ret+20(FP)
RET
TEXT runtime·thr_new(SB),NOSPLIT,$-4
MOVL $455, AX
INT $0x80
+ JAE 2(PC)
+ NEGL AX
MOVL AX, ret+8(FP)
RET
@@ -120,6 +124,8 @@ TEXT runtime·pipe2(SB),NOSPLIT,$12-16
MOVL flags+0(FP), BX
MOVL BX, 8(SP)
INT $0x80
+ JAE 2(PC)
+ NEGL AX
MOVL AX, errno+12(FP)
RET
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 010b2ec4d4..07734b0d7d 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -18,6 +18,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVQ ut+24(FP), R8
MOVL $454, AX
SYSCALL
+ JCC 2(PC)
+ NEGQ AX
MOVL AX, ret+32(FP)
RET
@@ -26,6 +28,8 @@ TEXT runtime·thr_new(SB),NOSPLIT,$0
MOVL size+8(FP), SI
MOVL $455, AX
SYSCALL
+ JCC 2(PC)
+ NEGQ AX
MOVL AX, ret+16(FP)
RET
@@ -118,6 +122,8 @@ TEXT runtime·pipe2(SB),NOSPLIT,$0-20
MOVL flags+0(FP), SI
MOVL $542, AX
SYSCALL
+ JCC 2(PC)
+ NEGQ AX
MOVL AX, errno+16(FP)
RET
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 1e12f9cfcb..b12e47c576 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -51,6 +51,7 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
ADD $20, R13 // arg 5 is passed on stack
MOVW $SYS__umtx_op, R7
SWI $0
+ RSB.CS $0, R0
SUB $20, R13
// BCS error
MOVW R0, ret+20(FP)
@@ -61,6 +62,7 @@ TEXT runtime·thr_new(SB),NOSPLIT,$0
MOVW size+4(FP), R1
MOVW $SYS_thr_new, R7
SWI $0
+ RSB.CS $0, R0
MOVW R0, ret+8(FP)
RET
@@ -144,6 +146,7 @@ TEXT runtime·pipe2(SB),NOSPLIT,$0-16
MOVW flags+0(FP), R1
MOVW $SYS_pipe2, R7
SWI $0
+ RSB.CS $0, R0
MOVW R0, errno+12(FP)
RET
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
index 8a4f9b7fa1..1aa09e87ca 100644
--- a/src/runtime/sys_freebsd_arm64.s
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -60,6 +60,9 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVD ut+24(FP), R4
MOVD $SYS__umtx_op, R8
SVC
+ BCC ok
+ NEG R0, R0
+ok:
MOVW R0, ret+32(FP)
RET
@@ -69,6 +72,9 @@ TEXT runtime·thr_new(SB),NOSPLIT,$0
MOVW size+8(FP), R1
MOVD $SYS_thr_new, R8
SVC
+ BCC ok
+ NEG R0, R0
+ok:
MOVW R0, ret+16(FP)
RET
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index 790df3825b..26c93ffe5b 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -125,7 +125,7 @@ while(<>) {
# without reading the header.
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
- if ($darwin && $func eq "ptrace") {
+ if ($darwin && $func eq "ptrace1") {
# The ptrace function is called from forkAndExecInChild where stack
# growth is forbidden.
$text .= "//go:nosplit\n"
diff --git a/src/syscall/ptrace_darwin.go b/src/syscall/ptrace_darwin.go
new file mode 100644
index 0000000000..a873d826b8
--- /dev/null
+++ b/src/syscall/ptrace_darwin.go
@@ -0,0 +1,14 @@
+// Copyright 2020 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.
+
+// +build !ios
+
+package syscall
+
+// Nosplit because it is called from forkAndExecInChild.
+//
+//go:nosplit
+func ptrace(request int, pid int, addr uintptr, data uintptr) error {
+ return ptrace1(request, pid, addr, data)
+}
diff --git a/src/syscall/ptrace_ios.go b/src/syscall/ptrace_ios.go
new file mode 100644
index 0000000000..2f61a88a08
--- /dev/null
+++ b/src/syscall/ptrace_ios.go
@@ -0,0 +1,12 @@
+// Copyright 2020 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 syscall
+
+// Nosplit because it is called from forkAndExecInChild.
+//
+//go:nosplit
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ panic("unimplemented")
+}
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 96fadf7837..687efff770 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -21,7 +21,7 @@ func setTimeval(sec, usec int64) Timeval {
//sys Stat(path string, stat *Stat_t) (err error) = SYS_stat64
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_statfs64
//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_fstatat64
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
+//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd)
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
index d267a4ae6e..ab57117475 100644
--- a/src/syscall/syscall_darwin_arm64.go
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -21,7 +21,7 @@ func setTimeval(sec, usec int64) Timeval {
//sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error)
//sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
+//sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd)
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index ee726fb24d..4f2cdf861e 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1971,7 +1971,7 @@ func libc_fstatat64_trampoline()
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
//go:nosplit
-func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
index ac530f3108..0d8598d816 100644
--- a/src/syscall/zsyscall_darwin_arm64.go
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -1971,7 +1971,7 @@ func libc_fstatat_trampoline()
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
//go:nosplit
-func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+func ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := syscall6(funcPC(libc_ptrace_trampoline), uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
if e1 != 0 {
err = errnoErr(e1)