Commit 31b1207f authored by Austin Clements's avatar Austin Clements

[dev.power64] all: merge default into dev.power64

Trivial merge except for src/runtime/asm_power64x.s and
src/runtime/signal_power64x.c

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/168950044
parents 84f7ac98 b8022403
...@@ -135,3 +135,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1 ...@@ -135,3 +135,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2 85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
...@@ -65,6 +65,7 @@ Aulus Egnatius Varialus <varialus@gmail.com> ...@@ -65,6 +65,7 @@ Aulus Egnatius Varialus <varialus@gmail.com>
Ben Olive <sionide21@gmail.com> Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us> Benjamin Black <b@b3k.us>
Benny Siegert <bsiegert@gmail.com> Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <berengar.lehr@gmx.de> Berengar Lehr <berengar.lehr@gmx.de>
Billie Harold Cleek <bhcleek@gmail.com> Billie Harold Cleek <bhcleek@gmail.com>
Bjorn Tillenius <bjorn@tillenius.me> Bjorn Tillenius <bjorn@tillenius.me>
...@@ -156,6 +157,7 @@ Evan Shaw <chickencha@gmail.com> ...@@ -156,6 +157,7 @@ Evan Shaw <chickencha@gmail.com>
Ewan Chou <coocood@gmail.com> Ewan Chou <coocood@gmail.com>
Fabrizio Milo <mistobaan@gmail.com> Fabrizio Milo <mistobaan@gmail.com>
Fan Hongjian <fan.howard@gmail.com> Fan Hongjian <fan.howard@gmail.com>
Fastly, Inc.
Fatih Arslan <fatih@arslan.io> Fatih Arslan <fatih@arslan.io>
Fazlul Shahriar <fshahriar@gmail.com> Fazlul Shahriar <fshahriar@gmail.com>
Felix Geisendörfer <haimuiba@gmail.com> Felix Geisendörfer <haimuiba@gmail.com>
...@@ -166,6 +168,7 @@ Francisco Souza <franciscossouza@gmail.com> ...@@ -166,6 +168,7 @@ Francisco Souza <franciscossouza@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com> Frederick Kelly Mayle III <frederickmayle@gmail.com>
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com> Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com> Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Gary Burd <gary@beagledreams.com> Gary Burd <gary@beagledreams.com>
Gautham Thambidorai <gautham.dorai@gmail.com> Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com> Georg Reinke <guelfey@gmail.com>
...@@ -315,6 +318,7 @@ Moriyoshi Koizumi <mozo@mozo.jp> ...@@ -315,6 +318,7 @@ Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com> Môshe van der Sterre <moshevds@gmail.com>
Nan Deng <monnand@gmail.com> Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com> Nathan John Youngman <nj@nathany.com>
Nathan P Finch <nate.finch@gmail.com>
ngmoco, LLC ngmoco, LLC
Nicholas Katsaros <nick@nickkatsaros.com> Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com> Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
......
...@@ -104,6 +104,7 @@ Ben Lynn <benlynn@gmail.com> ...@@ -104,6 +104,7 @@ Ben Lynn <benlynn@gmail.com>
Ben Olive <sionide21@gmail.com> Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us> Benjamin Black <b@b3k.us>
Benny Siegert <bsiegert@gmail.com> Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de> Berengar Lehr <Berengar.Lehr@gmx.de>
Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com> Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
Bill Thiede <couchmoney@gmail.com> Bill Thiede <couchmoney@gmail.com>
...@@ -241,6 +242,7 @@ Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com> ...@@ -241,6 +242,7 @@ Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com> Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Fumitoshi Ukai <ukai@google.com> Fumitoshi Ukai <ukai@google.com>
Gaal Yahas <gaal@google.com> Gaal Yahas <gaal@google.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com> Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
Gautham Thambidorai <gautham.dorai@gmail.com> Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com> Georg Reinke <guelfey@gmail.com>
...@@ -299,6 +301,7 @@ Jason Del Ponte <delpontej@gmail.com> ...@@ -299,6 +301,7 @@ Jason Del Ponte <delpontej@gmail.com>
Jason Travis <infomaniac7@gmail.com> Jason Travis <infomaniac7@gmail.com>
Jay Weisskopf <jay@jayschwa.net> Jay Weisskopf <jay@jayschwa.net>
Jean-Marc Eurin <jmeurin@google.com> Jean-Marc Eurin <jmeurin@google.com>
Jed Denlea <jed@fastly.com>
Jeff Hodges <jeff@somethingsimilar.com> Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com> Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
Jeff Sickel <jas@corpus-callosum.com> Jeff Sickel <jas@corpus-callosum.com>
...@@ -444,6 +447,7 @@ Môshe van der Sterre <moshevds@gmail.com> ...@@ -444,6 +447,7 @@ Môshe van der Sterre <moshevds@gmail.com>
Mrunal Patel <mrunalp@gmail.com> Mrunal Patel <mrunalp@gmail.com>
Nan Deng <monnand@gmail.com> Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com> Nathan John Youngman <nj@nathany.com>
Nathan P Finch <nate.finch@gmail.com>
Nicholas Katsaros <nick@nickkatsaros.com> Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com> Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com> Nicholas Sullivan <nicholas.sullivan@gmail.com>
......
This diff is collapsed.
...@@ -62,5 +62,6 @@ func Test8517(t *testing.T) { test8517(t) } ...@@ -62,5 +62,6 @@ func Test8517(t *testing.T) { test8517(t) }
func Test8811(t *testing.T) { test8811(t) } func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) } func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) } func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
func Test9026(t *testing.T) { test9026(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
...@@ -34,7 +34,7 @@ func test6997(t *testing.T) { ...@@ -34,7 +34,7 @@ func test6997(t *testing.T) {
if r == 0 { if r == 0 {
t.Error("pthread finished but wasn't cancelled??") t.Error("pthread finished but wasn't cancelled??")
} }
case <-time.After(5 * time.Second): case <-time.After(30 * time.Second):
t.Error("hung in pthread_cancel/pthread_join") t.Error("hung in pthread_cancel/pthread_join")
} }
} }
package cgotest
/*
typedef struct {} git_merge_file_input;
typedef struct {} git_merge_file_options;
void git_merge_file(
git_merge_file_input *in,
git_merge_file_options *opts) {}
*/
import "C"
import (
"fmt"
"testing"
)
func test9026(t *testing.T) {
var in C.git_merge_file_input
var opts *C.git_merge_file_options
C.git_merge_file(&in, opts)
// Test that the generated type names are deterministic.
// (Previously this would fail about 10% of the time.)
//
// Brittle: the assertion may fail spuriously when the algorithm
// changes, but should remain stable otherwise.
got := fmt.Sprintf("%T %T", in, opts)
want := "cgotest._Ctype_struct___12 *cgotest._Ctype_struct___13"
if got != want {
t.Errorf("Non-deterministic type names: got %s, want %s", got, want)
}
}
...@@ -944,6 +944,8 @@ type typeConv struct { ...@@ -944,6 +944,8 @@ type typeConv struct {
// Map from types to incomplete pointers to those types. // Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type ptrs map[dwarf.Type][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
ptrKeys []dwarf.Type
// Predeclared types. // Predeclared types.
bool ast.Expr bool ast.Expr
...@@ -1061,16 +1063,17 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) { ...@@ -1061,16 +1063,17 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
func (c *typeConv) FinishType(pos token.Pos) { func (c *typeConv) FinishType(pos token.Pos) {
// Completing one pointer type might produce more to complete. // Completing one pointer type might produce more to complete.
// Keep looping until they're all done. // Keep looping until they're all done.
for len(c.ptrs) > 0 { for len(c.ptrKeys) > 0 {
for dtype := range c.ptrs { dtype := c.ptrKeys[0]
c.ptrKeys = c.ptrKeys[1:]
// Note Type might invalidate c.ptrs[dtype]. // Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos) t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] { for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C) ptr.C.Set("%s*", t.C)
} }
delete(c.ptrs, dtype) c.ptrs[dtype] = nil // retain the map key
}
} }
} }
...@@ -1237,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { ...@@ -1237,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Placeholder initialization; completed in FinishType. // Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{} t.Go = &ast.StarExpr{}
t.C.Set("<incomplete>*") t.C.Set("<incomplete>*")
if _, ok := c.ptrs[dt.Type]; !ok {
c.ptrKeys = append(c.ptrKeys, dt.Type)
}
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t) c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType: case *dwarf.QualType:
......
...@@ -247,7 +247,7 @@ The arguments are space-separated tokens or double-quoted strings ...@@ -247,7 +247,7 @@ The arguments are space-separated tokens or double-quoted strings
passed to the generator as individual arguments when it is run. passed to the generator as individual arguments when it is run.
Quoted strings use Go syntax and are evaluated before execution; a Quoted strings use Go syntax and are evaluated before execution; a
quoted string appears a single argument to the generator. quoted string appears as a single argument to the generator.
Go generate sets several variables when it runs the generator: Go generate sets several variables when it runs the generator:
...@@ -260,7 +260,7 @@ Go generate sets several variables when it runs the generator: ...@@ -260,7 +260,7 @@ Go generate sets several variables when it runs the generator:
$GOPACKAGE $GOPACKAGE
The name of the package of the file containing the directive. The name of the package of the file containing the directive.
Other than variable substition and quoted-string evaluation, no Other than variable substitution and quoted-string evaluation, no
special processing such as "globbing" is performed on the command special processing such as "globbing" is performed on the command
line. line.
......
...@@ -58,7 +58,7 @@ Go generate sets several variables when it runs the generator: ...@@ -58,7 +58,7 @@ Go generate sets several variables when it runs the generator:
$GOPACKAGE $GOPACKAGE
The name of the package of the file containing the directive. The name of the package of the file containing the directive.
Other than variable substition and quoted-string evaluation, no Other than variable substitution and quoted-string evaluation, no
special processing such as "globbing" is performed on the command special processing such as "globbing" is performed on the command
line. line.
......
...@@ -8,6 +8,7 @@ package objfile ...@@ -8,6 +8,7 @@ package objfile
import ( import (
"debug/elf" "debug/elf"
"fmt"
"os" "os"
) )
...@@ -77,3 +78,27 @@ func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { ...@@ -77,3 +78,27 @@ func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
} }
return textStart, symtab, pclntab, nil return textStart, symtab, pclntab, nil
} }
func (f *elfFile) text() (textStart uint64, text []byte, err error) {
sect := f.elf.Section(".text")
if sect == nil {
return 0, nil, fmt.Errorf("text section not found")
}
textStart = sect.Addr
text, err = sect.Data()
return
}
func (f *elfFile) goarch() string {
switch f.elf.Machine {
case elf.EM_386:
return "386"
case elf.EM_X86_64:
return "amd64"
case elf.EM_ARM:
return "arm"
case elf.EM_PPC64:
return "power64"
}
return ""
}
...@@ -79,3 +79,15 @@ func (f *goobjFile) symbols() ([]Sym, error) { ...@@ -79,3 +79,15 @@ func (f *goobjFile) symbols() ([]Sym, error) {
func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
return 0, nil, nil, fmt.Errorf("pcln not available in go object file") return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
} }
// text does not make sense for Go object files, because
// each function has a separate section.
func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
return 0, nil, fmt.Errorf("text not available in go object file")
}
// goarch makes sense but is not exposed in debug/goobj's API,
// and we don't need it yet for any users of internal/objfile.
func (f *goobjFile) goarch() string {
return "GOARCH unimplemented for debug/goobj files"
}
...@@ -85,6 +85,30 @@ func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) ...@@ -85,6 +85,30 @@ func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error)
return textStart, symtab, pclntab, nil return textStart, symtab, pclntab, nil
} }
func (f *machoFile) text() (textStart uint64, text []byte, err error) {
sect := f.macho.Section("__text")
if sect == nil {
return 0, nil, fmt.Errorf("text section not found")
}
textStart = sect.Addr
text, err = sect.Data()
return
}
func (f *machoFile) goarch() string {
switch f.macho.Cpu {
case macho.Cpu386:
return "386"
case macho.CpuAmd64:
return "amd64"
case macho.CpuArm:
return "arm"
case macho.CpuPpc64:
return "power64"
}
return ""
}
type uint64s []uint64 type uint64s []uint64
func (x uint64s) Len() int { return len(x) } func (x uint64s) Len() int { return len(x) }
......
...@@ -14,6 +14,8 @@ import ( ...@@ -14,6 +14,8 @@ import (
type rawFile interface { type rawFile interface {
symbols() (syms []Sym, err error) symbols() (syms []Sym, err error)
pcln() (textStart uint64, symtab, pclntab []byte, err error) pcln() (textStart uint64, symtab, pclntab []byte, err error)
text() (textStart uint64, text []byte, err error)
goarch() string
} }
// A File is an opened executable file. // A File is an opened executable file.
...@@ -70,3 +72,11 @@ func (f *File) PCLineTable() (*gosym.Table, error) { ...@@ -70,3 +72,11 @@ func (f *File) PCLineTable() (*gosym.Table, error) {
} }
return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart))
} }
func (f *File) Text() (uint64, []byte, error) {
return f.raw.text()
}
func (f *File) GOARCH() string {
return f.raw.goarch()
}
...@@ -133,6 +133,25 @@ func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { ...@@ -133,6 +133,25 @@ func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
return textStart, symtab, pclntab, nil return textStart, symtab, pclntab, nil
} }
func (f *peFile) text() (textStart uint64, text []byte, err error) {
var imageBase uint64
switch oh := f.pe.OptionalHeader.(type) {
case *pe.OptionalHeader32:
imageBase = uint64(oh.ImageBase)
case *pe.OptionalHeader64:
imageBase = oh.ImageBase
default:
return 0, nil, fmt.Errorf("pe file format not recognized")
}
sect := f.pe.Section(".text")
if sect == nil {
return 0, nil, fmt.Errorf("text section not found")
}
textStart = imageBase + uint64(sect.VirtualAddress)
text, err = sect.Data()
return
}
func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
for _, s := range f.Symbols { for _, s := range f.Symbols {
if s.Name != name { if s.Name != name {
...@@ -168,3 +187,15 @@ func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { ...@@ -168,3 +187,15 @@ func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
} }
return data[ssym.Value:esym.Value], nil return data[ssym.Value:esym.Value], nil
} }
func (f *peFile) goarch() string {
// Not sure how to get the info we want from PE header.
// Look in symbol table for telltale rt0 symbol.
if _, err := findPESymbol(f.pe, "_rt0_386_windows"); err == nil {
return "386"
}
if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil {
return "amd64"
}
return ""
}
...@@ -88,6 +88,16 @@ func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) ...@@ -88,6 +88,16 @@ func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error)
return textStart, symtab, pclntab, nil return textStart, symtab, pclntab, nil
} }
func (f *plan9File) text() (textStart uint64, text []byte, err error) {
sect := f.plan9.Section("text")
if sect == nil {
return 0, nil, fmt.Errorf("text section not found")
}
textStart = f.plan9.LoadAddress + f.plan9.HdrSize
text, err = sect.Data()
return
}
func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
syms, err := f.Symbols() syms, err := f.Symbols()
if err != nil { if err != nil {
...@@ -122,3 +132,15 @@ func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { ...@@ -122,3 +132,15 @@ func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
textStart := f.LoadAddress + f.HdrSize textStart := f.LoadAddress + f.HdrSize
return data[ssym.Value-textStart : esym.Value-textStart], nil return data[ssym.Value-textStart : esym.Value-textStart], nil
} }
func (f *plan9File) goarch() string {
switch f.plan9.Magic {
case plan9obj.Magic386:
return "386"
case plan9obj.MagicAMD64:
return "amd64"
case plan9obj.MagicARM:
return "arm"
}
return ""
}
all: x86.go armasm.go
x86.go: bundle
./bundle -p main -x x86_ rsc.io/x86/x86asm | gofmt >x86.go
armasm.go: bundle
./bundle -p main -x arm_ rsc.io/arm/armasm | gofmt >armasm.go
bundle:
go build -o bundle code.google.com/p/rsc/cmd/bundle
// 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.
// Parsing of ELF executables (Linux, FreeBSD, and so on).
package main
import (
"debug/elf"
"os"
)
func elfSymbols(f *os.File) (syms []Sym, goarch string) {
p, err := elf.NewFile(f)
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
elfSyms, err := p.Symbols()
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
switch p.Machine {
case elf.EM_X86_64:
goarch = "amd64"
case elf.EM_386:
goarch = "386"
case elf.EM_ARM:
goarch = "arm"
}
for _, s := range elfSyms {
sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
switch s.Section {
case elf.SHN_UNDEF:
sym.Code = 'U'
case elf.SHN_COMMON:
sym.Code = 'B'
default:
i := int(s.Section)
if i < 0 || i >= len(p.Sections) {
break
}
sect := p.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
case elf.SHF_ALLOC:
sym.Code = 'R'
case elf.SHF_ALLOC | elf.SHF_WRITE:
sym.Code = 'D'
}
}
if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
sym.Code += 'a' - 'A'
}
syms = append(syms, sym)
}
return
}
// 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.
// Parsing of Mach-O executables (OS X).
package main
import (
"debug/macho"
"os"
"sort"
)
func machoSymbols(f *os.File) (syms []Sym, goarch string) {
p, err := macho.NewFile(f)
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
if p.Symtab == nil {
errorf("%s: no symbol table", f.Name())
return
}
switch p.Cpu {
case macho.Cpu386:
goarch = "386"
case macho.CpuAmd64:
goarch = "amd64"
case macho.CpuArm:
goarch = "arm"
}
// Build sorted list of addresses of all symbols.
// We infer the size of a symbol by looking at where the next symbol begins.
var addrs []uint64
for _, s := range p.Symtab.Syms {
addrs = append(addrs, s.Value)
}
sort.Sort(uint64s(addrs))
for _, s := range p.Symtab.Syms {
sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
if i < len(addrs) {
sym.Size = int64(addrs[i] - s.Value)
}
if s.Sect == 0 {
sym.Code = 'U'
} else if int(s.Sect) <= len(p.Sections) {
sect := p.Sections[s.Sect-1]
switch sect.Seg {
case "__TEXT":
sym.Code = 'R'
case "__DATA":
sym.Code = 'D'
}
switch sect.Seg + " " + sect.Name {
case "__TEXT __text":
sym.Code = 'T'
case "__DATA __bss", "__DATA __noptrbss":
sym.Code = 'B'
}
}
syms = append(syms, sym)
}
return
}
type uint64s []uint64
func (x uint64s) Len() int { return len(x) }
func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
This diff is collapsed.
...@@ -147,7 +147,7 @@ var x86Need = []string{ ...@@ -147,7 +147,7 @@ var x86Need = []string{
var armNeed = []string{ var armNeed = []string{
"fmthello.go:6", "fmthello.go:6",
"TEXT main.main(SB)", "TEXT main.main(SB)",
"B.LS main.main(SB)", //"B.LS main.main(SB)", // TODO(rsc): restore; golang.org/issue/9021
"BL fmt.Println(SB)", "BL fmt.Println(SB)",
"RET", "RET",
} }
......
// 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.
// Parsing of PE executables (Microsoft Windows).
package main
import (
"debug/pe"
"os"
"sort"
)
func peSymbols(f *os.File) (syms []Sym, goarch string) {
p, err := pe.NewFile(f)
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
// Build sorted list of addresses of all symbols.
// We infer the size of a symbol by looking at where the next symbol begins.
var addrs []uint64
var imageBase uint64
switch oh := p.OptionalHeader.(type) {
case *pe.OptionalHeader32:
imageBase = uint64(oh.ImageBase)
goarch = "386"
case *pe.OptionalHeader64:
imageBase = oh.ImageBase
goarch = "amd64"
default:
errorf("parsing %s: file format not recognized", f.Name())
return
}
for _, s := range p.Symbols {
const (
N_UNDEF = 0 // An undefined (extern) symbol
N_ABS = -1 // An absolute symbol (e_value is a constant, not an address)
N_DEBUG = -2 // A debugging symbol
)
sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
switch s.SectionNumber {
case N_UNDEF:
sym.Code = 'U'
case N_ABS:
sym.Code = 'C'
case N_DEBUG:
sym.Code = '?'
default:
if s.SectionNumber < 0 {
errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber)
return
}
if len(p.Sections) < int(s.SectionNumber) {
errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections))
return
}
sect := p.Sections[s.SectionNumber-1]
const (
text = 0x20
data = 0x40
bss = 0x80
permX = 0x20000000
permR = 0x40000000
permW = 0x80000000
)
ch := sect.Characteristics
switch {
case ch&text != 0:
sym.Code = 'T'
case ch&data != 0:
if ch&permW == 0 {
sym.Code = 'R'
} else {
sym.Code = 'D'
}
case ch&bss != 0:
sym.Code = 'B'
}
sym.Addr += imageBase + uint64(sect.VirtualAddress)
}
syms = append(syms, sym)
addrs = append(addrs, sym.Addr)
}
sort.Sort(uint64s(addrs))
for i := range syms {
j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
if j < len(addrs) {
syms[i].Size = int64(addrs[j] - syms[i].Addr)
}
}
return
}
// Copyright 2014 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.
// Parsing of Plan 9 a.out executables.
package main
import (
"debug/plan9obj"
"os"
"sort"
)
var validSymType = map[rune]bool{
'T': true,
't': true,
'D': true,
'd': true,
'B': true,
'b': true,
}
func plan9Symbols(f *os.File) (syms []Sym, goarch string) {
p, err := plan9obj.NewFile(f)
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
plan9Syms, err := p.Symbols()
if err != nil {
errorf("parsing %s: %v", f.Name(), err)
return
}
switch p.Magic {
case plan9obj.MagicAMD64:
goarch = "amd64"
case plan9obj.Magic386:
goarch = "386"
case plan9obj.MagicARM:
goarch = "arm"
}
// Build sorted list of addresses of all symbols.
// We infer the size of a symbol by looking at where the next symbol begins.
var addrs []uint64
for _, s := range plan9Syms {
if !validSymType[s.Type] {
continue
}
addrs = append(addrs, s.Value)
}
sort.Sort(uint64s(addrs))
for _, s := range plan9Syms {
if !validSymType[s.Type] {
continue
}
sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
if i < len(addrs) {
sym.Size = int64(addrs[i] - s.Value)
}
syms = append(syms, sym)
}
return
}
...@@ -141,6 +141,8 @@ type Dummy struct { ...@@ -141,6 +141,8 @@ type Dummy struct {
} }
func TestDrivers(t *testing.T) { func TestDrivers(t *testing.T) {
unregisterAllDrivers()
Register("test", fdriver)
Register("invalid", Dummy{}) Register("invalid", Dummy{})
all := Drivers() all := Drivers()
if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") { if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") {
......
...@@ -37,6 +37,11 @@ func Register(name string, driver driver.Driver) { ...@@ -37,6 +37,11 @@ func Register(name string, driver driver.Driver) {
drivers[name] = driver drivers[name] = driver
} }
func unregisterAllDrivers() {
// For tests.
drivers = make(map[string]driver.Driver)
}
// Drivers returns a sorted list of the names of the registered drivers. // Drivers returns a sorted list of the names of the registered drivers.
func Drivers() []string { func Drivers() []string {
var list []string var list []string
......
...@@ -70,7 +70,7 @@ func goroutineLeaked() bool { ...@@ -70,7 +70,7 @@ func goroutineLeaked() bool {
} }
fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
for stack, count := range stackCount { for stack, count := range stackCount {
fmt.Fprintf(os.Stderr, "%d instances of:\n%s", count, stack) fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
} }
return true return true
} }
......
...@@ -2284,3 +2284,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0 ...@@ -2284,3 +2284,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVL m_curg(AX), AX MOVL m_curg(AX), AX
MOVL (g_stack+stack_hi)(AX), AX MOVL (g_stack+stack_hi)(AX), AX
RET RET
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
...@@ -2229,3 +2229,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0 ...@@ -2229,3 +2229,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVQ m_curg(AX), AX MOVQ m_curg(AX), AX
MOVQ (g_stack+stack_hi)(AX), AX MOVQ (g_stack+stack_hi)(AX), AX
RET RET
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
...@@ -1079,3 +1079,9 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 ...@@ -1079,3 +1079,9 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
TEXT runtime·return0(SB), NOSPLIT, $0 TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX MOVL $0, AX
RET RET
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$0-0
BYTE $0x90 // NOP
CALL runtime·goexit1(SB) // does not return
...@@ -1320,3 +1320,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8 ...@@ -1320,3 +1320,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
MOVW saveG-8(SP), g MOVW saveG-8(SP), g
MOVW saveR11-4(SP), R11 MOVW saveR11-4(SP), R11
RET RET
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$-4-0
MOVW R0, R0 // NOP
BL runtime·goexit1(SB) // does not return
...@@ -980,3 +980,9 @@ TEXT runtime·return0(SB), NOSPLIT, $0 ...@@ -980,3 +980,9 @@ TEXT runtime·return0(SB), NOSPLIT, $0
// Must obey the gcc calling convention. // Must obey the gcc calling convention.
TEXT _cgo_topofstack(SB),NOSPLIT,$0 TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVD R0, 26(R0) MOVD R0, 26(R0)
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
TEXT runtime·goexit(SB),NOSPLIT,$-8-0
MOVD R0, R0 // NOP
BL runtime·goexit1(SB) // does not return
...@@ -36,10 +36,14 @@ func TestCgoTraceback(t *testing.T) { ...@@ -36,10 +36,14 @@ func TestCgoTraceback(t *testing.T) {
} }
func TestCgoExternalThreadPanic(t *testing.T) { func TestCgoExternalThreadPanic(t *testing.T) {
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { if runtime.GOOS == "plan9" {
t.Skipf("no pthreads on %s", runtime.GOOS) t.Skipf("no pthreads on %s", runtime.GOOS)
} }
got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", cgoExternalThreadPanicC) csrc := cgoExternalThreadPanicC
if runtime.GOOS == "windows" {
csrc = cgoExternalThreadPanicC_windows
}
got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
want := "panic: BOOM" want := "panic: BOOM"
if !strings.Contains(got, want) { if !strings.Contains(got, want) {
t.Fatalf("want failure containing %q. output:\n%s\n", want, got) t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
...@@ -169,3 +173,24 @@ start(void) ...@@ -169,3 +173,24 @@ start(void)
printf("pthread_create failed\n"); printf("pthread_create failed\n");
} }
` `
const cgoExternalThreadPanicC_windows = `
#include <stdlib.h>
#include <stdio.h>
void gopanic(void);
static void*
die(void* x)
{
gopanic();
return 0;
}
void
start(void)
{
if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
printf("_beginthreadex failed\n");
}
`
...@@ -117,11 +117,20 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) { ...@@ -117,11 +117,20 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
return return
} }
// Callers fills the slice pc with the program counters of function invocations // Callers fills the slice pc with the return program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames // on the calling goroutine's stack. The argument skip is the number of stack frames
// to skip before recording in pc, with 0 identifying the frame for Callers itself and // to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers. // 1 identifying the caller of Callers.
// It returns the number of entries written to pc. // It returns the number of entries written to pc.
//
// Note that since each slice entry pc[i] is a return program counter,
// looking up the file and line for pc[i] (for example, using (*Func).FileLine)
// will return the file and line number of the instruction immediately
// following the call.
// To look up the file and line number of the call itself, use pc[i]-1.
// As an exception to this rule, if pc[i-1] corresponds to the function
// runtime.sigpanic, then pc[i] is the program counter of a faulting
// instruction and should be used without any subtraction.
func Callers(skip int, pc []uintptr) int { func Callers(skip int, pc []uintptr) int {
// runtime.callers uses pc.array==nil as a signal // runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here // to print a stack trace. Pick off 0-length pc here
......
...@@ -413,7 +413,7 @@ dumpgoroutine(G *gp) ...@@ -413,7 +413,7 @@ dumpgoroutine(G *gp)
child.sp = nil; child.sp = nil;
child.depth = 0; child.depth = 0;
fn = dumpframe; fn = dumpframe;
runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, false); runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
// dump defer & panic records // dump defer & panic records
for(d = gp->defer; d != nil; d = d->link) { for(d = gp->defer; d != nil; d = d->link) {
......
...@@ -774,7 +774,7 @@ scanstack(G *gp) ...@@ -774,7 +774,7 @@ scanstack(G *gp)
runtime·throw("can't scan gchelper stack"); runtime·throw("can't scan gchelper stack");
fn = scanframe; fn = scanframe;
runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false); runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
runtime·tracebackdefers(gp, &fn, nil); runtime·tracebackdefers(gp, &fn, nil);
} }
...@@ -1966,7 +1966,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) ...@@ -1966,7 +1966,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
frame.fn = nil; frame.fn = nil;
frame.sp = (uintptr)p; frame.sp = (uintptr)p;
cb = getgcmaskcb; cb = getgcmaskcb;
runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, false); runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
if(frame.fn != nil) { if(frame.fn != nil) {
Func *f; Func *f;
StackMap *stackmap; StackMap *stackmap;
......
...@@ -562,7 +562,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) { ...@@ -562,7 +562,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
} }
func saveg(pc, sp uintptr, gp *g, r *StackRecord) { func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, false) n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, 0)
if n < len(r.Stack0) { if n < len(r.Stack0) {
r.Stack0[n] = 0 r.Stack0[n] = 0
} }
......
...@@ -114,7 +114,7 @@ Throw: ...@@ -114,7 +114,7 @@ Throw:
if(runtime·gotraceback(&crash)) { if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(ureg->pc, ureg->sp, 0, gp); runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(ureg); runtime·dumpregs(ureg);
......
...@@ -122,7 +122,7 @@ Throw: ...@@ -122,7 +122,7 @@ Throw:
if(runtime·gotraceback(&crash)) { if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(ureg->ip, ureg->sp, 0, gp); runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(ureg); runtime·dumpregs(ureg);
......
...@@ -97,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) ...@@ -97,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n"); runtime·printf("\n");
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·traceback(r->Eip, r->Esp, 0, gp); runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·dumpregs(r); runtime·dumpregs(r);
} }
......
...@@ -119,7 +119,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) ...@@ -119,7 +119,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n"); runtime·printf("\n");
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·traceback(r->Rip, r->Rsp, 0, gp); runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·dumpregs(r); runtime·dumpregs(r);
} }
......
...@@ -1643,12 +1643,10 @@ runtime·gosched_m(G *gp) ...@@ -1643,12 +1643,10 @@ runtime·gosched_m(G *gp)
} }
// Finishes execution of the current goroutine. // Finishes execution of the current goroutine.
// Need to mark it as nosplit, because it runs with sp > stackbase. // Must be NOSPLIT because it is called from Go.
// Since it does not return it does not matter. But if it is preempted
// at the split stack check, GC will complain about inconsistent sp.
#pragma textflag NOSPLIT #pragma textflag NOSPLIT
void void
runtime·goexit(void) runtime·goexit1(void)
{ {
void (*fn)(G*); void (*fn)(G*);
...@@ -2192,7 +2190,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp ...@@ -2192,7 +2190,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
runtime·memclr((byte*)&newg->sched, sizeof newg->sched); runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
newg->sched.sp = (uintptr)sp; newg->sched.sp = (uintptr)sp;
newg->sched.pc = (uintptr)runtime·goexit; newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
newg->sched.g = newg; newg->sched.g = newg;
runtime·gostartcallfn(&newg->sched, fn); runtime·gostartcallfn(&newg->sched, fn);
newg->gopc = (uintptr)callerpc; newg->gopc = (uintptr)callerpc;
...@@ -2532,7 +2530,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) ...@@ -2532,7 +2530,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
n = 0; n = 0;
if(traceback) if(traceback)
n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, false); n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
if(!traceback || n <= 0) { if(!traceback || n <= 0) {
// Normal traceback is impossible or has failed. // Normal traceback is impossible or has failed.
// See if it falls into several common cases. // See if it falls into several common cases.
...@@ -2542,13 +2540,13 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) ...@@ -2542,13 +2540,13 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
// Cgo, we can't unwind and symbolize arbitrary C code, // Cgo, we can't unwind and symbolize arbitrary C code,
// so instead collect Go stack that leads to the cgo call. // so instead collect Go stack that leads to the cgo call.
// This is especially important on windows, since all syscalls are cgo calls. // This is especially important on windows, since all syscalls are cgo calls.
n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, false); n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, 0);
} }
#ifdef GOOS_windows #ifdef GOOS_windows
if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) { if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
// Libcall, i.e. runtime syscall on windows. // Libcall, i.e. runtime syscall on windows.
// Collect Go stack that leads to the call. // Collect Go stack that leads to the call.
n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, false); n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, 0);
} }
#endif #endif
if(n == 0) { if(n == 0) {
......
...@@ -719,9 +719,15 @@ struct Stkframe ...@@ -719,9 +719,15 @@ struct Stkframe
BitVector* argmap; // force use of this argmap BitVector* argmap; // force use of this argmap
}; };
intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, bool); enum
{
TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
};
intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
void runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*); void runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp); void runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebackothers(G*); void runtime·tracebackothers(G*);
bool runtime·haszeroargs(uintptr pc); bool runtime·haszeroargs(uintptr pc);
bool runtime·topofstack(Func*); bool runtime·topofstack(Func*);
......
...@@ -109,7 +109,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) ...@@ -109,7 +109,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp); runtime·tracebacktrap(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(info, ctxt); runtime·dumpregs(info, ctxt);
......
...@@ -143,7 +143,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) ...@@ -143,7 +143,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp); runtime·tracebacktrap(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(info, ctxt); runtime·dumpregs(info, ctxt);
......
...@@ -108,7 +108,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) ...@@ -108,7 +108,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp); runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(info, ctxt); runtime·dumpregs(info, ctxt);
......
...@@ -124,7 +124,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) ...@@ -124,7 +124,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){ if(runtime·gotraceback(&crash)){
runtime·goroutineheader(gp); runtime·goroutineheader(gp);
runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp); runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp);
runtime·tracebackothers(gp); runtime·tracebackothers(gp);
runtime·printf("\n"); runtime·printf("\n");
runtime·dumpregs(info, ctxt); runtime·dumpregs(info, ctxt);
......
...@@ -620,7 +620,7 @@ copystack(G *gp, uintptr newsize) ...@@ -620,7 +620,7 @@ copystack(G *gp, uintptr newsize)
adjinfo.old = old; adjinfo.old = old;
adjinfo.delta = new.hi - old.hi; adjinfo.delta = new.hi - old.hi;
cb = adjustframe; cb = adjustframe;
runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, false); runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
// adjust other miscellaneous things that have pointers into stacks. // adjust other miscellaneous things that have pointers into stacks.
adjustctxt(gp, &adjinfo); adjustctxt(gp, &adjinfo);
......
...@@ -96,7 +96,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns ...@@ -96,7 +96,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
// the runtime.Callers function (pcbuf != nil), as well as the garbage // the runtime.Callers function (pcbuf != nil), as well as the garbage
// collector (callback != nil). A little clunky to merge these, but avoids // collector (callback != nil). A little clunky to merge these, but avoids
// duplicating the code and all its subtlety. // duplicating the code and all its subtlety.
func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, printall bool) int { func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
if goexitPC == 0 { if goexitPC == 0 {
gothrow("gentraceback before goexitPC initialization") gothrow("gentraceback before goexitPC initialization")
} }
...@@ -297,13 +297,13 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf ...@@ -297,13 +297,13 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
} }
} }
if printing { if printing {
if printall || showframe(f, gp) { if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp) {
// Print during crash. // Print during crash.
// main(0x1, 0x2, 0x3) // main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf // /home/rsc/go/src/runtime/x.go:23 +0xf
// //
tracepc := frame.pc // back up to CALL instruction for funcline. tracepc := frame.pc // back up to CALL instruction for funcline.
if n > 0 && frame.pc > f.entry && !waspanic { if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
tracepc-- tracepc--
} }
print(gofuncname(f), "(") print(gofuncname(f), "(")
...@@ -475,17 +475,32 @@ func printcreatedby(gp *g) { ...@@ -475,17 +475,32 @@ func printcreatedby(gp *g) {
} }
func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) { func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
traceback1(pc, sp, lr, gp, 0)
}
// tracebacktrap is like traceback but expects that the PC and SP were obtained
// from a trap, not from gp->sched or gp->syscallpc/gp->syscallsp or getcallerpc/getcallersp.
// Because they are from a trap instead of from a saved pair,
// the initial PC must not be rewound to the previous instruction.
// (All the saved pairs record a PC that is a return address, so we
// rewind it into the CALL instruction.)
func tracebacktrap(pc uintptr, sp uintptr, lr uintptr, gp *g) {
traceback1(pc, sp, lr, gp, _TraceTrap)
}
func traceback1(pc uintptr, sp uintptr, lr uintptr, gp *g, flags uint) {
var n int var n int
if readgstatus(gp)&^_Gscan == _Gsyscall { if readgstatus(gp)&^_Gscan == _Gsyscall {
// Override signal registers if blocked in system call. // Override registers if blocked in system call.
pc = gp.syscallpc pc = gp.syscallpc
sp = gp.syscallsp sp = gp.syscallsp
flags &^= _TraceTrap
} }
// Print traceback. By default, omits runtime frames. // Print traceback. By default, omits runtime frames.
// If that means we print nothing at all, repeat forcing all frames printed. // If that means we print nothing at all, repeat forcing all frames printed.
n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, false) n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
if n == 0 { if n == 0 && (flags&_TraceRuntimeFrames) == 0 {
n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, true) n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags|_TraceRuntimeFrames)
} }
if n == _TracebackMaxFrames { if n == _TracebackMaxFrames {
print("...additional frames elided...\n") print("...additional frames elided...\n")
...@@ -496,11 +511,11 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) { ...@@ -496,11 +511,11 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
func callers(skip int, pcbuf *uintptr, m int) int { func callers(skip int, pcbuf *uintptr, m int) int {
sp := getcallersp(unsafe.Pointer(&skip)) sp := getcallersp(unsafe.Pointer(&skip))
pc := uintptr(getcallerpc(unsafe.Pointer(&skip))) pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
return gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, false) return gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
} }
func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int { func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, false) return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, 0)
} }
func showframe(f *_func, gp *g) bool { func showframe(f *_func, gp *g) bool {
......
...@@ -38,7 +38,7 @@ func (v *Value) Load() (x interface{}) { ...@@ -38,7 +38,7 @@ func (v *Value) Load() (x interface{}) {
return return
} }
// Store sets the value of the Value to v. // Store sets the value of the Value to x.
// All calls to Store for a given Value must use values of the same concrete type. // All calls to Store for a given Value must use values of the same concrete type.
// Store of an inconsistent type panics, as does Store(nil). // Store of an inconsistent type panics, as does Store(nil).
func (v *Value) Store(x interface{}) { func (v *Value) Store(x interface{}) {
......
// run
// Copyright 2014 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.
// issue 7690 - Stack and other routines did not back up initial PC
// into CALL instruction, instead reporting line number of next instruction,
// which might be on a different line.
package main
import (
"bytes"
"regexp"
"runtime"
"strconv"
)
func main() {
buf1 := make([]byte, 1000)
buf2 := make([]byte, 1000)
runtime.Stack(buf1, false) // CALL is last instruction on this line
n := runtime.Stack(buf2, false) // CALL is followed by load of result from stack
buf1 = buf1[:bytes.IndexByte(buf1, 0)]
buf2 = buf2[:n]
re := regexp.MustCompile(`(?m)^main\.main\(\)\n.*/issue7690.go:([0-9]+)`)
m1 := re.FindStringSubmatch(string(buf1))
if m1 == nil {
println("BUG: cannot find main.main in first trace")
return
}
m2 := re.FindStringSubmatch(string(buf2))
if m2 == nil {
println("BUG: cannot find main.main in second trace")
return
}
n1, _ := strconv.Atoi(m1[1])
n2, _ := strconv.Atoi(m2[1])
if n1+1 != n2 {
println("BUG: expect runtime.Stack on back to back lines, have", n1, n2)
println(string(buf1))
println(string(buf2))
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment