Compare commits

...

12 Commits

Author SHA1 Message Date
Andrew Gerrand
fb10bce0c2 [release-branch.r58] document release.r58
««« CL 4643058 / 0a5e3e664637
document release.r58

R=rsc, r, bsiegert
CC=golang-dev
https://golang.org/cl/4643058
»»»

R=golang-dev
CC=golang-dev
https://golang.org/cl/4641084
2011-06-30 09:49:11 +10:00
Andrew Gerrand
ff5182390a [release-branch.r58] gofix: fixes for os/signal changes
««« CL 4630056 / 8fe2bc5c3d53
gofix: fixes for os/signal changes

Fixes #1971.

R=adg, rsc
CC=golang-dev
https://golang.org/cl/4630056

»»»

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4645071
2011-06-29 16:57:41 +10:00
Andrew Gerrand
36d155b2b5 [release-branch.r58] gopprof: update list of memory allocators
««« CL 4650048 / 09d52e36dab9
gopprof: update list of memory allocators

Also import new weblist command from Google version.

R=r, bradfitz
CC=golang-dev
https://golang.org/cl/4650048
»»»

R=rsc
CC=golang-dev
https://golang.org/cl/4654072
2011-06-29 15:40:29 +10:00
Andrew Gerrand
f86856b083 [release-branch.r58] ld: dwarf emit filenames in debug_line header instead of as extended opcodes.
««« CL 4609043 / caaab1e64d49
ld: dwarf emit filenames in debug_line header instead of as extended opcodes.

Makes it possible for older tools like objdump to find the filenames,
fixes  objdump -d -l --start-address=0x400c00 --stop-address=0x400c36 6.out
fixes #1950

R=rsc
CC=golang-dev
https://golang.org/cl/4609043
»»»

R=rsc
CC=golang-dev
https://golang.org/cl/4648068
2011-06-29 15:38:55 +10:00
Andrew Gerrand
f12a1d38b2 [release-branch.r58] 6g, 8g: fix goto fix
««« CL 4632041 / cbc2b570b2ca
6g, 8g: fix goto fix

R=ken2
CC=golang-dev
https://golang.org/cl/4632041
»»»

R=rsc
CC=golang-dev
https://golang.org/cl/4667046
2011-06-29 15:33:16 +10:00
Andrew Gerrand
3b32b3eb3d [release-branch.r58] gc: work around goto bug
««« CL 4629042 / ec3b60d1fe6e
gc: work around goto bug

R=ken2
CC=golang-dev
https://golang.org/cl/4629042
»»»

R=rsc
CC=golang-dev
https://golang.org/cl/4662063
2011-06-29 15:32:06 +10:00
Andrew Gerrand
f70c7b2b63 [release-branch.r58] doc/faq: remove misleading FAQ entry
««« CL 4638046 / 9017f7cbac7d
doc/faq: remove misleading FAQ entry

R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/4638046
»»»

R=r
CC=golang-dev
https://golang.org/cl/4648066
2011-06-29 15:00:27 +10:00
Andrew Gerrand
01a1c91696 [release-branch.r58] doc/faq: add question about converting from []T to []interface{}
««« CL 4639046 / 995095e59d58
doc/faq: add question about converting from []T to []interface{}

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4639046
»»»

R=r
CC=golang-dev
https://golang.org/cl/4630077
2011-06-29 14:58:01 +10:00
Andrew Gerrand
dbdc8698df [release-branch.r58] doc/GoCourseDay1: shrink the PDF by rewriting it using ps2pdf.
««« CL 4626056 / b83d5dcc660d
doc/GoCourseDay1: shrink the PDF by rewriting it using ps2pdf.
No difference in content or appearance.
Forgot to do this when I updated this file a few days ago.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4626056
»»»

R=r
CC=golang-dev
https://golang.org/cl/4630076
2011-06-29 14:56:46 +10:00
Andrew Gerrand
47906598d8 [release-branch.r58] docs/GoCourseDay1.pdf: fix error in operator table.
««« CL 4637041 / df607ef238c9
docs/GoCourseDay1.pdf: fix error in operator table.
Communications op was listed as a binary; it isn't any more.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4637041
»»»

R=r
CC=golang-dev
https://golang.org/cl/4625076
2011-06-29 14:55:32 +10:00
Andrew Gerrand
0ea0d7b65c [release-branch.r58] docs: Update notes for 3-day Go course.
««« CL 4605041 / 71776ebc7416
docs: Update notes for 3-day Go course.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/4605041
»»»

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4657058
2011-06-29 14:45:53 +10:00
Andrew Gerrand
35f3007cf1 create release-branch.r58 2011-06-29 13:46:53 +10:00
22 changed files with 827 additions and 77 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -14,6 +14,78 @@ hg pull
hg update release.r<i>NN</i>
</pre>
<h2 id="r58">r58 (released 2011/06/29)</h2>
<p>
The r58 release corresponds to
<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
with additional bug fixes.
This section highlights the most significant changes in this release.
For a more detailed summary, see the
<a href="weekly.html#2011-06-09">weekly release notes</a>.
For complete information, see the
<a href="http://code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
</p>
<h3 id="r58.lang">Language</h3>
<p>
This release fixes a <a href="http://code.google.com/p/go/source/detail?r=b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
</p>
<h3 id="r58.pkg">Packages</h3>
<p>
As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
necessary for these changes to package APIs.
</p>
<p>
<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
is now available via the new <code>Request</code> field on <a
href="/pkg/http/#Response">http.Response</a>.
Most instances of the type map[string][]string in have been
replaced with the new <a href="/pkg/http/#Values">Values</a> type.
</p>
<p>
<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
convenient and succinct API.
</p>
<p>
<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
function now escapes only those Unicode code points not classified as printable
by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
Previously Quote would escape all non-ASCII characters.
This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
formatting directive. The previous quoting behavior is still available via
strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.
</p>
<p>
<a href="/pkg/os/signal/">Package os/signal</a>'s
<a href="/pkg/os/#Signal">Signal</a> and
<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
<a href="/pkg/os/">os</a> package.
</p>
<p>
<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
</p>
<h3 id="r58.cmd">Tools</h3>
<p>
<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
variable to build and install your own code and external libraries outside of
the Go tree (and avoid writing Makefiles).
</p>
<h2 id="r57">r57 (released 2011/05/03)</h2>
<p>
@@ -162,6 +234,7 @@ For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> document
<h3 id="r57.minor">Minor revisions</h3>
<p>r57.1 fixes a <a href="http://code.google.com/p/go/source/detail?r=ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
<p>r57.2 fixes a <a href="http://code.google.com/p/go/source/detail?r=063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
<h2 id="r56">r56 (released 2011/03/16)</h2>

View File

@@ -14,7 +14,7 @@ hg pull
hg update weekly.<i>YYYY-MM-DD</i>
</pre>
<h2 id="2011-06-09">2011-06-09</h2>
<h2 id="2011-06-09">2011-06-09 (<a href="release.html#r58">base for r58</a>)</h2>
<pre>
This release includes changes to the strconv, http, and exp/draw packages.

View File

@@ -23,6 +23,17 @@ concepts: syntax, types, allocation, constants, I/O, sorting, printing,
goroutines, and channels.
</p>
<h3 id="course_notes">Course Notes</h3>
<p>
Slides from a 3-day course about the Go programming language.
A more thorough introduction than the tutorial.
</p>
<ul>
<li><a href="GoCourseDay1.pdf">Day 1: Basics</a> <small>[270KB PDF]</small>
<li><a href="GoCourseDay2.pdf">Day 2: Types, Methods, Interfaces</a> <small>[270KB PDF]</small>
<li><a href="GoCourseDay3.pdf">Day 3: Concurrency and Communication</a> <small>[180KB PDF]</small>
</ul>
<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
<p>
A document that gives tips for writing clear, idiomatic Go code.
@@ -209,7 +220,7 @@ from Hoares 1978 paper to Go provides insight into how and why Go works as it
does.
</i></p>
<h3 id="emerging_go"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
<h3 id="go_frontend_gcc"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
<p>
A description of the Go language frontend for gcc.
Ian Lance Taylor's paper delivered at the GCC Summit 2010.

View File

@@ -183,16 +183,6 @@ easier to understand what happens when things combine.
<h2 id="Usage">Usage</h2>
<h3 id="Who_should_use_the_language">
Who should use the language?</h3>
<p>
Go is an experiment. We hope adventurous users will give it a try and see
if they enjoy it. Not every programmer
will, but we hope enough will find satisfaction in the approach it
offers to justify further development.
</p>
<h3 id="Is_Google_using_go_internally"> Is Google using Go internally?</h3>
<p>
@@ -598,6 +588,24 @@ the interface idea. Sometimes, though, they're necessary to resolve ambiguities
among similar interfaces.
</p>
<h3 id="convert_slice_of_interface">
Can I convert a []T to an []interface{}?</h3>
<p>
Not directly because they do not have the same representation in memory.
It is necessary to copy the elements individually to the destination
slice. This example converts a slice of <code>int</code> to a slice of
<code>interface{}</code>:
</p>
<pre>
t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
</pre>
<h2 id="values">Values</h2>
<h3 id="conversions">

View File

@@ -10,8 +10,7 @@ After you've read this tutorial, you should look at
which digs deeper into how the language is used and
talks about the style and idioms of programming in Go.
Also, slides from a 3-day course about Go are available.
Although they're badly out of date, they provide some
background and a lot of examples:
They provide some background and a lot of examples:
<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.

View File

@@ -11,8 +11,7 @@ After you've read this tutorial, you should look at
which digs deeper into how the language is used and
talks about the style and idioms of programming in Go.
Also, slides from a 3-day course about Go are available.
Although they're badly out of date, they provide some
background and a lot of examples:
They provide some background and a lot of examples:
<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.

View File

@@ -124,6 +124,64 @@ newplist(void)
return pl;
}
void
clearstk(void)
{
Plist *pl;
Prog *p, *p1, *p2, *p3;
Node dst, end, zero, con;
if(plast->firstpc->to.offset <= 0)
return;
// reestablish context for inserting code
// at beginning of function.
pl = plast;
p1 = pl->firstpc;
p2 = p1->link;
pc = mal(sizeof(*pc));
clearp(pc);
p1->link = pc;
// zero stack frame
// MOVW $4(SP), R1
nodreg(&dst, types[tptr], 1);
p = gins(AMOVW, N, &dst);
p->from.type = D_CONST;
p->from.reg = REGSP;
p->from.offset = 4;
// MOVW $n(R1), R2
nodreg(&end, types[tptr], 2);
p = gins(AMOVW, N, &end);
p->from.type = D_CONST;
p->from.reg = 1;
p->from.offset = p1->to.offset;
// MOVW $0, R3
nodreg(&zero, types[TUINT32], 3);
nodconst(&con, types[TUINT32], 0);
gmove(&con, &zero);
// L:
// MOVW.P R3, 0(R1) +4
// CMP R1, R2
// BNE L
p = gins(AMOVW, &zero, &dst);
p->to.type = D_OREG;
p->to.offset = 4;
p->scond |= C_PBIT;
p3 = p;
p = gins(ACMP, &dst, N);
raddr(&end, p);
patch(gbranch(ABNE, T), p3);
// continue with original code.
gins(ANOP, N, N)->link = p2;
pc = P;
}
void
gused(Node *n)
{

View File

@@ -120,6 +120,44 @@ newplist(void)
return pl;
}
void
clearstk(void)
{
Plist *pl;
Prog *p1, *p2;
Node sp, di, cx, con, ax;
if((uint32)plast->firstpc->to.offset <= 0)
return;
// reestablish context for inserting code
// at beginning of function.
pl = plast;
p1 = pl->firstpc;
p2 = p1->link;
pc = mal(sizeof(*pc));
clearp(pc);
p1->link = pc;
// zero stack frame
nodreg(&sp, types[tptr], D_SP);
nodreg(&di, types[tptr], D_DI);
nodreg(&cx, types[TUINT64], D_CX);
nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
gins(ACLD, N, N);
gins(AMOVQ, &sp, &di);
gins(AMOVQ, &con, &cx);
nodconst(&con, types[TUINT64], 0);
nodreg(&ax, types[TUINT64], D_AX);
gins(AMOVQ, &con, &ax);
gins(AREP, N, N);
gins(ASTOSQ, N, N);
// continue with original code.
gins(ANOP, N, N)->link = p2;
pc = P;
}
void
gused(Node *n)
{

View File

@@ -122,6 +122,44 @@ newplist(void)
return pl;
}
void
clearstk(void)
{
Plist *pl;
Prog *p1, *p2;
Node sp, di, cx, con, ax;
if(plast->firstpc->to.offset <= 0)
return;
// reestablish context for inserting code
// at beginning of function.
pl = plast;
p1 = pl->firstpc;
p2 = p1->link;
pc = mal(sizeof(*pc));
clearp(pc);
p1->link = pc;
// zero stack frame
nodreg(&sp, types[tptr], D_SP);
nodreg(&di, types[tptr], D_DI);
nodreg(&cx, types[TUINT32], D_CX);
nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
gins(ACLD, N, N);
gins(AMOVL, &sp, &di);
gins(AMOVL, &con, &cx);
nodconst(&con, types[TUINT32], 0);
nodreg(&ax, types[TUINT32], D_AX);
gins(AMOVL, &con, &ax);
gins(AREP, N, N);
gins(ASTOSL, N, N);
// continue with original code.
gins(ANOP, N, N)->link = p2;
pc = P;
}
void
gused(Node *n)
{

View File

@@ -1241,9 +1241,14 @@ funccompile(Node *n, int isclosure)
stksize = 0;
dclcontext = PAUTO;
funcdepth = n->funcdepth + 1;
hasgoto = 0;
compile(n);
if(hasgoto)
clearstk();
curfn = nil;
funcdepth = 0;
dclcontext = PEXTERN;
}

View File

@@ -209,6 +209,7 @@ gen(Node *n)
break;
case OGOTO:
hasgoto = 1;
newlab(OGOTO, n, N);
gjmp(P);
break;

View File

@@ -1255,3 +1255,6 @@ void zhist(Biobuf *b, int line, vlong offset);
void zname(Biobuf *b, Sym *s, int t);
void data(void);
void text(void);
EXTERN int hasgoto;
void clearstk(void);

View File

@@ -14,6 +14,7 @@ GOFILES=\
httpserver.go\
procattr.go\
reflect.go\
signal.go\
typecheck.go\
include ../../Make.cmd

View File

@@ -10,6 +10,7 @@ import (
"go/token"
"os"
"strconv"
"strings"
)
type fix struct {
@@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
// imports returns true if f imports path.
func imports(f *ast.File, path string) bool {
return importSpec(f, path) != nil
}
// importSpec returns the import spec if f imports path,
// or nil otherwise.
func importSpec(f *ast.File, path string) *ast.ImportSpec {
for _, s := range f.Imports {
t, err := strconv.Unquote(s.Path.Value)
if err == nil && t == path {
return true
if importPath(s) == path {
return s
}
}
return false
return nil
}
// importPath returns the unquoted import path of s,
// or "" if the path is not properly quoted.
func importPath(s *ast.ImportSpec) string {
t, err := strconv.Unquote(s.Path.Value)
if err == nil {
return t
}
return ""
}
// isPkgDot returns true if t is the expression "pkg.name"
@@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
},
}
}
// addImport adds the import path to the file f, if absent.
func addImport(f *ast.File, path string) {
if imports(f, path) {
return
}
newImport := &ast.ImportSpec{
Path: &ast.BasicLit{
Kind: token.STRING,
Value: strconv.Quote(path),
},
}
var impdecl *ast.GenDecl
// Find an import decl to add to.
for _, decl := range f.Decls {
gen, ok := decl.(*ast.GenDecl)
if ok && gen.Tok == token.IMPORT {
impdecl = gen
break
}
}
// No import decl found. Add one.
if impdecl == nil {
impdecl = &ast.GenDecl{
Tok: token.IMPORT,
}
f.Decls = append(f.Decls, nil)
copy(f.Decls[1:], f.Decls)
f.Decls[0] = impdecl
}
// Ensure the import decl has parentheses, if needed.
if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
impdecl.Lparen = impdecl.Pos()
}
// Assume the import paths are alphabetically ordered.
// If they are not, the result is ugly, but legal.
insertAt := len(impdecl.Specs) // default to end of specs
for i, spec := range impdecl.Specs {
impspec := spec.(*ast.ImportSpec)
if importPath(impspec) > path {
insertAt = i
break
}
}
impdecl.Specs = append(impdecl.Specs, nil)
copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
impdecl.Specs[insertAt] = newImport
f.Imports = append(f.Imports, newImport)
}
// deleteImport deletes the import path from the file f, if present.
func deleteImport(f *ast.File, path string) {
oldImport := importSpec(f, path)
// Find the import node that imports path, if any.
for i, decl := range f.Decls {
gen, ok := decl.(*ast.GenDecl)
if !ok || gen.Tok != token.IMPORT {
continue
}
for j, spec := range gen.Specs {
impspec := spec.(*ast.ImportSpec)
if oldImport != impspec {
continue
}
// We found an import spec that imports path.
// Delete it.
copy(gen.Specs[j:], gen.Specs[j+1:])
gen.Specs = gen.Specs[:len(gen.Specs)-1]
// If this was the last import spec in this decl,
// delete the decl, too.
if len(gen.Specs) == 0 {
copy(f.Decls[i:], f.Decls[i+1:])
f.Decls = f.Decls[:len(f.Decls)-1]
} else if len(gen.Specs) == 1 {
gen.Lparen = token.NoPos // drop parens
}
break
}
}
// Delete it from f.Imports.
for i, imp := range f.Imports {
if imp == oldImport {
copy(f.Imports[i:], f.Imports[i+1:])
f.Imports = f.Imports[:len(f.Imports)-1]
break
}
}
}
func usesImport(f *ast.File, path string) (used bool) {
spec := importSpec(f, path)
if spec == nil {
return
}
name := spec.Name.String()
switch name {
case "<nil>":
// If the package name is not explicitly specified,
// make an educated guess. This is not guaranteed to be correct.
lastSlash := strings.LastIndex(path, "/")
if lastSlash == -1 {
name = path
} else {
name = path[lastSlash+1:]
}
case "_", ".":
// Not sure if this import is used - err on the side of caution.
return true
}
walk(f, func(n interface{}) {
sel, ok := n.(*ast.SelectorExpr)
if ok && isTopName(sel.X, name) {
used = true
}
})
return
}

49
src/cmd/gofix/signal.go Normal file
View File

@@ -0,0 +1,49 @@
// Copyright 2011 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 main
import (
"go/ast"
"strings"
)
func init() {
register(fix{
"signal",
signal,
`Adapt code to types moved from os/signal to signal.
http://codereview.appspot.com/4437091
`,
})
}
func signal(f *ast.File) (fixed bool) {
if !imports(f, "os/signal") {
return
}
walk(f, func(n interface{}) {
s, ok := n.(*ast.SelectorExpr)
if !ok || !isTopName(s.X, "signal") {
return
}
sel := s.Sel.String()
if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
s.X = &ast.Ident{Name: "os"}
fixed = true
}
})
if fixed {
addImport(f, "os")
if !usesImport(f, "os/signal") {
deleteImport(f, "os/signal")
}
}
return
}

View File

@@ -0,0 +1,96 @@
// Copyright 2011 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 main
func init() {
addTestCases(signalTests)
}
var signalTests = []testCase{
{
Name: "signal.0",
In: `package main
import (
_ "a"
"os/signal"
_ "z"
)
type T1 signal.UnixSignal
type T2 signal.Signal
func f() {
_ = signal.SIGHUP
_ = signal.Incoming
}
`,
Out: `package main
import (
_ "a"
"os"
"os/signal"
_ "z"
)
type T1 os.UnixSignal
type T2 os.Signal
func f() {
_ = os.SIGHUP
_ = signal.Incoming
}
`,
},
{
Name: "signal.1",
In: `package main
import (
"os"
"os/signal"
)
func f() {
var _ os.Error
_ = signal.SIGHUP
}
`,
Out: `package main
import "os"
func f() {
var _ os.Error
_ = os.SIGHUP
}
`,
},
{
Name: "signal.2",
In: `package main
import "os"
import "os/signal"
func f() {
var _ os.Error
_ = signal.SIGHUP
}
`,
Out: `package main
import "os"
func f() {
var _ os.Error
_ = os.SIGHUP
}
`,
},
}

View File

@@ -1804,7 +1804,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
{
vlong here;
@@ -1820,7 +1820,9 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
here = cpos();
seek(cout, unitstart, 0);
LPUT(here - unitstart - sizeof(int32));
LPUT(here - unitstart - sizeof(int32)); // unit_length
WPUT(3); // dwarf version
LPUT(header_length); // header lenght starting here
cflush();
seek(cout, here, 0);
}
@@ -1832,7 +1834,7 @@ writelines(void)
Prog *q;
Sym *s;
Auto *a;
vlong unitstart, offs;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
int currfile;
int i, lang, da, dt;
@@ -1842,6 +1844,7 @@ writelines(void)
char *n, *nn;
unitstart = -1;
headerend = -1;
pc = 0;
epc = 0;
lc = 1;
@@ -1859,7 +1862,7 @@ writelines(void)
// we're entering a new compilation unit
if (inithist(s->autom)) {
flushunit(dwinfo, epc, unitstart);
flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
@@ -1880,10 +1883,10 @@ writelines(void)
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
LPUT(0); // unit_length (*), will be filled in later.
LPUT(0); // unit_length (*), will be filled in by flushunit.
WPUT(3); // dwarf version (appendix F)
LPUT(11); // header_length (*), starting here.
LPUT(0); // header_length (*), filled in by flushunit.
// cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
cput(1); // default_is_stmt
cput(LINE_BASE); // line_base
@@ -1894,17 +1897,15 @@ writelines(void)
cput(1); // standard_opcode_lengths[3]
cput(1); // standard_opcode_lengths[4]
cput(0); // include_directories (empty)
cput(0); // file_names (empty) (emitted by DW_LNE's below)
// header_length ends here.
for (i=1; i < histfilesize; i++) {
cput(0); // start extended opcode
uleb128put(1 + strlen(histfile[i]) + 4);
cput(DW_LNE_define_file);
strnput(histfile[i], strlen(histfile[i]) + 4);
// 4 zeros: the string termination + 3 fields.
}
cput(0); // terminate file_names.
headerend = cpos();
pc = s->text->pc;
epc = pc;
currfile = 1;
@@ -2009,7 +2010,7 @@ writelines(void)
dwfunc->hash = nil;
}
flushunit(dwinfo, epc, unitstart);
flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}

View File

@@ -150,7 +150,8 @@ pprof [options] <profile>
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
or /pprof/filteredprofile.
For instance: "pprof http://myserver.com:80$HEAP_PAGE".
For instance:
pprof http://myserver.com:80$HEAP_PAGE
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
pprof --symbols <program>
Maps addresses to symbol names. In this mode, stdin should be a
@@ -532,7 +533,7 @@ sub Init() {
ConfigureObjTools($main::prog)
}
# Break the opt_list_prefix into the prefix_list array
# Break the opt_lib_prefix into the prefix_list array
@prefix_list = split (',', $main::opt_lib_prefix);
# Remove trailing / from the prefixes, in the list to prevent
@@ -626,7 +627,7 @@ sub Main() {
if ($main::opt_disasm) {
PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
} elsif ($main::opt_list) {
PrintListing($libs, $flat, $cumulative, $main::opt_list);
PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
} elsif ($main::opt_text) {
# Make sure the output is empty when have nothing to report
# (only matters when --heapcheck is given but we must be
@@ -814,7 +815,7 @@ sub InteractiveCommand {
my $ignore;
($routine, $ignore) = ParseInteractiveArgs($3);
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -841,21 +842,22 @@ sub InteractiveCommand {
return 1;
}
if (m/^\s*list\s*(.+)/) {
if (m/^\s*(web)?list\s*(.+)/) {
my $html = (defined($1) && ($1 eq "web"));
$main::opt_list = 1;
my $routine;
my $ignore;
($routine, $ignore) = ParseInteractiveArgs($1);
($routine, $ignore) = ParseInteractiveArgs($2);
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
my $flat = FlatProfile($reduced);
my $cumulative = CumulativeProfile($reduced);
PrintListing($libs, $flat, $cumulative, $routine);
PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
return 1;
}
if (m/^\s*disasm\s*(.+)/) {
@@ -866,7 +868,7 @@ sub InteractiveCommand {
($routine, $ignore) = ParseInteractiveArgs($1);
# Process current profile to account for various settings
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -890,7 +892,7 @@ sub InteractiveCommand {
($focus, $ignore) = ParseInteractiveArgs($2);
# Process current profile to account for various settings
my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore);
my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -916,6 +918,7 @@ sub InteractiveCommand {
sub ProcessProfile {
my $total_count = shift;
my $orig_profile = shift;
my $symbols = shift;
my $focus = shift;
@@ -923,7 +926,6 @@ sub ProcessProfile {
# Process current profile to account for various settings
my $profile = $orig_profile;
my $total_count = TotalProfile($profile);
printf("Total: %s %s\n", Unparse($total_count), Units());
if ($focus ne '') {
$profile = FocusProfile($symbols, $profile, $focus);
@@ -970,6 +972,11 @@ Commands:
list [routine_regexp] [-ignore1] [-ignore2]
Show source listing of routines whose names match "routine_regexp"
weblist [routine_regexp] [-ignore1] [-ignore2]
Displays a source listing of routines whose names match "routine_regexp"
in a web browser. You can click on source lines to view the
corresponding disassembly.
top [--cum] [-ignore1] [-ignore2]
top20 [--cum] [-ignore1] [-ignore2]
top37 [--cum] [-ignore1] [-ignore2]
@@ -1144,7 +1151,7 @@ sub PrintText {
$sym);
}
$lines++;
last if ($line_limit >= 0 && $lines > $line_limit);
last if ($line_limit >= 0 && $lines >= $line_limit);
}
}
@@ -1291,11 +1298,32 @@ sub ByName {
# Print source-listing for all all routines that match $main::opt_list
sub PrintListing {
my $total = shift;
my $libs = shift;
my $flat = shift;
my $cumulative = shift;
my $list_opts = shift;
my $html = shift;
my $output = \*STDOUT;
my $fname = "";
if ($html) {
# Arrange to write the output to a temporary file
$fname = TempName($main::next_tmpfile, "html");
$main::next_tmpfile++;
if (!open(TEMP, ">$fname")) {
print STDERR "$fname: $!\n";
return;
}
$output = \*TEMP;
print $output HtmlListingHeader();
printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
$main::prog, Unparse($total), Units());
}
my $listed = 0;
foreach my $lib (@{$libs}) {
my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
my $offset = AddressSub($lib->[1], $lib->[3]);
@@ -1307,15 +1335,98 @@ sub PrintListing {
my $addr = AddressAdd($start_addr, $offset);
for (my $i = 0; $i < $length; $i++) {
if (defined($cumulative->{$addr})) {
PrintSource($lib->[0], $offset,
$routine, $flat, $cumulative,
$start_addr, $end_addr);
$listed += PrintSource(
$lib->[0], $offset,
$routine, $flat, $cumulative,
$start_addr, $end_addr,
$html,
$output);
last;
}
$addr = AddressInc($addr);
}
}
}
if ($html) {
if ($listed > 0) {
print $output HtmlListingFooter();
close($output);
RunWeb($fname);
} else {
close($output);
unlink($fname);
}
}
}
sub HtmlListingHeader {
return <<'EOF';
<DOCTYPE html>
<html>
<head>
<title>Pprof listing</title>
<style type="text/css">
body {
font-family: sans-serif;
}
h1 {
font-size: 1.5em;
margin-bottom: 4px;
}
.legend {
font-size: 1.25em;
}
.line {
color: #aaaaaa;
}
.livesrc {
color: #0000ff;
cursor: pointer;
}
.livesrc:hover {
background-color: #cccccc;
}
.asm {
color: #888888;
display: none;
}
</style>
<script type="text/javascript">
function pprof_toggle_asm(e) {
var target;
if (!e) e = window.event;
if (e.target) target = e.target;
else if (e.srcElement) target = e.srcElement;
if (target && target.className == "livesrc") {
var asm = target.nextSibling;
if (asm && asm.className == "asm") {
asm.style.display = (asm.style.display == "block" ? "none" : "block");
e.preventDefault();
return false;
}
}
}
</script>
</head>
<body>
EOF
}
sub HtmlListingFooter {
return <<'EOF';
</body>
</html>
EOF
}
sub HtmlEscape {
my $text = shift;
$text =~ s/&/&amp;/g;
$text =~ s/</&lt;/g;
$text =~ s/>/&gt;/g;
return $text;
}
# Returns the indentation of the line, if it has any non-whitespace
@@ -1338,6 +1449,8 @@ sub PrintSource {
my $cumulative = shift;
my $start_addr = shift;
my $end_addr = shift;
my $html = shift;
my $output = shift;
# Disassemble all instructions (just to get line numbers)
my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
@@ -1353,7 +1466,7 @@ sub PrintSource {
}
if (!defined($filename)) {
print STDERR "no filename found in $routine\n";
return;
return 0;
}
# Hack 2: assume that the largest line number from $filename is the
@@ -1386,7 +1499,7 @@ sub PrintSource {
{
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
return;
return 0;
}
my $l = 0;
my $first_indentation = -1;
@@ -1414,12 +1527,21 @@ sub PrintSource {
# Assign all samples to the range $firstline,$lastline,
# Hack 4: If an instruction does not occur in the range, its samples
# are moved to the next instruction that occurs in the range.
my $samples1 = {};
my $samples2 = {};
my $running1 = 0; # Unassigned flat counts
my $running2 = 0; # Unassigned cumulative counts
my $total1 = 0; # Total flat counts
my $total2 = 0; # Total cumulative counts
my $samples1 = {}; # Map from line number to flat count
my $samples2 = {}; # Map from line number to cumulative count
my $running1 = 0; # Unassigned flat counts
my $running2 = 0; # Unassigned cumulative counts
my $total1 = 0; # Total flat counts
my $total2 = 0; # Total cumulative counts
my %disasm = (); # Map from line number to disassembly
my $running_disasm = ""; # Unassigned disassembly
my $skip_marker = "---\n";
if ($html) {
$skip_marker = "";
for (my $l = $firstline; $l <= $lastline; $l++) {
$disasm{$l} = "";
}
}
foreach my $e (@instructions) {
# Add up counts for all address that fall inside this instruction
my $c1 = 0;
@@ -1428,6 +1550,15 @@ sub PrintSource {
$c1 += GetEntry($flat, $a);
$c2 += GetEntry($cumulative, $a);
}
if ($html) {
$running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
HtmlPrintNumber($c1),
HtmlPrintNumber($c2),
$e->[0],
CleanDisassembly($e->[3]));
}
$running1 += $c1;
$running2 += $c2;
$total1 += $c1;
@@ -1442,6 +1573,10 @@ sub PrintSource {
AddEntry($samples2, $line, $running2);
$running1 = 0;
$running2 = 0;
if ($html) {
$disasm{$line} .= $running_disasm;
$running_disasm = '';
}
}
}
@@ -1449,16 +1584,28 @@ sub PrintSource {
AddEntry($samples1, $lastline, $running1);
AddEntry($samples2, $lastline, $running2);
printf("ROUTINE ====================== %s in %s\n" .
"%6s %6s Total %s (flat / cumulative)\n",
ShortFunctionName($routine),
$filename,
Units(),
Unparse($total1),
Unparse($total2));
if ($html) {
printf $output (
"<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
"Total:%6s %6s (flat / cumulative %s)\n",
HtmlEscape(ShortFunctionName($routine)),
HtmlEscape($filename),
Unparse($total1),
Unparse($total2),
Units());
} else {
printf $output (
"ROUTINE ====================== %s in %s\n" .
"%6s %6s Total %s (flat / cumulative)\n",
ShortFunctionName($routine),
$filename,
Unparse($total1),
Unparse($total2),
Units());
}
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
return;
return 0;
}
my $l = 0;
while (<FILE>) {
@@ -1468,16 +1615,47 @@ sub PrintSource {
(($l <= $oldlastline + 5) || ($l <= $lastline))) {
chop;
my $text = $_;
if ($l == $firstline) { printf("---\n"); }
printf("%6s %6s %4d: %s\n",
UnparseAlt(GetEntry($samples1, $l)),
UnparseAlt(GetEntry($samples2, $l)),
$l,
$text);
if ($l == $lastline) { printf("---\n"); }
if ($l == $firstline) { print $output $skip_marker; }
my $n1 = GetEntry($samples1, $l);
my $n2 = GetEntry($samples2, $l);
if ($html) {
my $dis = $disasm{$l};
if (!defined($dis) || $n1 + $n2 == 0) {
# No samples/disassembly for this source line
printf $output (
"<span class=\"line\">%5d</span> " .
"<span class=\"deadsrc\">%6s %6s %s</span>\n",
$l,
HtmlPrintNumber($n1),
HtmlPrintNumber($n2),
HtmlEscape($text));
} else {
printf $output (
"<span class=\"line\">%5d</span> " .
"<span class=\"livesrc\">%6s %6s %s</span>" .
"<span class=\"asm\">%s</span>\n",
$l,
HtmlPrintNumber($n1),
HtmlPrintNumber($n2),
HtmlEscape($text),
HtmlEscape($dis));
}
} else {
printf $output(
"%6s %6s %4d: %s\n",
UnparseAlt($n1),
UnparseAlt($n2),
$l,
$text);
}
if ($l == $lastline) { print $output $skip_marker; }
};
}
close(FILE);
if ($html) {
print $output "</pre>\n";
}
return 1;
}
# Return the source line for the specified file/linenumber.
@@ -1625,16 +1803,11 @@ sub PrintDisassembledFunction {
$address =~ s/^0x//;
$address =~ s/^0*//;
# Trim symbols
my $d = $e->[3];
while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
printf("%6s %6s %8s: %6s\n",
UnparseAlt($flat_count[$x]),
UnparseAlt($cum_count[$x]),
$address,
$d);
CleanDisassembly($e->[3]));
}
}
}
@@ -2254,6 +2427,16 @@ sub UnparseAlt {
}
}
# Alternate pretty-printed form: 0 maps to ""
sub HtmlPrintNumber {
my $num = shift;
if ($num == 0) {
return "";
} else {
return Unparse($num);
}
}
# Return output units
sub Units {
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
@@ -2415,6 +2598,8 @@ sub RemoveUninterestingFrames {
'copyin',
'gostring',
'gostringsize',
'growslice1',
'appendslice1',
'hash_init',
'hash_subtable_new',
'hash_conv',
@@ -2422,6 +2607,8 @@ sub RemoveUninterestingFrames {
'hash_insert_internal',
'hash_insert',
'mapassign',
'runtime.mapassign',
'runtime.appendslice',
'runtime.mapassign1',
'makechan',
'makemap',
@@ -2433,11 +2620,13 @@ sub RemoveUninterestingFrames {
'unsafe.New',
'runtime.mallocgc',
'runtime.catstring',
'runtime.growslice',
'runtime.ifaceT2E',
'runtime.ifaceT2I',
'runtime.makechan',
'runtime.makechan_c',
'runtime.makemap',
'runtime.makemap_c',
'runtime.makeslice',
'runtime.mal',
'runtime.slicebytetostring',
@@ -4302,6 +4491,14 @@ sub ShortFunctionName {
return $function;
}
# Trim overly long symbols found in disassembler output
sub CleanDisassembly {
my $d = shift;
while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
return $d;
}
##### Miscellaneous #####
# Find the right versions of the above object tools to use. The

22
test/fixedbugs/bug344.go Normal file
View File

@@ -0,0 +1,22 @@
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344
// Copyright 2011 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 main
import "fmt"
func main() {
// invalid use of goto.
// do whatever you like, just don't crash.
i := 42
a := []*int{&i, &i, &i, &i}
x := a[0]
goto start
for _, x = range a {
start:
fmt.Sprint(*x)
}
}