[dev.garbage] all: merge default (f38460037b72) into dev.garbage

This is the revision that dev.cc is branched from.

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/169590043
This commit is contained in:
Russ Cox 2014-11-14 11:37:54 -05:00
commit 3dcc62e1da
96 changed files with 1476 additions and 6289 deletions

View File

@ -135,3 +135,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1

View File

@ -65,6 +65,7 @@ Aulus Egnatius Varialus <varialus@gmail.com>
Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us>
Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <berengar.lehr@gmx.de>
Billie Harold Cleek <bhcleek@gmail.com>
Bjorn Tillenius <bjorn@tillenius.me>
@ -156,6 +157,7 @@ Evan Shaw <chickencha@gmail.com>
Ewan Chou <coocood@gmail.com>
Fabrizio Milo <mistobaan@gmail.com>
Fan Hongjian <fan.howard@gmail.com>
Fastly, Inc.
Fatih Arslan <fatih@arslan.io>
Fazlul Shahriar <fshahriar@gmail.com>
Felix Geisendörfer <haimuiba@gmail.com>
@ -166,6 +168,7 @@ Francisco Souza <franciscossouza@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com>
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Gary Burd <gary@beagledreams.com>
Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com>
@ -315,6 +318,7 @@ Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
Nathan P Finch <nate.finch@gmail.com>
ngmoco, LLC
Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>

View File

@ -104,6 +104,7 @@ Ben Lynn <benlynn@gmail.com>
Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us>
Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de>
Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
Bill Thiede <couchmoney@gmail.com>
@ -241,6 +242,7 @@ Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
Fumitoshi Ukai <ukai@google.com>
Gaal Yahas <gaal@google.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
Gautham Thambidorai <gautham.dorai@gmail.com>
Georg Reinke <guelfey@gmail.com>
@ -299,6 +301,7 @@ Jason Del Ponte <delpontej@gmail.com>
Jason Travis <infomaniac7@gmail.com>
Jay Weisskopf <jay@jayschwa.net>
Jean-Marc Eurin <jmeurin@google.com>
Jed Denlea <jed@fastly.com>
Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
Jeff Sickel <jas@corpus-callosum.com>
@ -444,6 +447,7 @@ Môshe van der Sterre <moshevds@gmail.com>
Mrunal Patel <mrunalp@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
Nathan P Finch <nate.finch@gmail.com>
Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>

View File

@ -78,17 +78,18 @@ well-established conventions.</p>
source code. For Bitbucket, GitHub, Google Code, and Launchpad, the
root directory of the repository is identified by the repository's
main URL, without the <code>http://</code> prefix. Subdirectories are named by
adding to that path. For example, the supplemental networking
libraries for Go are obtained by running</p>
adding to that path.
For example, the Go example programs are obtained by running</p>
<pre>
hg clone http://code.google.com/p/go.net
git clone https://github.com/golang/example
</pre>
<p>and thus the import path for the root directory of that repository is
"<code>code.google.com/p/go.net</code>". The websocket package is stored in a
subdirectory, so its import path is
"<code>code.google.com/p/go.net/websocket</code>".</p>
"<code>github.com/golang/example</code>".
The <a href="https://godoc.org/github.com/golang/example/stringutil">stringutil</a>
package is stored in a subdirectory, so its import path is
"<code>github.com/golang/example/stringutil</code>".</p>
<p>These paths are on the long side, but in exchange we get an
automatically managed name space for import paths and the ability for

View File

@ -62,7 +62,7 @@ details.
</tr>
<tr>
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/cover/">cover</a></td>
<td><a href="//godoc.org/golang.org/x/tools/cmd/cover/">cover</a></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>Cover is a program for creating and analyzing the coverage profiles
generated by <code>"go test -coverprofile"</code>.</td>
@ -83,13 +83,13 @@ gofmt</a> command with more general options.</td>
</tr>
<tr>
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/godoc/">godoc</a></td>
<td><a href="//godoc.org/golang.org/x/tools/cmd/godoc/">godoc</a></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>Godoc extracts and generates documentation for Go packages.</td>
</tr>
<tr>
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/vet/">vet</a></td>
<td><a href="//godoc.org/golang.org/x/tools/cmd/vet/">vet</a></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td>Vet examines Go source code and reports suspicious constructs, such as Printf
calls whose arguments do not align with the format string.</td>

View File

@ -60,37 +60,35 @@ To give you an idea of how a workspace looks in practice, here's an example:
<pre>
bin/
streak # command executable
todo # command executable
hello # command executable
outyet # command executable
pkg/
linux_amd64/
code.google.com/p/goauth2/
oauth.a # package object
github.com/nf/todo/
task.a # package object
github.com/golang/example/
stringutil.a # package object
src/
code.google.com/p/goauth2/
.hg/ # mercurial repository metadata
oauth/
oauth.go # package source
oauth_test.go # test source
github.com/nf/
streak/
.git/ # git repository metadata
oauth.go # command source
streak.go # command source
todo/
.git/ # git repository metadata
task/
task.go # package source
todo.go # command source
<a href="https://github.com/golang/example/">github.com/golang/example/</a>
.git/ # Git repository metadata
hello/
hello.go # command source
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # package source
reverse_test.go # test source
</pre>
<p>
This workspace contains three repositories (<code>goauth2</code>,
<code>streak</code>, and <code>todo</code>) comprising two commands
(<code>streak</code> and <code>todo</code>) and two libraries
(<code>oauth</code> and <code>task</code>).
This workspace contains one repository (<code>example</code>)
comprising two commands (<code>hello</code> and <code>outyet</code>)
and one library (<code>stringutil</code>).
</p>
<p>
A typical workspace would contain many source repositories containing many
packages and commands. Most Go programmers keep <i>all</i> their Go source code
and dependencies in a single workspace.
</p>
<p>
@ -277,29 +275,29 @@ Let's write a library and use it from the <code>hello</code> program.
<p>
Again, the first step is to choose a package path (we'll use
<code>github.com/user/newmath</code>) and create the package directory:
<code>github.com/user/stringutil</code>) and create the package directory:
</p>
<pre>
$ <b>mkdir $GOPATH/src/github.com/user/newmath</b>
$ <b>mkdir $GOPATH/src/github.com/user/stringutil</b>
</pre>
<p>
Next, create a file named <code>sqrt.go</code> in that directory with the
Next, create a file named <code>reverse.go</code> in that directory with the
following contents.
</p>
<pre>
// Package newmath is a trivial example package.
package newmath
// Package stringutil contains utility functions for working with strings.
package stringutil
// Sqrt returns an approximation to the square root of x.
func Sqrt(x float64) float64 {
z := 1.0
for i := 0; i &lt; 1000; i++ {
z -= (z*z - x) / (2 * z)
// Reverse returns its argument string reversed rune-wise left to right.
func Reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i &lt; len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return z
return string(r)
}
</pre>
@ -308,7 +306,7 @@ Now, test that the package compiles with <code>go build</code>:
</p>
<pre>
$ <b>go build github.com/user/newmath</b>
$ <b>go build github.com/user/stringutil</b>
</pre>
<p>
@ -326,7 +324,7 @@ directory of the workspace.
</p>
<p>
After confirming that the <code>newmath</code> package builds,
After confirming that the <code>stringutil</code> package builds,
modify your original <code>hello.go</code> (which is in
<code>$GOPATH/src/github.com/user/hello</code>) to use it:
</p>
@ -337,18 +335,18 @@ package main
import (
"fmt"
<b>"github.com/user/newmath"</b>
<b>"github.com/user/stringutil"</b>
)
func main() {
fmt.Printf("Hello, world. <b>Sqrt(2) = %v\n", newmath.Sqrt(2)</b>)
fmt.Printf(stringutil.Reverse("!oG ,olleH"))
}
</pre>
<p>
Whenever the <code>go</code> tool installs a package or binary, it also
installs whatever dependencies it has. So when you install the <code>hello</code>
program
installs whatever dependencies it has.
So when you install the <code>hello</code> program
</p>
<pre>
@ -356,16 +354,16 @@ $ <b>go install github.com/user/hello</b>
</pre>
<p>
the <code>newmath</code> package will be installed as well, automatically.
the <code>stringutil</code> package will be installed as well, automatically.
</p>
<p>
Running the new version of the program, you should see some numerical output:
Running the new version of the program, you should see a new, reversed message:
</p>
<pre>
$ <b>hello</b>
Hello, world. Sqrt(2) = 1.414213562373095
Hello, Go!
</pre>
<p>
@ -374,22 +372,22 @@ After the steps above, your workspace should look like this:
<pre>
bin/
hello # command executable
hello # command executable
pkg/
linux_amd64/ # this will reflect your OS and architecture
linux_amd64/ # this will reflect your OS and architecture
github.com/user/
newmath.a # package object
stringutil.a # package object
src/
github.com/user/
hello/
hello.go # command source
newmath/
sqrt.go # package source
hello.go # command source
stringutil/
reverse.go # package source
</pre>
<p>
Note that <code>go install</code> placed the <code>newmath.a</code> object in a
directory inside <code>pkg/linux_amd64</code> that mirrors its source
Note that <code>go install</code> placed the <code>stringutil.a</code> object
in a directory inside <code>pkg/linux_amd64</code> that mirrors its source
directory.
This is so that future invocations of the <code>go</code> tool can find the
package object and avoid recompiling the package unnecessarily.
@ -457,20 +455,29 @@ if the function calls a failure function such as <code>t.Error</code> or
</p>
<p>
Add a test to the <code>newmath</code> package by creating the file
<code>$GOPATH/src/github.com/user/newmath/sqrt_test.go</code> containing the
following Go code.
Add a test to the <code>stringutil</code> package by creating the file
<code>$GOPATH/src/github.com/user/stringutil/reverse_test.go</code> containing
the following Go code.
</p>
<pre>
package newmath
package stringutil
import "testing"
func TestSqrt(t *testing.T) {
const in, out = 4, 2
if x := Sqrt(in); x != out {
t.Errorf("Sqrt(%v) = %v, want %v", in, x, out)
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
</pre>
@ -480,8 +487,8 @@ Then run the test with <code>go test</code>:
</p>
<pre>
$ <b>go test github.com/user/newmath</b>
ok github.com/user/newmath 0.165s
$ <b>go test github.com/user/stringutil</b>
ok github.com/user/stringutil 0.165s
</pre>
<p>
@ -491,7 +498,7 @@ directory, you can omit the package path:
<pre>
$ <b>go test</b>
ok github.com/user/newmath 0.165s
ok github.com/user/stringutil 0.165s
</pre>
<p>
@ -507,16 +514,16 @@ An import path can describe how to obtain the package source code using a
revision control system such as Git or Mercurial. The <code>go</code> tool uses
this property to automatically fetch packages from remote repositories.
For instance, the examples described in this document are also kept in a
Mercurial repository hosted at Google Code,
<code><a href="//code.google.com/p/go.example">code.google.com/p/go.example</a></code>.
Git repository hosted at GitHub
<code><a href="https://github.com/golang/example">github.com/golang/example</a></code>.
If you include the repository URL in the package's import path,
<code>go get</code> will fetch, build, and install it automatically:
</p>
<pre>
$ <b>go get code.google.com/p/go.example/hello</b>
$ <b>go get github.com/golang/example/hello</b>
$ <b>$GOPATH/bin/hello</b>
Hello, world. Sqrt(2) = 1.414213562373095
Hello, Go examples!
</pre>
<p>
@ -533,37 +540,39 @@ tree should now look like this:
<pre>
bin/
hello # command executable
hello # command executable
pkg/
linux_amd64/
code.google.com/p/go.example/
newmath.a # package object
github.com/golang/example/
stringutil.a # package object
github.com/user/
newmath.a # package object
stringutil.a # package object
src/
code.google.com/p/go.example/
github.com/golang/example/
.git/ # Git repository metadata
hello/
hello.go # command source
newmath/
sqrt.go # package source
sqrt_test.go # test source
hello.go # command source
stringutil/
reverse.go # package source
reverse_test.go # test source
github.com/user/
hello/
hello.go # command source
newmath/
sqrt.go # package source
sqrt_test.go # test source
hello.go # command source
stringutil/
reverse.go # package source
reverse_test.go # test source
</pre>
<p>
The <code>hello</code> command hosted at Google Code depends on the
<code>newmath</code> package within the same repository. The imports in
<code>hello.go</code> file use the same import path convention, so the <code>go
get</code> command is able to locate and install the dependent package, too.
The <code>hello</code> command hosted at GitHub depends on the
<code>stringutil</code> package within the same repository. The imports in
<code>hello.go</code> file use the same import path convention, so the
<code>go get</code> command is able to locate and install the dependent
package, too.
</p>
<pre>
import "code.google.com/p/go.example/newmath"
import "github.com/golang/example/stringutil"
</pre>
<p>

View File

@ -121,7 +121,7 @@ are inside the go directory when issuing commands.
<p>To contribute to subrepositories, edit the <code>.hg/hgrc</code> for each
subrepository in the same way. For example, add the codereview extension to
<code>code.google.com/p/go.tools/.hg/hgrc</code>.
<code>golang.org/x/tools/.hg/hgrc</code>.
</p>
<h3>Understanding the extension</h3>

View File

@ -18,8 +18,7 @@ Stacks are now contiguous, reallocated when necessary rather than linking on new
"segments";
this release therefore eliminates the notorious "hot stack split" problem.
There are some new tools available including support in the <code>go</code> command
for build-time source code generation
and TODO.
for build-time source code generation.
The release also adds support for ARM processors on Android and Native Client (NaCl)
and AMD64 on Plan 9.
As always, Go 1.4 keeps the <a href="/doc/go1compat.html">promise
@ -121,9 +120,9 @@ compile but is easy to fix by adding an explicit dereference.
<p>
Go 1.4 can build binaries for ARM processors running the Android operating system.
It can also build a <code>.so</code> library that can be loaded by an Android application
using the supporting packages in the <a href="http://code.google.com/p/go.mobile">go.mobile</a> repository.
using the supporting packages in the <a href="https://golang.org/x/mobile">mobile</a> subrepository.
A brief description of the plans for this experimental port are available
<a href="/s/go14android">here</a>.
<a href="https://golang.org/s/go14android">here</a>.
</p>
<h3 id="naclarm">NaCl on ARM</h3>
@ -194,13 +193,12 @@ A consequence is that stacks are no longer segmented, eliminating the "hot split
When a stack limit is reached, a new, larger stack is allocated, all active frames for
the goroutine are copied there, and any pointers into the stack are updated.
Performance can be noticeably better in some cases and is always more predictable.
Details are available in <a href="/s/contigstacks">the design document</a>.
Details are available in <a href="https://golang.org/s/contigstacks">the design document</a>.
</p>
<p>
The use of contiguous stacks means that stacks can start smaller without triggering performance issues,
so the default starting size for a goroutine's stack in 1.4 has been reduced to 2048 bytes from 8192 bytes.
TODO: It may be bumped to 4096 for the release.
</p>
<p>
@ -281,7 +279,9 @@ More information about these changes is in the <a href="/doc/asm">assembly docum
<h3 id="gccgo">Status of gccgo</h3>
<p>
TODO gccgo news
The release schedules for the GCC and Go projects do not coincide.
GCC release 4.9 contains the Go 1.2 version of gccgo.
The next release, GCC 5, will likely have the Go 1.4 version of gccgo.
</p>
<h3 id="internalpackages">Internal packages</h3>
@ -319,7 +319,7 @@ from 1.5 and onward it will be enforced for any repository.
<p>
Full details of the mechanism are in
<a href="http://golang.org/s/go14internal">the design document</a>.
<a href="https://golang.org/s/go14internal">the design document</a>.
</p>
<h3 id="canonicalimports">Canonical import paths</h3>
@ -370,9 +370,36 @@ fails because of this check, the mis-imported package has been copied to the loc
and should be removed manually.
</p>
<p>
To complement this new feature, a check has been added at update time to verify
that the local package's remote repository matches that of its custom import.
The <code>go</code> <code>get</code> <code>-u</code> command will fail to
update a package if its remote repository has changed since it was first
downloaded.
The new <code>-f</code> flag overrides this check.
</p>
<p>
Further information is in
<a href="http://golang.org/s/go14customimport">the design document</a>.
<a href="https://golang.org/s/go14customimport">the design document</a>.
</p>
<h3 id="subrepo">Import paths for the subrepositories</h3>
<p>
The Go project subrepositories (<code>code.google.com/p/go.tools</code> and so on)
are now available under custom import paths replacing <code>code.google.com/p/go.</code> with <code>golang.org/x/</code>,
as in <code>golang.org/x/tools</code>.
We will add canonical import comments to the code around June 1, 2015,
at which point Go 1.4 and later will stop accepting the old <code>code.google.com</code> paths.
</p>
<p>
<em>Updating</em>: All code that imports from subrepositories should change
to use the new <code>golang.org</code> paths.
Go 1.0 and later can resolve and import the new paths, so updating will not break
compatibility with older releases.
Code that has not updated will stop compiling with Go 1.4 around June 1, 2015.
</p>
<h3 id="gogenerate">The go generate subcommand</h3>
@ -384,13 +411,13 @@ to automate the running of tools to generate source code before compilation.
For example, it can be used to run the <a href="/cmd/yacc"><code>yacc</code></a>
compiler-compiler on a <code>.y</code> file to produce the Go source file implementing the grammar,
or to automate the generation of <code>String</code> methods for typed constants using the new
<a href="http://godoc.org/code.google.com/p/go.tools/cmd/stringer">stringer</a>
tool in the <code>go.tools</code> repository.
<a href="http://godoc.org/golang.org/x/tools/cmd/stringer">stringer</a>
tool in the <code>golang.org/x/tools</code> subrepository.
</p>
<p>
For more information, see the
<a href="http://golang.org/s/go1.4-generate">design document</a>.
<a href="https://golang.org/s/go1.4-generate">design document</a>.
</p>
<h3 id="filenames">Change to file name handling</h3>
@ -465,17 +492,12 @@ rebuild the standard library and commands, to avoid overwriting the installation
</ul>
<h3 id="godoc">Changes to godoc</h3>
<p>
TODO godoc news
</p>
<h3 id="pkg">Changes to package source layout</h3>
<p>
In the main Go source repository, the source code for the packages was kept in
the directory <code>src/pkg</code>, which made sense but differed from
other repositories, including the Go sub-repositories such as <code>go.tools</code>.
other repositories, including the Go subrepositories.
In Go 1.4, the<code> pkg</code> level of the source tree is now gone, so for example
the <a href="/pkg/fmt/"><code>fmt</code></a> package's source, once kept in
directory <code>src/pkg/fmt</code>, now lives one level higher in <code>src/fmt</code>.
@ -487,6 +509,16 @@ need to know about the new location. All tools and services maintained by the Go
have been updated.
</p>
<h3 id="swig">SWIG</h3>
<p>
Due to the runtime changes in this release, Go 1.4 will require SWIG 3.0.3.
At time of writing that has not yet been released, but we expect it to be by
Go 1.4's release date.
TODO
</p>
<h3 id="misc">Miscellany</h3>
<p>
@ -544,14 +576,57 @@ There are no new packages in this release.
<h3 id="major_library_changes">Major changes to the library</h3>
<h4 id="scanner">bufio.Scanner</h4>
<p>
TODO major changes
The <a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> type in the
<a href="/pkg/bufio/"><code>bufio</code></a> package
has had a bug fixed that may require changes to custom
<a href="/pkg/bufio/#SplitFunc"><code>split functions</code></a>.
The bug made it impossible to generate an empty token at EOF; the fix
changes the end conditions seen by the split function.
Previously, scanning stopped at EOF if there was no more data.
As of 1.4, the split function will be called once at EOF after input is exhausted,
so the split function can generate a final empty token
as the documentation already promised.
</p>
<pre>
encoding/gob: remove unsafe (CL 102680045)
syscall: now frozen (CL 129820043); go.sys subrepo created: http://golang.org/s/go1.4-syscall
</pre>
<p>
<em>Updating</em>: Custom split functions may need to be modified to
handle empty tokens at EOF as desired.
</p>
<h4 id="syscall">syscall</h4>
<p>
The <a href="/pkg/syscall/"><code>syscall</code></a> package is now frozen except
for changes needed to maintain the core repository.
In particular, it will no longer be extended to support new or different system calls
that are not used by the core.
The reasons are described at length in <a href="https://golang.org/s/go1.4-syscall">a
separate document</a>.
</p>
<p>
A new subrepository, <a href="https://golang.org/x/sys">golang.org/x/sys</a>,
has been created to serve as the location for new developments to support system
calls on all kernels.
It has a nicer structure, with three packages that each hold the implementation of
system calls for one of
<a href="http://godoc.org/golang.org/x/sys/unix">Unix</a>,
<a href="http://godoc.org/golang.org/x/sys/windows">Windows</a> and
<a href="http://godoc.org/golang.org/x/sys/plan9">Plan 9</a>.
These packages will be curated more generously, accepting all reasonable changes
that reflect kernel interfaces in those operating systems.
See the documentation and the article mentioned above for more information.
</p>
<p>
<em>Updating</em>: Existing programs are not affected as the <code>syscall</code>
package is largely unchanged from the 1.3 release.
Future development that requires system calls not in the <code>syscall</code> package
should build on <code>golang.org/x/sys</code> instead.
</p>
<h3 id="minor_library_changes">Minor changes to the library</h3>
@ -562,37 +637,199 @@ See the relevant package documentation for more information about each change.
<ul>
<li> TODO changes
<li>
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>,
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>,
and <a href="/pkg/compress/zlib/"><code>compress/zlib</code></a>
packages now support a <code>Reset</code> method
for the decompressors, allowing them to reuse buffers and improve performance.
</li>
</ul>
<li>
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
now supports ALPN as defined in <a href="http://tools.ietf.org/html/rfc7301">RFC 7301</a>.
</li>
<li>
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
now supports programmatic selection of server certificates
through the new <a href="/pkg/crypto/tls/#Config.CertificateForName"><code>CertificateForName</code></a> function
of the <a href="/pkg/crypo/tls/#Config"><code>Config</code></a> struct.
</li>
<li>
Also in the crypto/tls package, the server now supports
<a href="https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00">TLS_FALLBACK_SCSV</a>
to help clients detect fallback attacks.
(The Go client does not support fallback at all, so it is not vulnerable to
those attacks.)
</li>
<li>
In the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package,
optional elements with a default value will now only be omitted if they have that value.
</li>
<li>
The <a href="/pkg/encoding/csv/"><code>encoding/csv</code></a> package no longer
quotes empty strings but does quote the end-of-data marker <code>\.</code> (backslash dot).
This is permitted by the definition of CSV and allows it to work better with Postgres.
</li>
<li>
The <a href="/pkg/encoding/gob/"><code>encoding/gob</code></a> package has been rewritten to eliminate
the use of unsafe operations, allowing it to be used in environments that do not permit use of the
<a href="/pkg/unsafe/"><code>unsafe</code></a> package.
For typical uses it will be 10-30% slower, but the delta is dependent on the type of the data and
in some cases, especially involving arrays, it can be faster.
There is no functional change.
</li>
<li>
In the <a href="/pkg/fmt/"><code>fmt</code></a> package,
formatting of pointers to maps has changed to be consistent with that of pointers
to structs, arrays, and so on.
For instance, <code>&amp;map[string]int{"one":</code> <code>1}</code> now prints by default as
<code>&amp;map[one:</code> <code>1]</code> rather than as a hexadecimal pointer value.
</li>
<li>
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
<a href="/pkg/net/http/#Request"><code>Request</code></a> type
has a new <a href="/pkg/net/http/#Request.BasicAuth"><code>BasicAuth</code></a> method
that returns the username and password from authenticated requests using the
HTTP Basic Authentication
Scheme.
</li>
<li>The <a href="/pkg/net/http/"><code>net/http</code></a> package's
<a href="/pkg/net/http/#Request"><code>Transport</code></a> type
has a new <a href="/pkg/net/http/#Transport.DialTLS"><code>DialTLS</code></a> hook
that allows customizing the behavior of outbound TLS connections.
</li>
<li>
The <a href="/pkg/net/http/httputil/"><code>net/http/httputil</code></a> package's
<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> type
has a new field,
<a href="/pkg/net/http/#ReverseProxy.ErrorLog"><code>ErrorLog</code></a>, that
provides user control of logging.
</li>
<li>
The <a href="/pkg/os/"><code>os</code></a> package
now implements symbolic links on the Windows operating system
through the <a href="/pkg/os/#Symlink"><code>Symlink</code></a> function.
Other operating systems already have this functionality.
</li>
<li>
The <a href="/pkg/reflect/"><code>reflect</code></a> package's
<a href="/pkg/reflect/#Type"><code>Type</code></a> interface
has a new method, <a href="/pkg/reflect/#type.Comparable"><code>Comparable</code></a>,
that reports whether the type implements general comparisons.
</li>
<li>
Also in the <a href="/pkg/reflect/"><code>reflect</code></a> package, the
<a href="/pkg/reflect/#Value"><code>Value</code></a> interface is now three instead of four words
because of changes to the implementation of interfaces in the runtime.
This saves memory but has no semantic effect.
</li>
<li>
The <a href="/pkg/runtime/"><code>runtime</code></a> package
now implements monotonic clocks on Windows,
as it already did for the other systems.
</li>
<li>
The <a href="/pkg/runtime/"><code>runtime</code></a> package's
<a href="/pkg/runtime/#MemStats.Mallocs"><code>Mallocs</code></a> counter
now counts very small allocations that were missed in Go 1.3.
This may break tests using <a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
or <a href="/pkg/testing/#AllocsPerRun"><code>AllocsPerRun</code></a>
due to the more accurate answer.
</li>
<li>
In the <a href="/pkg/runtime/"><code>runtime</code></a> package,
an array <a href="/pkg/runtime/#MemStats.PauseEnd"><code>PauseEnd</code></a>
has been added to the
<a href="/pkg/runtime/#MemStats"><code>MemStats</code></a>
and <a href="/pkg/runtime/#GCStats"><code>GCStats</code></a> structs.
This array is a circular buffer of times when garbage collection pauses ended.
The corresponding pause durations are already recorded in
<a href="/pkg/runtime/#MemStats.PauseNs"><code>PauseNs</code></a>
</li>
<li>
The <a href="/pkg/runtime/race/"><code>runtime/race</code></a> package
now supports FreeBSD, which means the
<a href="/pkg/cmd/go/"><code>go</code></a> command's <code>-race</code>
flag now works on FreeBSD.
</li>
<li>
The <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package
has a new type, <a href="/pkg/sync/atomic/#Value"><code>Value</code></a>.
<code>Value</code> provides an efficient mechanism for atomic loads and
stores of values of arbitrary type.
</li>
<li>
In the <a href="/pkg/syscall/"><code>syscall</code></a> package's
implementation on Linux, the
<a href="/pkg/syscall/#Setuid"><code>Setuid</code></a>
and <a href="/pkg/syscall/#Setgid"><code>Setgid</code></a> have been disabled
because those system calls operate on the calling thread, not the whole process, which is
different from other platforms and not the expected result.
</li>
<li>
The <a href="/pkg/testing/"><code>testing</code></a> package
has a new facility to provide more control over running a set of tests.
If the test code contains a function
<pre>
cmd/6l, liblink: use pc-relative addressing for all memory references, so that linking Go binaries at high addresses works (CL 125140043). This cuts the maximum size of a Go binary's text+data+bss from 4GB to 2GB.
bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043)
compress/flate, compress/gzip, compress/zlib: Reset support (https://codereview.appspot.com/97140043)
crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
crypto/tls: support programmatic selection of server certificates (CL 107400043)
encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
fmt: print type *map[T]T as &amp;map[k:v] (CL 154870043)
encoding/csv: do not quote empty strings, quote \. (CL 164760043)
net/http: add Request.BasicAuth method (CL 76540043)
net/http: add Transport.DialTLS hook (CL 137940043)
net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043)
os: implement symlink support for windows (CL 86160044)
reflect: add type.Comparable (CL 144020043)
reflect: Value is one word smaller
runtime: implement monotonic clocks on windows (CL 108700045)
runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043).
runtime/race: freebsd is supported (CL 107270043)
runtime: add PauseEnd array to MemStats and GCStats (CL 153670043)
swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released)
sync/atomic: add Value (CL 136710045)
syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)
testing: add Coverage (CL 98150043)
testing: add TestMain support (CL 148770043)
text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
text/template: allow comparison of signed and unsigned integers (CL 149780043)
time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)
func TestMain(m *<a href="/pkg/testing/#M"><code>testing.M</code></a>)
</pre>
that function will be called instead of running the tests directly.
The <code>M</code> struct contains methods to access and run the tests.
</li>
<li>
Also in the <a href="/pkg/testing/"><code>testing</code></a> package,
a new <a href="/pkg/testing/#Coverage"><code>Coverage</code></a>
function reports the current test coverage fraction,
enabling individual tests to report how much they are contributing to the
overall coverage.
</li>
<li>
The <a href="/pkg/text/scanner/"><code>text/scanner</code></a> package's
<a href="/pkg/text/scanner/#Scanner"><code>Scanner</code></a> type
has a new function,
<a href="/pkg/text/scanner/#Scanner.IsIdentRune"><code>IsIdentRune</code></a>,
allowing one to control the definition of an identifier when scanning.
</li>
<li>
The <a href="/pkg/text/template/"><code>text/template</code></a> package's boolean
functions <code>eq</code>, <code>lt</code>, and so on have been generalized to allow comparison
of signed and unsigned integers, simplifying their use in practice.
(Previously one could only compare values of the same signedness.)
All negative values compare less than all unsigned values.
</li>
<li>
The <code>time</code> package now uses the standard symbol for the micro prefix,
the micro symbol (U+00B5 'µ'), to print microsecond durations.
<a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> still accepts <code>us</code>
but the package no longer prints microseconds as <code>us</code>.
<br>
<em>Updating</em>: Code that depends on the output format of durations
but does not use ParseDuration will need to be updated.
</li>
</ul>

View File

@ -153,7 +153,7 @@ developed software based on Go 1.
<p>
Code in sub-repositories of the main go tree, such as
<a href="//code.google.com/p/go.net">code.google.com/p/go.net</a>,
<a href="//golang.org/x/net">golang.org/x/net</a>,
may be developed under
looser compatibility requirements. However, the sub-repositories
will be tagged as appropriate to identify versions that are compatible
@ -170,9 +170,9 @@ is therefore outside the purview of the guarantees made here.
As of Go version 1.4, the <code>syscall</code> package is frozen.
Any evolution of the system call interface must be supported elsewhere,
such as in the
<a href="http://godoc.org/code.google.com/p/go.sys">go.sys</a> subrepository.
<a href="//golang.org/x/sys">go.sys</a> subrepository.
For details and background, see
<a href="https://golang.org/s/go1.4-syscall">this document</a>.
<a href="//golang.org/s/go1.4-syscall">this document</a>.
</p>
<h2 id="tools">Tools</h2>

View File

@ -1616,7 +1616,7 @@ Go is a
fine language in which to implement a self-hosting compiler: a native lexer and
parser are already available in the <a href="/pkg/go/"><code>go</code></a> package
and a separate type checking
<a href="http://godoc.org/code.google.com/p/go.tools/go/types">package</a>
<a href="http://godoc.org/golang.org/x/tools/go/types">package</a>
has also been written.
</p>
@ -1715,7 +1715,7 @@ func main() {
<p>
Nowadays, most Go programmers use a tool,
<a href="http://godoc.org/code.google.com/p/go.tools/cmd/goimports">goimports</a>,
<a href="http://godoc.org/golang.org/x/tools/cmd/goimports">goimports</a>,
which automatically rewrites a Go source file to have the correct imports,
eliminating the unused imports issue in practice.
This program is easily connected to most editors to run automatically when a Go source file is written.

View File

@ -241,12 +241,12 @@ provides <b>essential setup instructions</b> for using the Go tools.
<p>
The source code for several Go tools (including <a href="/cmd/godoc/">godoc</a>)
is kept in <a href="https://code.google.com/p/go.tools">the go.tools repository</a>.
is kept in <a href="https://golang.org/x/tools">the go.tools repository</a>.
To install all of them, run the <code>go</code> <code>get</code> command:
</p>
<pre>
$ go get code.google.com/p/go.tools/cmd/...
$ go get golang.org/x/tools/cmd/...
</pre>
<p>
@ -254,7 +254,7 @@ Or if you just want to install a specific command (<code>godoc</code> in this ca
</p>
<pre>
$ go get code.google.com/p/go.tools/cmd/godoc
$ go get golang.org/x/tools/cmd/godoc
</pre>
<p>

View File

@ -1631,7 +1631,7 @@ def clpatch_or_undo(ui, repo, clname, opts, mode):
try:
cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
except:
return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get code.google.com/p/go.codereview/cmd/hgapplydiff\n"
return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get golang.org/x/codereview/cmd/hgapplydiff\n"
out, err = cmd.communicate(patch)
if cmd.returncode != 0 and not opts["ignore_hgapplydiff_failure"]:
@ -3451,6 +3451,7 @@ class FakeMercurialUI(object):
def __init__(self):
self.quiet = True
self.output = ''
self.debugflag = False
def write(self, *args, **opts):
self.output += ' '.join(args)

View File

@ -1,5 +1,5 @@
#!/bin/bash
echo 'misc/benchcmp has moved:' >&2
echo ' go get -u code.google.com/p/go.tools/cmd/benchcmp' >&2
echo ' go get -u golang.org/x/tools/cmd/benchcmp' >&2
exit 2

View File

@ -62,5 +62,6 @@ func Test8517(t *testing.T) { test8517(t) }
func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
func Test9026(t *testing.T) { test9026(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View File

@ -34,7 +34,7 @@ func test6997(t *testing.T) {
if r == 0 {
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")
}
}

View File

@ -0,0 +1,9 @@
package cgotest
import (
"testing"
"./issue9026"
)
func test9026(t *testing.T) { issue9026.Test(t) }

View File

@ -0,0 +1,36 @@
package issue9026
// This file appears in its own package since the assertion tests the
// per-package counter used to create fresh identifiers.
/*
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 Test(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 := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___1"
if got != want {
t.Errorf("Non-deterministic type names: got %s, want %s", got, want)
}
}

View File

@ -53,8 +53,8 @@ var (
)
const (
blogPath = "code.google.com/p/go.blog"
toolPath = "code.google.com/p/go.tools"
blogPath = "golang.org/x/blog"
toolPath = "golang.org/x/tools"
tourPath = "code.google.com/p/go-tour"
defaultToolTag = "release-branch.go1.3"
defaultTourTag = "release-branch.go1.3"
@ -64,9 +64,9 @@ const (
// These must be the command that cmd/go knows to install to $GOROOT/bin
// or $GOROOT/pkg/tool.
var toolPaths = []string{
"code.google.com/p/go.tools/cmd/cover",
"code.google.com/p/go.tools/cmd/godoc",
"code.google.com/p/go.tools/cmd/vet",
"golang.org/x/tools/cmd/cover",
"golang.org/x/tools/cmd/godoc",
"golang.org/x/tools/cmd/vet",
}
var preBuildCleanFiles = []string{

5100
misc/pprof

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,7 @@ type Scanner struct {
start int // First non-processed byte in buf.
end int // End of data in buf.
err error // Sticky error.
empties int // Count of successive empty tokens.
}
// SplitFunc is the signature of the split function used to tokenize the
@ -108,6 +109,8 @@ func (s *Scanner) Text() string {
// After Scan returns false, the Err method will return any error that
// occurred during scanning, except that if it was io.EOF, Err
// will return nil.
// Split panics if the split function returns 100 empty tokens without
// advancing the input. This is a common error mode for scanners.
func (s *Scanner) Scan() bool {
// Loop until we have a token.
for {
@ -125,6 +128,15 @@ func (s *Scanner) Scan() bool {
}
s.token = token
if token != nil {
if s.err == nil || advance > 0 {
s.empties = 0
} else {
// Returning tokens not advancing input at EOF.
s.empties++
if s.empties > 100 {
panic("bufio.Scan: 100 empty tokens without progressing")
}
}
return true
}
}
@ -172,6 +184,7 @@ func (s *Scanner) Scan() bool {
break
}
if n > 0 {
s.empties = 0
break
}
loop++

View File

@ -455,3 +455,70 @@ func TestEmptyTokens(t *testing.T) {
t.Fatal(err)
}
}
func loopAtEOFSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
if len(data) > 0 {
return 1, data[:1], nil
}
return 0, data, nil
}
func TestDontLoopForever(t *testing.T) {
s := NewScanner(strings.NewReader("abc"))
s.Split(loopAtEOFSplit)
// Expect a panic
defer func() {
err := recover()
if err == nil {
t.Fatal("should have panicked")
}
if msg, ok := err.(string); !ok || !strings.Contains(msg, "empty tokens") {
panic(err)
}
}()
for count := 0; s.Scan(); count++ {
if count > 1000 {
t.Fatal("looping")
}
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
}
func TestBlankLines(t *testing.T) {
s := NewScanner(strings.NewReader(strings.Repeat("\n", 1000)))
for count := 0; s.Scan(); count++ {
if count > 2000 {
t.Fatal("looping")
}
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
}
type countdown int
func (c *countdown) split(data []byte, atEOF bool) (advance int, token []byte, err error) {
if *c > 0 {
*c--
return 1, data[:1], nil
}
return 0, nil, nil
}
// Check that the looping-at-EOF check doesn't trigger for merely empty tokens.
func TestEmptyLinesOK(t *testing.T) {
c := countdown(10000)
s := NewScanner(strings.NewReader(strings.Repeat("\n", 10000)))
s.Split(c.split)
for s.Scan() {
}
if s.Err() != nil {
t.Fatal("after scan:", s.Err())
}
if c != 0 {
t.Fatalf("stopped with %d left to process", c)
}
}

View File

@ -199,7 +199,7 @@ regopt(Prog *firstp)
proginfo(&info, p);
// Avoid making variables for direct-called functions.
if(p->as == ABL && p->to.type == D_EXTERN)
if(p->as == ABL && p->to.name == D_EXTERN)
continue;
bit = mkvar(r, &p->from);

View File

@ -944,6 +944,8 @@ type typeConv struct {
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
ptrKeys []dwarf.Type
// Predeclared types.
bool ast.Expr
@ -1061,16 +1063,17 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
func (c *typeConv) FinishType(pos token.Pos) {
// Completing one pointer type might produce more to complete.
// Keep looping until they're all done.
for len(c.ptrs) > 0 {
for dtype := range c.ptrs {
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
delete(c.ptrs, dtype)
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
c.ptrKeys = c.ptrKeys[1:]
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
c.ptrs[dtype] = nil // retain the map key
}
}
@ -1237,6 +1240,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{}
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)
case *dwarf.QualType:

View File

@ -691,13 +691,6 @@ install(char *dir)
bpathf(&final_path, "%s/src/%s", goroot_final, dir);
name = lastelem(dir);
// For misc/prof, copy into the tool directory and we're done.
if(hasprefix(dir, "misc/")) {
copyfile(bpathf(&b, "%s/%s", tooldir, name),
bpathf(&b1, "%s/misc/%s", goroot, name), 1);
goto out;
}
// set up gcc command line on first run.
if(gccargs.len == 0) {
bprintf(&b, "%s %s", defaultcc, defaultcflags);
@ -1328,8 +1321,6 @@ static char *buildorder[] = {
"libbio",
"liblink",
"misc/pprof",
"cmd/cc", // must be before c
"cmd/gc", // must be before g
"cmd/%sl", // must be before a, c, g

View File

@ -344,8 +344,8 @@ main(int argc, char *argv[])
break;
}
}
if(j == nelem(debugtab))
fatal("unknown debug information -d '%s'\n", f[i]);
if(debugtab[j].name == nil)
sysfatal("unknown debug information -d '%s'\n", f[i]);
}
}

View File

@ -1826,7 +1826,15 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
warn := []string{"-w"}
if p.usesSwig() {
// When using SWIG, this compiler is only used to
// compile the C files generated by SWIG.
// We don't want warnings.
// See issue 9065 for details.
warn = nil
}
args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
return b.run(p.Dir, p.ImportPath, nil, args)
}

View File

@ -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.
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:
@ -260,7 +260,7 @@ Go generate sets several variables when it runs the generator:
$GOPACKAGE
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
line.
@ -590,7 +590,7 @@ Usage:
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.

View File

@ -58,7 +58,7 @@ Go generate sets several variables when it runs the generator:
$GOPACKAGE
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
line.

View File

@ -383,9 +383,10 @@ func findInternal(path string) (index int, ok bool) {
type targetDir int
const (
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
toBin // GOROOT/bin
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
toBin // GOROOT/bin
stalePath // the old import path; fail to build
)
// goTools is a map of Go program import path to install target directory.
@ -398,10 +399,14 @@ var goTools = map[string]targetDir{
"cmd/nm": toTool,
"cmd/objdump": toTool,
"cmd/pack": toTool,
"cmd/pprof": toTool,
"cmd/yacc": toTool,
"code.google.com/p/go.tools/cmd/cover": toTool,
"code.google.com/p/go.tools/cmd/godoc": toBin,
"code.google.com/p/go.tools/cmd/vet": toTool,
"golang.org/x/tools/cmd/cover": toTool,
"golang.org/x/tools/cmd/godoc": toBin,
"golang.org/x/tools/cmd/vet": toTool,
"code.google.com/p/go.tools/cmd/cover": stalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath,
}
// expandScanner expands a scanner.List error into all the errors in the list.
@ -462,6 +467,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
if p.Name == "main" {
// Report an error when the old code.google.com/p/go.tools paths are used.
if goTools[p.ImportPath] == stalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
p.Error = &PackageError{Err: e}
return p
}
_, elem := filepath.Split(p.Dir)
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {

View File

@ -433,20 +433,20 @@ TEST godoc installs into GOBIN
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir $d/gobin
GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc || ok=false
GOBIN=$d/gobin ./testgo get golang.org/x/tools/cmd/godoc || ok=false
if [ ! -x $d/gobin/godoc ]; then
echo did not install godoc to '$GOBIN'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc || true
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
ok=false
fi
TEST godoc installs into GOROOT
GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install code.google.com/p/go.tools/cmd/godoc || ok=false
./testgo install golang.org/x/tools/cmd/godoc || ok=false
if [ ! -x $GOROOT/bin/godoc ]; then
echo did not install godoc to '$GOROOT/bin'
./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc || true
./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
ok=false
fi
@ -561,8 +561,8 @@ fi
TEST without GOPATH, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
if GOPATH= GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with $GOPATH unset'
ok=false
fi
rm -rf $d
@ -571,8 +571,8 @@ rm -rf $d
TEST with GOPATH=GOROOT, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
if GOPATH=$d GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
ok=false
fi
rm -rf $d
@ -728,7 +728,7 @@ elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
fi
TEST go get cover
./testgo get code.google.com/p/go.tools/cmd/cover || ok=false
./testgo get golang.org/x/tools/cmd/cover || ok=false
unset GOPATH
rm -rf $d

View File

@ -53,7 +53,7 @@ func tool(toolName string) string {
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName)
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}

View File

@ -17,7 +17,7 @@ var cmdVet = &Command{
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.

View File

@ -0,0 +1,248 @@
// 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.
package objfile
import (
"bufio"
"debug/gosym"
"encoding/binary"
"fmt"
"io"
"regexp"
"sort"
"strings"
"text/tabwriter"
"cmd/internal/rsc.io/arm/armasm"
"cmd/internal/rsc.io/x86/x86asm"
)
// Disasm is a disassembler for a given File.
type Disasm struct {
syms []Sym //symbols in file, sorted by address
pcln *gosym.Table // pcln table
text []byte // bytes of text segment (actual instructions)
textStart uint64 // start PC of text
textEnd uint64 // end PC of text
goarch string // GOARCH string
disasm disasmFunc // disassembler function for goarch
byteOrder binary.ByteOrder // byte order for goarch
}
// Disasm returns a disassembler for the file f.
func (f *File) Disasm() (*Disasm, error) {
syms, err := f.Symbols()
if err != nil {
return nil, err
}
pcln, err := f.PCLineTable()
if err != nil {
return nil, err
}
textStart, textBytes, err := f.Text()
if err != nil {
return nil, err
}
goarch := f.GOARCH()
disasm := disasms[goarch]
byteOrder := byteOrders[goarch]
if disasm == nil || byteOrder == nil {
return nil, fmt.Errorf("unsupported architecture")
}
// Filter out section symbols, overwriting syms in place.
keep := syms[:0]
for _, sym := range syms {
switch sym.Name {
case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext":
// drop
default:
keep = append(keep, sym)
}
}
syms = keep
d := &Disasm{
syms: syms,
pcln: pcln,
text: textBytes,
textStart: textStart,
textEnd: textStart + uint64(len(textBytes)),
goarch: goarch,
disasm: disasm,
byteOrder: byteOrder,
}
return d, nil
}
// lookup finds the symbol name containing addr.
func (d *Disasm) lookup(addr uint64) (name string, base uint64) {
i := sort.Search(len(d.syms), func(i int) bool { return addr < d.syms[i].Addr })
if i > 0 {
s := d.syms[i-1]
if s.Addr != 0 && s.Addr <= addr && addr < s.Addr+uint64(s.Size) {
return s.Name, s.Addr
}
}
return "", 0
}
// base returns the final element in the path.
// It works on both Windows and Unix paths,
// regardless of host operating system.
func base(path string) string {
path = path[strings.LastIndex(path, "/")+1:]
path = path[strings.LastIndex(path, `\`)+1:]
return path
}
// Print prints a disassembly of the file to w.
// If filter is non-nil, the disassembly only includes functions with names matching filter.
// The disassembly only includes functions that overlap the range [start, end).
func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
if start < d.textStart {
start = d.textStart
}
if end > d.textEnd {
end = d.textEnd
}
printed := false
bw := bufio.NewWriter(w)
for _, sym := range d.syms {
symStart := sym.Addr
symEnd := sym.Addr + uint64(sym.Size)
if sym.Code != 'T' && sym.Code != 't' ||
symStart < d.textStart ||
symEnd <= start || end <= symStart ||
filter != nil && !filter.MatchString(sym.Name) {
continue
}
if printed {
fmt.Fprintf(bw, "\n")
}
printed = true
file, _, _ := d.pcln.PCToLine(sym.Addr)
fmt.Fprintf(bw, "TEXT %s(SB) %s\n", sym.Name, file)
tw := tabwriter.NewWriter(bw, 1, 8, 1, '\t', 0)
if symEnd > end {
symEnd = end
}
code := d.text[:end-d.textStart]
d.Decode(symStart, symEnd, func(pc, size uint64, file string, line int, text string) {
i := pc - d.textStart
fmt.Fprintf(tw, "\t%s:%d\t%#x\t", base(file), line, pc)
if size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" {
// Print instruction as bytes.
fmt.Fprintf(tw, "%x", code[i:i+size])
} else {
// Print instruction as 32-bit words.
for j := uint64(0); j < size; j += 4 {
if j > 0 {
fmt.Fprintf(tw, " ")
}
fmt.Fprintf(tw, "%08x", d.byteOrder.Uint32(code[i+j:]))
}
}
fmt.Fprintf(tw, "\t%s\n", text)
})
tw.Flush()
}
bw.Flush()
}
// Decode disassembles the text segment range [start, end), calling f for each instruction.
func (d *Disasm) Decode(start, end uint64, f func(pc, size uint64, file string, line int, text string)) {
if start < d.textStart {
start = d.textStart
}
if end > d.textEnd {
end = d.textEnd
}
code := d.text[:end-d.textStart]
lookup := d.lookup
for pc := start; pc < end; {
i := pc - d.textStart
text, size := d.disasm(code[i:], pc, lookup)
file, line, _ := d.pcln.PCToLine(pc)
f(pc, uint64(size), file, line, text)
pc += uint64(size)
}
}
type lookupFunc func(addr uint64) (sym string, base uint64)
type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int)
func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) {
return disasm_x86(code, pc, lookup, 32)
}
func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) {
return disasm_x86(code, pc, lookup, 64)
}
func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
inst, err := x86asm.Decode(code, 64)
var text string
size := inst.Len
if err != nil || size == 0 || inst.Op == 0 {
size = 1
text = "?"
} else {
text = x86asm.Plan9Syntax(inst, pc, lookup)
}
return text, size
}
type textReader struct {
code []byte
pc uint64
}
func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
if off < 0 || uint64(off) < r.pc {
return 0, io.EOF
}
d := uint64(off) - r.pc
if d >= uint64(len(r.code)) {
return 0, io.EOF
}
n = copy(data, r.code[d:])
if n < len(data) {
err = io.ErrUnexpectedEOF
}
return
}
func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
inst, err := armasm.Decode(code, armasm.ModeARM)
var text string
size := inst.Len
if err != nil || size == 0 || inst.Op == 0 {
size = 4
text = "?"
} else {
text = armasm.Plan9Syntax(inst, pc, lookup, textReader{code, pc})
}
return text, size
}
var disasms = map[string]disasmFunc{
"386": disasm_386,
"amd64": disasm_amd64,
"arm": disasm_arm,
}
var byteOrders = map[string]binary.ByteOrder{
"386": binary.LittleEndian,
"amd64": binary.LittleEndian,
"arm": binary.LittleEndian,
"power64": binary.BigEndian,
"power64le": binary.LittleEndian,
}

View File

@ -8,6 +8,7 @@ package objfile
import (
"debug/elf"
"fmt"
"os"
)
@ -77,3 +78,27 @@ func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
}
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 ""
}

View File

@ -79,3 +79,15 @@ func (f *goobjFile) symbols() ([]Sym, 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")
}
// 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"
}

View File

@ -85,6 +85,30 @@ func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error)
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
func (x uint64s) Len() int { return len(x) }

View File

@ -9,11 +9,14 @@ import (
"debug/gosym"
"fmt"
"os"
"sort"
)
type rawFile interface {
symbols() (syms []Sym, 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.
@ -60,9 +63,20 @@ func (f *File) Close() error {
}
func (f *File) Symbols() ([]Sym, error) {
return f.raw.symbols()
syms, err := f.raw.symbols()
if err != nil {
return nil, err
}
sort.Sort(byAddr(syms))
return syms, nil
}
type byAddr []Sym
func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
func (x byAddr) Len() int { return len(x) }
func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (f *File) PCLineTable() (*gosym.Table, error) {
textStart, symtab, pclntab, err := f.raw.pcln()
if err != nil {
@ -70,3 +84,11 @@ func (f *File) PCLineTable() (*gosym.Table, error) {
}
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()
}

View File

@ -133,6 +133,25 @@ func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
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) {
for _, s := range f.Symbols {
if s.Name != name {
@ -168,3 +187,15 @@ func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
}
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 ""
}

View File

@ -88,6 +88,16 @@ func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error)
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) {
syms, err := f.Symbols()
if err != nil {
@ -122,3 +132,15 @@ func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
textStart := f.LoadAddress + f.HdrSize
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 ""
}

View File

@ -1,10 +0,0 @@
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

View File

@ -1,65 +0,0 @@
// 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
}

View File

@ -1,77 +0,0 @@
// 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] }

View File

@ -32,27 +32,15 @@
package main
import (
"bufio"
"bytes"
"debug/elf"
"debug/gosym"
"debug/macho"
"debug/pe"
"debug/plan9obj"
"encoding/binary"
"flag"
"fmt"
"io"
"log"
"os"
"regexp"
"sort"
"strconv"
"strings"
"text/tabwriter"
"cmd/internal/rsc.io/arm/armasm"
"cmd/internal/rsc.io/x86/x86asm"
"cmd/internal/objfile"
)
var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
@ -85,446 +73,35 @@ func main() {
symRE = re
}
f, err := os.Open(flag.Arg(0))
f, err := objfile.Open(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
textStart, textData, symtab, pclntab, err := loadTables(f)
dis, err := f.Disasm()
if err != nil {
log.Fatalf("reading %s: %v", flag.Arg(0), err)
log.Fatal("disassemble %s: %v", flag.Arg(0), err)
}
syms, goarch, err := loadSymbols(f)
if err != nil {
log.Fatalf("reading %s: %v", flag.Arg(0), err)
}
switch flag.NArg() {
default:
usage()
case 1:
// disassembly of entire object
dis.Print(os.Stdout, symRE, 0, ^uint64(0))
os.Exit(0)
// Filter out section symbols, overwriting syms in place.
keep := syms[:0]
for _, sym := range syms {
switch sym.Name {
case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext":
// drop
default:
keep = append(keep, sym)
case 3:
// disassembly of PC range
start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 16, 64)
if err != nil {
log.Fatalf("invalid start PC: %v", err)
}
}
syms = keep
disasm := disasms[goarch]
if disasm == nil {
log.Fatalf("reading %s: unknown architecture", flag.Arg(0))
}
lookup := func(addr uint64) (string, uint64) {
i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr })
if i > 0 {
s := syms[i-1]
if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "runtime.etext" && s.Name != "etext" && s.Name != "_etext" {
return s.Name, s.Addr
}
end, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(2), "0x"), 16, 64)
if err != nil {
log.Fatalf("invalid end PC: %v", err)
}
return "", 0
}
pcln := gosym.NewLineTable(pclntab, textStart)
tab, err := gosym.NewTable(symtab, pcln)
if err != nil {
log.Fatalf("reading %s: %v", flag.Arg(0), err)
}
if flag.NArg() == 1 {
// disassembly of entire object - our format
dump(tab, lookup, disasm, goarch, syms, textData, textStart)
os.Exit(exitCode)
}
// disassembly of specific piece of object - gnu objdump format for pprof
gnuDump(tab, lookup, disasm, textData, textStart)
os.Exit(exitCode)
}
// base returns the final element in the path.
// It works on both Windows and Unix paths.
func base(path string) string {
path = path[strings.LastIndex(path, "/")+1:]
path = path[strings.LastIndex(path, `\`)+1:]
return path
}
func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, syms []Sym, textData []byte, textStart uint64) {
stdout := bufio.NewWriter(os.Stdout)
defer stdout.Flush()
printed := false
for _, sym := range syms {
if (sym.Code != 'T' && sym.Code != 't') || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) {
continue
}
if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) {
break
}
if printed {
fmt.Fprintf(stdout, "\n")
} else {
printed = true
}
file, _, _ := tab.PCToLine(sym.Addr)
fmt.Fprintf(stdout, "TEXT %s(SB) %s\n", sym.Name, file)
tw := tabwriter.NewWriter(stdout, 1, 8, 1, '\t', 0)
start := sym.Addr
end := sym.Addr + uint64(sym.Size)
for pc := start; pc < end; {
i := pc - textStart
text, size := disasm(textData[i:end-textStart], pc, lookup)
file, line, _ := tab.PCToLine(pc)
// ARM is word-based, so show actual word hex, not byte hex.
// Since ARM is little endian, they're different.
if goarch == "arm" && size == 4 {
fmt.Fprintf(tw, "\t%s:%d\t%#x\t%08x\t%s\n", base(file), line, pc, binary.LittleEndian.Uint32(textData[i:i+uint64(size)]), text)
} else {
fmt.Fprintf(tw, "\t%s:%d\t%#x\t%x\t%s\n", base(file), line, pc, textData[i:i+uint64(size)], text)
}
pc += uint64(size)
}
tw.Flush()
dis.Print(os.Stdout, symRE, start, end)
os.Exit(0)
}
}
func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) {
return disasm_x86(code, pc, lookup, 32)
}
func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) {
return disasm_x86(code, pc, lookup, 64)
}
func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
inst, err := x86asm.Decode(code, 64)
var text string
size := inst.Len
if err != nil || size == 0 || inst.Op == 0 {
size = 1
text = "?"
} else {
text = x86asm.Plan9Syntax(inst, pc, lookup)
}
return text, size
}
type textReader struct {
code []byte
pc uint64
}
func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
if off < 0 || uint64(off) < r.pc {
return 0, io.EOF
}
d := uint64(off) - r.pc
if d >= uint64(len(r.code)) {
return 0, io.EOF
}
n = copy(data, r.code[d:])
if n < len(data) {
err = io.ErrUnexpectedEOF
}
return
}
func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
inst, err := armasm.Decode(code, armasm.ModeARM)
var text string
size := inst.Len
if err != nil || size == 0 || inst.Op == 0 {
size = 4
text = "?"
} else {
text = armasm.Plan9Syntax(inst, pc, lookup, textReader{code, pc})
}
return text, size
}
var disasms = map[string]disasmFunc{
"386": disasm_386,
"amd64": disasm_amd64,
"arm": disasm_arm,
}
func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []byte, textStart uint64) {
start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 16, 64)
if err != nil {
log.Fatalf("invalid start PC: %v", err)
}
end, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(2), "0x"), 16, 64)
if err != nil {
log.Fatalf("invalid end PC: %v", err)
}
if start < textStart {
start = textStart
}
if end < start {
end = start
}
if end > textStart+uint64(len(textData)) {
end = textStart + uint64(len(textData))
}
stdout := bufio.NewWriter(os.Stdout)
defer stdout.Flush()
// For now, find spans of same PC/line/fn and
// emit them as having dummy instructions.
var (
spanPC uint64
spanFile string
spanLine int
spanFn *gosym.Func
)
flush := func(endPC uint64) {
if spanPC == 0 {
return
}
fmt.Fprintf(stdout, "%s:%d\n", spanFile, spanLine)
for pc := spanPC; pc < endPC; {
text, size := disasm(textData[pc-textStart:], pc, lookup)
fmt.Fprintf(stdout, " %x: %s\n", pc, text)
pc += uint64(size)
}
spanPC = 0
}
for pc := start; pc < end; pc++ {
file, line, fn := tab.PCToLine(pc)
if file != spanFile || line != spanLine || fn != spanFn {
flush(pc)
spanPC, spanFile, spanLine, spanFn = pc, file, line, fn
}
}
flush(end)
}
func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) {
if obj, err := elf.NewFile(f); err == nil {
if sect := obj.Section(".text"); sect != nil {
textStart = sect.Addr
textData, _ = sect.Data()
}
if sect := obj.Section(".gosymtab"); sect != nil {
if symtab, err = sect.Data(); err != nil {
return 0, nil, nil, nil, err
}
}
if sect := obj.Section(".gopclntab"); sect != nil {
if pclntab, err = sect.Data(); err != nil {
return 0, nil, nil, nil, err
}
}
return textStart, textData, symtab, pclntab, nil
}
if obj, err := macho.NewFile(f); err == nil {
if sect := obj.Section("__text"); sect != nil {
textStart = sect.Addr
textData, _ = sect.Data()
}
if sect := obj.Section("__gosymtab"); sect != nil {
if symtab, err = sect.Data(); err != nil {
return 0, nil, nil, nil, err
}
}
if sect := obj.Section("__gopclntab"); sect != nil {
if pclntab, err = sect.Data(); err != nil {
return 0, nil, nil, nil, err
}
}
return textStart, textData, symtab, pclntab, nil
}
if obj, err := pe.NewFile(f); err == nil {
var imageBase uint64
switch oh := obj.OptionalHeader.(type) {
case *pe.OptionalHeader32:
imageBase = uint64(oh.ImageBase)
case *pe.OptionalHeader64:
imageBase = oh.ImageBase
default:
return 0, nil, nil, nil, fmt.Errorf("pe file format not recognized")
}
if sect := obj.Section(".text"); sect != nil {
textStart = imageBase + uint64(sect.VirtualAddress)
textData, _ = sect.Data()
}
if pclntab, err = loadPETable(obj, "runtime.pclntab", "runtime.epclntab"); err != nil {
// We didn't find the symbols, so look for the names used in 1.3 and earlier.
// TODO: Remove code looking for the old symbols when we no longer care about 1.3.
var err2 error
if pclntab, err2 = loadPETable(obj, "pclntab", "epclntab"); err2 != nil {
return 0, nil, nil, nil, err
}
}
if symtab, err = loadPETable(obj, "runtime.symtab", "runtime.esymtab"); err != nil {
// Same as above.
var err2 error
if symtab, err2 = loadPETable(obj, "symtab", "esymtab"); err2 != nil {
return 0, nil, nil, nil, err
}
}
return textStart, textData, symtab, pclntab, nil
}
if obj, err := plan9obj.NewFile(f); err == nil {
textStart = obj.LoadAddress + obj.HdrSize
if sect := obj.Section("text"); sect != nil {
textData, _ = sect.Data()
}
if pclntab, err = loadPlan9Table(obj, "runtime.pclntab", "runtime.epclntab"); err != nil {
// We didn't find the symbols, so look for the names used in 1.3 and earlier.
// TODO: Remove code looking for the old symbols when we no longer care about 1.3.
var err2 error
if pclntab, err2 = loadPlan9Table(obj, "pclntab", "epclntab"); err2 != nil {
return 0, nil, nil, nil, err
}
}
if symtab, err = loadPlan9Table(obj, "runtime.symtab", "runtime.esymtab"); err != nil {
// Same as above.
var err2 error
if symtab, err2 = loadPlan9Table(obj, "symtab", "esymtab"); err2 != nil {
return 0, nil, nil, nil, err
}
}
return textStart, textData, symtab, pclntab, nil
}
return 0, nil, nil, nil, fmt.Errorf("unrecognized binary format")
}
func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
for _, s := range f.Symbols {
if s.Name != name {
continue
}
if s.SectionNumber <= 0 {
return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
}
if len(f.Sections) < int(s.SectionNumber) {
return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
}
return s, nil
}
return nil, fmt.Errorf("no %s symbol found", name)
}
func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
ssym, err := findPESymbol(f, sname)
if err != nil {
return nil, err
}
esym, err := findPESymbol(f, ename)
if err != nil {
return nil, err
}
if ssym.SectionNumber != esym.SectionNumber {
return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
}
sect := f.Sections[ssym.SectionNumber-1]
data, err := sect.Data()
if err != nil {
return nil, err
}
return data[ssym.Value:esym.Value], nil
}
func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
syms, err := f.Symbols()
if err != nil {
return nil, err
}
for _, s := range syms {
if s.Name != name {
continue
}
return &s, nil
}
return nil, fmt.Errorf("no %s symbol found", name)
}
func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
ssym, err := findPlan9Symbol(f, sname)
if err != nil {
return nil, err
}
esym, err := findPlan9Symbol(f, ename)
if err != nil {
return nil, err
}
sect := f.Section("text")
if sect == nil {
return nil, err
}
data, err := sect.Data()
if err != nil {
return nil, err
}
textStart := f.LoadAddress + f.HdrSize
return data[ssym.Value-textStart : esym.Value-textStart], nil
}
// TODO(rsc): This code is taken from cmd/nm. Arrange some way to share the code.
var exitCode = 0
func errorf(format string, args ...interface{}) {
log.Printf(format, args...)
exitCode = 1
}
func loadSymbols(f *os.File) (syms []Sym, goarch string, err error) {
f.Seek(0, 0)
buf := make([]byte, 16)
io.ReadFull(f, buf)
f.Seek(0, 0)
for _, p := range parsers {
if bytes.HasPrefix(buf, p.prefix) {
syms, goarch = p.parse(f)
sort.Sort(byAddr(syms))
return
}
}
err = fmt.Errorf("unknown file format")
return
}
type Sym struct {
Addr uint64
Size int64
Code rune
Name string
Type string
}
var parsers = []struct {
prefix []byte
parse func(*os.File) ([]Sym, string)
}{
{[]byte("\x7FELF"), elfSymbols},
{[]byte("\xFE\xED\xFA\xCE"), machoSymbols},
{[]byte("\xFE\xED\xFA\xCF"), machoSymbols},
{[]byte("\xCE\xFA\xED\xFE"), machoSymbols},
{[]byte("\xCF\xFA\xED\xFE"), machoSymbols},
{[]byte("MZ"), peSymbols},
{[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386
{[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips
{[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm
{[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64
}
type byAddr []Sym
func (x byAddr) Len() int { return len(x) }
func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }

View File

@ -5,113 +5,15 @@
package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"testing"
)
func loadSyms(t *testing.T) map[string]string {
switch runtime.GOOS {
case "android", "nacl":
t.Skipf("skipping on %s", runtime.GOOS)
}
cmd := exec.Command("go", "tool", "nm", os.Args[0])
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
}
syms := make(map[string]string)
scanner := bufio.NewScanner(bytes.NewReader(out))
for scanner.Scan() {
f := strings.Fields(scanner.Text())
if len(f) < 3 {
continue
}
syms[f[2]] = f[0]
}
if err := scanner.Err(); err != nil {
t.Fatalf("error reading symbols: %v", err)
}
return syms
}
func runObjDump(t *testing.T, exe, startaddr, endaddr string) (path, lineno string) {
switch runtime.GOOS {
case "android", "nacl":
t.Skipf("skipping on %s", runtime.GOOS)
}
cmd := exec.Command(exe, os.Args[0], startaddr, endaddr)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("go tool objdump %v: %v\n%s", os.Args[0], err, string(out))
}
f := strings.Split(string(out), "\n")
if len(f) < 1 {
t.Fatal("objdump output must have at least one line")
}
pathAndLineNo := f[0]
f = strings.Split(pathAndLineNo, ":")
if runtime.GOOS == "windows" {
switch len(f) {
case 2:
return f[0], f[1]
case 3:
return f[0] + ":" + f[1], f[2]
default:
t.Fatalf("no line number found in %q", pathAndLineNo)
}
}
if len(f) != 2 {
t.Fatalf("no line number found in %q", pathAndLineNo)
}
return f[0], f[1]
}
func testObjDump(t *testing.T, exe, startaddr, endaddr string, line int) {
srcPath, srcLineNo := runObjDump(t, exe, startaddr, endaddr)
fi1, err := os.Stat("objdump_test.go")
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
fi2, err := os.Stat(srcPath)
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
if !os.SameFile(fi1, fi2) {
t.Fatalf("objdump_test.go and %s are not same file", srcPath)
}
if srcLineNo != fmt.Sprint(line) {
t.Fatalf("line number = %v; want %d", srcLineNo, line)
}
}
func TestObjDump(t *testing.T) {
_, _, line, _ := runtime.Caller(0)
syms := loadSyms(t)
tmp, exe := buildObjdump(t)
defer os.RemoveAll(tmp)
startaddr := syms["cmd/objdump.TestObjDump"]
addr, err := strconv.ParseUint(startaddr, 16, 64)
if err != nil {
t.Fatalf("invalid start address %v: %v", startaddr, err)
}
endaddr := fmt.Sprintf("%x", addr+10)
testObjDump(t, exe, startaddr, endaddr, line-1)
testObjDump(t, exe, "0x"+startaddr, "0x"+endaddr, line-1)
}
func buildObjdump(t *testing.T) (tmp, exe string) {
switch runtime.GOOS {
case "android", "nacl":
@ -143,7 +45,7 @@ var x86Need = []string{
var armNeed = []string{
"fmthello.go:6",
"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)",
"RET",
}

View File

@ -1,99 +0,0 @@
// 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
}

View File

@ -1,70 +0,0 @@
// 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
}

8
src/cmd/pprof/README Normal file
View File

@ -0,0 +1,8 @@
The pprof in this directory is adapted from the pprof used inside Google
for C++, Java, and Go programs. Because it was developed for that broader
context, it is overgeneralized when used here for the specific use case
of profiling standard Go programs. However, we've left the abstractions
intact in order to share updates between this copy and Google's internal one.
Please do not take the level of abstraction in this program as an example
to follow in your own.

12
src/cmd/pprof/doc.go Normal file
View File

@ -0,0 +1,12 @@
// 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.
// Pprof interprets and displays profiles of Go programs.
//
// Usage:
//
// go tool pprof binary profile
//
// For more information, see http://blog.golang.org/profiling-go-programs.
package main

View File

@ -11,6 +11,7 @@ import (
"os"
"regexp"
"strings"
"sync"
"cmd/internal/objfile"
"cmd/pprof/internal/commands"
@ -100,7 +101,10 @@ func (flags) ExtraUsage() string {
// objTool implements plugin.ObjTool using Go libraries
// (instead of invoking GNU binutils).
type objTool struct{}
type objTool struct {
mu sync.Mutex
disasmCache map[string]*objfile.Disasm
}
func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
of, err := objfile.Open(name)
@ -119,8 +123,39 @@ func (*objTool) Demangle(names []string) (map[string]string, error) {
return make(map[string]string), nil
}
func (*objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
return nil, fmt.Errorf("disassembly not supported")
func (t *objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
d, err := t.cachedDisasm(file)
if err != nil {
return nil, err
}
var asm []plugin.Inst
d.Decode(start, end, func(pc, size uint64, file string, line int, text string) {
asm = append(asm, plugin.Inst{Addr: pc, File: file, Line: line, Text: text})
})
return asm, nil
}
func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.disasmCache == nil {
t.disasmCache = make(map[string]*objfile.Disasm)
}
d := t.disasmCache[file]
if d != nil {
return d, nil
}
f, err := objfile.Open(file)
if err != nil {
return nil, err
}
d, err = f.Disasm()
f.Close()
if err != nil {
return nil, err
}
t.disasmCache[file] = d
return d, nil
}
func (*objTool) SetConfig(config string) {

View File

@ -11,7 +11,7 @@
// two non-literal codes are a clear code and an EOF code.
//
// The TIFF file format uses a similar but incompatible version of the LZW
// algorithm. See the code.google.com/p/go.image/tiff/lzw package for an
// algorithm. See the golang.org/x/image/tiff/lzw package for an
// implementation.
package lzw

View File

@ -21,7 +21,7 @@ func (h Hash) HashFunc() Hash {
}
const (
MD4 Hash = 1 + iota // import code.google.com/p/go.crypto/md4
MD4 Hash = 1 + iota // import golang.org/x/crypto/md4
MD5 // import crypto/md5
SHA1 // import crypto/sha1
SHA224 // import crypto/sha256
@ -29,11 +29,11 @@ const (
SHA384 // import crypto/sha512
SHA512 // import crypto/sha512
MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
RIPEMD160 // import code.google.com/p/go.crypto/ripemd160
SHA3_224 // import code.google.com/p/go.crypto/sha3
SHA3_256 // import code.google.com/p/go.crypto/sha3
SHA3_384 // import code.google.com/p/go.crypto/sha3
SHA3_512 // import code.google.com/p/go.crypto/sha3
RIPEMD160 // import golang.org/x/crypto/ripemd160
SHA3_224 // import golang.org/x/crypto/sha3
SHA3_256 // import golang.org/x/crypto/sha3
SHA3_384 // import golang.org/x/crypto/sha3
SHA3_512 // import golang.org/x/crypto/sha3
maxHash
)

View File

@ -141,6 +141,8 @@ type Dummy struct {
}
func TestDrivers(t *testing.T) {
unregisterAllDrivers()
Register("test", fdriver)
Register("invalid", Dummy{})
all := Drivers()
if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") {

View File

@ -37,6 +37,11 @@ func Register(name string, driver driver.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.
func Drivers() []string {
var list []string

View File

@ -12,7 +12,7 @@ var importPathToPrefixTests = []struct {
}{
{"runtime", "runtime"},
{"sync/atomic", "sync/atomic"},
{"code.google.com/p/go.tools/godoc", "code.google.com/p/go.tools/godoc"},
{"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"},
{"foo.bar/baz.quux", "foo.bar/baz%2equux"},
{"", ""},
{"%foo%bar", "%25foo%25bar"},

View File

@ -30,7 +30,7 @@ import (
// set a cookie for bar.com.
//
// A public suffix list implementation is in the package
// code.google.com/p/go.net/publicsuffix.
// golang.org/x/net/publicsuffix.
type PublicSuffixList interface {
// PublicSuffix returns the public suffix of domain.
//

View File

@ -70,7 +70,7 @@ func goroutineLeaked() bool {
}
fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
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
}

View File

@ -2819,6 +2819,7 @@ func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) {
InsecureSkipVerify: true,
},
}
defer noVerifyTransport.CloseIdleConnections()
client := &Client{Transport: noVerifyTransport}
for pb.Next() {
res, err := client.Get(ts.URL)

View File

@ -246,7 +246,7 @@ func TestPipeLookPathLeak(t *testing.T) {
}
func numOpenFDS(t *testing.T) (n int, lsof []byte) {
lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
if err != nil {
t.Skip("skipping test; error finding or running lsof")
}

View File

@ -25,7 +25,8 @@ type file struct {
dirinfo *dirInfo // nil unless directory being read
}
// Fd returns the integer Unix file descriptor referencing the open file.
// Fd returns the integer Plan 9 file descriptor referencing the open file.
// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))

View File

@ -29,6 +29,7 @@ type file struct {
}
// Fd returns the integer Unix file descriptor referencing the open file.
// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))

View File

@ -36,6 +36,7 @@ type file struct {
}
// Fd returns the Windows handle referencing the open file.
// The handle is valid only until f.Close is called or f is garbage collected.
func (file *File) Fd() uintptr {
if file == nil {
return uintptr(syscall.InvalidHandle)

View File

@ -2284,3 +2284,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVL m_curg(AX), AX
MOVL (g_stack+stack_hi)(AX), AX
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

View File

@ -2229,3 +2229,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVQ m_curg(AX), AX
MOVQ (g_stack+stack_hi)(AX), AX
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

View File

@ -1079,3 +1079,9 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
TEXT runtime·return0(SB), NOSPLIT, $0
MOVL $0, AX
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

View File

@ -1320,3 +1320,9 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
MOVW saveG-8(SP), g
MOVW saveR11-4(SP), R11
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

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly
#include "textflag.h"
// Supply environ and __progname, because we don't

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build freebsd
#include "textflag.h"
// Supply environ and __progname, because we don't

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build netbsd
#include "textflag.h"
// Supply environ and __progname, because we don't

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build openbsd
#include "textflag.h"
// Supply environ, __progname and __guard_local, because

View File

@ -36,10 +36,14 @@ func TestCgoTraceback(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)
}
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"
if !strings.Contains(got, want) {
t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
@ -169,3 +173,24 @@ start(void)
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");
}
`

View File

@ -117,11 +117,20 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
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
// to skip before recording in pc, with 0 identifying the frame for Callers itself and
// 1 identifying the caller of Callers.
// 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 {
// runtime.callers uses pc.array==nil as a signal
// to print a stack trace. Pick off 0-length pc here

View File

@ -251,7 +251,9 @@ dumpbv(BitVector *bv, uintptr offset)
for(i = 0; i < bv->n; i += BitsPerPointer) {
switch(bv->bytedata[i/8] >> i%8 & 3) {
case BitsDead:
return;
// BitsDead has already been processed in makeheapobjbv.
// We should only see it in stack maps, in which case we should continue processing.
break;
case BitsScalar:
break;
case BitsPointer:
@ -400,7 +402,7 @@ dumpgoroutine(G *gp)
child.sp = nil;
child.depth = 0;
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
for(d = gp->defer; d != nil; d = d->link) {

View File

@ -41,7 +41,7 @@ var zerobase uintptr
// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
if size == 0 {
return unsafe.Pointer(&zerobase)
}
@ -391,7 +391,7 @@ func loadPtrMask(typ *_type) []uint8 {
// implementation of new builtin
func newobject(typ *_type) unsafe.Pointer {
flags := 0
flags := uint32(0)
if typ.kind&kindNoPointers != 0 {
flags |= flagNoScan
}
@ -400,7 +400,7 @@ func newobject(typ *_type) unsafe.Pointer {
// implementation of make builtin for slices
func newarray(typ *_type, n uintptr) unsafe.Pointer {
flags := 0
flags := uint32(0)
if typ.kind&kindNoPointers != 0 {
flags |= flagNoScan
}

View File

@ -1021,7 +1021,7 @@ scanstack(G *gp)
runtime·throw("can't scan gchelper stack");
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);
}
@ -2635,7 +2635,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
frame.fn = nil;
frame.sp = (uintptr)p;
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) {
Func *f;
StackMap *stackmap;

View File

@ -528,8 +528,6 @@ var allgs []*g // proc.c
// Most clients should use the runtime/pprof package instead
// of calling GoroutineProfile directly.
func GoroutineProfile(p []StackRecord) (n int, ok bool) {
sp := getcallersp(unsafe.Pointer(&p))
pc := getcallerpc(unsafe.Pointer(&p))
n = NumGoroutine()
if n <= len(p) {
@ -542,7 +540,11 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
if n <= len(p) {
ok = true
r := p
saveg(pc, sp, gp, &r[0])
sp := getcallersp(unsafe.Pointer(&p))
pc := getcallerpc(unsafe.Pointer(&p))
onM(func() {
saveg(pc, sp, gp, &r[0])
})
r = r[1:]
for _, gp1 := range allgs {
if gp1 == gp || readgstatus(gp1) == _Gdead {
@ -562,7 +564,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
}
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) {
r.Stack0[n] = 0
}
@ -573,8 +575,6 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
// If all is true, Stack formats stack traces of all other goroutines
// into buf after the trace for the current goroutine.
func Stack(buf []byte, all bool) int {
sp := getcallersp(unsafe.Pointer(&buf))
pc := getcallerpc(unsafe.Pointer(&buf))
mp := acquirem()
gp := mp.curg
if all {
@ -589,14 +589,19 @@ func Stack(buf []byte, all bool) int {
n := 0
if len(buf) > 0 {
gp.writebuf = buf[0:0:len(buf)]
goroutineheader(gp)
traceback(pc, sp, 0, gp)
if all {
tracebackothers(gp)
}
n = len(gp.writebuf)
gp.writebuf = nil
sp := getcallersp(unsafe.Pointer(&buf))
pc := getcallerpc(unsafe.Pointer(&buf))
onM(func() {
g0 := getg()
g0.writebuf = buf[0:0:len(buf)]
goroutineheader(gp)
traceback(pc, sp, 0, gp)
if all {
tracebackothers(gp)
}
n = len(g0.writebuf)
g0.writebuf = nil
})
}
if all {
@ -623,7 +628,11 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
}
if gp.m.curg == nil || gp == gp.m.curg {
goroutineheader(gp)
traceback(getcallerpc(unsafe.Pointer(&p)), getcallersp(unsafe.Pointer(&p)), 0, gp)
pc := getcallerpc(unsafe.Pointer(&p))
sp := getcallersp(unsafe.Pointer(&p))
onM(func() {
traceback(pc, sp, 0, gp)
})
} else {
goroutineheader(gp.m.curg)
traceback(^uintptr(0), ^uintptr(0), 0, gp.m.curg)
@ -639,7 +648,11 @@ func tracefree(p unsafe.Pointer, size uintptr) {
gp.m.traceback = 2
print("tracefree(", p, ", ", hex(size), ")\n")
goroutineheader(gp)
traceback(getcallerpc(unsafe.Pointer(&p)), getcallersp(unsafe.Pointer(&p)), 0, gp)
pc := getcallerpc(unsafe.Pointer(&p))
sp := getcallersp(unsafe.Pointer(&p))
onM(func() {
traceback(pc, sp, 0, gp)
})
print("\n")
gp.m.traceback = 0
unlock(&tracelock)

View File

@ -9,7 +9,7 @@
// Export the runtime entry point symbol.
//
// Used by the app package to start the Go runtime after loading
// a shared library via JNI. See code.google.com/p/go.mobile/app.
// a shared library via JNI. See golang.org/x/mobile/app.
void _rt0_arm_linux1();
#pragma cgo_export_static _rt0_arm_linux1

View File

@ -114,7 +114,7 @@ Throw:
if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp);
runtime·traceback(ureg->pc, ureg->sp, 0, gp);
runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(ureg);

View File

@ -122,7 +122,7 @@ Throw:
if(runtime·gotraceback(&crash)) {
runtime·goroutineheader(gp);
runtime·traceback(ureg->ip, ureg->sp, 0, gp);
runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·printf("\n");
runtime·dumpregs(ureg);

View File

@ -97,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
runtime·traceback(r->Eip, r->Esp, 0, gp);
runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}

View File

@ -119,7 +119,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
runtime·printf("\n");
if(runtime·gotraceback(&crash)){
runtime·traceback(r->Rip, r->Rsp, 0, gp);
runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}

View File

@ -994,7 +994,7 @@ runtime·newextram(void)
// the goroutine stack ends.
mp = runtime·allocm(nil);
gp = runtime·malg(4096);
gp->sched.pc = (uintptr)runtime·goexit;
gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
gp->sched.sp = gp->stack.hi;
gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
gp->sched.lr = 0;
@ -1647,12 +1647,10 @@ runtime·gosched_m(G *gp)
}
// Finishes execution of the current goroutine.
// Need to mark it as nosplit, because it runs with sp > stackbase.
// 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.
// Must be NOSPLIT because it is called from Go.
#pragma textflag NOSPLIT
void
runtime·goexit(void)
runtime·goexit1(void)
{
void (*fn)(G*);
@ -2198,7 +2196,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
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;
runtime·gostartcallfn(&newg->sched, fn);
newg->gopc = (uintptr)callerpc;
@ -2432,9 +2430,10 @@ static struct ProfState {
int32 hz;
} prof;
static void System(void) {}
static void ExternalCode(void) {}
static void GC(void) {}
static void System(void) { System(); }
static void ExternalCode(void) { ExternalCode(); }
static void GC(void) { GC(); }
extern void runtime·cpuproftick(uintptr*, int32);
extern byte runtime·etext[];
@ -2538,7 +2537,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
n = 0;
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) {
// Normal traceback is impossible or has failed.
// See if it falls into several common cases.
@ -2548,13 +2547,13 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
// Cgo, we can't unwind and symbolize arbitrary C code,
// so instead collect Go stack that leads to the cgo call.
// 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
if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
// Libcall, i.e. runtime syscall on windows.
// 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
if(n == 0) {

View File

@ -737,9 +737,15 @@ struct Stkframe
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·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
void runtime·tracebackothers(G*);
bool runtime·haszeroargs(uintptr pc);
bool runtime·topofstack(Func*);

View File

@ -259,6 +259,7 @@ func syncsemrelease(s *syncSema, n uint32) {
}
s.tail = w
goparkunlock(&s.lock, "semarelease")
releaseSudog(w)
} else {
unlock(&s.lock)
}

View File

@ -109,7 +109,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
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·printf("\n");
runtime·dumpregs(info, ctxt);

View File

@ -143,7 +143,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
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·printf("\n");
runtime·dumpregs(info, ctxt);

View File

@ -108,7 +108,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
if(runtime·gotraceback(&crash)){
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·printf("\n");
runtime·dumpregs(info, ctxt);

View File

@ -582,7 +582,7 @@ copystack(G *gp, uintptr newsize)
adjinfo.old = old;
adjinfo.delta = new.hi - old.hi;
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.
adjustctxt(gp, &adjinfo);

View File

@ -228,6 +228,34 @@ func atomicloaduint(ptr *uint) uint
//go:noescape
func setcallerpc(argp unsafe.Pointer, pc uintptr)
// getcallerpc returns the program counter (PC) of its caller's caller.
// getcallersp returns the stack pointer (SP) of its caller's caller.
// For both, the argp must be a pointer to the caller's first function argument.
// The implementation may or may not use argp, depending on
// the architecture.
//
// For example:
//
// func f(arg1, arg2, arg3 int) {
// pc := getcallerpc(unsafe.Pointer(&arg1))
// sp := getcallerpc(unsafe.Pointer(&arg2))
// }
//
// These two lines find the PC and SP immediately following
// the call to f (where f will return).
//
// The call to getcallerpc and getcallersp must be done in the
// frame being asked about. It would not be correct for f to pass &arg1
// to another function g and let g call getcallerpc/getcallersp.
// The call inside g might return information about g's caller or
// information about f's caller or complete garbage.
//
// The result of getcallersp is correct at the time of the return,
// but it may be invalidated by any subsequent call to a function
// that might relocate the stack in order to grow or shrink it.
// A general rule is that the result of getcallersp should be used
// immediately and can only be passed to nosplit functions.
//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr

View File

@ -96,11 +96,27 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
// the runtime.Callers function (pcbuf != nil), as well as the garbage
// collector (callback != nil). A little clunky to merge these, but avoids
// 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 {
gothrow("gentraceback before goexitPC initialization")
}
g := getg()
if g == gp && g == g.m.curg {
// The starting sp has been passed in as a uintptr, and the caller may
// have other uintptr-typed stack references as well.
// If during one of the calls that got us here or during one of the
// callbacks below the stack must be grown, all these uintptr references
// to the stack will not be updated, and gentraceback will continue
// to inspect the old stack memory, which may no longer be valid.
// Even if all the variables were updated correctly, it is not clear that
// we want to expose a traceback that begins on one stack and ends
// on another stack. That could confuse callers quite a bit.
// Instead, we require that gentraceback and any other function that
// accepts an sp for the current goroutine (typically obtained by
// calling getcallersp) must not run on that goroutine's stack but
// instead on the g0 stack.
gothrow("gentraceback cannot trace user goroutine on its own stack")
}
gotraceback := gotraceback(nil)
if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
if gp.syscallsp != 0 {
@ -297,13 +313,13 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
}
}
if printing {
if printall || showframe(f, gp) {
if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp) {
// Print during crash.
// main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf
//
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--
}
print(gofuncname(f), "(")
@ -475,17 +491,32 @@ func printcreatedby(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
if readgstatus(gp)&^_Gscan == _Gsyscall {
// Override signal registers if blocked in system call.
// Override registers if blocked in system call.
pc = gp.syscallpc
sp = gp.syscallsp
flags &^= _TraceTrap
}
// Print traceback. By default, omits runtime frames.
// 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)
if n == 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)
if n == 0 && (flags&_TraceRuntimeFrames) == 0 {
n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags|_TraceRuntimeFrames)
}
if n == _TracebackMaxFrames {
print("...additional frames elided...\n")
@ -496,11 +527,15 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
func callers(skip int, pcbuf *uintptr, m int) int {
sp := getcallersp(unsafe.Pointer(&skip))
pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
return gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, false)
var n int
onM(func() {
n = gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
})
return n
}
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 {

View File

@ -38,7 +38,7 @@ func (v *Value) Load() (x interface{}) {
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.
// Store of an inconsistent type panics, as does Store(nil).
func (v *Value) Store(x interface{}) {

View File

@ -0,0 +1,49 @@
// 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))
}
}

View File

@ -1,13 +1,11 @@
// $G $D/$F.go && $L -X main.tbd hello -X main.overwrite trumped -X main.nosuchsymbol neverseen $F.$A && ./$A.out
// NOTE: This test is not run by 'run.go' and so not run by all.bash.
// To run this test you must use the ./run shell script.
// skip
// Copyright 2012 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 the -X facility of the gc linker (6l etc.).
// This test is run by linkx_run.go.
package main
@ -15,10 +13,6 @@ var tbd string
var overwrite string = "dibs"
func main() {
if tbd != "hello" {
println("BUG: test/linkx tbd", len(tbd), tbd)
}
if overwrite != "trumped" {
println("BUG: test/linkx overwrite", len(overwrite), overwrite)
}
println(tbd)
println(overwrite)
}

33
test/linkx_run.go Normal file
View File

@ -0,0 +1,33 @@
// +build !nacl
// 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.
// Run the linkx test.
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
cmd := exec.Command("go", "run", "-ldflags=-X main.tbd hello -X main.overwrite trumped", "linkx.go")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(string(out))
fmt.Println(err)
os.Exit(1)
}
want := "hello\ntrumped\n"
got := string(out)
if got != want {
fmt.Printf("got %q want %q\n", got, want)
os.Exit(1)
}
}

View File

@ -907,8 +907,6 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
}
var skipOkay = map[string]bool{
"linkx.go": true, // like "run" but wants linker flags
"sinit.go": true,
"fixedbugs/bug248.go": true, // combines errorcheckdir and rundir in the same dir.
"fixedbugs/bug302.go": true, // tests both .$O and .a imports.
"fixedbugs/bug345.go": true, // needs the appropriate flags in gc invocation.

View File

@ -1,7 +1,4 @@
// $G -S $D/$F.go | egrep initdone >/dev/null && echo BUG sinit || true
// NOTE: This test is not run by 'run.go' and so not run by all.bash.
// To run this test you must use the ./run shell script.
// skip
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@ -9,6 +6,7 @@
// Test that many initializations can be done at link time and
// generate no executable init functions.
// This test is run by sinit_run.go.
package p
@ -106,20 +104,27 @@ var answers = [...]int{
}
var (
copy_zero = zero
copy_one = one
copy_pi = pi
copy_slice = slice
copy_zero = zero
copy_one = one
copy_pi = pi
copy_slice = slice
copy_sliceInt = sliceInt
copy_hello = hello
copy_bytes = bytes
copy_hello = hello
// Could be handled without an initialization function, but
// requires special handling for "a = []byte("..."); b = a"
// which is not a likely case.
// copy_bytes = bytes
// https://codereview.appspot.com/171840043 is one approach to
// make this special case work.
copy_four, copy_five = four, five
copy_x, copy_y = x, y
copy_nilslice = nilslice
copy_nilmap = nilmap
copy_nilfunc = nilfunc
copy_nilchan = nilchan
copy_nilptr = nilptr
copy_x, copy_y = x, y
copy_nilslice = nilslice
copy_nilmap = nilmap
copy_nilfunc = nilfunc
copy_nilchan = nilchan
copy_nilptr = nilptr
)
var copy_a = a
@ -172,7 +177,7 @@ var sx []int
var s0 = []int{0, 0, 0}
var s1 = []int{1, 2, 3}
func fi() int
func fi() int { return 1 }
var ax [10]int
var a0 = [10]int{0, 0, 0}
@ -202,58 +207,66 @@ var pt0b = &T{X: 0}
var pt1 = &T{X: 1, Y: 2}
var pt1a = &T{3, 4}
var copy_bx = bx
// The checks similar to
// var copy_bx = bx
// are commented out. The compiler no longer statically initializes them.
// See issue 7665 and https://codereview.appspot.com/93200044.
// If https://codereview.appspot.com/169040043 is submitted, and this
// test is changed to pass -complete to the compiler, then we can
// uncomment the copy lines again.
// var copy_bx = bx
var copy_b0 = b0
var copy_b1 = b1
var copy_fx = fx
// var copy_fx = fx
var copy_f0 = f0
var copy_f1 = f1
var copy_gx = gx
// var copy_gx = gx
var copy_g0 = g0
var copy_g1 = g1
var copy_ix = ix
// var copy_ix = ix
var copy_i0 = i0
var copy_i1 = i1
var copy_jx = jx
// var copy_jx = jx
var copy_j0 = j0
var copy_j1 = j1
var copy_cx = cx
// var copy_cx = cx
var copy_c0 = c0
var copy_c1 = c1
var copy_dx = dx
// var copy_dx = dx
var copy_d0 = d0
var copy_d1 = d1
var copy_sx = sx
// var copy_sx = sx
var copy_s0 = s0
var copy_s1 = s1
var copy_ax = ax
// var copy_ax = ax
var copy_a0 = a0
var copy_a1 = a1
var copy_tx = tx
// var copy_tx = tx
var copy_t0 = t0
var copy_t0a = t0a
var copy_t0b = t0b
var copy_t1 = t1
var copy_t1a = t1a
var copy_psx = psx
// var copy_psx = psx
var copy_ps0 = ps0
var copy_ps1 = ps1
var copy_pax = pax
// var copy_pax = pax
var copy_pa0 = pa0
var copy_pa1 = pa1
var copy_ptx = ptx
// var copy_ptx = ptx
var copy_pt0 = pt0
var copy_pt0a = pt0a
var copy_pt0b = pt0b
@ -266,6 +279,8 @@ type T1 int
func (t *T1) M() {}
type Mer interface { M() }
type Mer interface {
M()
}
var _ Mer = (*T1)(nil)

40
test/sinit_run.go Normal file
View File

@ -0,0 +1,40 @@
// +build !nacl
// 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.
// Run the sinit test.
package main
import (
"bytes"
"fmt"
"go/build"
"os"
"os/exec"
)
func main() {
letter, err := build.ArchChar(build.Default.GOARCH)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
cmd := exec.Command("go", "tool", letter+"g", "-S", "sinit.go")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(string(out))
fmt.Println(err)
os.Exit(1)
}
os.Remove("sinit." + letter)
if bytes.Contains(out, []byte("initdone")) {
fmt.Println("sinit generated an init function")
os.Exit(1)
}
}