]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.power64] all: merge default into dev.power64
authorAustin Clements <austin@google.com>
Mon, 3 Nov 2014 15:53:11 +0000 (10:53 -0500)
committerAustin Clements <austin@google.com>
Mon, 3 Nov 2014 15:53:11 +0000 (10:53 -0500)
Trivial merge except for src/runtime/asm_power64x.s and
src/runtime/signal_power64x.c

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/168950044

50 files changed:
.hgtags
AUTHORS
CONTRIBUTORS
doc/go1.4.html
misc/cgo/test/cgo_test.go
misc/cgo/test/issue6997_linux.go
misc/cgo/test/issue9026.go [new file with mode: 0644]
src/cmd/cgo/gcc.go
src/cmd/go/doc.go
src/cmd/go/generate.go
src/cmd/internal/objfile/elf.go
src/cmd/internal/objfile/goobj.go
src/cmd/internal/objfile/macho.go
src/cmd/internal/objfile/objfile.go
src/cmd/internal/objfile/pe.go
src/cmd/internal/objfile/plan9obj.go
src/cmd/objdump/Makefile [deleted file]
src/cmd/objdump/elf.go [deleted file]
src/cmd/objdump/macho.go [deleted file]
src/cmd/objdump/main.go
src/cmd/objdump/objdump_test.go
src/cmd/objdump/pe.go [deleted file]
src/cmd/objdump/plan9obj.go [deleted file]
src/database/sql/fakedb_test.go
src/database/sql/sql.go
src/net/http/main_test.go
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_amd64p32.s
src/runtime/asm_arm.s
src/runtime/asm_power64x.s
src/runtime/crash_cgo_test.go
src/runtime/extern.go
src/runtime/heapdump.c
src/runtime/mgc0.c
src/runtime/mprof.go
src/runtime/os_plan9_386.c
src/runtime/os_plan9_amd64.c
src/runtime/os_windows_386.c
src/runtime/os_windows_amd64.c
src/runtime/proc.c
src/runtime/runtime.h
src/runtime/signal_386.c
src/runtime/signal_amd64x.c
src/runtime/signal_arm.c
src/runtime/signal_power64x.c
src/runtime/stack.c
src/runtime/traceback.go
src/sync/atomic/value.go
test/fixedbugs/issue7690.go [new file with mode: 0644]

diff --git a/.hgtags b/.hgtags
index 5a5c4aed44ac1ccdd71093e6ded6a7101286f8c4..edd2163f701248fa6ce3debb20409531c8bc0c53 100644 (file)
--- a/.hgtags
+++ b/.hgtags
@@ -135,3 +135,4 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
 85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
+1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
diff --git a/AUTHORS b/AUTHORS
index 03e686e7519e9738633df8f2b8fcd816cf34144e..48a262bbd7c52a257d778273994d83cfb02d6a37 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -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>
index 7679f787422cec76ef41a7191033b3564718bed9..ec69858b605ede830e06ec7a81670181c021b0f2 100644 (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>
index 7e670c47cb9ff0384d7e452278174676fd843608..3310117a4d98e20993f3e190bc40786caf771bd2 100644 (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
@@ -281,7 +280,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>
@@ -370,6 +371,15 @@ 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>.
@@ -465,11 +475,6 @@ 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>
@@ -487,6 +492,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 +559,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="http://golang.org/s/go1.4-syscall">a
+separate document</a>.
+</p>
+
+<p>
+A new subrepository, <a href="http://code.google.com/p/go.sys">go.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/code.google.com/p/go.sys/unix">Unix</a>,
+<a href="http://godoc.org/code.google.com/p/go.sys/windows">Windows</a> and
+<a href="http://godoc.org/code.google.com/p/go.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>go.sys</code> instead.
+</p>
 
 <h3 id="minor_library_changes">Minor changes to the library</h3>
 
@@ -562,37 +620,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>
 
-<pre>
+<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>
 
-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)
+<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>
+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>
index 3b289ba7b505392d29bb795e88e79a83e0d3ee55..fbdfac87acb8ef69be9e4fe295c4ba7373a6550f 100644 (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) }
index 871bd517a7d2a24ef3e6c798bef243fb524c0794..5455f0c536af86f7cfde387c7b48506c38db830a 100644 (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")
        }
 }
diff --git a/misc/cgo/test/issue9026.go b/misc/cgo/test/issue9026.go
new file mode 100644 (file)
index 0000000..b5d975f
--- /dev/null
@@ -0,0 +1,33 @@
+package cgotest
+
+/*
+typedef struct {} git_merge_file_input;
+
+typedef struct {} git_merge_file_options;
+
+void git_merge_file(
+        git_merge_file_input *in,
+        git_merge_file_options *opts) {}
+*/
+import "C"
+import (
+       "fmt"
+       "testing"
+)
+
+func test9026(t *testing.T) {
+       var in C.git_merge_file_input
+       var opts *C.git_merge_file_options
+       C.git_merge_file(&in, opts)
+
+       // Test that the generated type names are deterministic.
+       // (Previously this would fail about 10% of the time.)
+       //
+       // Brittle: the assertion may fail spuriously when the algorithm
+       // changes, but should remain stable otherwise.
+       got := fmt.Sprintf("%T %T", in, opts)
+       want := "cgotest._Ctype_struct___12 *cgotest._Ctype_struct___13"
+       if got != want {
+               t.Errorf("Non-deterministic type names: got %s, want %s", got, want)
+       }
+}
index d77d56c22abc8c3b4a1b59259e0dbc5ba59ec996..abdd369d7139c1e522e3631505e64076bb80038d 100644 (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:
index 314c69bd8ca1739685c8fca271dc476f08146f8e..cf3a54565a202fe35be6aa53d37b50628d05229f 100644 (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.
 
index 4227abbe7c50a66bbf29f07447c5869d7d56a120..a83cce8f7acedae2e4ccb71da6bb44bb5ec2cf69 100644 (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.
 
index 8495fa753246a3bb9d54c230729648a07979b386..17755b84d2cfa78fd052cfb2f64fa263eaa71bdb 100644 (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 ""
+}
index a4f49ebe44db2e3f9be636be87dff4295e28b8da..a1d773023dc551bbfd4103b3b186e3b128306d34 100644 (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"
+}
index f845792ffa71c782681172d2ae9a2dbcbfccffdb..7dd84a339db519a4d0ea445ff6ab9fad71c0d923 100644 (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) }
index 09fa63e60bf234e9742d693d1bee4f2dc9f1668f..3d4a5d27cdbae8e2194b706cf9f0970fbacc9b2f 100644 (file)
@@ -14,6 +14,8 @@ import (
 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.
@@ -70,3 +72,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()
+}
index 868709eaf9e04a11e371e92822f0d2c78443e5cf..67e59c226b0f85dfaef20eec1183646e8c0ff6dc 100644 (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 ""
+}
index 80744f82a8c8246d20a6647fec3963d21247da5e..eb6cba5eb1e8f281d7c7a0ba8328da292323acea 100644 (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 ""
+}
diff --git a/src/cmd/objdump/Makefile b/src/cmd/objdump/Makefile
deleted file mode 100644 (file)
index 1b66c26..0000000
+++ /dev/null
@@ -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
diff --git a/src/cmd/objdump/elf.go b/src/cmd/objdump/elf.go
deleted file mode 100644 (file)
index 906e903..0000000
+++ /dev/null
@@ -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
-}
diff --git a/src/cmd/objdump/macho.go b/src/cmd/objdump/macho.go
deleted file mode 100644 (file)
index 6e0ad22..0000000
+++ /dev/null
@@ -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] }
index 0f66f20a400131cf34b63559eb3eaa300b5d1c87..0f125c98bfc00f09d8542fbf9e865449f00bbad9 100644 (file)
@@ -33,12 +33,7 @@ package main
 
 import (
        "bufio"
-       "bytes"
-       "debug/elf"
        "debug/gosym"
-       "debug/macho"
-       "debug/pe"
-       "debug/plan9obj"
        "encoding/binary"
        "flag"
        "fmt"
@@ -51,6 +46,8 @@ import (
        "strings"
        "text/tabwriter"
 
+       "cmd/internal/objfile"
+
        "cmd/internal/rsc.io/arm/armasm"
        "cmd/internal/rsc.io/x86/x86asm"
 )
@@ -85,21 +82,33 @@ 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)
+       syms, err := f.Symbols()
        if err != nil {
                log.Fatalf("reading %s: %v", flag.Arg(0), err)
        }
 
-       syms, goarch, err := loadSymbols(f)
+       tab, err := f.PCLineTable()
        if err != nil {
                log.Fatalf("reading %s: %v", flag.Arg(0), err)
        }
 
+       textStart, textBytes, err := f.Text()
+       if err != nil {
+               log.Fatalf("reading %s: %v", flag.Arg(0), err)
+       }
+
+       goarch := f.GOARCH()
+
+       disasm := disasms[goarch]
+       if disasm == nil {
+               log.Fatalf("reading %s: unknown architecture", flag.Arg(0))
+       }
+
        // Filter out section symbols, overwriting syms in place.
        keep := syms[:0]
        for _, sym := range syms {
@@ -112,37 +121,27 @@ func main() {
        }
        syms = keep
 
-       disasm := disasms[goarch]
-       if disasm == nil {
-               log.Fatalf("reading %s: unknown architecture", flag.Arg(0))
-       }
-
+       sort.Sort(ByAddr(syms))
        lookup := func(addr uint64) (string, uint64) {
-               i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr })
+               i := sort.Search(len(syms), func(i int) bool { return addr < syms[i].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" {
+                       if s.Addr != 0 && s.Addr <= addr && addr < s.Addr+uint64(s.Size) {
                                return s.Name, s.Addr
                        }
                }
                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)
+               dump(tab, lookup, disasm, goarch, syms, textBytes, textStart)
+               os.Exit(0)
        }
 
        // disassembly of specific piece of object - gnu objdump format for pprof
-       gnuDump(tab, lookup, disasm, textData, textStart)
-       os.Exit(exitCode)
+       gnuDump(tab, lookup, disasm, textBytes, textStart)
+       os.Exit(0)
 }
 
 // base returns the final element in the path.
@@ -153,13 +152,13 @@ func base(path string) string {
        return path
 }
 
-func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, syms []Sym, textData []byte, textStart uint64) {
+func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, syms []objfile.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) {
+               if (sym.Code != 'T' && sym.Code != 't') || sym.Size == 0 || 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)) {
@@ -307,224 +306,8 @@ func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []
        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
+type ByAddr []objfile.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 }
+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] }
index 41f51ebf207f978355c3982c1958924d6a6f6f05..5047f9aa8e379882d3d6c755ed91b336a4a975b7 100644 (file)
@@ -147,7 +147,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",
 }
diff --git a/src/cmd/objdump/pe.go b/src/cmd/objdump/pe.go
deleted file mode 100644 (file)
index 3819009..0000000
+++ /dev/null
@@ -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
-}
diff --git a/src/cmd/objdump/plan9obj.go b/src/cmd/objdump/plan9obj.go
deleted file mode 100644 (file)
index f851d41..0000000
+++ /dev/null
@@ -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
-}
index 171c322d49ac0796b6ddcd956526f68c337d3d8c..a993fd46ede488938419a84ea6c112b6e321a6cb 100644 (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") {
index ad9179cf7d7262e1f63d29f7823c8567eca62f9a..6e6f246aeecb745d6f7c567dfac6323073949dcf 100644 (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
index 9f1dfc3727214327c8ee762eb1c0ece77aa7223a..b8c71fd19fd21285d4ebb3721f58f1062433834b 100644 (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
 }
index 2d102b27358b618c46ed3a320d61587313234eb2..8cbabfed21cb6e8b5364a74bcfeea969394fc944 100644 (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
index ac9c58cf3e2cce8e23304fdd418f88af7aea9eab..2871a172af431d667c6d0502ffbd7eda44ee18f3 100644 (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
index de3ef3a237fc996b4a8c2bff215de0edc47f1483..0d62320de197df384cc681c15a5250877e251885 100644 (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
index 9a58fdc51e25a1d4e9853c6d0a47f68fd6933cd1..58aebf3884e74baee3c44f309233309ca859b894 100644 (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
index 713cc5f549c0908d221697e196179db668e9e13a..a75bb8ce1e0f1d56336ec393b8c7fe00d5460b2d 100644 (file)
@@ -980,3 +980,9 @@ TEXT runtime·return0(SB), NOSPLIT, $0
 // Must obey the gcc calling convention.
 TEXT _cgo_topofstack(SB),NOSPLIT,$0
        MOVD    R0, 26(R0)
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$-8-0
+       MOVD    R0, R0  // NOP
+       BL      runtime·goexit1(SB)    // does not return
index 5958ad8914637f9ddacc31b489638c0c8b7f0f3c..972eedc624ee3d192240d0b764cfa517f174a6ef 100644 (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");
+}
+`
index 1b8052bb563d7e6abc540cfffa093ac5e539ee81..6cc5df810cd6b94f12b3e11fb3206902c2f85785 100644 (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
index 71da419f150ec5511fe74c5ded597b81feeb3a5c..94a4bd2be5dac300bf4a00b67320a7286f500f50 100644 (file)
@@ -413,7 +413,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) {
index e5b6870c668d8a5887d9924a928aee7277a2b05c..897dc1415c0f51fd71c70701c664d7226e1448a0 100644 (file)
@@ -774,7 +774,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);
 }
 
@@ -1966,7 +1966,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;
index 803da56670bd9eb1215d92ef7d7894db1cd2656b..d64e3be6952dbf86c6fd3dad4912a811d7c945c5 100644 (file)
@@ -562,7 +562,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
        }
index 3490862244485d011608e67a07b6f8b223afccb3..42c6d161c7dfc2a6ef92869effe742a7a85b5ec2 100644 (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);
index 6b0f8ae3a217f3fd4b4137225cd1acac30501071..a9dc0eb966b67339567cdd4bb1f2fbea63a3a61d 100644 (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);
index 213582799b13604fc36a08cadfce9a9d603bbd89..9962f0dc2e4dde5ee816a11b360fbe14a515f088 100644 (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);
        }
index b96cf70d1ec0726ee4930e87e2043c722d0a4bf7..e4617e4cefa8fc7761c29a6d0bab992dad18a9c9 100644 (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);
        }
index 31c62d43f5798499bcf3d55f622600dd58bc25c9..feee8ea19ee1ff3b1a1a78d3014aa8b6b5cae3af 100644 (file)
@@ -1643,12 +1643,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*);
 
@@ -2192,7 +2190,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;
@@ -2532,7 +2530,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.
@@ -2542,13 +2540,13 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
                        // Cgo, we can't unwind and symbolize arbitrary C code,
                        // 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) {
index 2a607400636ad72d80c5bfd95bba92e8ca2980f8..977c4547dfbacf55f2627968e9c4d3fd39c72016 100644 (file)
@@ -719,9 +719,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*);
index d55e3045288f673f2c1dc3115f3e878b7f17179d..30a7488bd786f5dd2ba4b2144e9a805393bdb433 100644 (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);
index 44e68cecfccf8e8717bc3c12ac998e36f2c8ce8e..feb4afcce3481a64e1a459d45a50c059d38ef000 100644 (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);
index 3571cf3ac6715a38782a9bbc0e549dfb84ab46cf..afad5e7d166820093ede00e35072f92b01e7f18c 100644 (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);
index 89c5c78485d2bdfbba1dd2b04e009b89c02e2f86..c0bf1c4a51f15ca95469f1da09e1e7a3d857350e 100644 (file)
@@ -124,7 +124,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_LINK(info, ctxt), gp);
+               runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp);
                runtime·tracebackothers(gp);
                runtime·printf("\n");
                runtime·dumpregs(info, ctxt);
index ed8f4f872799be664a90c501de68094a8af7b07d..072bc242bc2a5d3cad6bd004a2d2011b17fd5f92 100644 (file)
@@ -620,7 +620,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);
index 24dc3eea951d6831e94425ef57d48a59c5ac12f1..834435b400d3d0be0bff6f4f499cd7090bd63445 100644 (file)
@@ -96,7 +96,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 // the runtime.Callers function (pcbuf != nil), as well as the garbage
 // 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")
        }
@@ -297,13 +297,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 +475,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 +511,11 @@ 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)
+       return gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
 }
 
 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 {
index ab46d9a240eb2628a5381222e23b2f9bdf4c207d..ab3aa11285478f214bad966f018dee3ab8c2bc1a 100644 (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{}) {
diff --git a/test/fixedbugs/issue7690.go b/test/fixedbugs/issue7690.go
new file mode 100644 (file)
index 0000000..4ad9e86
--- /dev/null
@@ -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))
+       }
+}