Compare commits

...

16 Commits

Author SHA1 Message Date
Russ Cox
adfa87c5d7 [release-branch.r58] cgo: handle new Apple LLVM-based gcc from Xcode 4.2
««« CL 4607045 / 142f0bc0d6e7
cgo: handle new Apple LLVM-based gcc from Xcode 4.2

That gcc does not include enumerator names and values
in its DWARF debug output.  Create a data block from which
we can read the values instead.

Fixes #1881.

R=iant
CC=golang-dev
https://golang.org/cl/4607045
»»»

R=adg
CC=golang-dev
https://golang.org/cl/4708042
2011-07-12 10:19:11 -04:00
Russ Cox
af97a0b94c [release-branch.r58] doc: document r58.1
««« CL 4700041 / 7c6b5a591a86
doc: document r58.1

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

R=adg
CC=golang-dev
https://golang.org/cl/4701041
2011-07-12 01:41:46 -04:00
Russ Cox
beca117ea3 [release-branch.r58] build: use awk instead of giant egrep regexp
««« CL 4603056 / 655a4be3968f
build: use awk instead of giant egrep regexp

Avoids buggy version of egrep on some Macs.

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

R=adg
CC=golang-dev
https://golang.org/cl/4695042
2011-07-11 23:38:12 -04:00
Russ Cox
ecfec2c61a [release-branch.r58] runtime/cgo: fix for OS X 10.7
««« CL 4603057 / 0905a2ca94c6
runtime/cgo: fix for OS X 10.7

Correct a few error messages (libcgo -> runtime/cgo)
and delete old nacl_386.c file too.

Fixes #1657.

R=iant
CC=golang-dev
https://golang.org/cl/4603057
»»»

R=adg
CC=golang-dev
https://golang.org/cl/4698041
2011-07-11 23:38:02 -04:00
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
30 changed files with 987 additions and 192 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -14,6 +14,86 @@ 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>
<h3 id="r58.minor">Minor revisions</h3>
<p>r58.1 adds
<a href="http://code.google.com/p/go/source/detail?r=293c25943586">build</a> and
<a href="http://code.google.com/p/go/source/detail?r=bf17e96b6582">runtime</a>
changes to make Go run on OS X 10.7 Lion.
</p>
<h2 id="r57">r57 (released 2011/05/03)</h2>
<p>
@@ -162,6 +242,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

@@ -13,6 +13,7 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
"encoding/binary"
"flag"
"fmt"
"go/ast"
@@ -477,7 +478,27 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
}
}
d := p.gccDebug(b.Bytes())
// Apple's LLVM-based gcc does not include the enumeration
// names and values in its DWARF debug output. In case we're
// using such a gcc, create a data block initialized with the values.
// We can read them out of the object file.
fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
for _, n := range names {
if n.Kind == "const" {
fmt.Fprintf(&b, "\t%s,\n", n.C)
} else {
fmt.Fprintf(&b, "\t0,\n")
}
}
fmt.Fprintf(&b, "\t0\n")
fmt.Fprintf(&b, "};\n")
d, bo, debugData := p.gccDebug(b.Bytes())
enumVal := make([]int64, len(debugData)/8)
for i := range enumVal {
enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
}
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
@@ -569,9 +590,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
n.Type.EnumValues[k] = 0, false
} else if n.Kind == "const" && i < len(enumVal) {
n.Const = strconv.Itoa64(enumVal[i])
}
}
}
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
@@ -593,6 +617,9 @@ func (p *Package) rewriteRef(f *File) {
// are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
if r.Name.Kind == "const" && r.Name.Const == "" {
error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
}
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
switch r.Context {
case "call", "call2":
@@ -692,29 +719,57 @@ func (p *Package) gccCmd() []string {
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and any messages
// printed to standard error.
func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
// returns the corresponding DWARF data and, if present, debug data block.
func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
runGcc(stdin, p.gccCmd())
// Try to parse f as ELF and Mach-O and hope one works.
var f interface {
DWARF() (*dwarf.Data, os.Error)
}
var err os.Error
if f, err = elf.Open(gccTmp); err != nil {
if f, err = macho.Open(gccTmp); err != nil {
if f, err = pe.Open(gccTmp); err != nil {
fatalf("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
if f, err := macho.Open(gccTmp); err == nil {
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
}
var data []byte
if f.Symtab != nil {
for i := range f.Symtab.Syms {
s := &f.Symtab.Syms[i]
// Mach-O still uses a leading _ to denote non-assembly symbols.
if s.Name == "_"+"__cgodebug_data" {
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value-sect.Addr:]
}
}
}
}
}
}
return d, f.ByteOrder, data
}
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err)
// Can skip debug data block in ELF and PE for now.
// The DWARF information is complete.
if f, err := elf.Open(gccTmp); err == nil {
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
}
return d, f.ByteOrder, nil
}
return d
if f, err := pe.Open(gccTmp); err == nil {
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
}
return d, binary.LittleEndian, nil
}
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
panic("not reached")
}
// gccDefines runs gcc -E -dM -xc - over the C program stdin

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

View File

@@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
}
}
if ndim == 0 {
err = DecodeError{"info", e.Offset, "missing dimension for array"}
goto Error
// LLVM generates this for x[].
t.Count = -1
}
case TagBaseType:

View File

@@ -546,6 +546,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
// Symbols returns the symbol table for f.
func (f *File) Symbols() ([]Symbol, os.Error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
}
type ImportedSymbol struct {
Name string
Version string

View File

@@ -15,7 +15,13 @@ fi
# Get list of directories from Makefile
dirs=$(gomake --no-print-directory echo-dirs)
dirpat=$(echo $dirs C | sed 's/ /|/g; s/.*/^(&)$/')
dirpat=$(echo $dirs C | awk '{
for(i=1;i<=NF;i++){
x=$i
gsub("/", "\\/", x)
printf("/^(%s)$/\n", x)
}
}')
for dir in $dirs; do (
cd $dir || exit 1
@@ -30,7 +36,7 @@ for dir in $dirs; do (
deps=$(
sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
cut -d '"' -f2 |
egrep "$dirpat" |
awk "$dirpat" |
grep -v "^$dir\$" |
sed 's/$/.install/' |
sed 's;^C\.install;runtime/cgo.install;' |

View File

@@ -8,11 +8,13 @@
static void* threadentry(void*);
static pthread_key_t k1, k2;
#define magic1 (0x23581321U)
static void
inittls(void)
{
uint32 x, y;
pthread_key_t tofree[16], k;
pthread_key_t tofree[128], k;
int i, ntofree;
int havek1, havek2;
@@ -35,9 +37,8 @@ inittls(void)
* 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c.
*
* The linker and runtime hard-code these constant offsets
* from %gs where we expect to find m and g. The code
* below verifies that the constants are correct once it has
* obtained the keys. Known to ../cmd/8l/obj.c:/468
* from %gs where we expect to find m and g.
* Known to ../cmd/8l/obj.c:/468
* and to ../pkg/runtime/darwin/386/sys.s:/468
*
* This is truly disgusting and a bit fragile, but taking care
@@ -48,55 +49,54 @@ inittls(void)
* require an extra instruction and memory reference in
* every stack growth prolog and would also require
* rewriting the code that 8c generates for extern registers.
*
* Things get more disgusting on OS X 10.7 Lion.
* The 0x48 base mentioned above is the offset of the tsd
* array within the per-thread structure on Leopard and Snow Leopard.
* On Lion, the base moved a little, so while the math above
* still applies, the base is different. Thus, we cannot
* look for specific key values if we want to build binaries
* that run on both systems. Instead, forget about the
* specific key values and just allocate and initialize per-thread
* storage until we find a key that writes to the memory location
* we want. Then keep that key.
*/
havek1 = 0;
havek2 = 0;
ntofree = 0;
while(!havek1 || !havek2) {
if(pthread_key_create(&k, nil) < 0) {
fprintf(stderr, "libcgo: pthread_key_create failed\n");
fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
abort();
}
if(k == 0x108) {
pthread_setspecific(k, (void*)magic1);
asm volatile("movl %%gs:0x468, %0" : "=r"(x));
asm volatile("movl %%gs:0x46c, %0" : "=r"(y));
if(x == magic1) {
havek1 = 1;
k1 = k;
continue;
}
if(k == 0x109) {
} else if(y == magic1) {
havek2 = 1;
k2 = k;
continue;
} else {
if(ntofree >= nelem(tofree)) {
fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
fprintf(stderr, "\ttried");
for(i=0; i<ntofree; i++)
fprintf(stderr, " %#x", (unsigned)tofree[i]);
fprintf(stderr, "\n");
abort();
}
tofree[ntofree++] = k;
}
if(ntofree >= nelem(tofree)) {
fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
fprintf(stderr, "\twanted 0x108 and 0x109\n");
fprintf(stderr, "\tgot");
for(i=0; i<ntofree; i++)
fprintf(stderr, " %#lx", tofree[i]);
fprintf(stderr, "\n");
abort();
}
tofree[ntofree++] = k;
pthread_setspecific(k, 0);
}
for(i=0; i<ntofree; i++)
pthread_key_delete(tofree[i]);
/*
* We got the keys we wanted. Make sure that we observe
* updates to k1 at 0x468, to verify that the TLS array
* offset from %gs hasn't changed.
* We got the keys we wanted. Free the others.
*/
pthread_setspecific(k1, (void*)0x12345678);
asm volatile("movl %%gs:0x468, %0" : "=r"(x));
pthread_setspecific(k1, (void*)0x87654321);
asm volatile("movl %%gs:0x468, %0" : "=r"(y));
if(x != 0x12345678 || y != 0x87654321) {
printf("libcgo: thread-local storage %#lx not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y);
abort();
}
for(i=0; i<ntofree; i++)
pthread_key_delete(tofree[i]);
}
static void

View File

@@ -8,24 +8,25 @@
static void* threadentry(void*);
static pthread_key_t k1, k2;
#define magic1 (0x23581321345589ULL)
static void
inittls(void)
{
uint64 x, y;
pthread_key_t tofree[16], k;
pthread_key_t tofree[128], k;
int i, ntofree;
int havek1, havek2;
/*
* Same logic, code as darwin_386.c:/inittls, except that words
* are 8 bytes long now, and the thread-local storage starts at 0x60.
* So the offsets are
* are 8 bytes long now, and the thread-local storage starts
* at 0x60 on Leopard / Snow Leopard. So the offsets are
* 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
*
* The linker and runtime hard-code these constant offsets
* from %gs where we expect to find m and g. The code
* below verifies that the constants are correct once it has
* obtained the keys. Known to ../cmd/6l/obj.c:/8a0
* from %gs where we expect to find m and g.
* Known to ../cmd/6l/obj.c:/8a0
* and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
*
* As disgusting as on the 386; same justification.
@@ -35,49 +36,37 @@ inittls(void)
ntofree = 0;
while(!havek1 || !havek2) {
if(pthread_key_create(&k, nil) < 0) {
fprintf(stderr, "libcgo: pthread_key_create failed\n");
fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
abort();
}
if(k == 0x108) {
pthread_setspecific(k, (void*)magic1);
asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
if(x == magic1) {
havek1 = 1;
k1 = k;
continue;
}
if(k == 0x109) {
} else if(y == magic1) {
havek2 = 1;
k2 = k;
continue;
} else {
if(ntofree >= nelem(tofree)) {
fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
fprintf(stderr, "\ttried");
for(i=0; i<ntofree; i++)
fprintf(stderr, " %#x", (unsigned)tofree[i]);
fprintf(stderr, "\n");
abort();
}
tofree[ntofree++] = k;
}
if(ntofree >= nelem(tofree)) {
fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
fprintf(stderr, "\twanted 0x108 and 0x109\n");
fprintf(stderr, "\tgot");
for(i=0; i<ntofree; i++)
fprintf(stderr, " %#x", (unsigned)tofree[i]);
fprintf(stderr, "\n");
abort();
}
tofree[ntofree++] = k;
pthread_setspecific(k, 0);
}
for(i=0; i<ntofree; i++)
pthread_key_delete(tofree[i]);
/*
* We got the keys we wanted. Make sure that we observe
* updates to k1 at 0x8a0, to verify that the TLS array
* offset from %gs hasn't changed.
* We got the keys we wanted. Free the others.
*/
pthread_setspecific(k1, (void*)0x123456789abcdef0ULL);
asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
pthread_setspecific(k2, (void*)0x0fedcba987654321);
asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
if(x != 0x123456789abcdef0ULL || y != 0x0fedcba987654321) {
printf("libcgo: thread-local storage %#x not at %%gs:0x8a0 - x=%#llx y=%#llx\n", (unsigned)k1, x, y);
abort();
}
for(i=0; i<ntofree; i++)
pthread_key_delete(tofree[i]);
}
void

View File

@@ -1,19 +0,0 @@
// Copyright 2010 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.
#include "libcgo.h"
static void
xinitcgo(void)
{
}
void (*initcgo)(void) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
// unimplemented
*(int*)0 = 0;
}

View File

@@ -40,7 +40,7 @@ xlibcgo_thread_start(ThreadStart *arg)
/* Make our own copy that can persist after we return. */
ts = malloc(sizeof *ts);
if(ts == nil) {
fprintf(stderr, "libcgo: out of memory in thread_start\n");
fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
abort();
}
*ts = *arg;

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)
}
}