[SCM] Packaging for Google Go branch, upstream, updated. upstream/2011.02.15

Ondřej Surý ondrej at sury.org
Fri Feb 18 10:46:55 UTC 2011


The following commit has been merged in the upstream branch:
commit c072558b90f1bbedc2022b0f30c8b1ac4712538e
Author: Ondřej Surý <ondrej at sury.org>
Date:   Fri Feb 18 09:50:58 2011 +0100

    Imported Upstream version 2011.02.15

diff --git a/AUTHORS b/AUTHORS
index e0b5e19..5733c43 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -30,6 +30,7 @@ Charles L. Dorian <cldorian at gmail.com>
 Chris Jones <chris at cjones.org>
 Chris Lennert <calennert at gmail.com>
 Christian Himpel <chressie at googlemail.com>
+Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
@@ -37,6 +38,7 @@ Corey Thomasson <cthom.lists at gmail.com>
 Dan Sinclair <dan.sinclair at gmail.com>
 Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Theophanes <kardianos at gmail.com>
+Dave Cheney <dave at cheney.net>
 David G. Andersen <dave.andersen at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 769a5b1..1f19a0d 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -63,6 +63,7 @@ Charles L. Dorian <cldorian at gmail.com>
 Chris Jones <chris at cjones.org> <chris.jones.yar at gmail.com>
 Chris Lennert <calennert at gmail.com>
 Christian Himpel <chressie at googlemail.com> <chressie at gmail.com>
+Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
@@ -72,6 +73,7 @@ Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Nadasi <dnadasi at google.com>
 Berengar Lehr <Berengar.Lehr at gmx.de>
 Daniel Theophanes <kardianos at gmail.com>
+Dave Cheney <dave at cheney.net>
 David Anderson <danderson at google.com>
 David G. Andersen <dave.andersen at gmail.com>
 David Symonds <dsymonds at golang.org>
diff --git a/doc/code.html b/doc/code.html
index 55afe09..9236cf2 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -160,9 +160,9 @@ is the package's default name for imports.
 Go's convention is that the package name is the last element of the
 import path: the package imported as <code>"crypto/rot13"</code>
 should be named <code>rot13</code>.
-At the moment, the Go tools impose a restriction that package names are unique
-across all packages linked into a single binary, but that restriction
-will be lifted soon.
+There is no requirement that package names be unique
+across all packages linked into a single binary,
+only that the import paths (their full file names) be unique.
 </p>
 
 <p>
diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go
index 8ecd97d..c97a699 100644
--- a/doc/codelab/wiki/final.go
+++ b/doc/codelab/wiki/final.go
@@ -64,7 +64,7 @@ func init() {
 }
 
 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
-	err := templates[tmpl].Execute(p, w)
+	err := templates[tmpl].Execute(w, p)
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
 	}
diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html
index fe99c32..fc8c27b 100644
--- a/doc/codelab/wiki/index.html
+++ b/doc/codelab/wiki/index.html
@@ -573,7 +573,11 @@ redirect the client to the edit Page so the content may be created:
 </p>
 
 <pre>
-func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+	title, err := getTitle(w, r)
+	if err != nil {
+		return
+	}
 	p, err := loadPage(title)
 	if err != nil {
 		http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
@@ -658,10 +662,14 @@ Now let's fix up <code>saveHandler</code>:
 </p>
 
 <pre>
-func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+	title, err := getTitle(w, r)
+	if err != nil {
+		return
+	}
 	body := r.FormValue(&#34;body&#34;)
 	p := &amp;Page{Title: title, Body: []byte(body)}
-	err := p.save()
+	err = p.save()
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
 		return
@@ -702,7 +710,7 @@ Then we create an <code>init</code> function, which will be called before
 <code>ParseFile</code> that does not return an error code; instead, it panics
 if an error is encountered. A panic is appropriate here; if the templates can't
 be loaded the only sensible thing to do is exit the program.
-</p
+</p>
 
 <pre>
 func init() {
@@ -726,7 +734,7 @@ the <code>Execute</code> method on the appropriate <code>Template</code> from
 
 <pre>
 func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
-	err := templates[tmpl].Execute(p, w)
+	err := templates[tmpl].Execute(w, p)
 	if err != nil {
 		http.Error(w, err.String(), http.StatusInternalServerError)
 	}
@@ -747,6 +755,7 @@ Then we can create a global variable to store our validation regexp:
 </p>
 
 <pre>
+var titleValidator = regexp.MustCompile(&#34;^[a-zA-Z0-9]+$&#34;)
 </pre>
 
 <p>
diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go
index cab092f..6729478 100644
--- a/doc/codelab/wiki/srcextract.go
+++ b/doc/codelab/wiki/srcextract.go
@@ -9,6 +9,7 @@ import (
 	"go/token"
 	"log"
 	"os"
+	"template"
 )
 
 var (
@@ -31,15 +32,6 @@ func main() {
 	if err != nil {
 		log.Fatal(err)
 	}
-	// create printer
-	p := &printer.Config{
-		Mode:     0,
-		Tabwidth: 8,
-		Styler:   nil,
-	}
-	if *html {
-		p.Mode = printer.GenHTML
-	}
 	// create filter
 	filter := func(name string) bool {
 		return name == *getName
@@ -48,8 +40,9 @@ func main() {
 	if !ast.FilterFile(file, filter) {
 		os.Exit(1)
 	}
-	b := new(bytes.Buffer)
-	p.Fprint(b, fs, file)
+	// print the AST
+	var b bytes.Buffer
+	printer.Fprint(&b, fs, file)
 	// drop package declaration
 	if !*showPkg {
 		for {
@@ -71,5 +64,9 @@ func main() {
 		}
 	}
 	// output
-	b.WriteTo(os.Stdout)
+	if *html {
+		template.HTMLEscape(os.Stdout, b.Bytes())
+	} else {
+		b.WriteTo(os.Stdout)
+	}
 }
diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html
index ff2c308..7ef97b4 100644
--- a/doc/codelab/wiki/wiki.html
+++ b/doc/codelab/wiki/wiki.html
@@ -477,7 +477,7 @@ redirect the client to the edit Page so the content may be created:
 </p>
 
 <pre>
-!./srcextract.bin -src=final.go -name=viewHandler
+!./srcextract.bin -src=final-noclosure.go -name=viewHandler
 </pre>
 
 <p>
@@ -539,7 +539,7 @@ Now let's fix up <code>saveHandler</code>:
 </p>
 
 <pre>
-!./srcextract.bin -src=final.go -name=saveHandler
+!./srcextract.bin -src=final-noclosure.go -name=saveHandler
 </pre>
 
 <p>
@@ -574,7 +574,7 @@ Then we create an <code>init</code> function, which will be called before
 <code>ParseFile</code> that does not return an error code; instead, it panics
 if an error is encountered. A panic is appropriate here; if the templates can't
 be loaded the only sensible thing to do is exit the program.
-</p
+</p>
 
 <pre>
 !./srcextract.bin -src=final.go -name=init
@@ -610,7 +610,7 @@ Then we can create a global variable to store our validation regexp:
 </p>
 
 <pre>
-!./srcextract.bin -src=final-noclosure.go -name=TitleValidator
+!./srcextract.bin -src=final-noclosure.go -name=titleValidator
 </pre>
 
 <p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index f965b5c..57da6ca 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -5,6 +5,112 @@
 <p>This page summarizes the changes between tagged releases of Go.
 For full details, see the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>.</p>
 
+<h3 id="2011-02-01">2011-02-15</h3>
+
+<pre>
+This release includes changes to the io and template packages.
+You may need to update your code.
+
+The io.ReadByter and io.ReadRuner interface types have been renamed to
+io.ByteReader and io.RuneReader respectively.
+
+The order of arguments to template.Execute has been reversed to be consistent
+the notion of "destination first", as with io.Copy, fmt.Fprint, and others.
+
+Gotest now works for package main in directories using Make.cmd-based makefiles.
+
+The memory allocation runtime problems from the last release are not completely
+fixed.  The virtual memory exhaustion problems encountered by people using
+ulimit -v have been fixed, but there remain known garbage collector problems
+when using GOMAXPROCS > 1.
+
+Other changes:
+* 5l: stopped generating 64-bit eor.
+* 8l: more work on plan9 support (thanks Yuval Pavel Zholkover).
+* archive/zip: handle files with data descriptors.
+* arm: working peep-hole optimizer.
+* asn1: marshal true as 255, not 1.
+* buffer.go: minor optimization, expanded comment.
+* build: drop syslog on DISABLE_NET_TESTS=1 (thanks Gustavo Niemeyer),
+       allow clean.bash to work on fresh checkout,
+       change "all tests pass" message to be more obvious,
+       fix spaces in GOROOT (thanks Christopher Nielsen).
+* bytes: fix bug in buffer.ReadBytes (thanks Evan Shaw).
+* 5g: better int64 code,
+       don’t use MVN instruction.
+* cgo: don't run cgo when not compiling (thanks Gustavo Niemeyer),
+       fix _cgo_run timestamp file order (thanks Gustavo Niemeyer),
+       fix handling of signed enumerations (thanks Gustavo Niemeyer),
+       os/arch dependent #cgo directives (thanks Gustavo Niemeyer),
+       rename internal f to avoid conflict with possible C global named f.
+* codereview: fix hgpatch on windows (thanks Yasuhiro Matsumoto),
+       record repository, base revision,
+       use cmd.communicate (thanks Yasuhiro Matsumoto).
+* container/ring: replace Iter() with Do().
+* crypto/cipher: add resync open to OCFB mode.
+* crypto/openpgp/armor: bug fixes.
+* crypto/openpgp/packet: new subpackage.
+* crypto/tls: load a chain of certificates from a file,
+       select best cipher suite, not worst.
+* crypto/x509: add support for name constraints.
+* debug/pe: ImportedSymbols fixes (thanks Wei Guangjing).
+* doc/code: update to reflect that package names need not be unique.
+* doc/codelab/wiki: a bunch of fixes (thanks Andrey Mirtchovski).
+* doc/install: update for new versions of Mercurial.
+* encoding/line: fix line returned after EOF.
+* flag: allow hexadecimal (0xFF) and octal (0377) input for integer flags.
+* fmt.Scan: scan binary-exponent floating format, 2.4p-3,
+       hexadecimal (0xFF) and octal (0377) integers.
+* fmt: document %%; also %b for floating point.
+* gc, ld: detect stale or incompatible object files,
+       package name main no longer reserved.
+* gc: correct receiver in method missing error (thanks Lorenzo Stoakes),
+       correct rounding of denormal constants (thanks Eoghan Sherry),
+       select receive bug fix.
+* go/printer, gofmt: smarter handling of multi-line raw strings.
+* go/printer: line comments must always end in a newline,
+       remove notion of "Styler", remove HTML mode.
+* gob: allow Decode(nil) and have it just discard the next value.
+* godoc: use IsAbs to test for absolute paths (fix for win32) (thanks Yasuhiro Matsumoto),
+       don't hide package lookup error if there's no command with the same name.
+* gotest: enable unit tests for main programs.
+* http: add Server type supporting timeouts,
+       add pipelining to ClientConn, ServerConn (thanks Petar Maymounkov),
+       handle unchunked, un-lengthed HTTP/1.1 responses.
+* io: add RuneReader.
+* json: correct Marshal documentation.
+* netchan: graceful handling of closed connection (thanks Graham Miller).
+* os: implement new Process API (thanks Alex Brainman).
+* regexp tests: make some benchmarks more meaningful.
+* regexp: add support for matching against text read from RuneReader interface.
+* rpc: make more tolerant of errors, properly discard values (thanks Roger Peppe).
+* runtime: detect failed thread creation on Windows,
+       faster allocator, garbage collector,
+       fix virtual memory exhaustion,
+       implemented windows console ctrl handler (SIGINT) (thanks Hector Chu),
+       more detailed panic traces, line number work,
+       improved Windows callback handling (thanks Hector Chu).
+* spec: adjust notion of Assignability,
+       allow import of packages named main,
+       clarification re: method sets of newly declared pointer types,
+       fix a few typos (thanks Anthony Martin),
+       fix Typeof() return type (thanks Gustavo Niemeyer),
+       move to Unicode 6.0.
+* sync: diagnose Unlock of unlocked Mutex,
+       new Waitgroup type (thanks Gustavo Niemeyer).
+* syscall: add SetsockoptIpMreq (thanks Dave Cheney),
+       add sockaddr_dl, sysctl with routing message support for darwin, freebsd (thanks Mikio Hara),
+       do not use NULL for zero-length read, write,
+       implement windows version of Fsync (thanks Alex Brainman),
+       make ForkExec acquire the ForkLock under windows (thanks Hector Chu),
+       make windows API return errno instead of bool (thanks Alex Brainman),
+       remove obsolete socket IO control (thanks Mikio Hara).
+* template: add simple formatter chaining (thanks Kyle Consalus),
+       allow a leading '*' to indirect through a pointer.
+* testing: include elapsed time in test output
+* windows: replace remaining __MINGW32__ instances with _WIN32 (thanks Joe Poirier).
+</pre>
+
 <h3 id="2011-02-01">2011-02-01</h3>
 
 <pre>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 3f6f89b..8f94f46 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -824,7 +824,7 @@ executions.  Here's a silly example.
 </p>
 
 <pre>
-for i := 0; i < 5; i++ {
+for i := 0; i &lt; 5; i++ {
     defer fmt.Printf("%d ", i)
 }
 </pre>
@@ -1486,7 +1486,7 @@ for a min function that chooses the least of a list of integers:
 func Min(a ...int) int {
     min := int(^uint(0) >> 1)  // largest int
     for _, i := range a {
-        if i < min {
+        if i &lt; min {
             min = i
         }
     }
@@ -2670,7 +2670,7 @@ suppresses the usual check for a <code>return</code> statement.
 // A toy implementation of cube root using Newton's method.
 func CubeRoot(x float64) float64 {
     z := x/3   // Arbitrary intitial value
-    for i := 0; i < 1e6; i++ {
+    for i := 0; i &lt; 1e6; i++ {
         prevz := z
         z -= (z*z*z-x) / (3*z*z)
         if veryClose(z, prevz) {
@@ -2705,7 +2705,7 @@ func init() {
 
 <p>
 When <code>panic</code> is called, including implicitly for run-time
-errors such indexing an array out of bounds or failing a type
+errors such as indexing an array out of bounds or failing a type
 assertion, it immediately stops execution of the current function
 and begins unwinding the stack of the goroutine, running any deferred
 functions along the way.  If that unwinding reaches the top of the
@@ -2727,7 +2727,7 @@ inside a server without killing the other executing goroutines.
 </p>
 
 <pre>
-func server(workChan <-chan *Work) {
+func server(workChan &lt;-chan *Work) {
     for work := range workChan {
         go safelyDo(work)
     }
@@ -2751,7 +2751,16 @@ calling <code>recover</code> handles the condition completely.
 </p>
 
 <p>
-Note that with this recovery pattern in place, the <code>do</code>
+Because <code>recover</code> always returns <code>nil</code> unless called directly
+from a deferred function, deferred code can call library routines that themselves
+use <code>panic</code> and <code>recover</code> without failing.  As an example,
+the deferred function in <code>safelyDo</code> might call a logging function before
+calling <code>recover</code>, and that logging code would run unaffected
+by the panicking state.
+</p>
+
+<p>
+With our recovery pattern in place, the <code>do</code>
 function (and anything it calls) can get out of any bad situation
 cleanly by calling <code>panic</code>.  We can use that idea to
 simplify error handling in complex software.  Let's look at an
@@ -2876,7 +2885,7 @@ func main() {
 }
 
 func QR(w http.ResponseWriter, req *http.Request) {
-    templ.Execute(req.FormValue("s"), w)
+    templ.Execute(w, req.FormValue("s"))
 }
 
 func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) {
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 4e5d9c6..a95ed70 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,5 +1,5 @@
 <!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of February 1, 2011 -->
+<!-- subtitle Version of February 8, 2011 -->
 
 <!--
 TODO
@@ -104,12 +104,12 @@ The following terms are used to denote specific Unicode character classes:
 <pre class="ebnf">
 unicode_char   = /* an arbitrary Unicode code point */ .
 unicode_letter = /* a Unicode code point classified as "Letter" */ .
-unicode_digit  = /* a Unicode code point classified as "Digit" */ .
+unicode_digit  = /* a Unicode code point classified as "Decimal Digit" */ .
 </pre>
 
 <p>
-In <a href="http://www.unicode.org/versions/Unicode5.2.0/">The Unicode Standard 5.2</a>,
-Section 4.5 General Category-Normative
+In <a href="http://www.unicode.org/versions/Unicode6.0.0/">The Unicode Standard 6.0</a>,
+Section 4.5 "General Category"
 defines a set of character categories.  Go treats
 those characters in category Lu, Ll, Lt, Lm, or Lo as Unicode letters,
 and those in category Nd as Unicode digits.
@@ -610,6 +610,17 @@ type literals.
 </p>
 
 <p>
+The <i>static type</i> (or just <i>type</i>) of a variable is the
+type defined by its declaration.  Variables of interface type
+also have a distinct <i>dynamic type</i>, which
+is the actual type of the value stored in the variable at run-time.
+The dynamic type may vary during execution but is always
+<a href="#Assignability">assignable</a>
+to the static type of the interface variable.  For non-interface
+types, the dynamic type is always the static type.
+</p>
+
+<p>
 Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
 is a predeclared type or a type literal, the corresponding underlying
 type is <code>T</code> itself. Otherwise, <code>T</code>'s underlying type
@@ -630,6 +641,7 @@ is <code>string</code>. The underlying type of <code>[]T1</code>, <code>T3</code
 and <code>T4</code> is <code>[]T1</code>.
 </p>
 
+<h3 id="Method_sets">Method sets</h3>
 <p>
 A type may have a <i>method set</i> associated with it
 (§<a href="#Interface_types">Interface types</a>, §<a href="#Method_declarations">Method declarations</a>).
@@ -642,16 +654,6 @@ is the set of all methods with receiver <code>*T</code> or <code>T</code>
 Any other type has an empty method set.
 In a method set, each method must have a unique name.
 </p>
-<p>
-The <i>static type</i> (or just <i>type</i>) of a variable is the
-type defined by its declaration.  Variables of interface type
-also have a distinct <i>dynamic type</i>, which
-is the actual type of the value stored in the variable at run-time.
-The dynamic type may vary during execution but is always
-<a href="#Assignability">assignable</a>
-to the static type of the interface variable.  For non-interface
-types, the dynamic type is always the static type.
-</p>
 
 
 <h3 id="Boolean_types">Boolean types</h3>
@@ -917,7 +919,8 @@ a type named <code>T</code>:
 </p>
 <ul>
 	<li>If <code>S</code> contains an anonymous field <code>T</code>, the
-	    method set of <code>S</code> includes the method set of <code>T</code>.
+	    <a href="#Method_sets">method set</a> of <code>S</code> includes the
+	    method set of <code>T</code>.
 	</li>
 
 	<li>If <code>S</code> contains an anonymous field <code>*T</code>, the
@@ -1016,7 +1019,7 @@ func(n int) func(p *T)
 <h3 id="Interface_types">Interface types</h3>
 
 <p>
-An interface type specifies a <a href="#Types">method set</a> called its <i>interface</i>.
+An interface type specifies a <a href="#Method_sets">method set</a> called its <i>interface</i>.
 A variable of interface type can store a value of any type with a method set
 that is any superset of the interface. Such a type is said to
 <i>implement the interface</i>.
@@ -1349,11 +1352,12 @@ by a value of type <code>T</code>.
 </ul>
 
 <p>
-If <code>T</code> is a struct type, either all fields of <code>T</code>
-must be <a href="#Exported_identifiers">exported</a>, or the assignment must be in
-the same package in which <code>T</code> is declared.
+If <code>T</code> is a struct type with non-<a href="#Exported_identifiers">exported</a>
+fields, the assignment must be in the same package in which <code>T</code> is declared,
+or <code>x</code> must be the receiver of a method call.
 In other words, a struct value can be assigned to a struct variable only if
-every field of the struct may be legally assigned individually by the program.
+every field of the struct may be legally assigned individually by the program,
+or if the assignment is initializing the receiver of a method of the struct type.
 </p>
 
 <p>
@@ -1677,7 +1681,7 @@ type Cipher interface {
 
 <p>
 The declared type does not inherit any <a href="#Method_declarations">methods</a>
-bound to the existing type, but the <a href="#Types">method set</a>
+bound to the existing type, but the <a href="#Method_sets">method set</a>
 of an interface type or of elements of a composite type remains unchanged:
 </p>
 
@@ -1690,6 +1694,10 @@ func (m *Mutex) Unlock()  { /* Unlock implementation */ }
 // NewMutex has the same composition as Mutex but its method set is empty.
 type NewMutex Mutex
 
+// The method set of the <a href="#Pointer_types">base type</a> of PtrMutex remains unchanged,
+// but the method set of PtrMutex is empty.
+type PtrMutex *Mutex
+
 // The method set of *PrintableMutex contains the methods
 // Lock and Unlock bound to its anonymous field Mutex.
 type PrintableMutex struct {
@@ -2593,8 +2601,8 @@ if Join(Split(value, len(value)/2)) != value {
 </pre>
 
 <p>
-A method call <code>x.m()</code> is valid if the method set of
-(the type of) <code>x</code> contains <code>m</code> and the
+A method call <code>x.m()</code> is valid if the <a href="#Method_sets">method set</a>
+of (the type of) <code>x</code> contains <code>m</code> and the
 argument list can be assigned to the parameter list of <code>m</code>.
 If <code>x</code> is <a href="#Address_operators">addressable</a> and <code>&amp;x</code>'s method
 set contains <code>m</code>, <code>x.m()</code> is shorthand
@@ -2889,8 +2897,8 @@ Comparison operators compare two operands and yield a value of type <code>bool</
 <pre class="grammar">
 ==    equal
 !=    not equal
-<     less
-<=    less or equal
+&lt;     less
+&lt;=    less or equal
 >     greater
 >=    greater or equal
 </pre>
@@ -3057,7 +3065,7 @@ need to be presented regarding send, receive, select, and goroutines.</span>
 <h3 id="Method_expressions">Method expressions</h3>
 
 <p>
-If <code>M</code> is in the method set of type <code>T</code>,
+If <code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
 <code>T.M</code> is a function that is callable as a regular function
 with the same arguments as <code>M</code> prefixed by an additional
 argument that is the receiver of the method.
@@ -4004,7 +4012,7 @@ the channel until the channel is closed; it does not produce the zero value sent
 before the channel is closed
 (§<a href="#Close_and_closed"><code>close</code> and <code>closed</code></a>).
 </li>
-</ol
+</ol>
 
 <p>
 The iteration values are assigned to the respective
@@ -4436,7 +4444,7 @@ At any time the following relationship holds:
 </p>
 
 <pre>
-0 <= len(s) <= cap(s)
+0 &lt;= len(s) &lt;= cap(s)
 </pre>
 
 <p>
@@ -4646,13 +4654,6 @@ func recover() interface{}
 </pre>
 
 <p>
-<span class="alert">TODO: Most of this text could move to the respective
-comments in <code>runtime.go</code> once the functions are implemented.
-They are here, at least for now, for reference and discussion.
-</span>
-</p>
-
-<p>
 When a function <code>F</code> calls <code>panic</code>, normal
 execution of <code>F</code> stops immediately.  Any functions whose
 execution was <a href="#Defer_statements">deferred</a> by the
@@ -4667,117 +4668,43 @@ the argument to <code>panic</code>.  This termination sequence is
 called <i>panicking</i>.
 </p>
 
+<pre>
+panic(42)
+panic("unreachable")
+panic(Error("cannot parse"))
+</pre>
+
 <p>
 The <code>recover</code> function allows a program to manage behavior
 of a panicking goroutine.  Executing a <code>recover</code> call
-inside a deferred function (but not any function called by it) stops
+<i>inside</i> a deferred function (but not any function called by it) stops
 the panicking sequence by restoring normal execution, and retrieves
 the error value passed to the call of <code>panic</code>.  If
 <code>recover</code> is called outside the deferred function it will
-not stop a panicking sequence.  In this case, and when the goroutine
-is not panicking, <code>recover</code> returns <code>nil</code>.
+not stop a panicking sequence.  In this case, or when the goroutine
+is not panicking, or if the argument supplied to <code>panic</code>
+was <code>nil</code>, <code>recover</code> returns <code>nil</code>.
 </p>
 
 <p>
-If the function defined here,
+The <code>protect</code> function in the example below invokes
+the function argument <code>g</code> and protects callers from
+run-time panics raised by <code>g</code>.
 </p>
 
 <pre>
-func f(hideErrors bool) {
+func protect(g func()) {
 	defer func() {
+		log.Println("done")  // Println executes normally even in there is a panic
 		if x := recover(); x != nil {
-			println("panicking with value", x)
-			if !hideErrors {
-				panic(x)  // go back to panicking
-			}
-		}
-		println("function returns normally") // executes only when hideErrors==true
-	}()
-	println("before")
-	p()
-	println("after")	// never executes
-}
-
-func p() {
-	panic(3)
-}
-</pre>
-
-<p>
-is called with <code>hideErrors=true</code>, it prints
-</p>
-
-<pre>
-before
-panicking with value 3
-function returns normally
-</pre>
-
-<p>
-and resumes normal execution in the function that called <code>f</code>. Otherwise, it prints
-</p>
-
-<pre>
-before
-panicking with value 3
-</pre>
-
-<p>
-and, absent further <code>recover</code> calls, terminates the program.
-</p>
-
-<p>
-Since deferred functions run before assigning the return values to the caller
-of the deferring function, a deferred invocation of a function literal may modify the
-invoking function's return values in the event of a panic. This permits a function to protect its
-caller from panics that occur in functions it calls.
-</p>
-
-<pre>
-func IsPrintable(s string) (ok bool) {
-	ok = true
-	defer func() {
-		if recover() != nil {
-			println("input is not printable")
-			ok = false
+			log.Printf("runtime panic: %v", x)
 		}
-		// Panicking has stopped; execution will resume normally in caller.
-		// The return value will be true normally, false if a panic occurred.
-	}()
-	panicIfNotPrintable(s)	// will panic if validations fails.
-	return
-}
-</pre>
-
-<!---
-<p>
-A deferred function that calls <code>recover</code> will see the
-argument passed to <code>panic</code>.  However, functions called
-<i>from</i> the deferred function run normally, without behaving as
-though they are panicking.  This allows deferred code to run normally
-in case recovery is necessary and guarantees that functions that manage
-their own panics will not fail incorrectly.  The function
-</p>
-
-<pre>
-func g() {
-	s := ReadString()
-	defer func() {
-		if IsPrintable(s) {
-			println("finished processing", s)
-		} else {
-			println("finished processing unprintable string")
-		}
-	}()
-	Analyze(s)
+	}
+	log.Println("start")
+	g()
 }
 </pre>
 
-<p>
-will not cause <code>IsPrintable</code> to print <code>"input is not printable"</code>
-due to a <code>panic</code> triggered by the call to <code>Analyze</code>.
-</p>
--->
 
 <h3 id="Bootstrapping">Bootstrapping</h3>
 
@@ -5064,8 +4991,12 @@ The importing of packages, by construction, guarantees that there can
 be no cyclic dependencies in initialization.
 </p>
 <p>
-A complete program, possibly created by linking multiple packages,
-must have one package called <code>main</code>, with a function
+A complete program is created by linking a single, unimported package
+called the <i>main package</i> with all the packages it imports, transitively.
+The main package must
+have package name <code>main</code> and
+declare a function <code>main</code> that takes no 
+arguments and returns no value.
 </p>
 
 <pre>
@@ -5073,20 +5004,12 @@ func main() { ... }
 </pre>
 
 <p>
-defined.
-The function <code>main.main()</code> takes no arguments and returns no value.
-</p>
-<p>
-Program execution begins by initializing the <code>main</code> package and then
-invoking <code>main.main()</code>.
-</p>
-<p>
-When <code>main.main()</code> returns, the program exits.  It does not wait for
-other (non-<code>main</code>) goroutines to complete.
+Program execution begins by initializing the main package and then
+invoking the function <code>main</code>.
 </p>
 <p>
-Implementation restriction: The compiler assumes package <code>main</code>
-is not imported by any other package.
+When the function <code>main</code> returns, the program exits.
+It does not wait for other (non-<code>main</code>) goroutines to complete.
 </p>
 
 <h2 id="Run_time_panics">Run-time panics</h2>
@@ -5133,8 +5056,8 @@ func Alignof(variable ArbitraryType) int
 func Offsetof(selector ArbitraryType) int
 func Sizeof(variable ArbitraryType) int
 
-func Reflect(val interface {}) (typ runtime.Type, addr uintptr)
-func Typeof(val interface {}) reflect.Type
+func Reflect(val interface{}) (typ runtime.Type, addr uintptr)
+func Typeof(val interface{}) (typ interface{})
 func Unreflect(typ runtime.Type, addr uintptr) interface{}
 </pre>
 
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
index ece2203..e3d946f 100644
--- a/doc/go_tutorial.html
+++ b/doc/go_tutorial.html
@@ -5,10 +5,13 @@ This document is a tutorial introduction to the basics of the Go programming
 language, intended for programmers familiar with C or C++. It is not a comprehensive
 guide to the language; at the moment the document closest to that is the
 <a href='/doc/go_spec.html'>language specification</a>.
-After you've read this tutorial, you might want to look at
+After you've read this tutorial, you should look at
 <a href='/doc/effective_go.html'>Effective Go</a>,
-which digs deeper into how the language is used.
-Also, slides from a 3-day course about Go are available:
+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:
 <a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
 <a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
 <a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
@@ -258,11 +261,11 @@ of course you can change a string <i>variable</i> simply by
 reassigning it.  This snippet from <code>strings.go</code> is legal code:
 <p>
 <pre> <!-- progs/strings.go /hello/ /ciao/ -->
-11        s := &quot;hello&quot;
-12        if s[1] != 'e' { os.Exit(1) }
-13        s = &quot;good bye&quot;
-14        var p *string = &amp;s
-15        *p = &quot;ciao&quot;
+10        s := &quot;hello&quot;
+11        if s[1] != 'e' { os.Exit(1) }
+12        s = &quot;good bye&quot;
+13        var p *string = &amp;s
+14        *p = &quot;ciao&quot;
 </pre>
 <p>
 However the following statements are illegal because they would modify
diff --git a/doc/go_tutorial.txt b/doc/go_tutorial.txt
index 5eea3c9..2b2a0cd 100644
--- a/doc/go_tutorial.txt
+++ b/doc/go_tutorial.txt
@@ -6,10 +6,13 @@ This document is a tutorial introduction to the basics of the Go programming
 language, intended for programmers familiar with C or C++. It is not a comprehensive
 guide to the language; at the moment the document closest to that is the
 <a href='/doc/go_spec.html'>language specification</a>.
-After you've read this tutorial, you might want to look at
+After you've read this tutorial, you should look at
 <a href='/doc/effective_go.html'>Effective Go</a>,
-which digs deeper into how the language is used.
-Also, slides from a 3-day course about Go are available:
+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:
 <a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
 <a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
 <a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
diff --git a/doc/htmlgen.go b/doc/htmlgen.go
index 5d0bad8..4d68767 100644
--- a/doc/htmlgen.go
+++ b/doc/htmlgen.go
@@ -18,13 +18,13 @@ import (
 )
 
 var (
-	lines   = make([][]byte, 0, 10000) // assume big enough
-	linebuf = make([]byte, 10000)      // assume big enough
+	lines = make([][]byte, 0, 2000) // probably big enough; grows if not
 
 	empty   = []byte("")
 	newline = []byte("\n")
 	tab     = []byte("\t")
 	quote   = []byte(`"`)
+	indent  = []byte{' ', ' ', ' ', ' '}
 
 	sectionMarker = []byte("----\n")
 	preStart      = []byte("<pre>")
@@ -52,9 +52,7 @@ func read() {
 		if err != nil {
 			log.Fatal(err)
 		}
-		n := len(lines)
-		lines = lines[0 : n+1]
-		lines[n] = line
+		lines = append(lines, line)
 	}
 }
 
@@ -173,19 +171,7 @@ func trim(l []byte) []byte {
 	return l
 }
 
-// expand tabs to 4 spaces. don't worry about columns.
+// expand tabs to spaces. don't worry about columns.
 func expandTabs(l []byte) []byte {
-	j := 0 // position in linebuf.
-	for _, c := range l {
-		if c == '\t' {
-			for k := 0; k < 4; k++ {
-				linebuf[j] = ' '
-				j++
-			}
-		} else {
-			linebuf[j] = c
-			j++
-		}
-	}
-	return linebuf[0:j]
+	return bytes.Replace(l, tab, indent, -1)
 }
diff --git a/doc/install.html b/doc/install.html
index 5917da9..d8fa8b4 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -110,6 +110,21 @@ package repository will most likely be old and broken.)
 If that fails, try installing manually from the <a href="http://mercurial.selenic.com/wiki/Download">Mercurial Download</a> page.</p>
 </p>
 
+<p>
+Mercurial versions 1.7.x and up require the configuration of
+<a href="http://mercurial.selenic.com/wiki/CACertificates">Certification Authorities</a>
+(CAs). Error messages of the form:
+</p>
+<pre>
+warning: go.googlecode.com certificate with fingerprint b1:af: ... bc not verified (check hostfingerprints or web.cacerts config setting)
+</pre>
+<p>
+when using Mercurial indicate that the CAs are missing.
+Check your Mercurial version (<code>hg --version</code>) and
+<a href="http://mercurial.selenic.com/wiki/CACertificates#Configuration_of_HTTPS_certificate_authorities">configure the CAs</a>
+if necessary.
+</p>
+
 <h2 id="fetch">Fetch the repository</h2>
 
 <p>
@@ -138,8 +153,7 @@ If all goes well, it will finish by printing output like:
 </p>
 
 <pre>
---- cd ../test
-N known bugs; 0 unexpected bugs
+ALL TESTS PASSED
 
 ---
 Installed Go for linux/amd64 in /home/you/go.
diff --git a/include/libc.h b/include/libc.h
index 1103bcf..a91039d 100644
--- a/include/libc.h
+++ b/include/libc.h
@@ -291,7 +291,7 @@ extern	char*	getgoarch(void);
 extern	char*	getgoroot(void);
 extern	char*	getgoversion(void);
 
-#ifdef __MINGW32__
+#ifdef _WIN32
 struct timespec {
 	int tv_sec;
 	long tv_nsec;
diff --git a/include/u.h b/include/u.h
index 3cc1f33..690b2f6 100644
--- a/include/u.h
+++ b/include/u.h
@@ -78,7 +78,7 @@ extern "C" {
 #define _NEEDUINT 1
 #define _NEEDULONG 1
 
-#ifdef __MINGW32__
+#ifdef _WIN32
 typedef jmp_buf sigjmp_buf;
 #endif
 typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
@@ -139,7 +139,7 @@ typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
 #	undef _NEEDUSHORT
 #	undef _NEEDUINT
 #	undef _NEEDULONG
-#elif defined(__MINGW32__)
+#elif defined(_WIN32)
 #else
 	/* No idea what system this is -- try some defaults */
 #	include <pthread.h>
@@ -208,7 +208,7 @@ typedef u64int uint64;
  */
 #if defined(__GNUC__)
 #	undef strcmp	/* causes way too many warnings */
-#	if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__) && !defined(__MINGW32__))
+#	if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__) && !defined(_WIN32))
 #		undef AUTOLIB
 #		define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
 #		undef AUTOFRAMEWORK
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index 0952705..96efc85 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -253,7 +253,7 @@ class CL(object):
 
 	def Flush(self, ui, repo):
 		if self.name == "new":
-			self.Upload(ui, repo, gofmt_just_warn=True)
+			self.Upload(ui, repo, gofmt_just_warn=True, creating=True)
 		dir = CodeReviewDir(ui, repo)
 		path = dir + '/cl.' + self.name
 		f = open(path+'!', "w")
@@ -279,8 +279,8 @@ class CL(object):
 		typecheck(s, str)
 		return s
 
-	def Upload(self, ui, repo, send_mail=False, gofmt=True, gofmt_just_warn=False):
-		if not self.files:
+	def Upload(self, ui, repo, send_mail=False, gofmt=True, gofmt_just_warn=False, creating=False, quiet=False):
+		if not self.files and not creating:
 			ui.warn("no files in change list\n")
 		if ui.configbool("codereview", "force_gofmt", True) and gofmt:
 			CheckFormat(ui, repo, self.files, just_warn=gofmt_just_warn)
@@ -292,15 +292,20 @@ class CL(object):
 			("cc", JoinComma(self.cc)),
 			("description", self.desc),
 			("base_hashes", ""),
-			# Would prefer not to change the subject
-			# on reupload, but /upload requires it.
-			("subject", self.Subject()),
 		]
 
 		if self.name != "new":
 			form_fields.append(("issue", self.name))
 		vcs = None
-		if self.files:
+		# We do not include files when creating the issue,
+		# because we want the patch sets to record the repository
+		# and base revision they are diffs against.  We use the patch
+		# set message for that purpose, but there is no message with
+		# the first patch set.  Instead the message gets used as the
+		# new CL's overall subject.  So omit the diffs when creating
+		# and then we'll run an immediate upload.
+		# This has the effect that every CL begins with an empty "Patch set 1".
+		if self.files and not creating:
 			vcs = MercurialVCS(upload_options, ui, repo)
 			data = vcs.GenerateDiff(self.files)
 			files = vcs.GetBaseFiles(data)
@@ -311,6 +316,12 @@ class CL(object):
 				uploaded_diff_file = [("data", "data.diff", data)]
 		else:
 			uploaded_diff_file = [("data", "data.diff", emptydiff)]
+		
+		if vcs and self.name != "new":
+			form_fields.append(("subject", "diff -r " + vcs.base_rev + " " + getremote(ui, repo, {}).path))
+		else:
+			# First upload sets the subject for the CL itself.
+			form_fields.append(("subject", self.Subject()))
 		ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
 		response_body = MySend("/upload", body, content_type=ctype)
 		patchset = None
@@ -320,7 +331,10 @@ class CL(object):
 			msg = lines[0]
 			patchset = lines[1].strip()
 			patches = [x.split(" ", 1) for x in lines[2:]]
-		ui.status(msg + "\n")
+		if response_body.startswith("Issue updated.") and quiet:
+			pass
+		else:
+			ui.status(msg + "\n")
 		set_status("uploaded CL metadata + diffs")
 		if not response_body.startswith("Issue created.") and not response_body.startswith("Issue updated."):
 			raise util.Abort("failed to update issue: " + response_body)
@@ -342,14 +356,15 @@ class CL(object):
 		self.Flush(ui, repo)
 		return
 
-	def Mail(self, ui,repo):
+	def Mail(self, ui, repo):
 		pmsg = "Hello " + JoinComma(self.reviewer)
 		if self.cc:
 			pmsg += " (cc: %s)" % (', '.join(self.cc),)
 		pmsg += ",\n"
 		pmsg += "\n"
+		repourl = getremote(ui, repo, {}).path
 		if not self.mailed:
-			pmsg += "I'd like you to review this change.\n"
+			pmsg += "I'd like you to review this change to\n" + repourl + "\n"
 		else:
 			pmsg += "Please take another look.\n"
 		typecheck(pmsg, str)
@@ -1082,7 +1097,10 @@ def change(ui, repo, *pats, **opts):
 		dirty[cl] = True
 
 	for d, _ in dirty.items():
+		name = d.name
 		d.Flush(ui, repo)
+		if name == "new":
+			d.Upload(ui, repo, quiet=True)
 
 	if opts["stdout"]:
 		ui.write(cl.EditorText())
@@ -1124,15 +1142,12 @@ def clpatch(ui, repo, clname, **opts):
 	if err != "":
 		return err
 	try:
-		cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=True)
+		cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
 	except:
 		return "hgpatch: " + ExceptionDetail()
-	if os.fork() == 0:
-		cmd.stdin.write(patch)
-		os._exit(0)
-	cmd.stdin.close()
-	out = cmd.stdout.read()
-	if cmd.wait() != 0 and not opts["ignore_hgpatch_failure"]:
+
+	out, err = cmd.communicate(patch)
+	if cmd.returncode != 0 and not opts["ignore_hgpatch_failure"]:
 		return "hgpatch failed"
 	cl.local = True
 	cl.files = out.strip().split()
diff --git a/lib/godoc/package.html b/lib/godoc/package.html
index 570ae40..4205f93 100644
--- a/lib/godoc/package.html
+++ b/lib/godoc/package.html
@@ -5,7 +5,7 @@
 -->
 
 {.section PAst}
-	<pre>{@ FSet|html}</pre>
+	<pre>{@ FSet|html-esc}</pre>
 {.end}
 {.section PDoc}
 	<!-- PackageName is printed as title by the top-level template -->
@@ -31,46 +31,45 @@
 		<h2 id="Constants">Constants</h2>
 		{.repeated section @}
 			{Doc|html-comment}
-			<pre>{Decl FSet|html}</pre>
+			<pre>{Decl FSet|html-esc}</pre>
 		{.end}
 	{.end}
 	{.section Vars}
 		<h2 id="Variables">Variables</h2>
 		{.repeated section @}
 			{Doc|html-comment}
-			<pre>{Decl FSet|html}</pre>
+			<pre>{Decl FSet|html-esc}</pre>
 		{.end}
 	{.end}
 	{.section Funcs}
 		{.repeated section @}
 			{# Name is a string - no need for FSet}
 			<h2 id="{Name|html-esc}">func <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h2>
-			<p><code>{Decl FSet|html}</code></p>
+			<p><code>{Decl FSet|html-esc}</code></p>
 			{Doc|html-comment}
 		{.end}
 	{.end}
 	{.section Types}
 		{.repeated section @}
-			{# Type.Name is a string - no need for FSet}
 			<h2 id="{Type.Name FSet|html-esc}">type <a href="/{Decl FSet|url-pos}">{Type.Name FSet|html-esc}</a></h2>
 			{Doc|html-comment}
-			<p><pre>{Decl FSet|html}</pre></p>
+			<p><pre>{Decl FSet|html-esc}</pre></p>
 			{.repeated section Consts}
 				{Doc|html-comment}
-				<pre>{Decl FSet|html}</pre>
+				<pre>{Decl FSet|html-esc}</pre>
 			{.end}
 			{.repeated section Vars}
 				{Doc|html-comment}
-				<pre>{Decl FSet|html}</pre>
+				<pre>{Decl FSet|html-esc}</pre>
 			{.end}
 			{.repeated section Factories}
 				<h3 id="{Type.Name FSet|html-esc}.{Name|html-esc}">func <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h3>
-				<p><code>{Decl FSet|html}</code></p>
+				<p><code>{Decl FSet|html-esc}</code></p>
 				{Doc|html-comment}
 			{.end}
 			{.repeated section Methods}
-				<h3 id="{Type.Name FSet|html-esc}.{Name|html-esc}">func ({Recv FSet|html}) <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h3>
-				<p><code>{Decl FSet|html}</code></p>
+				<h3 id="{Type.Name FSet|html-esc}.{Name|html-esc}">func ({Recv FSet|html-esc}) <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h3>
+				<p><code>{Decl FSet|html-esc}</code></p>
 				{Doc|html-comment}
 			{.end}
 		{.end}
diff --git a/misc/dashboard/godashboard/main.html b/misc/dashboard/godashboard/main.html
index 8eb2786..9572f18 100644
--- a/misc/dashboard/godashboard/main.html
+++ b/misc/dashboard/godashboard/main.html
@@ -12,7 +12,7 @@
       <li>Build Status</li>
       <li><a href="/package">Packages</a></li>
       <li><a href="/project">Projects</a></li>
-      <li><a href="/benchmarks">Benchmarks</a></li>
+<!--      <li><a href="/benchmarks">Benchmarks</a></li> -->
       <li><a href="http://golang.org/">golang.org</a></li>
     </ul>
     
diff --git a/misc/dashboard/godashboard/package.html b/misc/dashboard/godashboard/package.html
index 08dd6a3..13640c8 100644
--- a/misc/dashboard/godashboard/package.html
+++ b/misc/dashboard/godashboard/package.html
@@ -10,7 +10,7 @@
       <li><a href="/">Build Status</a></li>
       <li>Packages</li>
       <li><a href="/project">Projects</a></li>
-      <li><a href="/benchmarks">Benchmarks</a></li>
+<!--      <li><a href="/benchmarks">Benchmarks</a></li> -->
       <li><a href="http://golang.org/">golang.org</a></li>
     </ul>
 
diff --git a/misc/dashboard/godashboard/project.html b/misc/dashboard/godashboard/project.html
index a936380..f1cf7c0 100644
--- a/misc/dashboard/godashboard/project.html
+++ b/misc/dashboard/godashboard/project.html
@@ -14,7 +14,7 @@
       <li><a href="/">Build Status</a></li>
       <li><a href="/package">Packages</a></li>
       <li>Projects</li>
-      <li><a href="/benchmarks">Benchmarks</a></li>
+<!--      <li><a href="/benchmarks">Benchmarks</a></li> -->
       <li><a href="http://golang.org/">golang.org</a></li>
     </ul>
 
diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go
index bc11bb7..3ca5ed8 100644
--- a/misc/goplay/goplay.go
+++ b/misc/goplay/goplay.go
@@ -66,7 +66,7 @@ func FrontPage(w http.ResponseWriter, req *http.Request) {
 	if err != nil {
 		data = helloWorld
 	}
-	frontPage.Execute(data, w)
+	frontPage.Execute(w, data)
 }
 
 // Compile is an HTTP handler that reads Go source code from the request,
@@ -123,7 +123,7 @@ func Compile(w http.ResponseWriter, req *http.Request) {
 	if *htmlOutput {
 		w.Write(out)
 	} else {
-		output.Execute(out, w)
+		output.Execute(w, out)
 	}
 }
 
@@ -132,9 +132,9 @@ func Compile(w http.ResponseWriter, req *http.Request) {
 func error(w http.ResponseWriter, out []byte, err os.Error) {
 	w.WriteHeader(404)
 	if out != nil {
-		output.Execute(out, w)
+		output.Execute(w, out)
 	} else {
-		output.Execute(err.String(), w)
+		output.Execute(w, err.String())
 	}
 }
 
diff --git a/src/Make.cmd b/src/Make.cmd
index 34f5663..2b9aba4 100644
--- a/src/Make.cmd
+++ b/src/Make.cmd
@@ -27,3 +27,22 @@ CLEANFILES+=$(TARG)
 
 nuke: clean
 	rm -f $(QUOTED_GOBIN)/$(TARG)
+
+# for gotest
+testpackage: _test/main.a
+
+testpackage-clean:
+	rm -f _test/main.a _gotest_.$O
+
+testpackage: _test/main.a
+
+_test/main.a: _gotest_.$O
+	@mkdir -p _test
+	rm -f $@
+	gopack grc $@ _gotest_.$O
+
+_gotest_.$O: $(GOFILES) $(GOTESTFILES)
+	$(GC) -o $@ $(GOFILES) $(GOTESTFILES)
+
+importpath:
+	echo main
diff --git a/src/Make.pkg b/src/Make.pkg
index 0ffab72..ca0fa9e 100644
--- a/src/Make.pkg
+++ b/src/Make.pkg
@@ -113,20 +113,20 @@ dir:
 
 ifdef CGOFILES
 _cgo_run: $(CGOFILES)
-	@touch _cgo_run
 	CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES)
+	touch _cgo_run
 
 # _CGO_CFLAGS and _CGO_LDFLAGS are defined via the evaluation of _cgo_flags.
 # The include happens before the commands in the recipe run,
 # so it cannot be done in the same recipe that runs cgo.
-_cgo_flags: _cgo_run
+_load_cgo_flags: _cgo_run
 	$(eval include _cgo_flags)
 
 # Include any previous flags in case cgo files are up to date.
 -include _cgo_flags
 
 # Ugly but necessary - cgo writes these files too.
-_cgo_gotypes.go _cgo_export.c _cgo_export.h _cgo_main.c _cgo_defun.c: _cgo_flags
+_cgo_gotypes.go _cgo_export.c _cgo_export.h _cgo_main.c _cgo_defun.c: _load_cgo_flags
 	@true
 
 %.cgo1.go %.cgo2.c: _cgo_defun.c
@@ -167,7 +167,7 @@ _CGO_LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup
 _CGO_LDFLAGS_windows=-shared -lm -mthreads
 
 # Have to compile the runtime header.
-RUNTIME_CFLAGS=-I"$(pkgdir)"
+RUNTIME_CFLAGS=-I$(pkgdir)
 
 # Compile _cgo_defun.c with 6c; needs access to the runtime headers.
 _cgo_defun.$O: _cgo_defun.c
diff --git a/src/clean.bash b/src/clean.bash
index d96eb52..5c1dded 100755
--- a/src/clean.bash
+++ b/src/clean.bash
@@ -25,8 +25,8 @@ for i in lib9 libbio libmach cmd pkg \
 do(
 	cd "$GOROOT"/src/$i || exit 1
 	if test -f clean.bash; then
-		bash clean.bash
+		bash clean.bash --gomake $MAKE
 	else
-		gomake clean
+		$MAKE clean
 	fi
 )done
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index b36094a..e762f56 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -187,7 +187,7 @@ assemble(char *file)
 	pass = 1;
 	pinit(file);
 
-	Bprint(&obuf, "%s\n", thestring);
+	Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 
 	for(i=0; i<nDlist; i++)
 		dodefine(Dlist[i]);
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 43eb73c..d45aabc 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -373,7 +373,7 @@ outcode(void)
 		}
 	}
 
-	Bprint(&outbuf, "%s\n", thestring);
+	Bprint(&outbuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 	if(ndynimp > 0 || ndynexp > 0) {
 		int i;
 
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index 78f2f4a..4da8db2 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -64,17 +64,21 @@ cgen64(Node *n, Node *res)
 		return;
 
 	case OCOM:
+		regalloc(&t1, lo1.type, N);
+		gmove(ncon(-1), &t1);
+
 		split64(res, &lo2, &hi2);
 		regalloc(&n1, lo1.type, N);
 
 		gins(AMOVW, &lo1, &n1);
-		gins(AMVN, &n1, &n1);
+		gins(AEOR, &t1, &n1);
 		gins(AMOVW, &n1, &lo2);
 
 		gins(AMOVW, &hi1, &n1);
-		gins(AMVN, &n1, &n1);
+		gins(AEOR, &t1, &n1);
 		gins(AMOVW, &n1, &hi2);
 
+		regfree(&t1);
 		regfree(&n1);
 		splitclean();
 		splitclean();
@@ -204,14 +208,17 @@ cgen64(Node *n, Node *res)
 				// here and below (verify it optimizes to EOR)
 				gins(AEOR, &al, &al);
 				gins(AEOR, &ah, &ah);
-			} else if(v > 32) {
+			} else
+			if(v > 32) {
 				gins(AEOR, &al, &al);
 				//	MOVW	bl<<(v-32), ah
 				gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
-			} else if(v == 32) {
+			} else
+			if(v == 32) {
 				gins(AEOR, &al, &al);
 				gins(AMOVW, &bl, &ah);
-			} else if(v > 0) {
+			} else
+			if(v > 0) {
 				//	MOVW	bl<<v, al
 				gshift(AMOVW, &bl, SHIFT_LL, v, &al);
 
@@ -341,7 +348,8 @@ olsh_break:
 					gins(AEOR, &al, &al);
 					gins(AEOR, &ah, &ah);
 				}
-			} else if(v > 32) {
+			} else
+			if(v > 32) {
 				if(bh.type->etype == TINT32) {
 					//	MOVW	bh->(v-32), al
 					gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
@@ -353,7 +361,8 @@ olsh_break:
 					gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
 					gins(AEOR, &ah, &ah);
 				}
-			} else if(v == 32) {
+			} else
+			if(v == 32) {
 				gins(AMOVW, &bh, &al);
 				if(bh.type->etype == TINT32) {
 					//	MOVW	bh->31, ah
@@ -361,7 +370,8 @@ olsh_break:
 				} else {
 					gins(AEOR, &ah, &ah);
 				}
-			} else if( v > 0) {
+			} else
+			if( v > 0) {
 				//	MOVW	bl>>v, al
 				gshift(AMOVW, &bl, SHIFT_LR, v, &al);
 	
@@ -384,11 +394,16 @@ olsh_break:
 
 		regalloc(&s, types[TUINT32], N);
 		regalloc(&creg, types[TUINT32], N);
-		if (is64(r->type)) {
+		if(is64(r->type)) {
 			// shift is >= 1<<32
 			split64(r, &cl, &ch);
 			gmove(&ch, &s);
-			p1 = gins(ATST, &s, N);
+			gins(ATST, &s, N);
+			if(bh.type->etype == TINT32)
+				p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+			else
+				p1 = gins(AEOR, &ah, &ah);
+			p1->scond = C_SCOND_NE;
 			p6 = gbranch(ABNE, T);
 			gmove(&cl, &s);
 			splitclean();
@@ -441,7 +456,6 @@ olsh_break:
 			p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
 		else
 			p1 = gins(AEOR, &ah, &ah);
-		p1->scond = C_SCOND_EQ;
 		p4 = gbranch(ABEQ, T);
 
 		// check if shift is < 64
@@ -461,33 +475,23 @@ olsh_break:
 			//	MOVW	bh->(s-32), al
 			p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
 			p1->scond = C_SCOND_LO;
-
-			//	MOVW	bh->31, ah
-			p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-			p1->scond = C_SCOND_LO;
 		} else {
 			//	MOVW	bh>>(v-32), al
 			p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
 			p1->scond = C_SCOND_LO;
-
-			p1 = gins(AEOR, &ah, &ah);
-			p1->scond = C_SCOND_LO;
 		}
 
 		//	BLO	end
 		p5 = gbranch(ABLO, T);
 
 		// s >= 64
-		if (p6 != P) patch(p6, pc);
+		if(p6 != P)
+			patch(p6, pc);
 		if(bh.type->etype == TINT32) {
 			//	MOVW	bh->31, al
 			gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
-
-			//	MOVW	bh->31, ah
-			gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
 		} else {
 			gins(AEOR, &al, &al);
-			gins(AEOR, &ah, &ah);
 		}
 
 		patch(p2, pc);
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index ce74d64..0c6dbbf 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -87,6 +87,10 @@ Dconv(Fmt *fp)
 	int32 v;
 
 	a = va_arg(fp->args, Addr*);
+	if(a == A) {
+		sprint(str, "<nil>");
+		goto conv;
+	}
 	i = a->type;
 	switch(i) {
 
@@ -183,7 +187,7 @@ Dconv(Fmt *fp)
 //		a->type = D_ADDR;
 //		goto conv;
 	}
-//conv:
+conv:
 	return fmtstrcpy(fp, str);
 }
 
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index f619a62..ca12d70 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -48,7 +48,6 @@ peep(void)
 /*
  * complete R structure
  */
-	t = 0;
 	for(r=firstr; r!=R; r=r1) {
 		r1 = r->link;
 		if(r1 == R)
@@ -68,7 +67,6 @@ peep(void)
 			r1->p1 = r2;
 
 			r = r2;
-			t++;
 
 		case ADATA:
 		case AGLOBL:
@@ -77,8 +75,10 @@ peep(void)
 			p = p->link;
 		}
 	}
+//dumpit("begin", firstr);
 
 loop1:
+
 	t = 0;
 	for(r=firstr; r!=R; r=r->link) {
 		p = r->prog;
@@ -99,71 +99,75 @@ loop1:
 		case AMOVW:
 		case AMOVF:
 		case AMOVD:
-			if(!regtyp(&p->to))
-				break;
-//			if(isdconst(&p->from)) {
-//				constprop(&p->from, &p->to, r->s1);
-//				break;
-//			}
-			if(!regtyp(&p->from))
-				break;
-			if(p->from.type != p->to.type)
-				break;
-			if(copyprop(r)) {
-				excise(r);
-				t++;
-				break;
+			if(regtyp(&p->from))
+			if(p->from.type == p->to.type)
+			if(p->scond == C_SCOND_NONE) {
+				if(copyprop(r)) {
+					excise(r);
+					t++;
+					break;
+				}
+				if(subprop(r) && copyprop(r)) {
+					excise(r);
+					t++;
+					break;
+				}
 			}
-			if(subprop(r) && copyprop(r)) {
-				excise(r);
-				t++;
-				break;
+			break;
+
+			if(p->scond == C_SCOND_NONE)
+			if(regtyp(&p->to))
+			if(isdconst(&p->from)) {
+				constprop(&p->from, &p->to, r->s1);
 			}
+			break;
 		}
 	}
 	if(t)
 		goto loop1;
-	/*
-	 * look for MOVB x,R; MOVB R,R
-	 */
+
+return;
+
 	for(r=firstr; r!=R; r=r->link) {
 		p = r->prog;
 		switch(p->as) {
-		default:
-			continue;
-		case AEOR:
-			/*
-			 * EOR -1,x,y => MVN x,y
-			 */
-			if(isdconst(&p->from) && p->from.offset == -1) {
-				p->as = AMVN;
-				p->from.type = D_REG;
-				if(p->reg != NREG)
-					p->from.reg = p->reg;
-				else
-					p->from.reg = p->to.reg;
-				p->reg = NREG;
-			}
-			continue;
+//		case AEOR:
+//			/*
+//			 * EOR -1,x,y => MVN x,y
+//			 */
+//			if(isdconst(&p->from) && p->from.offset == -1) {
+//				p->as = AMVN;
+//				p->from.type = D_REG;
+//				if(p->reg != NREG)
+//					p->from.reg = p->reg;
+//				else
+//					p->from.reg = p->to.reg;
+//				p->reg = NREG;
+//			}
+//			break;
+
 		case AMOVH:
 		case AMOVHU:
 		case AMOVB:
 		case AMOVBU:
+			/*
+			 * look for MOVB x,R; MOVB R,R
+			 */
 			if(p->to.type != D_REG)
-				continue;
+				break;
+			if(r1 == R)
+				break;
+			p1 = r1->prog;
+			if(p1->as != p->as)
+				break;
+			if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+				break;
+			if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+				break;
+			excise(r1);
 			break;
 		}
 		r1 = r->link;
-		if(r1 == R)
-			continue;
-		p1 = r1->prog;
-		if(p1->as != p->as)
-			continue;
-		if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
-			continue;
-		if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
-			continue;
-		excise(r1);
 	}
 
 //	for(r=firstr; r!=R; r=r->link) {
@@ -335,6 +339,8 @@ subprop(Reg *r0)
 
 		case AMULLU:
 		case AMULA:
+		case AMVN:
+			return 0;
 
 		case ACMN:
 		case AADD:
@@ -347,7 +353,6 @@ subprop(Reg *r0)
 		case AORR:
 		case AAND:
 		case AEOR:
-		case AMVN:
 		case AMUL:
 		case AMULU:
 		case ADIV:
@@ -364,7 +369,8 @@ subprop(Reg *r0)
 		case ADIVD:
 		case ADIVF:
 			if(p->to.type == v1->type)
-			if(p->to.reg == v1->reg) {
+			if(p->to.reg == v1->reg)
+			if(p->scond == C_SCOND_NONE) {
 				if(p->reg == NREG)
 					p->reg = p->to.reg;
 				goto gotit;
@@ -376,6 +382,7 @@ subprop(Reg *r0)
 		case AMOVW:
 			if(p->to.type == v1->type)
 			if(p->to.reg == v1->reg)
+			if(p->scond == C_SCOND_NONE)
 				goto gotit;
 			break;
 
@@ -662,7 +669,7 @@ shiftprop(Reg *r)
 			FAIL("can't swap");
 		if(p1->reg == NREG && p1->to.reg == n)
 			FAIL("shift result used twice");
-	case AMVN:
+//	case AMVN:
 		if(p1->from.type == D_SHIFT)
 			FAIL("shift result used in shift");
 		if(p1->from.type != D_REG || p1->from.reg != n)
@@ -971,7 +978,7 @@ copyu(Prog *p, Adr *v, Adr *s)
 		}
 		return 0;
 
-	case ANOP:	/* read, write */
+	case ANOP:	/* read,, write */
 	case AMOVW:
 	case AMOVF:
 	case AMOVD:
@@ -979,6 +986,8 @@ copyu(Prog *p, Adr *v, Adr *s)
 	case AMOVHU:
 	case AMOVB:
 	case AMOVBU:
+	case AMOVFW:
+	case AMOVWF:
 	case AMOVDW:
 	case AMOVWD:
 	case AMOVFD:
@@ -1014,6 +1023,7 @@ copyu(Prog *p, Adr *v, Adr *s)
 
 	case AMULLU:	/* read, read, write, write */
 	case AMULA:
+	case AMVN:
 		return 2;
 
 	case AADD:	/* read, read, write */
@@ -1027,7 +1037,6 @@ copyu(Prog *p, Adr *v, Adr *s)
 	case AORR:
 	case AAND:
 	case AEOR:
-	case AMVN:
 	case AMUL:
 	case AMULU:
 	case ADIV:
@@ -1043,12 +1052,12 @@ copyu(Prog *p, Adr *v, Adr *s)
 	case ADIVF:
 	case ADIVD:
 
-	case ACMPF:
+	case ACMPF:	/* read, read, */
 	case ACMPD:
-	case ATST:
 	case ACMP:
 	case ACMN:
 	case ACASE:
+	case ATST:	/* read,, */
 		if(s != A) {
 			if(copysub(&p->from, v, s, 1))
 				return 1;
@@ -1150,53 +1159,6 @@ copyu(Prog *p, Adr *v, Adr *s)
 	return 0;
 }
 
-int
-a2type(Prog *p)
-{
-
-	switch(p->as) {
-
-	case ATST:
-	case ACMP:
-	case ACMN:
-
-	case AMULLU:
-	case AMULA:
-
-	case AADD:
-	case ASUB:
-	case ARSB:
-	case ASLL:
-	case ASRL:
-	case ASRA:
-	case AORR:
-	case AAND:
-	case AEOR:
-	case AMVN:
-	case AMUL:
-	case AMULU:
-	case ADIV:
-	case ADIVU:
-	case AMOD:
-	case AMODU:
-		return D_REG;
-
-	case ACMPF:
-	case ACMPD:
-
-	case AADDF:
-	case AADDD:
-	case ASUBF:
-	case ASUBD:
-	case AMULF:
-	case AMULD:
-	case ADIVF:
-	case ADIVD:
-		return D_FREG;
-	}
-	return D_NONE;
-}
-
 /*
  * direct reference,
  * could be set/use depending on
@@ -1233,15 +1195,15 @@ copyau(Adr *a, Adr *v)
 		return 1;
 	if(v->type == D_REG) {
 		if(a->type == D_CONST && a->reg != NREG) {
-			if(v->reg == a->reg)
+			if(a->reg == v->reg)
 				return 1;
 		} else
 		if(a->type == D_OREG) {
-			if(v->reg == a->reg)
+			if(a->reg == v->reg)
 				return 1;
 		} else
 		if(a->type == D_REGREG) {
-			if(v->reg == a->reg)
+			if(a->reg == v->reg)
 				return 1;
 			if(a->offset == v->reg)
 				return 1;
@@ -1256,17 +1218,33 @@ copyau(Adr *a, Adr *v)
 	return 0;
 }
 
+/*
+ * compare v to the center
+ * register in p (p->reg)
+ * the trick is that this
+ * register might be D_REG
+ * D_FREG. there are basically
+ * two cases,
+ *	ADD r,r,r
+ *	CMP r,r,
+ */
 int
 copyau1(Prog *p, Adr *v)
 {
 
-	if(regtyp(v)) {
-		if(a2type(p) == v->type)
-		if(p->reg == v->reg) {
-			if(a2type(p) != v->type)
-				print("botch a2type %P\n", p);
-			return 1;
+	if(regtyp(v))
+	if(p->reg == v->reg) {
+		if(p->to.type != D_NONE) {
+			if(v->type == p->to.type)
+				return 1;
+			return 0;
+		}
+		if(p->from.type != D_NONE) {
+			if(v->type == p->from.type)
+				return 1;
+			return 0;
 		}
+		print("copyau1: cant tell %P\n", p);
 	}
 	return 0;
 }
@@ -1479,24 +1457,24 @@ applypred(Reg *rstart, Joininfo *j, int cond, int branch)
 		pred = predinfo[rstart->prog->as - ABEQ].notscond;
 
 	for(r = j->start;; r = successor(r)) {
-		if (r->prog->as == AB) {
-			if (r != j->last || branch == Delbranch)
+		if(r->prog->as == AB) {
+			if(r != j->last || branch == Delbranch)
 				excise(r);
 			else {
-				if (cond == Truecond)
+				if(cond == Truecond)
 					r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
 				else
 					r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
 			}
 		}
 		else
-		if (predicable(r->prog))
+		if(predicable(r->prog))
 			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
-		if (r->s1 != r->link) {
+		if(r->s1 != r->link) {
 			r->s1 = r->link;
 			r->link->p1 = r;
 		}
-		if (r == j->last)
+		if(r == j->last)
 			break;
 	}
 }
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index eaf02b2..f31f705 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -140,8 +140,8 @@ regopt(Prog *firstp)
 	if(first == 0) {
 		fmtinstall('Q', Qconv);
 	}
-	first++;
 
+	first++;
 	if(debug['K']) {
 		if(first != 13)
 			return;
@@ -491,7 +491,7 @@ brk:
 	 * peep-hole on basic block
 	 */
 	if(!debug['R'] || debug['P']) {
-//		peep();
+		peep();
 	}
 
 	/*
@@ -1375,3 +1375,71 @@ noreturn(Prog *p)
 			return 1;
 	return 0;
 }
+
+void
+dumpone(Reg *r)
+{
+	int z;
+	Bits bit;
+
+	print("%d:%P", r->loop, r->prog);
+	for(z=0; z<BITS; z++)
+		bit.b[z] =
+			r->set.b[z] |
+			r->use1.b[z] |
+			r->use2.b[z] |
+			r->refbehind.b[z] |
+			r->refahead.b[z] |
+			r->calbehind.b[z] |
+			r->calahead.b[z] |
+			r->regdiff.b[z] |
+			r->act.b[z] |
+				0;
+//	if(bany(&bit)) {
+//		print("\t");
+//		if(bany(&r->set))
+//			print(" s:%Q", r->set);
+//		if(bany(&r->use1))
+//			print(" u1:%Q", r->use1);
+//		if(bany(&r->use2))
+//			print(" u2:%Q", r->use2);
+//		if(bany(&r->refbehind))
+//			print(" rb:%Q ", r->refbehind);
+//		if(bany(&r->refahead))
+//			print(" ra:%Q ", r->refahead);
+//		if(bany(&r->calbehind))
+//			print("cb:%Q ", r->calbehind);
+//		if(bany(&r->calahead))
+//			print(" ca:%Q ", r->calahead);
+//		if(bany(&r->regdiff))
+//			print(" d:%Q ", r->regdiff);
+//		if(bany(&r->act))
+//			print(" a:%Q ", r->act);
+//	}
+	print("\n");
+}
+
+void
+dumpit(char *str, Reg *r0)
+{
+	Reg *r, *r1;
+
+	print("\n%s\n", str);
+	for(r = r0; r != R; r = r->link) {
+		dumpone(r);
+		r1 = r->p2;
+		if(r1 != R) {
+			print("	pred:");
+			for(; r1 != R; r1 = r1->p2link)
+				print(" %.4ud", r1->prog->loc);
+			print("\n");
+		}
+//		r1 = r->s1;
+//		if(r1 != R) {
+//			print("	succ:");
+//			for(; r1 != R; r1 = r1->s1)
+//				print(" %.4ud", r1->prog->loc);
+//			print("\n");
+//		}
+	}
+}
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 3456562..7163997 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -637,13 +637,6 @@ wput(int32 l)
 		cflush();
 }
 
-void
-wputl(ushort w)
-{
-	cput(w);
-	cput(w>>8);
-}
-
 
 void
 hput(int32 l)
@@ -672,20 +665,6 @@ lput(int32 l)
 }
 
 void
-lputl(int32 l)
-{
-
-	cbp[3] = l>>24;
-	cbp[2] = l>>16;
-	cbp[1] = l>>8;
-	cbp[0] = l;
-	cbp += 4;
-	cbc -= 4;
-	if(cbc <= 0)
-		cflush();
-}
-
-void
 cflush(void)
 {
 	int n;
@@ -1491,15 +1470,24 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
 		o1 |= (p->scond & C_SCOND) << 28;
 		break;
 	case 80:	/* fmov zfcon,freg */
-		if((p->scond & C_SCOND) != C_SCOND_NONE)
-			diag("floating point cannot be conditional");	// cant happen
-		o1 = 0xf3000110;	// EOR 64
-
-		// always clears the double float register
+		if(p->as == AMOVD) {
+			o1 = 0xeeb00b00;	// VMOV imm 64
+			o2 = oprrr(ASUBD, p->scond);
+		} else {
+			o1 = 0x0eb00a00;	// VMOV imm 32
+			o2 = oprrr(ASUBF, p->scond);
+		}
+		v = 0x70;	// 1.0
 		r = p->to.reg;
-		o1 |= r << 0;
+
+		// movf $1.0, r
+		o1 |= (p->scond & C_SCOND) << 28;
 		o1 |= r << 12;
-		o1 |= r << 16;
+		o1 |= (v&0xf) << 0;
+		o1 |= (v&0xf0) << 12;
+
+		// subf r,r,r
+		o2 |= r | (r<<16) | (r<<12);
 		break;
 	case 81:	/* fmov sfcon,freg */
 		o1 = 0x0eb00a00;		// VMOV imm 32
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index c310284..e42be4e 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -410,6 +410,7 @@ Sym*	lookup(char*, int);
 void	cput(int);
 void	hput(int32);
 void	lput(int32);
+void	lputb(int32);
 void	lputl(int32);
 void*	mysbrk(uint32);
 void	names(void);
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 9ad0193..8b3135e 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -236,7 +236,7 @@ Optab	optab[] =
 	{ ALDREX,	C_SOREG,C_NONE,	C_REG,		77, 4, 0 },
 	{ ASTREX,	C_SOREG,C_REG,	C_REG,		78, 4, 0 },
 
-	{ AMOVF,	C_ZFCON,C_NONE,	C_FREG,		80, 4, 0 },
+	{ AMOVF,	C_ZFCON,C_NONE,	C_FREG,		80, 8, 0 },
 	{ AMOVF,	C_SFCON,C_NONE,	C_FREG,		81, 4, 0 },
 
 	{ ACMPF,	C_FREG,	C_REG,	C_NONE,		82, 8, 0 },
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 1b8bb63..37144c8 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -189,7 +189,7 @@ assemble(char *file)
 	pass = 1;
 	pinit(file);
 
-	Bprint(&obuf, "%s\n", thestring);
+	Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 
 	for(i=0; i<nDlist; i++)
 		dodefine(Dlist[i]);
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 47975a0..6d886f4 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -231,7 +231,7 @@ outcode(void)
 	}
 	Binit(&b, f, OWRITE);
 
-	Bprint(&b, "%s\n", thestring);
+	Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 	if(ndynimp > 0 || ndynexp > 0) {
 		int i;
 
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index d6ffa4f..d179e77 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -63,52 +63,6 @@ entryvalue(void)
 	return s->value;
 }
 
-void
-wputl(uint16 w)
-{
-	cput(w);
-	cput(w>>8);
-}
-
-void
-wputb(uint16 w)
-{
-	cput(w>>8);
-	cput(w);
-}
-
-void
-lputb(int32 l)
-{
-	cput(l>>24);
-	cput(l>>16);
-	cput(l>>8);
-	cput(l);
-}
-
-void
-vputb(uint64 v)
-{
-	lputb(v>>32);
-	lputb(v);
-}
-
-void
-lputl(int32 l)
-{
-	cput(l);
-	cput(l>>8);
-	cput(l>>16);
-	cput(l>>24);
-}
-
-void
-vputl(uint64 v)
-{
-	lputl(v);
-	lputl(v>>32);
-}
-
 vlong
 datoff(vlong addr)
 {
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 7f22493..70473ec 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -429,6 +429,7 @@ vlong	rnd(vlong, vlong);
 void	span(void);
 void	undef(void);
 vlong	symaddr(Sym*);
+void	vputb(uint64);
 void	vputl(uint64);
 void	wputb(uint16);
 void	wputl(uint16);
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index bf298b2..d5fa959 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -189,7 +189,7 @@ assemble(char *file)
 	pass = 1;
 	pinit(file);
 
-	Bprint(&obuf, "%s\n", thestring);
+	Bprint(&obuf, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 
 	for(i=0; i<nDlist; i++)
 		dodefine(Dlist[i]);
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index be48885..d07a543 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -230,7 +230,7 @@ outcode(void)
 	}
 	Binit(&b, f, OWRITE);
 
-	Bprint(&b, "%s\n", thestring);
+	Bprint(&b, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 	if(ndynimp > 0 || ndynexp > 0) {
 		int i;
 
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 6e83d8d..d90eab7 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -59,45 +59,6 @@ entryvalue(void)
 	return s->value;
 }
 
-void
-wputl(ushort w)
-{
-	cput(w);
-	cput(w>>8);
-}
-
-void
-wput(ushort w)
-{
-	cput(w>>8);
-	cput(w);
-}
-
-void
-lput(int32 l)
-{
-	cput(l>>24);
-	cput(l>>16);
-	cput(l>>8);
-	cput(l);
-}
-
-void
-lputl(int32 l)
-{
-	cput(l);
-	cput(l>>8);
-	cput(l>>16);
-	cput(l>>24);
-}
-
-void
-vputl(uvlong l)
-{
-	lputl(l >> 32);
-	lputl(l);
-}
-
 vlong
 datoff(vlong addr)
 {
@@ -688,6 +649,8 @@ asmb(void)
 	ElfPhdr *ph, *pph;
 	ElfShdr *sh;
 	Section *sect;
+	Sym *sym;
+	int i;
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -741,7 +704,7 @@ asmb(void)
 			seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
 			break;
 		case 2:
-			seek(cout, HEADR+segtext.filelen+segdata.filelen, 0);
+			symo = HEADR+segtext.filelen+segdata.filelen;
 			break;
 		case 3:
 		case 4:
@@ -761,11 +724,27 @@ asmb(void)
 			symo = rnd(symo, PEFILEALIGN);
 			break;
 		}
-		if(HEADTYPE != 10 && !debug['s']) {
+		if(!debug['s']) {
 			seek(cout, symo, 0);
-			if(debug['v'])
-				Bprint(&bso, "%5.2f dwarf\n", cputime());
-			dwarfemitdebugsections();
+			
+			if(HEADTYPE == 2) {
+				asmplan9sym();
+				cflush();
+				
+				sym = lookup("pclntab", 0);
+				if(sym != nil) {
+					lcsize = sym->np;
+					for(i=0; i < lcsize; i++)
+						cput(sym->p[i]);
+					
+					cflush();
+				}
+				
+			} else if(HEADTYPE != 10) {
+				if(debug['v'])
+					Bprint(&bso, "%5.2f dwarf\n", cputime());
+				dwarfemitdebugsections();
+			}
 		}
 	}
 	if(debug['v'])
@@ -777,25 +756,25 @@ asmb(void)
 		if(iself)
 			goto Elfput;
 	case 0:	/* garbage */
-		lput(0x160L<<16);		/* magic and sections */
-		lput(0L);			/* time and date */
-		lput(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
-		lput(symsize);			/* nsyms */
-		lput((0x38L<<16)|7L);		/* size of optional hdr and flags */
-		lput((0413<<16)|0437L);		/* magic and version */
-		lput(rnd(HEADR+segtext.filelen, 4096));	/* sizes */
-		lput(segdata.filelen);
-		lput(segdata.len - segdata.filelen);
-		lput(entryvalue());		/* va of entry */
-		lput(INITTEXT-HEADR);		/* va of base of text */
-		lput(segdata.vaddr);			/* va of base of data */
-		lput(segdata.vaddr+segdata.filelen);		/* va of base of bss */
-		lput(~0L);			/* gp reg mask */
-		lput(0L);
-		lput(0L);
-		lput(0L);
-		lput(0L);
-		lput(~0L);			/* gp value ?? */
+		lputb(0x160L<<16);		/* magic and sections */
+		lputb(0L);			/* time and date */
+		lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
+		lputb(symsize);			/* nsyms */
+		lputb((0x38L<<16)|7L);		/* size of optional hdr and flags */
+		lputb((0413<<16)|0437L);		/* magic and version */
+		lputb(rnd(HEADR+segtext.filelen, 4096));	/* sizes */
+		lputb(segdata.filelen);
+		lputb(segdata.len - segdata.filelen);
+		lputb(entryvalue());		/* va of entry */
+		lputb(INITTEXT-HEADR);		/* va of base of text */
+		lputb(segdata.vaddr);			/* va of base of data */
+		lputb(segdata.vaddr+segdata.filelen);		/* va of base of bss */
+		lputb(~0L);			/* gp reg mask */
+		lputb(0L);
+		lputb(0L);
+		lputb(0L);
+		lputb(0L);
+		lputb(~0L);			/* gp value ?? */
 		break;
 		lputl(0);			/* x */
 	case 1:	/* unix coff */
@@ -814,7 +793,7 @@ asmb(void)
 		lputl(rnd(segtext.filelen, INITRND));	/* text sizes */
 		lputl(segdata.filelen);			/* data sizes */
 		lputl(segdata.len - segdata.filelen);			/* bss sizes */
-		lput(entryvalue());		/* va of entry */
+		lputb(entryvalue());		/* va of entry */
 		lputl(INITTEXT);		/* text start */
 		lputl(segdata.vaddr);			/* data start */
 		/*
@@ -868,14 +847,14 @@ asmb(void)
 		break;
 	case 2:	/* plan9 */
 		magic = 4*11*11+7;
-		lput(magic);		/* magic */
-		lput(segtext.filelen);			/* sizes */
-		lput(segdata.filelen);
-		lput(segdata.len - segdata.filelen);
-		lput(symsize);			/* nsyms */
-		lput(entryvalue());		/* va of entry */
-		lput(spsize);			/* sp offsets */
-		lput(lcsize);			/* line offsets */
+		lputb(magic);		/* magic */
+		lputb(segtext.filelen);			/* sizes */
+		lputb(segdata.filelen);
+		lputb(segdata.len - segdata.filelen);
+		lputb(symsize);			/* nsyms */
+		lputb(entryvalue());		/* va of entry */
+		lputb(spsize);			/* sp offsets */
+		lputb(lcsize);			/* line offsets */
 		break;
 	case 3:
 		/* MS-DOS .COM */
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index e0746fc..f2546cf 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -363,9 +363,9 @@ void	follow(void);
 void	instinit(void);
 void	listinit(void);
 Sym*	lookup(char*, int);
-void	lput(int32);
+void	lputb(int32);
 void	lputl(int32);
-void	vputl(uvlong);
+void	vputl(uint64);
 void	strnput(char*, int);
 void	main(int, char*[]);
 void*	mal(uint32);
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index fefb6d8..9c687f2 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -188,6 +188,7 @@ main(int argc, char *argv[])
 			INITRND = 0;
 		break;
 	case 2:	/* plan 9 */
+		tlsoffset = -8;
 		HEADR = 32L;
 		if(INITTEXT == -1)
 			INITTEXT = 4096+32;
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 878a73d..67acfa1 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -250,6 +250,7 @@ patch(void)
 	Prog *p, *q;
 	Sym *s;
 	int32 vexit;
+	Sym *plan9_tos;
 
 	if(debug['v'])
 		Bprint(&bso, "%5.2f mkfwd\n", cputime());
@@ -260,6 +261,10 @@ patch(void)
 	Bflush(&bso);
 	s = lookup("exit", 0);
 	vexit = s->value;
+	
+	if(HEADTYPE == 2)
+		plan9_tos = lookup("_tos", 0);
+	
 	for(cursym = textp; cursym != nil; cursym = cursym->next) {
 		for(p = cursym->text; p != P; p = p->link) {
 			if(HEADTYPE == 10) {	// Windows
@@ -303,9 +308,15 @@ patch(void)
 			if(HEADTYPE == 2) {	// Plan 9
 				if(p->from.type == D_INDIR+D_GS
 				&& p->to.type >= D_AX && p->to.type <= D_DI) {
+					q = appendp(p);
+					q->from = p->from;
+					q->from.type = D_INDIR + p->to.type;
+					q->to = p->to;
+					q->as = p->as;
 					p->as = AMOVL;
-					p->from.type = D_ADDR+D_STATIC;
-					p->from.offset += 0xdfffefc0;
+					p->from.type = D_EXTERN;
+					p->from.sym = plan9_tos;
+					p->from.offset = 0;
 				}
 			}
 			if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
@@ -389,6 +400,7 @@ dostkoff(void)
 	int a;
 	Prog *pmorestack;
 	Sym *symmorestack;
+	Sym *plan9_tos;
 
 	pmorestack = P;
 	symmorestack = lookup("runtime.morestack", 0);
@@ -399,6 +411,9 @@ dostkoff(void)
 		pmorestack = symmorestack->text;
 		symmorestack->text->from.scale |= NOSPLIT;
 	}
+	
+	if(HEADTYPE == 2)	
+		plan9_tos = lookup("_tos", 0);
 
 	for(cursym = textp; cursym != nil; cursym = cursym->next) {
 		if(cursym->text == nil || cursym->text->link == nil)
@@ -443,9 +458,15 @@ dostkoff(void)
 			
 			case 2:	// Plan 9
 				p->as = AMOVL;
-				p->from.type = D_ADDR+D_STATIC;
-				p->from.offset = 0xdfffefc0;
+				p->from.type = D_EXTERN;
+				p->from.sym = plan9_tos;
 				p->to.type = D_CX;
+				
+				p = appendp(p);
+				p->as = AMOVL;
+				p->from.type = D_INDIR+D_CX;
+				p->from.offset = tlsoffset + 0;
+				p->to.type = D_CX;				
 				break;
 			
 			default:
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index c486834..b3aa9ad 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -25,9 +25,12 @@ the package.  For example:
 
 CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
 within these comments to tweak the behavior of gcc.  Values defined
-in multiple directives are concatenated together.  For example:
+in multiple directives are concatenated together.  Options prefixed
+by $GOOS, $GOARCH, or $GOOS/$GOARCH are only defined in matching
+systems.  For example:
 
 	// #cgo CFLAGS: -DPNG_DEBUG=1
+	// #cgo linux CFLAGS: -DLINUX=1
 	// #cgo LDFLAGS: -lpng
 	// #include <png.h>
 	import "C"
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index cadc6fa..e6ce21e 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -19,6 +19,7 @@ import (
 	"go/parser"
 	"go/token"
 	"os"
+	"runtime"
 	"strconv"
 	"strings"
 	"unicode"
@@ -66,6 +67,8 @@ func cname(s string) string {
 func (p *Package) ParseFlags(f *File, srcfile string) {
 	linesIn := strings.Split(f.Preamble, "\n", -1)
 	linesOut := make([]string, 0, len(linesIn))
+
+NextLine:
 	for _, line := range linesIn {
 		l := strings.TrimSpace(line)
 		if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
@@ -79,11 +82,29 @@ func (p *Package) ParseFlags(f *File, srcfile string) {
 			fatal("%s: bad #cgo line: %s", srcfile, line)
 		}
 
-		k := fields[0]
-		v := strings.TrimSpace(fields[1])
+		var k string
+		kf := strings.Fields(fields[0])
+		switch len(kf) {
+		case 1:
+			k = kf[0]
+		case 2:
+			k = kf[1]
+			switch kf[0] {
+			case runtime.GOOS:
+			case runtime.GOARCH:
+			case runtime.GOOS + "/" + runtime.GOARCH:
+			default:
+				continue NextLine
+			}
+		default:
+			fatal("%s: bad #cgo option: %s", srcfile, fields[0])
+		}
+
 		if k != "CFLAGS" && k != "LDFLAGS" {
 			fatal("%s: unsupported #cgo option %s", srcfile, k)
 		}
+
+		v := strings.TrimSpace(fields[1])
 		args, err := splitQuoted(v)
 		if err != nil {
 			fatal("%s: bad #cgo option %s: %s", srcfile, k, err.String())
@@ -288,7 +309,7 @@ func (p *Package) guessKinds(f *File) []*Name {
 	var b bytes.Buffer
 	b.WriteString(builtinProlog)
 	b.WriteString(f.Preamble)
-	b.WriteString("void f(void) {\n")
+	b.WriteString("void __cgo__f__(void) {\n")
 	b.WriteString("#line 0 \"cgo-test\"\n")
 	for i, n := range toSniff {
 		fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
@@ -753,6 +774,8 @@ var dwarfToName = map[string]string{
 	"double complex":         "complexdouble",
 }
 
+const signedDelta = 64
+
 // Type returns a *Type with the same memory layout as
 // dtype when used as the type of a variable or a struct field.
 func (c *typeConv) Type(dtype dwarf.Type) *Type {
@@ -818,7 +841,19 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
 		t.Align = 1
 
 	case *dwarf.EnumType:
-		switch t.Size {
+		if t.Align = t.Size; t.Align >= c.ptrSize {
+			t.Align = c.ptrSize
+		}
+		t.C = "enum " + dt.EnumName
+		signed := 0
+		t.EnumValues = make(map[string]int64)
+		for _, ev := range dt.Val {
+			t.EnumValues[ev.Name] = ev.Val
+			if ev.Val < 0 {
+				signed = signedDelta
+			}
+		}
+		switch t.Size + int64(signed) {
 		default:
 			fatal("unexpected: %d-byte enum type - %s", t.Size, dtype)
 		case 1:
@@ -829,14 +864,14 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
 			t.Go = c.uint32
 		case 8:
 			t.Go = c.uint64
-		}
-		if t.Align = t.Size; t.Align >= c.ptrSize {
-			t.Align = c.ptrSize
-		}
-		t.C = "enum " + dt.EnumName
-		t.EnumValues = make(map[string]int64)
-		for _, ev := range dt.Val {
-			t.EnumValues[ev.Name] = ev.Val
+		case 1 + signedDelta:
+			t.Go = c.int8
+		case 2 + signedDelta:
+			t.Go = c.int16
+		case 4 + signedDelta:
+			t.Go = c.int32
+		case 8 + signedDelta:
+			t.Go = c.int64
 		}
 
 	case *dwarf.FloatType:
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index a6f509d..59529a6 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -32,10 +32,11 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
 	if err != nil {
 		fatal("%s", err)
 	}
-	pid, err := os.ForkExec(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2})
+	p, err := os.StartProcess(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2})
 	if err != nil {
 		fatal("%s", err)
 	}
+	defer p.Release()
 	r0.Close()
 	w1.Close()
 	w2.Close()
@@ -55,7 +56,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
 	<-c
 	<-c
 
-	w, err := os.Wait(pid, 0)
+	w, err := p.Wait(0)
 	if err != nil {
 		fatal("%s", err)
 	}
diff --git a/src/cmd/clean.bash b/src/cmd/clean.bash
index 6349919..92d8cc5 100644
--- a/src/cmd/clean.bash
+++ b/src/cmd/clean.bash
@@ -3,9 +3,14 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+gomake=gomake
+if [ "$1" == "--gomake" -a "$2" != "" ]; then
+	gomake=$2
+fi
+
 for i in cc 6l 6a 6c 8l 8a 8c 8g 5l 5a 5c 5g gc 6g gopack nm cgo cov ebnflint godefs godoc gofmt goinstall gotest goyacc hgpatch prof
 do
 	cd $i
-	gomake clean
+	$gomake clean
 	cd ..
 done
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index ed20e7e..833eba1 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -54,7 +54,8 @@ widstruct(Type *t, uint32 o, int flag)
 		if(f->type->width < 0)
 			fatal("invalid width %lld", f->type->width);
 		w = f->type->width;
-		o = rnd(o, f->type->align);
+		if(f->type->align > 0)
+			o = rnd(o, f->type->align);
 		f->width = o;	// really offset for TFIELD
 		if(f->nname != N) {
 			// this same stackparam logic is in addrescapes
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 994840e..86e3cae 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -242,14 +242,6 @@ import_package:
 		
 		if(safemode && !curio.importsafe)
 			yyerror("cannot import unsafe package %Z", importpkg->path);
-
-		// NOTE(rsc): This is no longer a technical restriction:
-		// the 6g tool chain would work just fine without giving
-		// special meaning to a package being named main.
-		// Other implementations might need the restriction
-		// (gccgo does), so it stays in the language and the compiler.
-		if(strcmp($2->name, "main") == 0)
-			yyerror("cannot import package main");
 	}
 
 import_safety:
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 45b1257..e79d3b0 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -405,7 +405,7 @@ void
 importfile(Val *f, int line)
 {
 	Biobuf *imp;
-	char *file;
+	char *file, *p, *q;
 	int32 c;
 	int len;
 	Strlit *path;
@@ -423,6 +423,15 @@ importfile(Val *f, int line)
 		errorexit();
 	}
 
+	// The package name main is no longer reserved,
+	// but we reserve the import path "main" to identify
+	// the main package, just as we reserve the import 
+	// path "math" to identify the standard math package.
+	if(strcmp(f->u.sval->s, "main") == 0) {
+		yyerror("cannot import \"main\"");
+		errorexit();
+	}
+
 	if(strcmp(f->u.sval->s, "unsafe") == 0) {
 		if(safemode) {
 			yyerror("cannot import package unsafe");
@@ -432,7 +441,7 @@ importfile(Val *f, int line)
 		cannedimports("unsafe.6", unsafeimport);
 		return;
 	}
-
+	
 	path = f->u.sval;
 	if(islocalname(path)) {
 		cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
@@ -459,9 +468,24 @@ importfile(Val *f, int line)
 	len = strlen(namebuf);
 	if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
 		if(!skiptopkgdef(imp)) {
-			yyerror("import not package file: %s", namebuf);
+			yyerror("import %s: not a package file", file);
+			errorexit();
+		}
+	}
+	
+	// check object header
+	p = Brdstr(imp, '\n', 1);
+	if(strcmp(p, "empty archive") != 0) {
+		if(strncmp(p, "go object ", 10) != 0) {
+			yyerror("import %s: not a go object file", file);
 			errorexit();
 		}
+		q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
+		if(strcmp(p+10, q) != 0) {
+			yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
+			errorexit();
+		}
+		free(q);
 	}
 
 	// assume files move (get installed)
@@ -479,6 +503,7 @@ importfile(Val *f, int line)
 	curio.infile = file;
 	curio.nlsemi = 0;
 	typecheckok = 1;
+
 	for(;;) {
 		c = getc();
 		if(c == EOF)
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index 7b7e666..b11a4f5 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -179,7 +179,7 @@ mpdivfltflt(Mpflt *a, Mpflt *b)
 double
 mpgetflt(Mpflt *a)
 {
-	int s, i;
+	int s, i, e;
 	uvlong v, vm;
 	double f;
 
@@ -200,12 +200,12 @@ mpgetflt(Mpflt *a)
 		a->exp -= 1;
 	}
 
-	// the magic numbers (64, 63, 53, 10) are
+	// the magic numbers (64, 63, 53, 10, -1074) are
 	// IEEE specific. this should be done machine
 	// independently or in the 6g half of the compiler
 
-	// pick up the mantissa in a uvlong
-	s = 53;
+	// pick up the mantissa and a rounding bit in a uvlong
+	s = 53+1;
 	v = 0;
 	for(i=Mpnorm-1; s>=Mpscale; i--) {
 		v = (v<<Mpscale) | a->val.a[i];
@@ -224,13 +224,26 @@ mpgetflt(Mpflt *a)
 	if(s > 0)
 		v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
 
+	// gradual underflow
+	e = Mpnorm*Mpscale + a->exp - 53;
+	if(e < -1074) {
+		s = -e - 1074;
+		if(s > 54)
+			s = 54;
+		v |= vm & ((1ULL<<s) - 1);
+		vm >>= s;
+		e = -1074;
+	}
+
 //print("vm=%.16llux v=%.16llux\n", vm, v);
 	// round toward even
-	if(v != (1ULL<<63) || (vm&1ULL) != 0)
-		vm += v>>63;
+	if(v != 0 || (vm&2ULL) != 0)
+		vm = (vm>>1) + (vm&1ULL);
+	else
+		vm >>= 1;
 
 	f = (double)(vm);
-	f = ldexp(f, Mpnorm*Mpscale + a->exp - 53);
+	f = ldexp(f, e);
 
 	if(a->val.neg)
 		f = -f;
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index 0d0d70a..fbabe0d 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -21,7 +21,7 @@ dumpobj(void)
 		errorexit();
 	}
 
-	Bprint(bout, "%s\n", thestring);
+	Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
 	Bprint(bout, "  exports automatically generated from\n");
 	Bprint(bout, "  %s in package \"%s\"\n", curio.infile, localpkg->name);
 	dumpexport();
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 5686e95..58a1477 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -157,7 +157,7 @@ walkselect(Node *sel)
 			if(n->left == N || isblank(n->left))
 				n->left = nodnil();
 			else if(n->left->op == ONAME &&
-					(!n->colas || (n->class&PHEAP) == 0) &&
+					(!n->colas || (n->left->class&PHEAP) == 0) &&
 					convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
 				n->left = nod(OADDR, n->left, N);
 				n->left->etype = 1;  // pointer does not escape
@@ -170,9 +170,9 @@ walkselect(Node *sel)
 				typecheck(&a, Erv);
 				r = nod(OAS, n->left, tmp);
 				typecheck(&r, Etop);
+				cas->nbody = concat(list1(r), cas->nbody);
 				cas->nbody = concat(n->ninit, cas->nbody);
 				n->ninit = nil;
-				cas->nbody = concat(list1(r), cas->nbody);
 				n->left = a;
 			}
 		}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index cb5e2a8..0755ca3 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -203,6 +203,7 @@ fatal(char *fmt, ...)
 
 	flusherrors();
 
+*(int*)0=0;
 	print("%L: internal compiler error: ", lineno);
 	va_start(arg, fmt);
 	vfprint(1, fmt, arg);
@@ -213,7 +214,7 @@ fatal(char *fmt, ...)
 	if(strncmp(getgoversion(), "release", 7) == 0) {
 		print("\n");
 		print("Please file a bug report including a short program that triggers the error.\n");
-		print("http://code.google.com/p/go/issues/entry?template=compilerbug");
+		print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
 	}
 	hcrash();
 	errorexit();
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 931d032..5edca96 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -96,7 +96,7 @@ typecheck(Node **np, int top)
 	Node *n, *l, *r;
 	NodeList *args;
 	int lno, ok, ntop;
-	Type *t, *missing, *have;
+	Type *t, *tp, *missing, *have;
 	Sym *sym;
 	Val v;
 	char *why;
@@ -552,6 +552,7 @@ reswitch:
 			ok = Erv;
 			goto ret;
 		}
+		tp = t;
 		if(isptr[t->etype] && t->type->etype != TINTER) {
 			t = t->type;
 			if(t == T)
@@ -563,7 +564,7 @@ reswitch:
 			if(lookdot(n, t, 1))
 				yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
 			else
-				yyerror("%#N undefined (type %T has no field or method %S)", n, t, n->right->sym);
+				yyerror("%#N undefined (type %T has no field or method %S)", n, tp, n->right->sym);
 			goto error;
 		}
 		switch(n->op) {
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
index 66b01aa..da1466b 100644
--- a/src/cmd/godoc/format.go
+++ b/src/cmd/godoc/format.go
@@ -11,7 +11,6 @@
 package main
 
 import (
-	"bytes"
 	"fmt"
 	"go/scanner"
 	"go/token"
@@ -335,12 +334,12 @@ func selectionTag(w io.Writer, text []byte, selections int) {
 }
 
 
-// FormatText HTML-escapes text and returns it wrapped in <pre> tags.
-// Conscutive text segments are wrapped in HTML spans (with tags as
+// FormatText HTML-escapes text and writes it to w.
+// Consecutive text segments are wrapped in HTML spans (with tags as
 // defined by startTags and endTag) as follows:
 //
-//	- if line >= 0, line numbers are printed before each line, starting
-//	  with the value of line
+//	- if line >= 0, line number (ln) spans are inserted before each line,
+//	  starting with the value of line
 //	- if the text is Go source, comments get the "comment" span class
 //	- each occurrence of the regular expression pattern gets the "highlight"
 //	  span class
@@ -349,10 +348,7 @@ func selectionTag(w io.Writer, text []byte, selections int) {
 // Comments, highlights, and selections may overlap arbitrarily; the respective
 // HTML span classes are specified in the startTags variable.
 //
-func FormatText(text []byte, line int, goSource bool, pattern string, selection Selection) []byte {
-	var buf bytes.Buffer
-	buf.WriteString("<pre>\n")
-
+func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) {
 	var comments, highlights Selection
 	if goSource {
 		comments = commentSelection(text)
@@ -370,11 +366,8 @@ func FormatText(text []byte, line int, goSource bool, pattern string, selection
 				}
 			}
 		}
-		FormatSelections(&buf, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
+		FormatSelections(w, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
 	} else {
-		template.HTMLEscape(&buf, text)
+		template.HTMLEscape(w, text)
 	}
-
-	buf.WriteString("</pre>\n")
-	return buf.Bytes()
 }
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 6a00a3e..c91dc33 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -274,7 +274,7 @@ func relativePath(path string) string {
 // ----------------------------------------------------------------------------
 // Tab conversion
 
-var spaces = []byte("                ") // 16 spaces seems like a good number
+var spaces = []byte("                                ") // 32 spaces seems like a good number
 
 const (
 	indenting = iota
@@ -291,25 +291,31 @@ type tconv struct {
 
 func (p *tconv) writeIndent() (err os.Error) {
 	i := p.indent
-	for i > len(spaces) {
+	for i >= len(spaces) {
 		i -= len(spaces)
 		if _, err = p.output.Write(spaces); err != nil {
 			return
 		}
 	}
-	_, err = p.output.Write(spaces[0:i])
+	// i < len(spaces)
+	if i > 0 {
+		_, err = p.output.Write(spaces[0:i])
+	}
 	return
 }
 
 
 func (p *tconv) Write(data []byte) (n int, err os.Error) {
+	if len(data) == 0 {
+		return
+	}
 	pos := 0 // valid if p.state == collecting
 	var b byte
 	for n, b = range data {
 		switch p.state {
 		case indenting:
 			switch b {
-			case '\t', '\v':
+			case '\t':
 				p.indent += *tabwidth
 			case '\n':
 				p.indent = 0
@@ -336,7 +342,7 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) {
 		}
 	}
 	n = len(data)
-	if p.state == collecting {
+	if pos < n && p.state == collecting {
 		_, err = p.output.Write(data[pos:])
 	}
 	return
@@ -346,47 +352,51 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) {
 // ----------------------------------------------------------------------------
 // Templates
 
-// Write an AST-node to w; optionally html-escaped.
-func writeNode(w io.Writer, fset *token.FileSet, node interface{}, html bool) {
-	mode := printer.TabIndent | printer.UseSpaces
-	if html {
-		mode |= printer.GenHTML
-	}
+// Write an AST node to w.
+func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
 	// convert trailing tabs into spaces using a tconv filter
 	// to ensure a good outcome in most browsers (there may still
 	// be tabs in comments and strings, but converting those into
 	// the right number of spaces is much harder)
-	(&printer.Config{mode, *tabwidth, nil}).Fprint(&tconv{output: w}, fset, node)
+	//
+	// TODO(gri) rethink printer flags - perhaps tconv can be eliminated
+	//           with an another printer mode (which is more efficiently
+	//           implemented in the printer than here with another layer)
+	mode := printer.TabIndent | printer.UseSpaces
+	(&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
 }
 
 
-// Write text to w; optionally html-escaped.
-func writeText(w io.Writer, text []byte, html bool) {
-	if html {
-		template.HTMLEscape(w, text)
-		return
+// Write anything to w.
+func writeAny(w io.Writer, fset *token.FileSet, x interface{}) {
+	switch v := x.(type) {
+	case []byte:
+		w.Write(v)
+	case string:
+		w.Write([]byte(v))
+	case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
+		writeNode(w, fset, x)
+	default:
+		fmt.Fprint(w, x)
 	}
-	w.Write(text)
 }
 
 
-// Write anything to w; optionally html-escaped.
-func writeAny(w io.Writer, fset *token.FileSet, html bool, x interface{}) {
+// Write anything html-escaped to w.
+func writeAnyHTML(w io.Writer, fset *token.FileSet, x interface{}) {
 	switch v := x.(type) {
 	case []byte:
-		writeText(w, v, html)
+		template.HTMLEscape(w, v)
 	case string:
-		writeText(w, []byte(v), html)
+		template.HTMLEscape(w, []byte(v))
 	case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
-		writeNode(w, fset, x, html)
+		var buf bytes.Buffer
+		writeNode(&buf, fset, x)
+		FormatText(w, buf.Bytes(), -1, true, "", nil)
 	default:
-		if html {
-			var buf bytes.Buffer
-			fmt.Fprint(&buf, x)
-			writeText(w, buf.Bytes(), true)
-		} else {
-			fmt.Fprint(w, x)
-		}
+		var buf bytes.Buffer
+		fmt.Fprint(&buf, x)
+		template.HTMLEscape(w, buf.Bytes())
 	}
 }
 
@@ -401,24 +411,16 @@ func fileset(x []interface{}) *token.FileSet {
 }
 
 
-// Template formatter for "html" format.
-func htmlFmt(w io.Writer, format string, x ...interface{}) {
-	writeAny(w, fileset(x), true, x[0])
-}
-
-
 // Template formatter for "html-esc" format.
 func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
-	var buf bytes.Buffer
-	writeAny(&buf, fileset(x), false, x[0])
-	template.HTMLEscape(w, buf.Bytes())
+	writeAnyHTML(w, fileset(x), x[0])
 }
 
 
 // Template formatter for "html-comment" format.
 func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
 	var buf bytes.Buffer
-	writeAny(&buf, fileset(x), false, x[0])
+	writeAny(&buf, fileset(x), x[0])
 	// TODO(gri) Provide list of words (e.g. function parameters)
 	//           to be emphasized by ToHTML.
 	doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
@@ -427,14 +429,14 @@ func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
 
 // Template formatter for "" (default) format.
 func textFmt(w io.Writer, format string, x ...interface{}) {
-	writeAny(w, fileset(x), false, x[0])
+	writeAny(w, fileset(x), x[0])
 }
 
 
 // Template formatter for "urlquery-esc" format.
 func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
 	var buf bytes.Buffer
-	writeAny(&buf, fileset(x), false, x[0])
+	writeAny(&buf, fileset(x), x[0])
 	template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes()))))
 }
 
@@ -603,7 +605,6 @@ func numlinesFmt(w io.Writer, format string, x ...interface{}) {
 
 var fmap = template.FormatterMap{
 	"":             textFmt,
-	"html":         htmlFmt,
 	"html-esc":     htmlEscFmt,
 	"html-comment": htmlCommentFmt,
 	"urlquery-esc": urlQueryEscFmt,
@@ -683,7 +684,7 @@ func servePage(w http.ResponseWriter, title, subtitle, query string, content []b
 		content,
 	}
 
-	if err := godocHTML.Execute(&d, w); err != nil {
+	if err := godocHTML.Execute(w, &d); err != nil {
 		log.Printf("godocHTML.Execute: %s", err)
 	}
 }
@@ -751,7 +752,7 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
 
 func applyTemplate(t *template.Template, name string, data interface{}) []byte {
 	var buf bytes.Buffer
-	if err := t.Execute(data, &buf); err != nil {
+	if err := t.Execute(&buf, data); err != nil {
 		log.Printf("%s.Execute: %s", name, err)
 	}
 	return buf.Bytes()
@@ -775,8 +776,12 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
 		return
 	}
 
-	contents := FormatText(src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
-	servePage(w, title+" "+relpath, "", "", contents)
+	var buf bytes.Buffer
+	buf.WriteString("<pre>")
+	FormatText(&buf, src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+	buf.WriteString("</pre>")
+
+	servePage(w, title+" "+relpath, "", "", buf.Bytes())
 }
 
 
@@ -891,6 +896,11 @@ type PageInfo struct {
 }
 
 
+func (info *PageInfo) IsEmpty() bool {
+	return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
+}
+
+
 type httpHandler struct {
 	pattern string // url pattern; e.g. "/pkg/"
 	fsRoot  string // file system root to which the pattern is mapped
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 581409c..56f31f5 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -430,7 +430,6 @@ func (a *AltWords) filter(s string) *AltWords {
 // Indexer
 
 // Adjust these flags as seems best.
-const includeNonGoFiles = true
 const includeMainPackages = true
 const includeTestFiles = true
 
@@ -728,7 +727,7 @@ func isWhitelisted(filename string) bool {
 }
 
 
-func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
+func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool) {
 	if !f.IsRegular() {
 		return
 	}
@@ -746,7 +745,7 @@ func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
 		}
 		goFile = true
 
-	case !includeNonGoFiles || !isWhitelisted(f.Name):
+	case !fulltextIndex || !isWhitelisted(f.Name):
 		return
 	}
 
@@ -811,7 +810,7 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
 		}
 		for _, f := range list {
 			if !f.IsDirectory() {
-				x.visitFile(dirname, f)
+				x.visitFile(dirname, f, fulltextIndex)
 			}
 		}
 	}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index f1b11a7..ea1e3c4 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -83,20 +83,21 @@ func exec(rw http.ResponseWriter, args []string) (status int) {
 	if *verbose {
 		log.Printf("executing %v", args)
 	}
-	pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds)
+	p, err := os.StartProcess(bin, args, os.Environ(), *goroot, fds)
 	defer r.Close()
 	w.Close()
 	if err != nil {
-		log.Printf("os.ForkExec(%q): %v", bin, err)
+		log.Printf("os.StartProcess(%q): %v", bin, err)
 		return 2
 	}
+	defer p.Release()
 
 	var buf bytes.Buffer
 	io.Copy(&buf, r)
-	wait, err := os.Wait(pid, 0)
+	wait, err := p.Wait(0)
 	if err != nil {
 		os.Stderr.Write(buf.Bytes())
-		log.Printf("os.Wait(%d, 0): %v", pid, err)
+		log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
 		return 2
 	}
 	status = wait.ExitStatus()
@@ -317,7 +318,7 @@ func main() {
 	}
 	relpath := path
 	abspath := path
-	if len(path) > 0 && path[0] != '/' {
+	if !pathutil.IsAbs(path) {
 		abspath = absolutePath(path, pkgHandler.fsRoot)
 	} else {
 		relpath = relativePath(path)
@@ -336,12 +337,17 @@ func main() {
 	//            if there are multiple packages in a directory.
 	info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
 
-	if info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
+	if info.IsEmpty() {
 		// try again, this time assume it's a command
-		if len(path) > 0 && path[0] != '/' {
+		if !pathutil.IsAbs(path) {
 			abspath = absolutePath(path, cmdHandler.fsRoot)
 		}
-		info = cmdHandler.getPageInfo(abspath, relpath, "", mode)
+		cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
+		// only use the cmdInfo if it actually contains a result
+		// (don't hide errors reported from looking up a package)
+		if !cmdInfo.IsEmpty() {
+			info = cmdInfo
+		}
 	}
 	if info.Err != nil {
 		log.Fatalf("%v", info.Err)
@@ -366,7 +372,11 @@ func main() {
 				if i > 0 {
 					fmt.Println()
 				}
-				writeAny(os.Stdout, info.FSet, *html, d)
+				if *html {
+					writeAnyHTML(os.Stdout, info.FSet, d)
+				} else {
+					writeAny(os.Stdout, info.FSet, d)
+				}
 				fmt.Println()
 			}
 			return
@@ -376,7 +386,7 @@ func main() {
 		}
 	}
 
-	if err := packageText.Execute(info, os.Stdout); err != nil {
+	if err := packageText.Execute(os.Stdout, info); err != nil {
 		log.Printf("packageText.Execute: %s", err)
 	}
 }
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
index c2838ed..c5f4c1e 100755
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -25,9 +25,14 @@ type Snippet struct {
 
 func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
 	// TODO instead of pretty-printing the node, should use the original source instead
-	var buf bytes.Buffer
-	writeNode(&buf, fset, decl, false)
-	return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)}
+	var buf1 bytes.Buffer
+	writeNode(&buf1, fset, decl)
+	// wrap text with <pre> tag
+	var buf2 bytes.Buffer
+	buf2.WriteString("<pre>")
+	FormatText(&buf2, buf1.Bytes(), -1, true, id.Name, nil)
+	buf2.WriteString("</pre>")
+	return &Snippet{fset.Position(id.Pos()).Line, buf2.Bytes()}
 }
 
 
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index a032bd3..cc028cc 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -60,10 +60,10 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string {
 			continue // ignore empty paths (don't assume ".")
 		}
 		// len(path) > 0: normalize path
-		if path[0] != '/' {
-			path = pathutil.Join(cwd, path)
-		} else {
+		if pathutil.IsAbs(path) {
 			path = pathutil.Clean(path)
+		} else {
+			path = pathutil.Join(cwd, path)
 		}
 		// we have a non-empty absolute path
 		if filter != nil && !filter(path) {
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index d7b70c4..41c12b8 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -113,19 +113,20 @@ func processFile(f *os.File) os.Error {
 		simplify(file)
 	}
 
-	var res bytes.Buffer
-	_, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, fset, file)
+	var buf bytes.Buffer
+	_, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
 	if err != nil {
 		return err
 	}
+	res := buf.Bytes()
 
-	if bytes.Compare(src, res.Bytes()) != 0 {
+	if !bytes.Equal(src, res) {
 		// formatting has changed
 		if *list {
 			fmt.Fprintln(os.Stdout, f.Name())
 		}
 		if *write {
-			err = ioutil.WriteFile(f.Name(), res.Bytes(), 0)
+			err = ioutil.WriteFile(f.Name(), res, 0)
 			if err != nil {
 				return err
 			}
@@ -133,7 +134,7 @@ func processFile(f *os.File) os.Error {
 	}
 
 	if !*list && !*write {
-		_, err = os.Stdout.Write(res.Bytes())
+		_, err = os.Stdout.Write(res)
 	}
 
 	return err
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
index b5f4de1..2f60a3e 100755
--- a/src/cmd/gofmt/test.sh
+++ b/src/cmd/gofmt/test.sh
@@ -42,7 +42,7 @@ apply1() {
 	bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
 	bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
 	bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
-	bug302.go | bug306.go ) return ;;
+	bug302.go | bug306.go | bug322.go ) return ;;
 	esac
 	# the following directories are skipped because they contain test
 	# cases for syntax errors and thus won't parse in the first place:
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index 93a648b..8d4d6c5 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -75,7 +75,7 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) {
 
 	var buf bytes.Buffer
 	md := makedata{pkg, goFiles, cgoFiles, oFiles}
-	if err := makefileTemplate.Execute(&md, &buf); err != nil {
+	if err := makefileTemplate.Execute(&buf, &md); err != nil {
 		return nil, err
 	}
 	return buf.Bytes(), nil
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index a16e98c..702f104 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -131,6 +131,7 @@ Arfile *astart, *amiddle, *aend;	/* Temp file control block pointers */
 int	allobj = 1;			/* set when all members are object files of the same type */
 int	symdefsize;			/* size of symdef file */
 char	*pkgstmt;		/* string "package foo" */
+char	*objhdr;		/* string "go object darwin 386 release.2010-01-01 2345+" */
 int	dupfound;			/* flag for duplicate symbol */
 Hashchain	*hash[NHASH];		/* hash table of text symbols */
 
@@ -246,6 +247,8 @@ main(int argc, char *argv[])
 	argc -= 3;
 	argv += 3;
 	(*comfun)(cp, argc, argv);	/* do the command */
+	if(errors && cflag)
+		remove(cp);
 	cp = 0;
 	while (argc--) {
 		if (*argv) {
@@ -590,10 +593,11 @@ void
 scanobj(Biobuf *b, Arfile *ap, long size)
 {
 	int obj;
-	vlong offset;
+	vlong offset, offset1;
 	Dir *d;
 	static int lastobj = -1;
 	uchar buf[4];
+	char *p;
 
 	if (!allobj)			/* non-object file encountered */
 		return;
@@ -628,14 +632,32 @@ scanobj(Biobuf *b, Arfile *ap, long size)
 		Bseek(b, offset, 0);
 		return;
 	}
-	if (lastobj >= 0 && obj != lastobj) {
+
+	offset1 = Boffset(b);
+	Bseek(b, offset, 0);
+	p = Brdstr(b, '\n', 1);
+	Bseek(b, offset1, 0);
+	if(p == nil || strncmp(p, "go object ", 10) != 0) {
+		fprint(2, "gopack: malformed object file %s\n", file);
+		errors++;
+		Bseek(b, offset, 0);
+		free(p);
+		return;
+	}
+	
+	if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) {
 		fprint(2, "gopack: inconsistent object file %s\n", file);
 		errors++;
 		allobj = 0;
-		Bseek(b, offset, 0);
+		free(p);
 		return;
 	}
 	lastobj = obj;
+	if(objhdr == nil)
+		objhdr = p;
+	else
+		free(p);
+		
 	if (!readar(b, obj, offset+size, 0)) {
 		fprint(2, "gopack: invalid symbol reference in file %s\n", file);
 		errors++;
@@ -677,7 +699,7 @@ char*	importblock;
 void
 getpkgdef(char **datap, int *lenp)
 {
-	char *tag;
+	char *tag, *hdr;
 
 	if(pkgname == nil) {
 		pkgname = "__emptyarchive__";
@@ -688,7 +710,11 @@ getpkgdef(char **datap, int *lenp)
 	if(safe || Sflag)
 		tag = "safe";
 
-	*datap = smprint("import\n$$\npackage %s %s\n%s\n$$\n", pkgname, tag, importblock);
+	hdr = "empty archive";
+	if(objhdr != nil)
+		hdr = objhdr;
+
+	*datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock);
 	*lenp = strlen(*datap);
 }
 
diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest
index 87c6800..69eaae7 100755
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -119,6 +119,12 @@ nmgrep() {
 	done
 }
 
+localname() {
+	# The package main has been renamed to __main__ when imported.
+	# Adjust its uses.
+	echo $1 | sed 's/^main\./__main__./'
+}
+
 importpath=$(gomake -s importpath)
 {
 	# test functions are named TestFoo
@@ -139,9 +145,20 @@ importpath=$(gomake -s importpath)
 	echo
 	# imports
 	if echo "$tests" | egrep -v '_test\.' >/dev/null; then
-		if [ "$importpath" != "testing" ]; then
+		case "$importpath" in
+		testing)
+			;;
+		main)
+			# Import path main is reserved, so import with
+			# explicit reference to ./_test/main instead.
+			# Also, the file we are writing defines a function named main,
+			# so rename this import to __main__ to avoid name conflict.
+			echo 'import __main__ "./_test/main"'
+			;;
+		*)
 			echo 'import "'$importpath'"'
-		fi
+			;;
+		esac
 	fi
 	if $havex; then
 		echo 'import "./_xtest_"'
@@ -153,23 +170,20 @@ importpath=$(gomake -s importpath)
 	echo 'var tests = []testing.InternalTest{'
 	for i in $tests
 	do
-		echo '	{"'$i'", '$i'},'
+		j=$(localname $i)
+		echo '	{"'$i'", '$j'},'
 	done
 	echo '}'
 	# benchmark array
-	if [ "$benchmarks" = "" ]
-	then
-		# keep the empty array gofmt-safe.
-		# (not an issue for the test array, which is never empty.)
-		echo 'var benchmarks = []testing.InternalBenchmark{}'
-	else
-		echo 'var benchmarks = []testing.InternalBenchmark{'
-		for i in $benchmarks
-		do
-			echo '	{"'$i'", '$i'},'
-		done
-		echo '}'
-	fi
+	# The comment makes the multiline declaration
+	# gofmt-safe even when there are no benchmarks.
+	echo 'var benchmarks = []testing.InternalBenchmark{ //'
+	for i in $benchmarks
+	do
+		j=$(localname $i)
+		echo '	{"'$i'", '$j'},'
+	done
+	echo '}'
 	# body
 	echo
 	echo 'func main() {'
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 8966b2a..2c6a6d0 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -148,8 +148,6 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
 		}
 		if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0)
 			fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name);
-		else if(strcmp(pkg, "main") != 0 && strcmp(name, "main") == 0)
-			fprint(2, "%s: %s: importing %s, found package main", argv0, filename, pkg);
 		loadpkgdata(filename, pkg, p0, p1 - p0);
 	}
 
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index b1a62f2..c144d42 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -378,10 +378,9 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
 	int n, c1, c2, c3, c4;
 	uint32 magic;
 	vlong import0, import1, eof;
-	char src[1024];
+	char *t;
 
 	eof = Boffset(f) + len;
-	src[0] = '\0';
 
 	pn = strdup(pn);
 	
@@ -415,22 +414,34 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
 	line = Brdline(f, '\n');
 	if(line == nil) {
 		if(Blinelen(f) > 0) {
-			diag("%s: malformed object file", pn);
+			diag("%s: not an object file", pn);
 			return;
 		}
 		goto eof;
 	}
 	n = Blinelen(f) - 1;
-	if(n != strlen(thestring) || strncmp(line, thestring, n) != 0) {
-		if(line)
-			line[n] = '\0';
+	line[n] = '\0';
+	if(strncmp(line, "go object ", 10) != 0) {
 		if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
 			print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
 			errorexit();
 		}
-		diag("file not %s [%s]\n", thestring, line);
+		if(strcmp(line, thestring) == 0) {
+			// old header format: just $GOOS
+			diag("%s: stale object file", pn);
+			return;
+		}
+		diag("%s: not an object file", pn);
+		return;
+	}
+	t = smprint("%s %s %s", getgoos(), thestring, getgoversion());
+	if(strcmp(line+10, t) != 0) {
+		diag("%s: object is [%s] expected [%s]", pn, line+10, t);
+		free(t);
 		return;
 	}
+	free(t);
+	line[n] = '\n';
 
 	/* skip over exports and other info -- ends with \n!\n */
 	import0 = Boffset(f);
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 4ac5d37..16dfb0d 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -156,6 +156,7 @@ vlong	adduint8(Sym*, uint8);
 vlong	adduint16(Sym*, uint16);
 void	asmsym(void);
 void	asmelfsym64(void);
+void	asmplan9sym(void);
 void	strnput(char*, int);
 void	dodata(void);
 void	address(void);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 26e4def..22777b6 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -136,6 +136,62 @@ asmelfsym32(void)
 	genasmsym(putelfsym32);
 }
 
+void
+putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+	int i;
+		
+	switch(t) {
+	case 'T':
+	case 't':
+	case 'L':
+	case 'l':
+	case 'D':
+	case 'd':
+	case 'B':
+	case 'b':
+	case 'a':
+	case 'p':
+	
+	case 'f':
+	case 'z':
+	case 'Z':
+		
+	case 'm':
+		lputb(addr);
+		cput(t+0x80); /* 0x80 is variable length */
+		
+		if(t == 'z' || t == 'Z') {
+			cput(0);
+			for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+				cput(s[i]);
+				cput(s[i+1]);
+			}
+			cput(0);
+			cput(0);
+			i++;
+		} else {
+			/* skip the '<' in filenames */
+			if(t=='f')
+				s++;
+			
+			for(i=0; s[i]; i++)
+				cput(s[i]);
+			cput(0);
+		}
+		
+		symsize += 4 + 1 + i + 1;
+		break;
+	default:
+		return;
+	};	
+}
+
+void
+asmplan9sym(void)
+{
+	genasmsym(putplan9sym);
+}
 
 static Sym *symt;
 
@@ -165,6 +221,52 @@ slputb(int32 v)
 }
 
 void
+wputl(ushort w)
+{
+	cput(w);
+	cput(w>>8);
+}
+
+void
+wputb(ushort w)
+{
+	cput(w>>8);
+	cput(w);
+}
+
+void
+lputb(int32 l)
+{
+	cput(l>>24);
+	cput(l>>16);
+	cput(l>>8);
+	cput(l);
+}
+
+void
+lputl(int32 l)
+{
+	cput(l);
+	cput(l>>8);
+	cput(l>>16);
+	cput(l>>24);
+}
+
+void
+vputb(uint64 v)
+{
+	lputb(v>>32);
+	lputb(v);
+}
+
+void
+vputl(uint64 v)
+{
+	lputl(v);
+	lputl(v >> 32);
+}
+
+void
 putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
 {
 	int i, f, l;
diff --git a/src/env.bash b/src/env.bash
index 2518c42..4fc7628 100644
--- a/src/env.bash
+++ b/src/env.bash
@@ -38,7 +38,7 @@ fi
 
 # Tried to use . <($MAKE ...) here, but it cannot set environment
 # variables in the version of bash that ships with OS X.  Amazing.
-eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GO_ENV')
+eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GOHOSTARCH|GOHOSTOS|GO_ENV')
 
 # Shell doesn't tell us whether make succeeded,
 # so Make.inc generates a fake variable name.
diff --git a/src/libmach/obj.c b/src/libmach/obj.c
index dacb2ae..1ffe7a0 100644
--- a/src/libmach/obj.c
+++ b/src/libmach/obj.c
@@ -116,34 +116,24 @@ objtype(Biobuf *bp, char **name)
 	int i;
 	char buf[MAXIS];
 	int c;
-
-Retry:
-	if(Bread(bp, buf, MAXIS) < MAXIS)
-		return -1;
-	Bseek(bp, -MAXIS, 1);
-	for (i = 0; i < Maxobjtype; i++) {
-		if (obj[i].is && (*obj[i].is)(buf)) {
-			if (name)
-				*name = obj[i].name;
-			return i;
-		}
-	}
+	char *p;
 
 	/*
-	 * Maybe there's an import block we need to skip
+	 * Look for import block.
 	 */
-	for(i = 0; i < MAXIS; i++) {
-		if(isalpha(buf[i]) || isdigit(buf[i]))
-			continue;
-		if(i == 0 || buf[i] != '\n')
-			return -1;
-		break;
-	}
+	p = Brdline(bp, '\n');
+	if(p == nil)
+		return -1;
+	if(Blinelen(bp) < 10 || strncmp(p, "go object ", 10) != 0)
+		return -1;
+	Bseek(bp, -1, 1);
 
 	/*
 	 * Found one.  Skip until "\n!\n"
 	 */
-	while((c = Bgetc(bp)) != Beof) {
+	for(;;) {
+		if((c = Bgetc(bp)) == Beof)
+			return -1;
 		if(c != '\n')
 			continue;
 		c = Bgetc(bp);
@@ -156,8 +146,20 @@ Retry:
 			Bungetc(bp);
 			continue;
 		}
-		goto Retry;
+		break;
 	}
+
+	if(Bread(bp, buf, MAXIS) < MAXIS)
+		return -1;
+	Bseek(bp, -MAXIS, 1);
+	for (i = 0; i < Maxobjtype; i++) {
+		if (obj[i].is && (*obj[i].is)(buf)) {
+			if (name)
+				*name = obj[i].name;
+			return i;
+		}
+	}
+
 	return -1;
 }
 
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index 6ba6951..619167c 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -187,7 +187,7 @@ NOBENCH=\
 
 # Disable tests that depend on an external network.
 ifeq ($(DISABLE_NET_TESTS),1)
-NOTEST+=http net
+NOTEST+=http net syslog
 endif
 
 # Disable tests that windows cannot run yet.
@@ -211,19 +211,19 @@ test.dirs: $(addsuffix .test, $(TEST))
 bench.dirs: $(addsuffix .bench, $(BENCH))
 
 %.clean:
-	+cd $* && gomake clean
+	+cd $* && $(MAKE) clean
 
 %.install:
-	+cd $* && gomake install
+	+cd $* && $(MAKE) install
 
 %.nuke:
-	+cd $* && gomake nuke
+	+cd $* && $(MAKE) nuke
 
 %.test:
-	+cd $* && gomake test
+	+cd $* && $(MAKE) test
 
 %.bench:
-	+cd $* && gomake bench
+	+cd $* && $(MAKE) bench
 
 clean: clean.dirs
 
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index 579ba16..d8d9bba 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -42,6 +42,10 @@ type File struct {
 	bodyOffset   int64
 }
 
+func (f *File) hasDataDescriptor() bool {
+	return f.Flags&0x8 != 0
+}
+
 // OpenReader will open the Zip file specified by name and return a Reader.
 func OpenReader(name string) (*Reader, os.Error) {
 	f, err := os.Open(name, os.O_RDONLY, 0644)
@@ -93,7 +97,16 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
 			return
 		}
 	}
-	r := io.NewSectionReader(f.zipr, off+f.bodyOffset, int64(f.CompressedSize))
+	size := int64(f.CompressedSize)
+	if f.hasDataDescriptor() {
+		if size == 0 {
+			// permit SectionReader to see the rest of the file
+			size = f.zipsize - (off + f.bodyOffset)
+		} else {
+			size += dataDescriptorLen
+		}
+	}
+	r := io.NewSectionReader(f.zipr, off+f.bodyOffset, size)
 	switch f.Method {
 	case 0: // store (no compression)
 		rc = nopCloser{r}
@@ -103,7 +116,7 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
 		err = UnsupportedMethod
 	}
 	if rc != nil {
-		rc = &checksumReader{rc, crc32.NewIEEE(), f.CRC32}
+		rc = &checksumReader{rc, crc32.NewIEEE(), f, r}
 	}
 	return
 }
@@ -111,7 +124,8 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
 type checksumReader struct {
 	rc   io.ReadCloser
 	hash hash.Hash32
-	sum  uint32
+	f    *File
+	zipr io.Reader // for reading the data descriptor
 }
 
 func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
@@ -120,7 +134,12 @@ func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
 	if err != os.EOF {
 		return
 	}
-	if r.hash.Sum32() != r.sum {
+	if r.f.hasDataDescriptor() {
+		if err = readDataDescriptor(r.zipr, r.f); err != nil {
+			return
+		}
+	}
+	if r.hash.Sum32() != r.f.CRC32 {
 		err = ChecksumError
 	}
 	return
@@ -205,6 +224,18 @@ func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
 	return
 }
 
+func readDataDescriptor(r io.Reader, f *File) (err os.Error) {
+	defer func() {
+		if rerr, ok := recover().(os.Error); ok {
+			err = rerr
+		}
+	}()
+	read(r, &f.CRC32)
+	read(r, &f.CompressedSize)
+	read(r, &f.UncompressedSize)
+	return
+}
+
 func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
 	// look for directoryEndSignature in the last 1k, then in the last 65k
 	var b []byte
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index 3c24f14..72e8ccc 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -52,6 +52,15 @@ var tests = []ZipTest{
 	},
 	{Name: "readme.zip"},
 	{Name: "readme.notzip", Error: FormatError},
+	{
+		Name: "dd.zip",
+		File: []ZipTestFile{
+			{
+				Name:    "filename",
+				Content: []byte("This is a test textfile.\n"),
+			},
+		},
+	},
 }
 
 func TestReader(t *testing.T) {
@@ -102,16 +111,18 @@ func readTestZip(t *testing.T, zt ZipTest) {
 	}
 
 	// test invalid checksum
-	z.File[0].CRC32++ // invalidate
-	r, err := z.File[0].Open()
-	if err != nil {
-		t.Error(err)
-		return
-	}
-	var b bytes.Buffer
-	_, err = io.Copy(&b, r)
-	if err != ChecksumError {
-		t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+	if !z.File[0].hasDataDescriptor() { // skip test when crc32 in dd
+		z.File[0].CRC32++ // invalidate
+		r, err := z.File[0].Open()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		var b bytes.Buffer
+		_, err = io.Copy(&b, r)
+		if err != ChecksumError {
+			t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+		}
 	}
 }
 
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 8a8c727..bfe0aae 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -4,6 +4,7 @@ const (
 	fileHeaderSignature      = 0x04034b50
 	directoryHeaderSignature = 0x02014b50
 	directoryEndSignature    = 0x06054b50
+	dataDescriptorLen        = 12
 )
 
 type FileHeader struct {
diff --git a/src/pkg/archive/zip/testdata/dd.zip b/src/pkg/archive/zip/testdata/dd.zip
new file mode 100644
index 0000000..e53378b
Binary files /dev/null and b/src/pkg/archive/zip/testdata/dd.zip differ
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/asn1/marshal.go
index 2454871..57b8f20 100644
--- a/src/pkg/asn1/marshal.go
+++ b/src/pkg/asn1/marshal.go
@@ -317,7 +317,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
 	switch v := value.(type) {
 	case *reflect.BoolValue:
 		if v.Get() {
-			return out.WriteByte(1)
+			return out.WriteByte(255)
 		} else {
 			return out.WriteByte(0)
 		}
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 4aa7437..1acd4e0 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -154,17 +154,20 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
 }
 
 // WriteTo writes data to w until the buffer is drained or an error
-// occurs. The return value n is the number of bytes written.
+// occurs. The return value n is the number of bytes written; it always
+// fits into an int, but it is int64 to match the io.WriterTo interface.
 // Any error encountered during the write is also returned.
 func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
 	b.lastRead = opInvalid
-	for b.off < len(b.buf) {
+	if b.off < len(b.buf) {
 		m, e := w.Write(b.buf[b.off:])
-		n += int64(m)
 		b.off += m
+		n = int64(m)
 		if e != nil {
 			return n, e
 		}
+		// otherwise all bytes were written, by definition of
+		// Write method in io.Writer
 	}
 	// Buffer is now empty; reset.
 	b.Truncate(0)
@@ -309,13 +312,14 @@ func (b *Buffer) UnreadByte() os.Error {
 // delim.
 func (b *Buffer) ReadBytes(delim byte) (line []byte, err os.Error) {
 	i := IndexByte(b.buf[b.off:], delim)
-	size := i + 1 - b.off
+	size := i + 1
 	if i < 0 {
 		size = len(b.buf) - b.off
 		err = os.EOF
 	}
 	line = make([]byte, size)
 	copy(line, b.buf[b.off:])
+	b.off += size
 	return
 }
 
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
index 2af9ffd..56a2d92 100644
--- a/src/pkg/bytes/buffer_test.go
+++ b/src/pkg/bytes/buffer_test.go
@@ -350,25 +350,36 @@ func TestNext(t *testing.T) {
 }
 
 var readBytesTests = []struct {
-	buffer   []byte
+	buffer   string
 	delim    byte
-	expected []byte
+	expected []string
 	err      os.Error
 }{
-	{err: os.EOF},
-	{[]byte{}, 0, []byte{}, os.EOF},
-	{[]byte("a\x00"), 0, []byte("a\x00"), nil},
-	{[]byte("hello\x01world"), 1, []byte("hello\x01"), nil},
-	{[]byte("foo\nbar"), 0, []byte("foo\nbar"), os.EOF},
-	{[]byte("alpha beta gamma"), ' ', []byte("alpha "), nil},
+	{"", 0, []string{""}, os.EOF},
+	{"a\x00", 0, []string{"a\x00"}, nil},
+	{"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil},
+	{"hello\x01world", 1, []string{"hello\x01"}, nil},
+	{"foo\nbar", 0, []string{"foo\nbar"}, os.EOF},
+	{"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil},
+	{"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, os.EOF},
 }
 
 func TestReadBytes(t *testing.T) {
 	for _, test := range readBytesTests {
-		buf := NewBuffer(test.buffer)
-		bytes, err := buf.ReadBytes(test.delim)
-		if !Equal(bytes, test.expected) || err != test.err {
-			t.Errorf("expected %q, %v got %q, %v", test.expected, test.err, bytes, err)
+		buf := NewBufferString(test.buffer)
+		var err os.Error
+		for _, expected := range test.expected {
+			var bytes []byte
+			bytes, err = buf.ReadBytes(test.delim)
+			if string(bytes) != expected {
+				t.Errorf("expected %q, got %q", expected, bytes)
+			}
+			if err != nil {
+				break
+			}
+		}
+		if err != test.err {
+			t.Errorf("expected error %v, got %v", test.err, err)
 		}
 	}
 }
diff --git a/src/pkg/container/ring/ring.go b/src/pkg/container/ring/ring.go
index 335afbc..5925164 100644
--- a/src/pkg/container/ring/ring.go
+++ b/src/pkg/container/ring/ring.go
@@ -138,16 +138,13 @@ func (r *Ring) Len() int {
 }
 
 
-func (r *Ring) Iter() <-chan interface{} {
-	c := make(chan interface{})
-	go func() {
-		if r != nil {
-			c <- r.Value
-			for p := r.Next(); p != r; p = p.next {
-				c <- p.Value
-			}
+// Do calls function f on each element of the ring, in forward order.
+// The behavior of Do is undefined if f changes *r.
+func (r *Ring) Do(f func(interface{})) {
+	if r != nil {
+		f(r.Value)
+		for p := r.Next(); p != r; p = p.next {
+			f(p.Value)
 		}
-		close(c)
-	}()
-	return c
+	}
 }
diff --git a/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
index ee3c411..778c083 100644
--- a/src/pkg/container/ring/ring_test.go
+++ b/src/pkg/container/ring/ring_test.go
@@ -35,12 +35,12 @@ func verify(t *testing.T, r *Ring, N int, sum int) {
 	// iteration
 	n = 0
 	s := 0
-	for p := range r.Iter() {
+	r.Do(func(p interface{}) {
 		n++
 		if p != nil {
 			s += p.(int)
 		}
-	}
+	})
 	if n != N {
 		t.Errorf("number of forward iterations == %d; expected %d", n, N)
 	}
@@ -128,16 +128,6 @@ func makeN(n int) *Ring {
 	return r
 }
 
-
-func sum(r *Ring) int {
-	s := 0
-	for p := range r.Iter() {
-		s += p.(int)
-	}
-	return s
-}
-
-
 func sumN(n int) int { return (n*n + n) / 2 }
 
 
diff --git a/src/pkg/crypto/cipher/ocfb.go b/src/pkg/crypto/cipher/ocfb.go
index 43cb5a5..b2d8775 100644
--- a/src/pkg/crypto/cipher/ocfb.go
+++ b/src/pkg/crypto/cipher/ocfb.go
@@ -12,11 +12,21 @@ type ocfbEncrypter struct {
 	outUsed int
 }
 
+// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
+// performed.
+type OCFBResyncOption bool
+
+const (
+	OCFBResync   OCFBResyncOption = true
+	OCFBNoResync OCFBResyncOption = false
+)
+
 // NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
 // feedback mode using the given Block, and an initial amount of ciphertext.
 // randData must be random bytes and be the same length as the Block's block
-// size.
-func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) {
+// size. Resync determines if the "resynchronization step" from RFC 4880, 13.9
+// step 7 is performed. Different parts of OpenPGP vary on this point.
+func NewOCFBEncrypter(block Block, randData []byte, resync OCFBResyncOption) (Stream, []byte) {
 	blockSize := block.BlockSize()
 	if len(randData) != blockSize {
 		return nil, nil
@@ -38,7 +48,13 @@ func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) {
 	prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
 	prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
 
-	block.Encrypt(x.fre, prefix[2:])
+	if resync {
+		block.Encrypt(x.fre, prefix[2:])
+	} else {
+		x.fre[0] = prefix[blockSize]
+		x.fre[1] = prefix[blockSize+1]
+		x.outUsed = 2
+	}
 	return x, prefix
 }
 
@@ -64,8 +80,10 @@ type ocfbDecrypter struct {
 // NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
 // feedback mode using the given Block. Prefix must be the first blockSize + 2
 // bytes of the ciphertext, where blockSize is the Block's block size. If an
-// incorrect key is detected then nil is returned.
-func NewOCFBDecrypter(block Block, prefix []byte) Stream {
+// incorrect key is detected then nil is returned. Resync determines if the
+// "resynchronization step" from RFC 4880, 13.9 step 7 is performed. Different
+// parts of OpenPGP vary on this point.
+func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
 	blockSize := block.BlockSize()
 	if len(prefix) != blockSize+2 {
 		return nil
@@ -93,7 +111,13 @@ func NewOCFBDecrypter(block Block, prefix []byte) Stream {
 		return nil
 	}
 
-	block.Encrypt(x.fre, prefix[2:])
+	if resync {
+		block.Encrypt(x.fre, prefix[2:])
+	} else {
+		x.fre[0] = prefix[blockSize]
+		x.fre[1] = prefix[blockSize+1]
+		x.outUsed = 2
+	}
 	return x
 }
 
diff --git a/src/pkg/crypto/cipher/ocfb_test.go b/src/pkg/crypto/cipher/ocfb_test.go
index 289bb7c..40938b5 100644
--- a/src/pkg/crypto/cipher/ocfb_test.go
+++ b/src/pkg/crypto/cipher/ocfb_test.go
@@ -11,29 +11,34 @@ import (
 	"testing"
 )
 
-func TestOCFB(t *testing.T) {
+func testOCFB(t *testing.T, resync OCFBResyncOption) {
 	block, err := aes.NewCipher(commonKey128)
 	if err != nil {
 		t.Error(err)
 		return
 	}
 
-	plaintext := []byte("this is the plaintext")
+	plaintext := []byte("this is the plaintext, which is long enough to span several blocks.")
 	randData := make([]byte, block.BlockSize())
 	rand.Reader.Read(randData)
-	ocfb, prefix := NewOCFBEncrypter(block, randData)
+	ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
 	ciphertext := make([]byte, len(plaintext))
 	ocfb.XORKeyStream(ciphertext, plaintext)
 
-	ocfbdec := NewOCFBDecrypter(block, prefix)
+	ocfbdec := NewOCFBDecrypter(block, prefix, resync)
 	if ocfbdec == nil {
-		t.Error("NewOCFBDecrypter failed")
+		t.Errorf("NewOCFBDecrypter failed (resync: %t)", resync)
 		return
 	}
 	plaintextCopy := make([]byte, len(plaintext))
 	ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
 
 	if !bytes.Equal(plaintextCopy, plaintext) {
-		t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+		t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync)
 	}
 }
+
+func TestOCFB(t *testing.T) {
+	testOCFB(t, OCFBNoResync)
+	testOCFB(t, OCFBResync)
+}
diff --git a/src/pkg/crypto/openpgp/armor/armor.go b/src/pkg/crypto/openpgp/armor/armor.go
index 97080f6..0c5ae9d 100644
--- a/src/pkg/crypto/openpgp/armor/armor.go
+++ b/src/pkg/crypto/openpgp/armor/armor.go
@@ -112,7 +112,7 @@ func (l *lineReader) Read(p []byte) (n int, err os.Error) {
 		return 0, os.EOF
 	}
 
-	if len(line) != 64 {
+	if len(line) > 64 {
 		return 0, ArmorCorrupt
 	}
 
diff --git a/src/pkg/crypto/openpgp/armor/armor_test.go b/src/pkg/crypto/openpgp/armor/armor_test.go
index e4ffd41..9334e94 100644
--- a/src/pkg/crypto/openpgp/armor/armor_test.go
+++ b/src/pkg/crypto/openpgp/armor/armor_test.go
@@ -34,7 +34,7 @@ func TestDecodeEncode(t *testing.T) {
 		t.Error(err)
 	}
 
-	if adler32.Checksum(contents) != 0x789d7f00 {
+	if adler32.Checksum(contents) != 0x27b144be {
 		t.Errorf("contents: got: %x", contents)
 	}
 
@@ -73,13 +73,11 @@ func TestLongHeader(t *testing.T) {
 const armorExample1 = `-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.10 (GNU/Linux)
 
-iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
-kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
-cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
-byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
-WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
-okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
-=wfQG
+iJwEAAECAAYFAk1Fv/0ACgkQo01+GMIMMbsYTwQAiAw+QAaNfY6WBdplZ/uMAccm
+4g+81QPmTSGHnetSb6WBiY13kVzK4HQiZH8JSkmmroMLuGeJwsRTEL4wbjRyUKEt
+p1xwUZDECs234F1xiG5enc5SGlRtP7foLBz9lOsjx+LEcA4sTl5/2eZR9zyFZqWW
+TxRjs+fJCIFuo71xb1g=
+=/teI
 -----END PGP SIGNATURE-----`
 
 const armorLongLine = `-----BEGIN PGP SIGNATURE-----
diff --git a/src/pkg/crypto/openpgp/armor/encode.go b/src/pkg/crypto/openpgp/armor/encode.go
index 410e734..0f7de02 100644
--- a/src/pkg/crypto/openpgp/armor/encode.go
+++ b/src/pkg/crypto/openpgp/armor/encode.go
@@ -116,6 +116,7 @@ func (e *encoding) Close() (err os.Error) {
 	if err != nil {
 		return
 	}
+	e.breaker.Close()
 
 	var checksumBytes [3]byte
 	checksumBytes[0] = byte(e.crc >> 16)
@@ -144,11 +145,9 @@ func Encode(out io.Writer, blockType string, headers map[string]string) (w io.Wr
 		}
 	}
 
-	if len(headers) > 0 {
-		_, err := out.Write(newline)
-		if err != nil {
-			return
-		}
+	_, err = out.Write(newline)
+	if err != nil {
+		return
 	}
 
 	e := &encoding{
diff --git a/src/pkg/crypto/openpgp/error/error.go b/src/pkg/crypto/openpgp/error/error.go
index 2d80ce3..053d159 100644
--- a/src/pkg/crypto/openpgp/error/error.go
+++ b/src/pkg/crypto/openpgp/error/error.go
@@ -5,6 +5,10 @@
 // This package contains common error types for the OpenPGP packages.
 package error
 
+import (
+	"strconv"
+)
+
 // A StructuralError is returned when OpenPGP data is found to be syntactically
 // invalid.
 type StructuralError string
@@ -44,3 +48,17 @@ func (ki keyIncorrect) String() string {
 }
 
 var KeyIncorrectError = keyIncorrect(0)
+
+type unknownIssuer int
+
+func (unknownIssuer) String() string {
+	return "signature make by unknown entity"
+}
+
+var UnknownIssuerError = unknownIssuer(0)
+
+type UnknownPacketTypeError uint8
+
+func (upte UnknownPacketTypeError) String() string {
+	return "unknown OpenPGP packet type: " + strconv.Itoa(int(upte))
+}
diff --git a/src/pkg/crypto/openpgp/packet/Makefile b/src/pkg/crypto/openpgp/packet/Makefile
new file mode 100644
index 0000000..0f0d94e
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/Makefile
@@ -0,0 +1,22 @@
+# 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.
+
+include ../../../../Make.inc
+
+TARG=crypto/openpgp/packet
+GOFILES=\
+	compressed.go\
+	encrypted_key.go\
+	literal.go\
+	one_pass_signature.go\
+	packet.go\
+	private_key.go\
+	public_key.go\
+	reader.go\
+	signature.go\
+	symmetrically_encrypted.go\
+	symmetric_key_encrypted.go\
+	userid.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/packet/compressed.go b/src/pkg/crypto/openpgp/packet/compressed.go
new file mode 100644
index 0000000..1c15c24
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/compressed.go
@@ -0,0 +1,39 @@
+// 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 packet
+
+import (
+	"compress/flate"
+	"compress/zlib"
+	"crypto/openpgp/error"
+	"io"
+	"os"
+	"strconv"
+)
+
+// Compressed represents a compressed OpenPGP packet. The decompressed contents
+// will contain more OpenPGP packets. See RFC 4880, section 5.6.
+type Compressed struct {
+	Body io.Reader
+}
+
+func (c *Compressed) parse(r io.Reader) os.Error {
+	var buf [1]byte
+	_, err := readFull(r, buf[:])
+	if err != nil {
+		return err
+	}
+
+	switch buf[0] {
+	case 1:
+		c.Body = flate.NewReader(r)
+	case 2:
+		c.Body, err = zlib.NewReader(r)
+	default:
+		err = error.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
+	}
+
+	return err
+}
diff --git a/src/pkg/crypto/openpgp/packet/compressed_test.go b/src/pkg/crypto/openpgp/packet/compressed_test.go
new file mode 100644
index 0000000..24fe501
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/compressed_test.go
@@ -0,0 +1,41 @@
+// 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 packet
+
+import (
+	"bytes"
+	"encoding/hex"
+	"os"
+	"io/ioutil"
+	"testing"
+)
+
+func TestCompressed(t *testing.T) {
+	packet, err := Read(readerFromHex(compressedHex))
+	if err != nil {
+		t.Errorf("failed to read Compressed: %s", err)
+		return
+	}
+
+	c, ok := packet.(*Compressed)
+	if !ok {
+		t.Error("didn't find Compressed packet")
+		return
+	}
+
+	contents, err := ioutil.ReadAll(c.Body)
+	if err != nil && err != os.EOF {
+		t.Error(err)
+		return
+	}
+
+	expected, _ := hex.DecodeString(compressedExpectedHex)
+	if !bytes.Equal(expected, contents) {
+		t.Errorf("got:%x want:%x", contents, expected)
+	}
+}
+
+const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
+const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key.go b/src/pkg/crypto/openpgp/packet/encrypted_key.go
new file mode 100644
index 0000000..4a926cd
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key.go
@@ -0,0 +1,66 @@
+// 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 packet
+
+import (
+	"crypto/openpgp/error"
+	"crypto/rand"
+	"crypto/rsa"
+	"encoding/binary"
+	"io"
+	"os"
+	"strconv"
+)
+
+// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
+// section 5.1.
+type EncryptedKey struct {
+	KeyId      uint64
+	Algo       PublicKeyAlgorithm
+	Encrypted  []byte
+	CipherFunc CipherFunction // only valid after a sucessful Decrypt
+	Key        []byte         // only valid after a sucessful Decrypt
+}
+
+func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
+	var buf [10]byte
+	_, err = readFull(r, buf[:])
+	if err != nil {
+		return
+	}
+	if buf[0] != 3 {
+		return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
+	}
+	e.KeyId = binary.BigEndian.Uint64(buf[1:9])
+	e.Algo = PublicKeyAlgorithm(buf[9])
+	if e.Algo == PubKeyAlgoRSA || e.Algo == PubKeyAlgoRSAEncryptOnly {
+		e.Encrypted, _, err = readMPI(r)
+	}
+	_, err = consumeAll(r)
+	return
+}
+
+// DecryptRSA decrypts an RSA encrypted session key with the given private key.
+func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
+	if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly {
+		return error.InvalidArgumentError("EncryptedKey not RSA encrypted")
+	}
+	b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted)
+	if err != nil {
+		return
+	}
+	e.CipherFunc = CipherFunction(b[0])
+	e.Key = b[1 : len(b)-2]
+	expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
+	var checksum uint16
+	for _, v := range e.Key {
+		checksum += uint16(v)
+	}
+	if checksum != expectedChecksum {
+		return error.StructuralError("EncryptedKey checksum incorrect")
+	}
+
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
new file mode 100644
index 0000000..755ae7a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
@@ -0,0 +1,67 @@
+// 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 packet
+
+import (
+	"big"
+	"crypto/rsa"
+	"fmt"
+	"testing"
+)
+
+func bigFromBase10(s string) *big.Int {
+	b, ok := new(big.Int).SetString(s, 10)
+	if !ok {
+		panic("bigFromBase10 failed")
+	}
+	return b
+}
+
+func TestEncryptedKey(t *testing.T) {
+	p, err := Read(readerFromHex(encryptedKeyHex))
+	if err != nil {
+		t.Errorf("error from Read: %s", err)
+		return
+	}
+	ek, ok := p.(*EncryptedKey)
+	if !ok {
+		t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+		return
+	}
+
+	if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
+		t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+		return
+	}
+
+	pub := rsa.PublicKey{
+		E: 65537,
+		N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+	}
+
+	priv := &rsa.PrivateKey{
+		PublicKey: pub,
+		D:         bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+	}
+
+	err = ek.DecryptRSA(priv)
+	if err != nil {
+		t.Errorf("error from DecryptRSA: %s", err)
+		return
+	}
+
+	if ek.CipherFunc != CipherAES256 {
+		t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+		return
+	}
+
+	keyHex := fmt.Sprintf("%x", ek.Key)
+	if keyHex != expectedKeyHex {
+		t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+	}
+}
+
+const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
diff --git a/src/pkg/crypto/openpgp/packet/literal.go b/src/pkg/crypto/openpgp/packet/literal.go
new file mode 100644
index 0000000..5f72d6a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/literal.go
@@ -0,0 +1,53 @@
+// 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 packet
+
+import (
+	"encoding/binary"
+	"io"
+	"os"
+)
+
+// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
+type LiteralData struct {
+	IsBinary bool
+	FileName string
+	Time     uint32 // Unix epoc time. Either creation time or modification time. 0 means undefined.
+	Body     io.Reader
+}
+
+// ForEyesOnly return whether the contents of the LiteralData have been marked
+// as especially sensitive.
+func (l *LiteralData) ForEyesOnly() bool {
+	return l.FileName == "_CONSOLE"
+}
+
+func (l *LiteralData) parse(r io.Reader) (err os.Error) {
+	var buf [256]byte
+
+	_, err = readFull(r, buf[:2])
+	if err != nil {
+		return
+	}
+
+	l.IsBinary = buf[0] == 'b'
+	fileNameLen := int(buf[1])
+
+	_, err = readFull(r, buf[:fileNameLen])
+	if err != nil {
+		return
+	}
+
+	l.FileName = string(buf[:fileNameLen])
+
+	_, err = readFull(r, buf[:4])
+	if err != nil {
+		return
+	}
+
+	l.Time = binary.BigEndian.Uint32(buf[:4])
+	l.Body = r
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/one_pass_signature.go b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
new file mode 100644
index 0000000..acbf58b
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
@@ -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 packet
+
+import (
+	"crypto"
+	"crypto/openpgp/error"
+	"crypto/openpgp/s2k"
+	"encoding/binary"
+	"io"
+	"os"
+	"strconv"
+)
+
+// OnePassSignature represents a one-pass signature packet. See RFC 4880,
+// section 5.4.
+type OnePassSignature struct {
+	SigType    SignatureType
+	Hash       crypto.Hash
+	PubKeyAlgo PublicKeyAlgorithm
+	KeyId      uint64
+	IsLast     bool
+}
+
+func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
+	var buf [13]byte
+
+	_, err = readFull(r, buf[:])
+	if err != nil {
+		return
+	}
+	if buf[0] != 3 {
+		err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
+	}
+
+	var ok bool
+	ops.Hash, ok = s2k.HashIdToHash(buf[2])
+	if !ok {
+		return error.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
+	}
+
+	ops.SigType = SignatureType(buf[1])
+	ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
+	ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
+	ops.IsLast = buf[12] != 0
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/packet.go b/src/pkg/crypto/openpgp/packet/packet.go
new file mode 100644
index 0000000..80e25e2
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/packet.go
@@ -0,0 +1,395 @@
+// 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.
+
+// This package implements parsing and serialisation of OpenPGP packets, as
+// specified in RFC 4880.
+package packet
+
+import (
+	"crypto/aes"
+	"crypto/cast5"
+	"crypto/cipher"
+	"crypto/openpgp/error"
+	"io"
+	"os"
+)
+
+// readFull is the same as io.ReadFull except that reading zero bytes returns
+// ErrUnexpectedEOF rather than EOF.
+func readFull(r io.Reader, buf []byte) (n int, err os.Error) {
+	n, err = io.ReadFull(r, buf)
+	if err == os.EOF {
+		err = io.ErrUnexpectedEOF
+	}
+	return
+}
+
+// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
+func readLength(r io.Reader) (length int64, isPartial bool, err os.Error) {
+	var buf [4]byte
+	_, err = readFull(r, buf[:1])
+	if err != nil {
+		return
+	}
+	switch {
+	case buf[0] < 192:
+		length = int64(buf[0])
+	case buf[0] < 224:
+		length = int64(buf[0]-192) << 8
+		_, err = readFull(r, buf[0:1])
+		if err != nil {
+			return
+		}
+		length += int64(buf[0]) + 192
+	case buf[0] < 255:
+		length = int64(1) << (buf[0] & 0x1f)
+		isPartial = true
+	default:
+		_, err = readFull(r, buf[0:4])
+		if err != nil {
+			return
+		}
+		length = int64(buf[0])<<24 |
+			int64(buf[1])<<16 |
+			int64(buf[2])<<8 |
+			int64(buf[3])
+	}
+	return
+}
+
+// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
+// The continuation lengths are parsed and removed from the stream and EOF is
+// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
+type partialLengthReader struct {
+	r         io.Reader
+	remaining int64
+	isPartial bool
+}
+
+func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
+	for r.remaining == 0 {
+		if !r.isPartial {
+			return 0, os.EOF
+		}
+		r.remaining, r.isPartial, err = readLength(r.r)
+		if err != nil {
+			return 0, err
+		}
+	}
+
+	toRead := int64(len(p))
+	if toRead > r.remaining {
+		toRead = r.remaining
+	}
+
+	n, err = r.r.Read(p[:int(toRead)])
+	r.remaining -= int64(n)
+	if n < int(toRead) && err == os.EOF {
+		err = io.ErrUnexpectedEOF
+	}
+	return
+}
+
+// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
+// underlying Reader returns EOF before the limit has been reached.
+type spanReader struct {
+	r io.Reader
+	n int64
+}
+
+func (l *spanReader) Read(p []byte) (n int, err os.Error) {
+	if l.n <= 0 {
+		return 0, os.EOF
+	}
+	if int64(len(p)) > l.n {
+		p = p[0:l.n]
+	}
+	n, err = l.r.Read(p)
+	l.n -= int64(n)
+	if l.n > 0 && err == os.EOF {
+		err = io.ErrUnexpectedEOF
+	}
+	return
+}
+
+// readHeader parses a packet header and returns an io.Reader which will return
+// the contents of the packet. See RFC 4880, section 4.2.
+func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err os.Error) {
+	var buf [4]byte
+	_, err = io.ReadFull(r, buf[:1])
+	if err != nil {
+		return
+	}
+	if buf[0]&0x80 == 0 {
+		err = error.StructuralError("tag byte does not have MSB set")
+		return
+	}
+	if buf[0]&0x40 == 0 {
+		// Old format packet
+		tag = packetType((buf[0] & 0x3f) >> 2)
+		lengthType := buf[0] & 3
+		if lengthType == 3 {
+			length = -1
+			contents = r
+			return
+		}
+		lengthBytes := 1 << lengthType
+		_, err = readFull(r, buf[0:lengthBytes])
+		if err != nil {
+			return
+		}
+		for i := 0; i < lengthBytes; i++ {
+			length <<= 8
+			length |= int64(buf[i])
+		}
+		contents = &spanReader{r, length}
+		return
+	}
+
+	// New format packet
+	tag = packetType(buf[0] & 0x3f)
+	length, isPartial, err := readLength(r)
+	if err != nil {
+		return
+	}
+	if isPartial {
+		contents = &partialLengthReader{
+			remaining: length,
+			isPartial: true,
+			r:         r,
+		}
+		length = -1
+	} else {
+		contents = &spanReader{r, length}
+	}
+	return
+}
+
+// serialiseHeader writes an OpenPGP packet header to w. See RFC 4880, section
+// 4.2.
+func serialiseHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
+	var buf [5]byte
+	var n int
+
+	buf[0] = 0x80 | 0x40 | byte(ptype)
+	if length < 192 {
+		buf[1] = byte(length)
+		n = 2
+	} else if length < 8384 {
+		length -= 192
+		buf[1] = byte(length >> 8)
+		buf[2] = byte(length)
+		n = 3
+	} else {
+		buf[0] = 255
+		buf[1] = byte(length >> 24)
+		buf[2] = byte(length >> 16)
+		buf[3] = byte(length >> 8)
+		buf[4] = byte(length)
+		n = 5
+	}
+
+	_, err = w.Write(buf[:n])
+	return
+}
+
+// Packet represents an OpenPGP packet. Users are expected to try casting
+// instances of this interface to specific packet types.
+type Packet interface {
+	parse(io.Reader) os.Error
+}
+
+// consumeAll reads from the given Reader until error, returning the number of
+// bytes read.
+func consumeAll(r io.Reader) (n int64, err os.Error) {
+	var m int
+	var buf [1024]byte
+
+	for {
+		m, err = r.Read(buf[:])
+		n += int64(m)
+		if err == os.EOF {
+			err = nil
+			return
+		}
+		if err != nil {
+			return
+		}
+	}
+
+	panic("unreachable")
+}
+
+// packetType represents the numeric ids of the different OpenPGP packet types. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
+type packetType uint8
+
+const (
+	packetTypeEncryptedKey              packetType = 1
+	packetTypeSignature                 packetType = 2
+	packetTypeSymmetricKeyEncrypted     packetType = 3
+	packetTypeOnePassSignature          packetType = 4
+	packetTypePrivateKey                packetType = 5
+	packetTypePublicKey                 packetType = 6
+	packetTypePrivateSubkey             packetType = 7
+	packetTypeCompressed                packetType = 8
+	packetTypeSymmetricallyEncrypted    packetType = 9
+	packetTypeLiteralData               packetType = 11
+	packetTypeUserId                    packetType = 13
+	packetTypePublicSubkey              packetType = 14
+	packetTypeSymmetricallyEncryptedMDC packetType = 18
+)
+
+// Read reads a single OpenPGP packet from the given io.Reader. If there is an
+// error parsing a packet, the whole packet is consumed from the input.
+func Read(r io.Reader) (p Packet, err os.Error) {
+	tag, _, contents, err := readHeader(r)
+	if err != nil {
+		return
+	}
+
+	switch tag {
+	case packetTypeEncryptedKey:
+		p = new(EncryptedKey)
+	case packetTypeSignature:
+		p = new(Signature)
+	case packetTypeSymmetricKeyEncrypted:
+		p = new(SymmetricKeyEncrypted)
+	case packetTypeOnePassSignature:
+		p = new(OnePassSignature)
+	case packetTypePrivateKey, packetTypePrivateSubkey:
+		pk := new(PrivateKey)
+		if tag == packetTypePrivateSubkey {
+			pk.IsSubKey = true
+		}
+		p = pk
+	case packetTypePublicKey, packetTypePublicSubkey:
+		pk := new(PublicKey)
+		if tag == packetTypePublicSubkey {
+			pk.IsSubKey = true
+		}
+		p = pk
+	case packetTypeCompressed:
+		p = new(Compressed)
+	case packetTypeSymmetricallyEncrypted:
+		p = new(SymmetricallyEncrypted)
+	case packetTypeLiteralData:
+		p = new(LiteralData)
+	case packetTypeUserId:
+		p = new(UserId)
+	case packetTypeSymmetricallyEncryptedMDC:
+		se := new(SymmetricallyEncrypted)
+		se.MDC = true
+		p = se
+	default:
+		err = error.UnknownPacketTypeError(tag)
+	}
+	if p != nil {
+		err = p.parse(contents)
+	}
+	if err != nil {
+		consumeAll(contents)
+	}
+	return
+}
+
+// SignatureType represents the different semantic meanings of an OpenPGP
+// signature. See RFC 4880, section 5.2.1.
+type SignatureType uint8
+
+const (
+	SigTypeBinary        SignatureType = 0
+	SigTypeText          SignatureType = 1
+	SigTypeGenericCert   = 0x10
+	SigTypePersonaCert   = 0x11
+	SigTypeCasualCert    = 0x12
+	SigTypePositiveCert  = 0x13
+	SigTypeSubkeyBinding = 0x18
+)
+
+// PublicKeyAlgorithm represents the different public key system specified for
+// OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
+type PublicKeyAlgorithm uint8
+
+const (
+	PubKeyAlgoRSA            PublicKeyAlgorithm = 1
+	PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
+	PubKeyAlgoRSASignOnly    PublicKeyAlgorithm = 3
+	PubKeyAlgoElgamal        PublicKeyAlgorithm = 16
+	PubKeyAlgoDSA            PublicKeyAlgorithm = 17
+)
+
+// CipherFunction represents the different block ciphers specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
+type CipherFunction uint8
+
+const (
+	CipherCAST5  = 3
+	CipherAES128 = 7
+	CipherAES192 = 8
+	CipherAES256 = 9
+)
+
+// keySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) keySize() int {
+	switch cipher {
+	case CipherCAST5:
+		return cast5.KeySize
+	case CipherAES128:
+		return 16
+	case CipherAES192:
+		return 24
+	case CipherAES256:
+		return 32
+	}
+	return 0
+}
+
+// blockSize returns the block size, in bytes, of cipher.
+func (cipher CipherFunction) blockSize() int {
+	switch cipher {
+	case CipherCAST5:
+		return 8
+	case CipherAES128, CipherAES192, CipherAES256:
+		return 16
+	}
+	return 0
+}
+
+// new returns a fresh instance of the given cipher.
+func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+	switch cipher {
+	case CipherCAST5:
+		block, _ = cast5.NewCipher(key)
+	case CipherAES128, CipherAES192, CipherAES256:
+		block, _ = aes.NewCipher(key)
+	}
+	return
+}
+
+// readMPI reads a big integer from r. The bit length returned is the bit
+// length that was specified in r. This is preserved so that the integer can be
+// reserialised exactly.
+func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
+	var buf [2]byte
+	_, err = readFull(r, buf[0:])
+	if err != nil {
+		return
+	}
+	bitLength = uint16(buf[0])<<8 | uint16(buf[1])
+	numBytes := (int(bitLength) + 7) / 8
+	mpi = make([]byte, numBytes)
+	_, err = readFull(r, mpi)
+	return
+}
+
+// writeMPI serialises a big integer to r.
+func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
+	_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
+	if err == nil {
+		_, err = w.Write(mpiBytes)
+	}
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/packet_test.go b/src/pkg/crypto/openpgp/packet/packet_test.go
new file mode 100644
index 0000000..6789d2a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/packet_test.go
@@ -0,0 +1,192 @@
+// 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 packet
+
+import (
+	"bytes"
+	"crypto/openpgp/error"
+	"encoding/hex"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func TestReadFull(t *testing.T) {
+	var out [4]byte
+
+	b := bytes.NewBufferString("foo")
+	n, err := readFull(b, out[:3])
+	if n != 3 || err != nil {
+		t.Errorf("full read failed n:%d err:%s", n, err)
+	}
+
+	b = bytes.NewBufferString("foo")
+	n, err = readFull(b, out[:4])
+	if n != 3 || err != io.ErrUnexpectedEOF {
+		t.Errorf("partial read failed n:%d err:%s", n, err)
+	}
+
+	b = bytes.NewBuffer(nil)
+	n, err = readFull(b, out[:3])
+	if n != 0 || err != io.ErrUnexpectedEOF {
+		t.Errorf("empty read failed n:%d err:%s", n, err)
+	}
+}
+
+func readerFromHex(s string) io.Reader {
+	data, err := hex.DecodeString(s)
+	if err != nil {
+		panic("readerFromHex: bad input")
+	}
+	return bytes.NewBuffer(data)
+}
+
+var readLengthTests = []struct {
+	hexInput  string
+	length    int64
+	isPartial bool
+	err       os.Error
+}{
+	{"", 0, false, io.ErrUnexpectedEOF},
+	{"1f", 31, false, nil},
+	{"c0", 0, false, io.ErrUnexpectedEOF},
+	{"c101", 256 + 1 + 192, false, nil},
+	{"e0", 1, true, nil},
+	{"e1", 2, true, nil},
+	{"e2", 4, true, nil},
+	{"ff", 0, false, io.ErrUnexpectedEOF},
+	{"ff00", 0, false, io.ErrUnexpectedEOF},
+	{"ff0000", 0, false, io.ErrUnexpectedEOF},
+	{"ff000000", 0, false, io.ErrUnexpectedEOF},
+	{"ff00000000", 0, false, nil},
+	{"ff01020304", 16909060, false, nil},
+}
+
+func TestReadLength(t *testing.T) {
+	for i, test := range readLengthTests {
+		length, isPartial, err := readLength(readerFromHex(test.hexInput))
+		if test.err != nil {
+			if err != test.err {
+				t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+			}
+			continue
+		}
+		if err != nil {
+			t.Errorf("%d: unexpected error: %s", i, err)
+			continue
+		}
+		if length != test.length || isPartial != test.isPartial {
+			t.Errorf("%d: bad result got:(%d,%t) want:(%d,%t)", i, length, isPartial, test.length, test.isPartial)
+		}
+	}
+}
+
+var partialLengthReaderTests = []struct {
+	hexInput  string
+	err       os.Error
+	hexOutput string
+}{
+	{"e0", io.ErrUnexpectedEOF, ""},
+	{"e001", io.ErrUnexpectedEOF, ""},
+	{"e0010102", nil, "0102"},
+	{"ff00000000", nil, ""},
+	{"e10102e1030400", nil, "01020304"},
+	{"e101", io.ErrUnexpectedEOF, ""},
+}
+
+func TestPartialLengthReader(t *testing.T) {
+	for i, test := range partialLengthReaderTests {
+		r := &partialLengthReader{readerFromHex(test.hexInput), 0, true}
+		out, err := ioutil.ReadAll(r)
+		if test.err != nil {
+			if err != test.err {
+				t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+			}
+			continue
+		}
+		if err != nil {
+			t.Errorf("%d: unexpected error: %s", i, err)
+			continue
+		}
+
+		got := fmt.Sprintf("%x", out)
+		if got != test.hexOutput {
+			t.Errorf("%d: got:%s want:%s", i, test.hexOutput, got)
+		}
+	}
+}
+
+var readHeaderTests = []struct {
+	hexInput        string
+	structuralError bool
+	unexpectedEOF   bool
+	tag             int
+	length          int64
+	hexOutput       string
+}{
+	{"", false, false, 0, 0, ""},
+	{"7f", true, false, 0, 0, ""},
+
+	// Old format headers
+	{"80", false, true, 0, 0, ""},
+	{"8001", false, true, 0, 1, ""},
+	{"800102", false, false, 0, 1, "02"},
+	{"81000102", false, false, 0, 1, "02"},
+	{"820000000102", false, false, 0, 1, "02"},
+	{"860000000102", false, false, 1, 1, "02"},
+	{"83010203", false, false, 0, -1, "010203"},
+
+	// New format headers
+	{"c0", false, true, 0, 0, ""},
+	{"c000", false, false, 0, 0, ""},
+	{"c00102", false, false, 0, 1, "02"},
+	{"c0020203", false, false, 0, 2, "0203"},
+	{"c00202", false, true, 0, 2, ""},
+	{"c3020203", false, false, 3, 2, "0203"},
+}
+
+func TestReadHeader(t *testing.T) {
+	for i, test := range readHeaderTests {
+		tag, length, contents, err := readHeader(readerFromHex(test.hexInput))
+		if test.structuralError {
+			if _, ok := err.(error.StructuralError); ok {
+				continue
+			}
+			t.Errorf("%d: expected StructuralError, got:%s", i, err)
+			continue
+		}
+		if err != nil {
+			if len(test.hexInput) == 0 && err == os.EOF {
+				continue
+			}
+			if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+				t.Errorf("%d: unexpected error from readHeader: %s", i, err)
+			}
+			continue
+		}
+		if int(tag) != test.tag || length != test.length {
+			t.Errorf("%d: got:(%d,%d) want:(%d,%d)", i, int(tag), length, test.tag, test.length)
+			continue
+		}
+
+		body, err := ioutil.ReadAll(contents)
+		if err != nil {
+			if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+				t.Errorf("%d: unexpected error from contents: %s", i, err)
+			}
+			continue
+		}
+		if test.unexpectedEOF {
+			t.Errorf("%d: expected ErrUnexpectedEOF from contents but got no error", i)
+			continue
+		}
+		got := fmt.Sprintf("%x", body)
+		if got != test.hexOutput {
+			t.Errorf("%d: got:%s want:%s", i, got, test.hexOutput)
+		}
+	}
+}
diff --git a/src/pkg/crypto/openpgp/packet/private_key.go b/src/pkg/crypto/openpgp/packet/private_key.go
new file mode 100644
index 0000000..b228917
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/private_key.go
@@ -0,0 +1,164 @@
+// 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 packet
+
+import (
+	"big"
+	"bytes"
+	"crypto/cipher"
+	"crypto/openpgp/error"
+	"crypto/openpgp/s2k"
+	"crypto/rsa"
+	"crypto/sha1"
+	"io"
+	"io/ioutil"
+	"os"
+	"strconv"
+)
+
+// PrivateKey represents a possibly encrypted private key. See RFC 4880,
+// section 5.5.3.
+type PrivateKey struct {
+	PublicKey
+	Encrypted     bool // if true then the private key is unavailable until Decrypt has been called.
+	encryptedData []byte
+	cipher        CipherFunction
+	s2k           func(out, in []byte)
+	PrivateKey    interface{} // An *rsa.PrivateKey.
+	sha1Checksum  bool
+	iv            []byte
+}
+
+func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
+	err = (&pk.PublicKey).parse(r)
+	if err != nil {
+		return
+	}
+	var buf [1]byte
+	_, err = readFull(r, buf[:])
+	if err != nil {
+		return
+	}
+
+	s2kType := buf[0]
+
+	switch s2kType {
+	case 0:
+		pk.s2k = nil
+		pk.Encrypted = false
+	case 254, 255:
+		_, err = readFull(r, buf[:])
+		if err != nil {
+			return
+		}
+		pk.cipher = CipherFunction(buf[0])
+		pk.Encrypted = true
+		pk.s2k, err = s2k.Parse(r)
+		if err != nil {
+			return
+		}
+		if s2kType == 254 {
+			pk.sha1Checksum = true
+		}
+	default:
+		return error.UnsupportedError("deprecated s2k function in private key")
+	}
+
+	if pk.Encrypted {
+		blockSize := pk.cipher.blockSize()
+		if blockSize == 0 {
+			return error.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
+		}
+		pk.iv = make([]byte, blockSize)
+		_, err = readFull(r, pk.iv)
+		if err != nil {
+			return
+		}
+	}
+
+	pk.encryptedData, err = ioutil.ReadAll(r)
+	if err != nil {
+		return
+	}
+
+	if !pk.Encrypted {
+		return pk.parsePrivateKey(pk.encryptedData)
+	}
+
+	return
+}
+
+// Decrypt decrypts an encrypted private key using a passphrase.
+func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
+	if !pk.Encrypted {
+		return nil
+	}
+
+	key := make([]byte, pk.cipher.keySize())
+	pk.s2k(key, passphrase)
+	block := pk.cipher.new(key)
+	cfb := cipher.NewCFBDecrypter(block, pk.iv)
+
+	data := pk.encryptedData
+	cfb.XORKeyStream(data, data)
+
+	if pk.sha1Checksum {
+		if len(data) < sha1.Size {
+			return error.StructuralError("truncated private key data")
+		}
+		h := sha1.New()
+		h.Write(data[:len(data)-sha1.Size])
+		sum := h.Sum()
+		if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
+			return error.StructuralError("private key checksum failure")
+		}
+		data = data[:len(data)-sha1.Size]
+	} else {
+		if len(data) < 2 {
+			return error.StructuralError("truncated private key data")
+		}
+		var sum uint16
+		for i := 0; i < len(data)-2; i++ {
+			sum += uint16(data[i])
+		}
+		if data[len(data)-2] != uint8(sum>>8) ||
+			data[len(data)-1] != uint8(sum) {
+			return error.StructuralError("private key checksum failure")
+		}
+		data = data[:len(data)-2]
+	}
+
+	return pk.parsePrivateKey(data)
+}
+
+func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
+	// TODO(agl): support DSA and ECDSA private keys.
+	rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
+	rsaPriv := new(rsa.PrivateKey)
+	rsaPriv.PublicKey = *rsaPub
+
+	buf := bytes.NewBuffer(data)
+	d, _, err := readMPI(buf)
+	if err != nil {
+		return
+	}
+	p, _, err := readMPI(buf)
+	if err != nil {
+		return
+	}
+	q, _, err := readMPI(buf)
+	if err != nil {
+		return
+	}
+
+	rsaPriv.D = new(big.Int).SetBytes(d)
+	rsaPriv.P = new(big.Int).SetBytes(p)
+	rsaPriv.Q = new(big.Int).SetBytes(q)
+	pk.PrivateKey = rsaPriv
+	pk.Encrypted = false
+	pk.encryptedData = nil
+
+	return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/private_key_test.go b/src/pkg/crypto/openpgp/packet/private_key_test.go
new file mode 100644
index 0000000..e941cc7
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/private_key_test.go
@@ -0,0 +1,37 @@
+// 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 packet
+
+import (
+	"testing"
+)
+
+func TestPrivateKeyRead(t *testing.T) {
+	packet, err := Read(readerFromHex(privKeyHex))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	privKey := packet.(*PrivateKey)
+
+	if !privKey.Encrypted {
+		t.Error("private key isn't encrypted")
+		return
+	}
+
+	err = privKey.Decrypt([]byte("testing"))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted {
+		t.Errorf("failed to parse, got: %#v", privKey)
+	}
+}
+
+// Generated with `gpg --export-secret-keys "Test Key 2"`
+const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
diff --git a/src/pkg/crypto/openpgp/packet/public_key.go b/src/pkg/crypto/openpgp/packet/public_key.go
new file mode 100644
index 0000000..4a2ed0a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/public_key.go
@@ -0,0 +1,260 @@
+// 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 packet
+
+import (
+	"big"
+	"crypto/dsa"
+	"crypto/openpgp/error"
+	"crypto/rsa"
+	"crypto/sha1"
+	"encoding/binary"
+	"hash"
+	"io"
+	"os"
+)
+
+// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
+type PublicKey struct {
+	CreationTime uint32 // seconds since the epoch
+	PubKeyAlgo   PublicKeyAlgorithm
+	PublicKey    interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
+	Fingerprint  [20]byte
+	KeyId        uint64
+	IsSubKey     bool
+
+	n, e, p, q, g, y parsedMPI
+}
+
+func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
+	// RFC 4880, section 5.5.2
+	var buf [6]byte
+	_, err = readFull(r, buf[:])
+	if err != nil {
+		return
+	}
+	if buf[0] != 4 {
+		return error.UnsupportedError("public key version")
+	}
+	pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4])
+	pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
+	switch pk.PubKeyAlgo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+		err = pk.parseRSA(r)
+	case PubKeyAlgoDSA:
+		err = pk.parseDSA(r)
+	default:
+		err = error.UnsupportedError("public key type")
+	}
+	if err != nil {
+		return
+	}
+
+	// RFC 4880, section 12.2
+	fingerPrint := sha1.New()
+	pk.SerializeSignaturePrefix(fingerPrint)
+	pk.Serialize(fingerPrint)
+	copy(pk.Fingerprint[:], fingerPrint.Sum())
+	pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
+
+	return
+}
+
+// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
+	pk.n.bytes, pk.n.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+	pk.e.bytes, pk.e.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+
+	if len(pk.e.bytes) > 3 {
+		err = error.UnsupportedError("large public exponent")
+		return
+	}
+	rsa := &rsa.PublicKey{
+		N: new(big.Int).SetBytes(pk.n.bytes),
+		E: 0,
+	}
+	for i := 0; i < len(pk.e.bytes); i++ {
+		rsa.E <<= 8
+		rsa.E |= int(pk.e.bytes[i])
+	}
+	pk.PublicKey = rsa
+	return
+}
+
+// parseRSA parses DSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
+	pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+	pk.q.bytes, pk.q.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+	pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+	pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+	if err != nil {
+		return
+	}
+
+	dsa := new(dsa.PublicKey)
+	dsa.P = new(big.Int).SetBytes(pk.p.bytes)
+	dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
+	dsa.G = new(big.Int).SetBytes(pk.g.bytes)
+	dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
+	pk.PublicKey = dsa
+	return
+}
+
+// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
+// The prefix is used when calculating a signature over this public key. See
+// RFC 4880, section 5.2.4.
+func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
+	var pLength uint16
+	switch pk.PubKeyAlgo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+		pLength += 2 + uint16(len(pk.n.bytes))
+		pLength += 2 + uint16(len(pk.e.bytes))
+	case PubKeyAlgoDSA:
+		pLength += 2 + uint16(len(pk.p.bytes))
+		pLength += 2 + uint16(len(pk.q.bytes))
+		pLength += 2 + uint16(len(pk.g.bytes))
+		pLength += 2 + uint16(len(pk.y.bytes))
+	default:
+		panic("unknown public key algorithm")
+	}
+	pLength += 6
+	h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
+	return
+}
+
+// Serialize marshals the PublicKey to w in the form of an OpenPGP public key
+// packet, not including the packet header.
+func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
+	var buf [6]byte
+	buf[0] = 4
+	buf[1] = byte(pk.CreationTime >> 24)
+	buf[2] = byte(pk.CreationTime >> 16)
+	buf[3] = byte(pk.CreationTime >> 8)
+	buf[4] = byte(pk.CreationTime)
+	buf[5] = byte(pk.PubKeyAlgo)
+
+	_, err = w.Write(buf[:])
+	if err != nil {
+		return
+	}
+
+	switch pk.PubKeyAlgo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+		return writeMPIs(w, pk.n, pk.e)
+	case PubKeyAlgoDSA:
+		return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+	}
+	return error.InvalidArgumentError("bad public-key algorithm")
+}
+
+// CanSign returns true iff this public key can generate signatures
+func (pk *PublicKey) CanSign() bool {
+	return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElgamal
+}
+
+// VerifySignature returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.Error) {
+	if !pk.CanSign() {
+		return error.InvalidArgumentError("public key cannot generate signatures")
+	}
+
+	rsaPublicKey, ok := pk.PublicKey.(*rsa.PublicKey)
+	if !ok {
+		// TODO(agl): support DSA and ECDSA keys.
+		return error.UnsupportedError("non-RSA public key")
+	}
+
+	signed.Write(sig.HashSuffix)
+	hashBytes := signed.Sum()
+
+	if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+		return error.SignatureError("hash tag doesn't match")
+	}
+
+	err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.Signature)
+	if err != nil {
+		return error.SignatureError("RSA verification failure")
+	}
+	return nil
+}
+
+// VerifyKeySignature returns nil iff sig is a valid signature, make by this
+// public key, of the public key in signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
+	h := sig.Hash.New()
+	if h == nil {
+		return error.UnsupportedError("hash function")
+	}
+
+	// RFC 4880, section 5.2.4
+	pk.SerializeSignaturePrefix(h)
+	pk.Serialize(h)
+	signed.SerializeSignaturePrefix(h)
+	signed.Serialize(h)
+
+	return pk.VerifySignature(h, sig)
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, make by this
+// public key, of the given user id.
+func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
+	h := sig.Hash.New()
+	if h == nil {
+		return error.UnsupportedError("hash function")
+	}
+
+	// RFC 4880, section 5.2.4
+	pk.SerializeSignaturePrefix(h)
+	pk.Serialize(h)
+
+	var buf [5]byte
+	buf[0] = 0xb4
+	buf[1] = byte(len(id) >> 24)
+	buf[2] = byte(len(id) >> 16)
+	buf[3] = byte(len(id) >> 8)
+	buf[4] = byte(len(id))
+	h.Write(buf[:])
+	h.Write([]byte(id))
+
+	return pk.VerifySignature(h, sig)
+}
+
+// A parsedMPI is used to store the contents of a big integer, along with the
+// bit length that was specified in the original input. This allows the MPI to
+// be reserialised exactly.
+type parsedMPI struct {
+	bytes     []byte
+	bitLength uint16
+}
+
+// writeMPIs is a utility function for serialising several big integers to the
+// given Writer.
+func writeMPIs(w io.Writer, mpis ...parsedMPI) (err os.Error) {
+	for _, mpi := range mpis {
+		err = writeMPI(w, mpi.bitLength, mpi.bytes)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/public_key_test.go b/src/pkg/crypto/openpgp/packet/public_key_test.go
new file mode 100644
index 0000000..c015f64
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/public_key_test.go
@@ -0,0 +1,58 @@
+// 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 packet
+
+import (
+	"bytes"
+	"encoding/hex"
+	"testing"
+)
+
+var pubKeyTests = []struct {
+	hexData        string
+	hexFingerprint string
+	creationTime   uint32
+	pubKeyAlgo     PublicKeyAlgorithm
+	keyId          uint64
+}{
+	{rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb},
+	{dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed},
+}
+
+func TestPublicKeyRead(t *testing.T) {
+	for i, test := range pubKeyTests {
+		packet, err := Read(readerFromHex(test.hexData))
+		if err != nil {
+			t.Errorf("#%d: Read error: %s", i, err)
+			return
+		}
+		pk, ok := packet.(*PublicKey)
+		if !ok {
+			t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+			return
+		}
+		if pk.PubKeyAlgo != test.pubKeyAlgo {
+			t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
+		}
+		if pk.CreationTime != test.creationTime {
+			t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime)
+		}
+		expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
+		if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
+			t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
+		}
+		if pk.KeyId != test.keyId {
+			t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
+		}
+	}
+}
+
+const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
+
+const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
+
+const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
+
+const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"
diff --git a/src/pkg/crypto/openpgp/packet/reader.go b/src/pkg/crypto/openpgp/packet/reader.go
new file mode 100644
index 0000000..5febc3b
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/reader.go
@@ -0,0 +1,63 @@
+// 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 packet
+
+import (
+	"crypto/openpgp/error"
+	"io"
+	"os"
+)
+
+// Reader reads packets from an io.Reader and allows packets to be 'unread' so
+// that they result from the next call to Next.
+type Reader struct {
+	q       []Packet
+	readers []io.Reader
+}
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown packet types are skipped.
+func (r *Reader) Next() (p Packet, err os.Error) {
+	if len(r.q) > 0 {
+		p = r.q[len(r.q)-1]
+		r.q = r.q[:len(r.q)-1]
+		return
+	}
+
+	for len(r.readers) > 0 {
+		p, err = Read(r.readers[len(r.readers)-1])
+		if err == nil {
+			return
+		}
+		if err == os.EOF {
+			r.readers = r.readers[:len(r.readers)-1]
+			continue
+		}
+		if _, ok := err.(error.UnknownPacketTypeError); !ok {
+			return nil, err
+		}
+	}
+
+	return nil, os.EOF
+}
+
+// Push causes the Reader to start reading from a new io.Reader. When an EOF
+// error is seen from the new io.Reader, it is popped and the Reader continues
+// to read from the next most recent io.Reader.
+func (r *Reader) Push(reader io.Reader) {
+	r.readers = append(r.readers, reader)
+}
+
+// Unread causes the given Packet to be returned from the next call to Next.
+func (r *Reader) Unread(p Packet) {
+	r.q = append(r.q, p)
+}
+
+func NewReader(r io.Reader) *Reader {
+	return &Reader{
+		q:       nil,
+		readers: []io.Reader{r},
+	}
+}
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
new file mode 100644
index 0000000..fd2518a
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/signature.go
@@ -0,0 +1,468 @@
+// 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 packet
+
+import (
+	"crypto"
+	"crypto/openpgp/error"
+	"crypto/openpgp/s2k"
+	"crypto/rand"
+	"crypto/rsa"
+	"encoding/binary"
+	"hash"
+	"io"
+	"os"
+	"strconv"
+)
+
+// Signature represents a signature. See RFC 4880, section 5.2.
+type Signature struct {
+	SigType    SignatureType
+	PubKeyAlgo PublicKeyAlgorithm
+	Hash       crypto.Hash
+
+	// HashSuffix is extra data that is hashed in after the signed data.
+	HashSuffix []byte
+	// HashTag contains the first two bytes of the hash for fast rejection
+	// of bad signed data.
+	HashTag      [2]byte
+	CreationTime uint32 // Unix epoch time
+	Signature    []byte
+
+	// The following are optional so are nil when not included in the
+	// signature.
+
+	SigLifetimeSecs, KeyLifetimeSecs                        *uint32
+	PreferredSymmetric, PreferredHash, PreferredCompression []uint8
+	IssuerKeyId                                             *uint64
+	IsPrimaryId                                             *bool
+
+	// FlagsValid is set if any flags were given. See RFC 4880, section
+	// 5.2.3.21 for details.
+	FlagsValid                                                           bool
+	FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
+
+	outSubpackets []outputSubpacket
+}
+
+func (sig *Signature) parse(r io.Reader) (err os.Error) {
+	// RFC 4880, section 5.2.3
+	var buf [5]byte
+	_, err = readFull(r, buf[:1])
+	if err != nil {
+		return
+	}
+	if buf[0] != 4 {
+		err = error.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
+		return
+	}
+
+	_, err = readFull(r, buf[:5])
+	if err != nil {
+		return
+	}
+	sig.SigType = SignatureType(buf[0])
+	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
+	switch sig.PubKeyAlgo {
+	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+	default:
+		err = error.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
+		return
+	}
+
+	var ok bool
+	sig.Hash, ok = s2k.HashIdToHash(buf[2])
+	if !ok {
+		return error.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
+	}
+
+	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
+	l := 6 + hashedSubpacketsLength
+	sig.HashSuffix = make([]byte, l+6)
+	sig.HashSuffix[0] = 4
+	copy(sig.HashSuffix[1:], buf[:5])
+	hashedSubpackets := sig.HashSuffix[6:l]
+	_, err = readFull(r, hashedSubpackets)
+	if err != nil {
+		return
+	}
+	// See RFC 4880, section 5.2.4
+	trailer := sig.HashSuffix[l:]
+	trailer[0] = 4
+	trailer[1] = 0xff
+	trailer[2] = uint8(l >> 24)
+	trailer[3] = uint8(l >> 16)
+	trailer[4] = uint8(l >> 8)
+	trailer[5] = uint8(l)
+
+	err = parseSignatureSubpackets(sig, hashedSubpackets, true)
+	if err != nil {
+		return
+	}
+
+	_, err = readFull(r, buf[:2])
+	if err != nil {
+		return
+	}
+	unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
+	unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
+	_, err = readFull(r, unhashedSubpackets)
+	if err != nil {
+		return
+	}
+	err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
+	if err != nil {
+		return
+	}
+
+	_, err = readFull(r, sig.HashTag[:2])
+	if err != nil {
+		return
+	}
+
+	// We have already checked that the public key algorithm is RSA.
+	sig.Signature, _, err = readMPI(r)
+	return
+}
+
+// parseSignatureSubpackets parses subpackets of the main signature packet. See
+// RFC 4880, section 5.2.3.1.
+func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err os.Error) {
+	for len(subpackets) > 0 {
+		subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
+		if err != nil {
+			return
+		}
+	}
+
+	if sig.CreationTime == 0 {
+		err = error.StructuralError("no creation time in signature")
+	}
+
+	return
+}
+
+type signatureSubpacketType uint8
+
+const (
+	creationTimeSubpacket        signatureSubpacketType = 2
+	signatureExpirationSubpacket signatureSubpacketType = 3
+	keyExpirySubpacket           signatureSubpacketType = 9
+	prefSymmetricAlgosSubpacket  signatureSubpacketType = 11
+	issuerSubpacket              signatureSubpacketType = 16
+	prefHashAlgosSubpacket       signatureSubpacketType = 21
+	prefCompressionSubpacket     signatureSubpacketType = 22
+	primaryUserIdSubpacket       signatureSubpacketType = 25
+	keyFlagsSubpacket            signatureSubpacketType = 27
+)
+
+// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
+func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
+	// RFC 4880, section 5.2.3.1
+	var length uint32
+	switch {
+	case subpacket[0] < 192:
+		length = uint32(subpacket[0])
+		subpacket = subpacket[1:]
+	case subpacket[0] < 255:
+		if len(subpacket) < 2 {
+			goto Truncated
+		}
+		length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
+		subpacket = subpacket[2:]
+	default:
+		if len(subpacket) < 5 {
+			goto Truncated
+		}
+		length = uint32(subpacket[1])<<24 |
+			uint32(subpacket[2])<<16 |
+			uint32(subpacket[3])<<8 |
+			uint32(subpacket[4])
+		subpacket = subpacket[5:]
+	}
+	if length > uint32(len(subpacket)) {
+		goto Truncated
+	}
+	rest = subpacket[length:]
+	subpacket = subpacket[:length]
+	if len(subpacket) == 0 {
+		err = error.StructuralError("zero length signature subpacket")
+		return
+	}
+	packetType := subpacket[0] & 0x7f
+	isCritial := subpacket[0]&0x80 == 0x80
+	subpacket = subpacket[1:]
+	switch signatureSubpacketType(packetType) {
+	case creationTimeSubpacket:
+		if !isHashed {
+			err = error.StructuralError("signature creation time in non-hashed area")
+			return
+		}
+		if len(subpacket) != 4 {
+			err = error.StructuralError("signature creation time not four bytes")
+			return
+		}
+		sig.CreationTime = binary.BigEndian.Uint32(subpacket)
+	case signatureExpirationSubpacket:
+		// Signature expiration time, section 5.2.3.10
+		if !isHashed {
+			return
+		}
+		if len(subpacket) != 4 {
+			err = error.StructuralError("expiration subpacket with bad length")
+			return
+		}
+		sig.SigLifetimeSecs = new(uint32)
+		*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+	case keyExpirySubpacket:
+		// Key expiration time, section 5.2.3.6
+		if !isHashed {
+			return
+		}
+		if len(subpacket) != 4 {
+			err = error.StructuralError("key expiration subpacket with bad length")
+			return
+		}
+		sig.KeyLifetimeSecs = new(uint32)
+		*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+	case prefSymmetricAlgosSubpacket:
+		// Preferred symmetric algorithms, section 5.2.3.7
+		if !isHashed {
+			return
+		}
+		sig.PreferredSymmetric = make([]byte, len(subpacket))
+		copy(sig.PreferredSymmetric, subpacket)
+	case issuerSubpacket:
+		// Issuer, section 5.2.3.5
+		if len(subpacket) != 8 {
+			err = error.StructuralError("issuer subpacket with bad length")
+			return
+		}
+		sig.IssuerKeyId = new(uint64)
+		*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
+	case prefHashAlgosSubpacket:
+		// Preferred hash algorithms, section 5.2.3.8
+		if !isHashed {
+			return
+		}
+		sig.PreferredHash = make([]byte, len(subpacket))
+		copy(sig.PreferredHash, subpacket)
+	case prefCompressionSubpacket:
+		// Preferred compression algorithms, section 5.2.3.9
+		if !isHashed {
+			return
+		}
+		sig.PreferredCompression = make([]byte, len(subpacket))
+		copy(sig.PreferredCompression, subpacket)
+	case primaryUserIdSubpacket:
+		// Primary User ID, section 5.2.3.19
+		if !isHashed {
+			return
+		}
+		if len(subpacket) != 1 {
+			err = error.StructuralError("primary user id subpacket with bad length")
+			return
+		}
+		sig.IsPrimaryId = new(bool)
+		if subpacket[0] > 0 {
+			*sig.IsPrimaryId = true
+		}
+	case keyFlagsSubpacket:
+		// Key flags, section 5.2.3.21
+		if !isHashed {
+			return
+		}
+		if len(subpacket) == 0 {
+			err = error.StructuralError("empty key flags subpacket")
+			return
+		}
+		sig.FlagsValid = true
+		if subpacket[0]&1 != 0 {
+			sig.FlagCertify = true
+		}
+		if subpacket[0]&2 != 0 {
+			sig.FlagSign = true
+		}
+		if subpacket[0]&4 != 0 {
+			sig.FlagEncryptCommunications = true
+		}
+		if subpacket[0]&8 != 0 {
+			sig.FlagEncryptStorage = true
+		}
+
+	default:
+		if isCritial {
+			err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
+			return
+		}
+	}
+	return
+
+Truncated:
+	err = error.StructuralError("signature subpacket truncated")
+	return
+}
+
+// subpacketLengthLength returns the length, in bytes, of an encoded length value.
+func subpacketLengthLength(length int) int {
+	if length < 192 {
+		return 1
+	}
+	if length < 16320 {
+		return 2
+	}
+	return 5
+}
+
+// serialiseSubpacketLength marshals the given length into to.
+func serialiseSubpacketLength(to []byte, length int) int {
+	if length < 192 {
+		to[0] = byte(length)
+		return 1
+	}
+	if length < 16320 {
+		length -= 192
+		to[0] = byte(length >> 8)
+		to[1] = byte(length)
+		return 2
+	}
+	to[0] = 255
+	to[1] = byte(length >> 24)
+	to[2] = byte(length >> 16)
+	to[3] = byte(length >> 8)
+	to[4] = byte(length)
+	return 5
+}
+
+// subpacketsLength returns the serialised length, in bytes, of the given
+// subpackets.
+func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
+	for _, subpacket := range subpackets {
+		if subpacket.hashed == hashed {
+			length += subpacketLengthLength(len(subpacket.contents) + 1)
+			length += 1 // type byte
+			length += len(subpacket.contents)
+		}
+	}
+	return
+}
+
+// serialiseSubpackets marshals the given subpackets into to.
+func serialiseSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
+	for _, subpacket := range subpackets {
+		if subpacket.hashed == hashed {
+			n := serialiseSubpacketLength(to, len(subpacket.contents)+1)
+			to[n] = byte(subpacket.subpacketType)
+			to = to[1+n:]
+			n = copy(to, subpacket.contents)
+			to = to[n:]
+		}
+	}
+	return
+}
+
+// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
+func (sig *Signature) buildHashSuffix() (err os.Error) {
+	sig.outSubpackets = sig.buildSubpackets()
+	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
+
+	var ok bool
+	l := 6 + hashedSubpacketsLen
+	sig.HashSuffix = make([]byte, l+6)
+	sig.HashSuffix[0] = 4
+	sig.HashSuffix[1] = uint8(sig.SigType)
+	sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
+	sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
+	if !ok {
+		sig.HashSuffix = nil
+		return error.InvalidArgumentError("hash cannot be repesented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+	}
+	sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
+	sig.HashSuffix[5] = byte(hashedSubpacketsLen)
+	serialiseSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
+	trailer := sig.HashSuffix[l:]
+	trailer[0] = 4
+	trailer[1] = 0xff
+	trailer[2] = byte(l >> 24)
+	trailer[3] = byte(l >> 16)
+	trailer[4] = byte(l >> 8)
+	trailer[5] = byte(l)
+	return
+}
+
+// SignRSA signs a message with an RSA private key. The hash, h, must contain
+// the hash of message to be signed and will be mutated by this function.
+func (sig *Signature) SignRSA(h hash.Hash, priv *rsa.PrivateKey) (err os.Error) {
+	err = sig.buildHashSuffix()
+	if err != nil {
+		return
+	}
+
+	h.Write(sig.HashSuffix)
+	digest := h.Sum()
+	copy(sig.HashTag[:], digest)
+	sig.Signature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest)
+	return
+}
+
+// Serialize marshals sig to w. SignRSA must have been called first.
+func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
+	if sig.Signature == nil {
+		return error.InvalidArgumentError("Signature: need to call SignRSA before Serialize")
+	}
+
+	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
+	length := len(sig.HashSuffix) - 6 /* trailer not included */ +
+		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
+		2 /* hash tag */ + 2 /* length of signature MPI */ + len(sig.Signature)
+	err = serialiseHeader(w, packetTypeSignature, length)
+	if err != nil {
+		return
+	}
+
+	_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
+	if err != nil {
+		return
+	}
+
+	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
+	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
+	unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
+	serialiseSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
+
+	_, err = w.Write(unhashedSubpackets)
+	if err != nil {
+		return
+	}
+	_, err = w.Write(sig.HashTag[:])
+	if err != nil {
+		return
+	}
+	return writeMPI(w, 8*uint16(len(sig.Signature)), sig.Signature)
+}
+
+// outputSubpacket represents a subpacket to be marshaled.
+type outputSubpacket struct {
+	hashed        bool // true if this subpacket is in the hashed area.
+	subpacketType signatureSubpacketType
+	contents      []byte
+}
+
+func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
+	creationTime := make([]byte, 4)
+	creationTime[0] = byte(sig.CreationTime >> 24)
+	creationTime[1] = byte(sig.CreationTime >> 16)
+	creationTime[2] = byte(sig.CreationTime >> 8)
+	creationTime[3] = byte(sig.CreationTime)
+	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, creationTime})
+
+	if sig.IssuerKeyId != nil {
+		keyId := make([]byte, 8)
+		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
+		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, keyId})
+	}
+
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/signature_test.go b/src/pkg/crypto/openpgp/packet/signature_test.go
new file mode 100644
index 0000000..1305548
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/signature_test.go
@@ -0,0 +1,28 @@
+// 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 packet
+
+import (
+	"bytes"
+	"crypto"
+	"encoding/hex"
+	"testing"
+)
+
+func TestSignatureRead(t *testing.T) {
+	signatureData, _ := hex.DecodeString(signatureDataHex)
+	buf := bytes.NewBuffer(signatureData)
+	packet, err := Read(buf)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	sig, ok := packet.(*Signature)
+	if !ok || sig.SigType != SigTypeBinary || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA1 {
+		t.Errorf("failed to parse, got: %#v", packet)
+	}
+}
+
+const signatureDataHex = "89011c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644
index 0000000..d9010f8
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -0,0 +1,102 @@
+// 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 packet
+
+import (
+	"crypto/cipher"
+	"crypto/openpgp/error"
+	"crypto/openpgp/s2k"
+	"io"
+	"os"
+	"strconv"
+)
+
+// This is the largest session key that we'll support. Since no 512-bit cipher
+// has even been seriously used, this is comfortably large.
+const maxSessionKeySizeInBytes = 64
+
+// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
+// 4880, section 5.3.
+type SymmetricKeyEncrypted struct {
+	CipherFunc   CipherFunction
+	Encrypted    bool
+	Key          []byte // Empty unless Encrypted is false.
+	s2k          func(out, in []byte)
+	encryptedKey []byte
+}
+
+func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
+	// RFC 4880, section 5.3.
+	var buf [2]byte
+	_, err = readFull(r, buf[:])
+	if err != nil {
+		return
+	}
+	if buf[0] != 4 {
+		return error.UnsupportedError("SymmetricKeyEncrypted version")
+	}
+	ske.CipherFunc = CipherFunction(buf[1])
+
+	if ske.CipherFunc.keySize() == 0 {
+		return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
+	}
+
+	ske.s2k, err = s2k.Parse(r)
+	if err != nil {
+		return
+	}
+
+	encryptedKey := make([]byte, maxSessionKeySizeInBytes)
+	// The session key may follow. We just have to try and read to find
+	// out. If it exists then we limit it to maxSessionKeySizeInBytes.
+	n, err := readFull(r, encryptedKey)
+	if err != nil && err != io.ErrUnexpectedEOF {
+		return
+	}
+	err = nil
+	if n != 0 {
+		if n == maxSessionKeySizeInBytes {
+			return error.UnsupportedError("oversized encrypted session key")
+		}
+		ske.encryptedKey = encryptedKey[:n]
+	}
+
+	ske.Encrypted = true
+
+	return
+}
+
+// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
+// ske.Key will contain the session key.
+func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
+	if !ske.Encrypted {
+		return nil
+	}
+
+	key := make([]byte, ske.CipherFunc.keySize())
+	ske.s2k(key, passphrase)
+
+	if len(ske.encryptedKey) == 0 {
+		ske.Key = key
+	} else {
+		// the IV is all zeros
+		iv := make([]byte, ske.CipherFunc.blockSize())
+		c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
+		c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
+		ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
+		if ske.CipherFunc.blockSize() == 0 {
+			return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
+		}
+		ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
+		ske.Key = ske.encryptedKey[1:]
+		if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
+			ske.Key = nil
+			return error.StructuralError("length of decrypted key not a multiple of block size")
+		}
+	}
+
+	ske.Encrypted = false
+	return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
new file mode 100644
index 0000000..717c8ff
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
@@ -0,0 +1,62 @@
+// 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 packet
+
+import (
+	"bytes"
+	"encoding/hex"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func TestSymmetricKeyEncrypted(t *testing.T) {
+	buf := readerFromHex(symmetricallyEncryptedHex)
+	packet, err := Read(buf)
+	if err != nil {
+		t.Errorf("failed to read SymmetricKeyEncrypted: %s", err)
+		return
+	}
+	ske, ok := packet.(*SymmetricKeyEncrypted)
+	if !ok {
+		t.Error("didn't find SymmetricKeyEncrypted packet")
+		return
+	}
+	err = ske.Decrypt([]byte("password"))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	packet, err = Read(buf)
+	if err != nil {
+		t.Errorf("failed to read SymmetricallyEncrypted: %s", err)
+		return
+	}
+	se, ok := packet.(*SymmetricallyEncrypted)
+	if !ok {
+		t.Error("didn't find SymmetricallyEncrypted packet")
+		return
+	}
+	r, err := se.Decrypt(ske.CipherFunc, ske.Key)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	contents, err := ioutil.ReadAll(r)
+	if err != nil && err != os.EOF {
+		t.Error(err)
+		return
+	}
+
+	expectedContents, _ := hex.DecodeString(symmetricallyEncryptedContentsHex)
+	if !bytes.Equal(expectedContents, contents) {
+		t.Errorf("bad contents got:%x want:%x", contents, expectedContents)
+	}
+}
+
+const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
+const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
new file mode 100644
index 0000000..fc19ffe
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -0,0 +1,206 @@
+// 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 packet
+
+import (
+	"crypto/cipher"
+	"crypto/openpgp/error"
+	"crypto/sha1"
+	"crypto/subtle"
+	"hash"
+	"io"
+	"os"
+	"strconv"
+)
+
+// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
+// sections 5.7 and 5.13.
+type SymmetricallyEncrypted struct {
+	MDC      bool // true iff this is a type 18 packet and thus has an embedded MAC.
+	contents io.Reader
+	prefix   []byte
+}
+
+func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
+	if se.MDC {
+		// See RFC 4880, section 5.13.
+		var buf [1]byte
+		_, err := readFull(r, buf[:])
+		if err != nil {
+			return err
+		}
+		if buf[0] != 1 {
+			return error.UnsupportedError("unknown SymmetricallyEncrypted version")
+		}
+	}
+	se.contents = r
+	return nil
+}
+
+// Decrypt returns a ReadCloser, from which the decrypted contents of the
+// packet can be read. An incorrect key can, with high probability, be detected
+// immediately and this will result in a KeyIncorrect error being returned.
+func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) {
+	keySize := c.keySize()
+	if keySize == 0 {
+		return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
+	}
+	if len(key) != keySize {
+		return nil, error.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+	}
+
+	if se.prefix == nil {
+		se.prefix = make([]byte, c.blockSize()+2)
+		_, err := readFull(se.contents, se.prefix)
+		if err != nil {
+			return nil, err
+		}
+	} else if len(se.prefix) != c.blockSize()+2 {
+		return nil, error.InvalidArgumentError("can't try ciphers with different block lengths")
+	}
+
+	ocfbResync := cipher.OCFBResync
+	if se.MDC {
+		// MDC packets use a different form of OCFB mode.
+		ocfbResync = cipher.OCFBNoResync
+	}
+
+	s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+	if s == nil {
+		return nil, error.KeyIncorrectError
+	}
+
+	plaintext := cipher.StreamReader{S: s, R: se.contents}
+
+	if se.MDC {
+		// MDC packets have an embedded hash that we need to check.
+		h := sha1.New()
+		h.Write(se.prefix)
+		return &seMDCReader{in: plaintext, h: h}, nil
+	}
+
+	// Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+	return seReader{plaintext}, nil
+}
+
+// seReader wraps an io.Reader with a no-op Close method.
+type seReader struct {
+	in io.Reader
+}
+
+func (ser seReader) Read(buf []byte) (int, os.Error) {
+	return ser.in.Read(buf)
+}
+
+func (ser seReader) Close() os.Error {
+	return nil
+}
+
+const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
+
+// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
+// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
+// MDC packet containing a hash of the previous contents which is checked
+// against the running hash. See RFC 4880, section 5.13.
+type seMDCReader struct {
+	in          io.Reader
+	h           hash.Hash
+	trailer     [mdcTrailerSize]byte
+	scratch     [mdcTrailerSize]byte
+	trailerUsed int
+	error       bool
+	eof         bool
+}
+
+func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) {
+	if ser.error {
+		err = io.ErrUnexpectedEOF
+		return
+	}
+	if ser.eof {
+		err = os.EOF
+		return
+	}
+
+	// If we haven't yet filled the trailer buffer then we must do that
+	// first.
+	for ser.trailerUsed < mdcTrailerSize {
+		n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
+		ser.trailerUsed += n
+		if err == os.EOF {
+			if ser.trailerUsed != mdcTrailerSize {
+				n = 0
+				err = io.ErrUnexpectedEOF
+				ser.error = true
+				return
+			}
+			ser.eof = true
+			n = 0
+			return
+		}
+
+		if err != nil {
+			n = 0
+			return
+		}
+	}
+
+	// If it's a short read then we read into a temporary buffer and shift
+	// the data into the caller's buffer.
+	if len(buf) <= mdcTrailerSize {
+		n, err = readFull(ser.in, ser.scratch[:len(buf)])
+		copy(buf, ser.trailer[:n])
+		ser.h.Write(buf[:n])
+		copy(ser.trailer[:], ser.trailer[n:])
+		copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
+		if n < len(buf) {
+			ser.eof = true
+			err = os.EOF
+		}
+		return
+	}
+
+	n, err = ser.in.Read(buf[mdcTrailerSize:])
+	copy(buf, ser.trailer[:])
+	ser.h.Write(buf[:n])
+	copy(ser.trailer[:], buf[n:])
+
+	if err == os.EOF {
+		ser.eof = true
+	}
+	return
+}
+
+func (ser *seMDCReader) Close() os.Error {
+	if ser.error {
+		return error.SignatureError("error during reading")
+	}
+
+	for !ser.eof {
+		// We haven't seen EOF so we need to read to the end
+		var buf [1024]byte
+		_, err := ser.Read(buf[:])
+		if err == os.EOF {
+			break
+		}
+		if err != nil {
+			return error.SignatureError("error during reading")
+		}
+	}
+
+	// This is a new-format packet tag byte for a type 19 (MDC) packet.
+	const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+	if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
+		return error.SignatureError("MDC packet not found")
+	}
+	ser.h.Write(ser.trailer[:2])
+
+	final := ser.h.Sum()
+	if subtle.ConstantTimeCompare(final, ser.trailer[2:]) == 1 {
+		return error.SignatureError("hash mismatch")
+	}
+	return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
new file mode 100644
index 0000000..ee5a30d
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -0,0 +1,78 @@
+// 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 packet
+
+import (
+	"bytes"
+	"crypto/openpgp/error"
+	"crypto/sha1"
+	"encoding/hex"
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+// TestReader wraps a []byte and returns reads of a specific length.
+type testReader struct {
+	data   []byte
+	stride int
+}
+
+func (t *testReader) Read(buf []byte) (n int, err os.Error) {
+	n = t.stride
+	if n > len(t.data) {
+		n = len(t.data)
+	}
+	if n > len(buf) {
+		n = len(buf)
+	}
+	copy(buf, t.data)
+	t.data = t.data[n:]
+	if len(t.data) == 0 {
+		err = os.EOF
+	}
+	return
+}
+
+func testMDCReader(t *testing.T) {
+	mdcPlaintext, _ := hex.DecodeString(mdcPlaintextHex)
+
+	for stride := 1; stride < len(mdcPlaintext)/2; stride++ {
+		r := &testReader{data: mdcPlaintext, stride: stride}
+		mdcReader := &seMDCReader{in: r, h: sha1.New()}
+		body, err := ioutil.ReadAll(mdcReader)
+		if err != nil {
+			t.Errorf("stride: %d, error: %s", stride, err)
+			continue
+		}
+		if !bytes.Equal(body, mdcPlaintext[:len(mdcPlaintext)-22]) {
+			t.Errorf("stride: %d: bad contents %x", stride, body)
+			continue
+		}
+
+		err = mdcReader.Close()
+		if err != nil {
+			t.Errorf("stride: %d, error on Close: %s", err)
+		}
+	}
+
+	mdcPlaintext[15] ^= 80
+
+	r := &testReader{data: mdcPlaintext, stride: 2}
+	mdcReader := &seMDCReader{in: r, h: sha1.New()}
+	_, err := ioutil.ReadAll(mdcReader)
+	if err != nil {
+		t.Errorf("corruption test, error: %s", err)
+		return
+	}
+	err = mdcReader.Close()
+	if err == nil {
+		t.Error("corruption: no error")
+	} else if _, ok := err.(*error.SignatureError); !ok {
+		t.Errorf("corruption: expected SignatureError, got: %s", err)
+	}
+}
+
+const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
diff --git a/src/pkg/crypto/openpgp/packet/userid.go b/src/pkg/crypto/openpgp/packet/userid.go
new file mode 100644
index 0000000..ed2ad77
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/userid.go
@@ -0,0 +1,105 @@
+// 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 packet
+
+import (
+	"io"
+	"io/ioutil"
+	"os"
+	"strings"
+)
+
+// UserId contains text that is intended to represent the name and email
+// address of the key holder. See RFC 4880, section 5.11. By convention, this
+// takes the form "Full Name (Comment) <email at example.com>"
+type UserId struct {
+	Id string // By convention, this takes the form "Full Name (Comment) <email at example.com>" which is split out in the fields below.
+
+	Name, Comment, Email string
+}
+
+func (uid *UserId) parse(r io.Reader) (err os.Error) {
+	// RFC 4880, section 5.11
+	b, err := ioutil.ReadAll(r)
+	if err != nil {
+		return
+	}
+	uid.Id = string(b)
+	uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
+	return
+}
+
+// parseUserId extracts the name, comment and email from a user id string that
+// is formatted as "Full Name (Comment) <email at example.com>".
+func parseUserId(id string) (name, comment, email string) {
+	var n, c, e struct {
+		start, end int
+	}
+	var state int
+
+	for offset, rune := range id {
+		switch state {
+		case 0:
+			// Entering name
+			n.start = offset
+			state = 1
+			fallthrough
+		case 1:
+			// In name
+			if rune == '(' {
+				state = 2
+				n.end = offset
+			} else if rune == '<' {
+				state = 5
+				n.end = offset
+			}
+		case 2:
+			// Entering comment
+			c.start = offset
+			state = 3
+			fallthrough
+		case 3:
+			// In comment
+			if rune == ')' {
+				state = 4
+				c.end = offset
+			}
+		case 4:
+			// Between comment and email
+			if rune == '<' {
+				state = 5
+			}
+		case 5:
+			// Entering email
+			e.start = offset
+			state = 6
+			fallthrough
+		case 6:
+			// In email
+			if rune == '>' {
+				state = 7
+				e.end = offset
+			}
+		default:
+			// After email
+		}
+	}
+	switch state {
+	case 1:
+		// ended in the name
+		n.end = len(id)
+	case 3:
+		// ended in comment
+		c.end = len(id)
+	case 6:
+		// ended in email
+		e.end = len(id)
+	}
+
+	name = strings.TrimSpace(id[n.start:n.end])
+	comment = strings.TrimSpace(id[c.start:c.end])
+	email = strings.TrimSpace(id[e.start:e.end])
+	return
+}
diff --git a/src/pkg/crypto/openpgp/packet/userid_test.go b/src/pkg/crypto/openpgp/packet/userid_test.go
new file mode 100644
index 0000000..394873d
--- /dev/null
+++ b/src/pkg/crypto/openpgp/packet/userid_test.go
@@ -0,0 +1,42 @@
+// 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 packet
+
+import (
+	"testing"
+)
+
+var userIdTests = []struct {
+	id                   string
+	name, comment, email string
+}{
+	{"", "", "", ""},
+	{"John Smith", "John Smith", "", ""},
+	{"John Smith ()", "John Smith", "", ""},
+	{"John Smith () <>", "John Smith", "", ""},
+	{"(comment", "", "comment", ""},
+	{"(comment)", "", "comment", ""},
+	{"<email", "", "", "email"},
+	{"<email>   sdfk", "", "", "email"},
+	{"  John Smith  (  Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
+	{"  John Smith  < email > lksdfj", "John Smith", "", "email"},
+	{"(<foo", "", "<foo", ""},
+	{"René Descartes (العربي)", "René Descartes", "العربي", ""},
+}
+
+func TestParseUserId(t *testing.T) {
+	for i, test := range userIdTests {
+		name, comment, email := parseUserId(test.id)
+		if name != test.name {
+			t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
+		}
+		if comment != test.comment {
+			t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
+		}
+		if email != test.email {
+			t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
+		}
+	}
+}
diff --git a/src/pkg/crypto/openpgp/s2k/s2k.go b/src/pkg/crypto/openpgp/s2k/s2k.go
index f369d7e..873b33d 100644
--- a/src/pkg/crypto/openpgp/s2k/s2k.go
+++ b/src/pkg/crypto/openpgp/s2k/s2k.go
@@ -7,15 +7,12 @@
 package s2k
 
 import (
-	"crypto/md5"
+	"crypto"
 	"crypto/openpgp/error"
-	"crypto/ripemd160"
-	"crypto/sha1"
-	"crypto/sha256"
-	"crypto/sha512"
 	"hash"
 	"io"
 	"os"
+	"strconv"
 )
 
 // Simple writes to out the result of computing the Simple S2K function (RFC
@@ -87,9 +84,13 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
 		return
 	}
 
-	h := hashFuncFromType(buf[1])
+	hash, ok := HashIdToHash(buf[1])
+	if !ok {
+		return nil, error.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
+	}
+	h := hash.New()
 	if h == nil {
-		return nil, error.UnsupportedError("hash for S2K function")
+		return nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hash)))
 	}
 
 	switch buf[0] {
@@ -122,25 +123,38 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
 	return nil, error.UnsupportedError("S2K function")
 }
 
-// hashFuncFromType returns a hash.Hash which corresponds to the given hash
-// type byte. See RFC 4880, section 9.4.
-func hashFuncFromType(hashType byte) hash.Hash {
-	switch hashType {
-	case 1:
-		return md5.New()
-	case 2:
-		return sha1.New()
-	case 3:
-		return ripemd160.New()
-	case 8:
-		return sha256.New()
-	case 9:
-		return sha512.New384()
-	case 10:
-		return sha512.New()
-	case 11:
-		return sha256.New224()
+// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
+// Go's crypto.Hash type. See RFC 4880, section 9.4.
+var hashToHashIdMapping = []struct {
+	id   byte
+	hash crypto.Hash
+}{
+	{1, crypto.MD5},
+	{2, crypto.SHA1},
+	{3, crypto.RIPEMD160},
+	{8, crypto.SHA256},
+	{9, crypto.SHA384},
+	{10, crypto.SHA512},
+	{11, crypto.SHA224},
+}
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+	for _, m := range hashToHashIdMapping {
+		if m.id == id {
+			return m.hash, true
+		}
 	}
+	return 0, false
+}
 
-	return nil
+// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+	for _, m := range hashToHashIdMapping {
+		if m.hash == h {
+			return m.id, true
+		}
+	}
+	return 0, false
 }
diff --git a/src/pkg/crypto/rand/rand_windows.go b/src/pkg/crypto/rand/rand_windows.go
index 4b2b7a2..281d6dc 100755
--- a/src/pkg/crypto/rand/rand_windows.go
+++ b/src/pkg/crypto/rand/rand_windows.go
@@ -28,15 +28,15 @@ func (r *rngReader) Read(b []byte) (n int, err os.Error) {
 	if r.prov == 0 {
 		const provType = syscall.PROV_RSA_FULL
 		const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
-		ok, errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
-		if !ok {
+		errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+		if errno != 0 {
 			r.mu.Unlock()
 			return 0, os.NewSyscallError("CryptAcquireContext", errno)
 		}
 	}
 	r.mu.Unlock()
-	ok, errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
-	if !ok {
+	errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+	if errno != 0 {
 		return 0, os.NewSyscallError("CryptGenRandom", errno)
 	}
 	return len(b), nil
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index af46ea5..809c8c1 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -57,6 +57,7 @@ Curves:
 
 	var suite *cipherSuite
 	var suiteId uint16
+FindCipherSuite:
 	for _, id := range clientHello.cipherSuites {
 		for _, supported := range config.cipherSuites() {
 			if id == supported {
@@ -67,7 +68,7 @@ Curves:
 					continue
 				}
 				suiteId = id
-				break
+				break FindCipherSuite
 			}
 		}
 	}
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index b11d322..e8290d7 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -124,14 +124,22 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
 		return
 	}
 
-	certDERBlock, _ := pem.Decode(certPEMBlock)
-	if certDERBlock == nil {
+	var certDERBlock *pem.Block
+	for {
+		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+		if certDERBlock == nil {
+			break
+		}
+		if certDERBlock.Type == "CERTIFICATE" {
+			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+		}
+	}
+
+	if len(cert.Certificate) == 0 {
 		err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
 		return
 	}
 
-	cert.Certificate = [][]byte{certDERBlock.Bytes}
-
 	keyPEMBlock, err := ioutil.ReadFile(keyFile)
 	if err != nil {
 		return
@@ -153,7 +161,7 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
 
 	// We don't need to parse the public key for TLS, but we so do anyway
 	// to check that it looks sane and matches the private key.
-	x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
+	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
 	if err != nil {
 		return
 	}
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 5992634..3af8ba8 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -331,6 +331,10 @@ type Certificate struct {
 	DNSNames       []string
 	EmailAddresses []string
 
+	// Name constraints
+	PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
+	PermittedDNSDomains         []string
+
 	PolicyIdentifiers []asn1.ObjectIdentifier
 }
 
@@ -475,6 +479,18 @@ type policyInformation struct {
 	// policyQualifiers omitted
 }
 
+// RFC 5280, 4.2.1.10
+type nameConstraints struct {
+	Permitted []generalSubtree "optional,tag:0"
+	Excluded  []generalSubtree "optional,tag:1"
+}
+
+type generalSubtree struct {
+	Name string "tag:2,optional,ia5"
+	Min  int    "optional,tag:0"
+	Max  int    "optional,tag:1"
+}
+
 func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
 	switch algo {
 	case RSA:
@@ -603,6 +619,43 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
 				// If we didn't parse any of the names then we
 				// fall through to the critical check below.
 
+			case 30:
+				// RFC 5280, 4.2.1.10
+
+				// NameConstraints ::= SEQUENCE {
+				//      permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+				//      excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+				//
+				// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+				//
+				// GeneralSubtree ::= SEQUENCE {
+				//      base                    GeneralName,
+				//      minimum         [0]     BaseDistance DEFAULT 0,
+				//      maximum         [1]     BaseDistance OPTIONAL }
+				//
+				// BaseDistance ::= INTEGER (0..MAX)
+
+				var constraints nameConstraints
+				_, err := asn1.Unmarshal(e.Value, &constraints)
+				if err != nil {
+					return nil, err
+				}
+
+				if len(constraints.Excluded) > 0 && e.Critical {
+					return out, UnhandledCriticalExtension{}
+				}
+
+				for _, subtree := range constraints.Permitted {
+					if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 {
+						if e.Critical {
+							return out, UnhandledCriticalExtension{}
+						}
+						continue
+					}
+					out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
+				}
+				continue
+
 			case 35:
 				// RFC 5280, 4.2.1.1
 				var a authKeyId
@@ -699,10 +752,11 @@ var (
 	oidExtensionBasicConstraints    = []int{2, 5, 29, 19}
 	oidExtensionSubjectAltName      = []int{2, 5, 29, 17}
 	oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
+	oidExtensionNameConstraints     = []int{2, 5, 29, 30}
 )
 
 func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
-	ret = make([]extension, 6 /* maximum number of elements. */ )
+	ret = make([]extension, 7 /* maximum number of elements. */ )
 	n := 0
 
 	if template.KeyUsage != 0 {
@@ -779,6 +833,22 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
 		n++
 	}
 
+	if len(template.PermittedDNSDomains) > 0 {
+		ret[n].Id = oidExtensionNameConstraints
+		ret[n].Critical = template.PermittedDNSDomainsCritical
+
+		var out nameConstraints
+		out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains))
+		for i, permitted := range template.PermittedDNSDomains {
+			out.Permitted[i] = generalSubtree{Name: permitted}
+		}
+		ret[n].Value, err = asn1.Marshal(out)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
 	// Adding another extension here? Remember to update the maximum number
 	// of elements in the make() at the top of the function.
 
@@ -793,7 +863,8 @@ var (
 // CreateSelfSignedCertificate creates a new certificate based on
 // a template. The following members of template are used: SerialNumber,
 // Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
-// MaxPathLen, SubjectKeyId, DNSNames.
+// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
+// PermittedDNSDomains.
 //
 // The certificate is signed by parent. If parent is equal to template then the
 // certificate is self-signed. The parameter pub is the public key of the
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index 2fe47fd..57889e7 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -171,7 +171,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 		IsCA:                  true,
 		DNSNames:              []string{"test.example.com"},
 
-		PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
+		PolicyIdentifiers:   []asn1.ObjectIdentifier{[]int{1, 2, 3}},
+		PermittedDNSDomains: []string{".example.com", "example.com"},
 	}
 
 	derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
@@ -190,6 +191,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 		t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
 	}
 
+	if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" {
+		t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains)
+	}
+
 	err = cert.CheckSignatureFrom(cert)
 	if err != nil {
 		t.Errorf("Signature verification failed: %s", err)
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index 82c0240..1bcbdc5 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -57,7 +57,6 @@ type ImportDirectory struct {
 	FirstThunk         uint32
 
 	dll string
-	rva []uint32
 }
 
 // Data reads and returns the contents of the PE section.
@@ -267,34 +266,28 @@ func (f *File) ImportedSymbols() ([]string, os.Error) {
 		}
 		ida = append(ida, dt)
 	}
-	for i, _ := range ida {
+	names, _ := ds.Data()
+	var all []string
+	for _, dt := range ida {
+		dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
+		d, _ = ds.Data()
+		// seek to OriginalFirstThunk
+		d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
 		for len(d) > 0 {
 			va := binary.LittleEndian.Uint32(d[0:4])
 			d = d[4:]
 			if va == 0 {
 				break
 			}
-			ida[i].rva = append(ida[i].rva, va)
-		}
-	}
-	for _, _ = range ida {
-		for len(d) > 0 {
-			va := binary.LittleEndian.Uint32(d[0:4])
-			d = d[4:]
-			if va == 0 {
-				break
+			if va&0x80000000 > 0 { // is Ordinal
+				// TODO add dynimport ordinal support.
+				//ord := va&0x0000FFFF
+			} else {
+				fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+				all = append(all, fn+":"+dt.dll)
 			}
 		}
 	}
-	names, _ := ds.Data()
-	var all []string
-	for _, dt := range ida {
-		dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress))
-		for _, va := range dt.rva {
-			fn, _ := getString(names, int(va-ds.VirtualAddress+2))
-			all = append(all, fn+":"+dt.dll)
-		}
-	}
 
 	return all, nil
 }
diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go
index bbe530c..69ad5fe 100644
--- a/src/pkg/ebnf/ebnf_test.go
+++ b/src/pkg/ebnf/ebnf_test.go
@@ -15,31 +15,31 @@ var fset = token.NewFileSet()
 
 
 var grammars = []string{
-	`Program = .
-	`,
-
-	`Program = foo .
-	foo = "foo" .
-	`,
-
-	`Program = "a" | "b" "c" .
-	`,
-
-	`Program = "a" ... "z" .
-	`,
-
-	`Program = Song .
-	 Song = { Note } .
-	 Note = Do | (Re | Mi | Fa | So | La) | Ti .
-	 Do = "c" .
-	 Re = "d" .
-	 Mi = "e" .
-	 Fa = "f" .
-	 So = "g" .
-	 La = "a" .
-	 Ti = ti .
-	 ti = "b" .
-	`,
+`Program = .
+`,
+
+`Program = foo .
+foo = "foo" .
+`,
+
+`Program = "a" | "b" "c" .
+`,
+
+`Program = "a" ... "z" .
+`,
+
+`Program = Song .
+ Song = { Note } .
+ Note = Do | (Re | Mi | Fa | So | La) | Ti .
+ Do = "c" .
+ Re = "d" .
+ Mi = "e" .
+ Fa = "f" .
+ So = "g" .
+ La = "a" .
+ Ti = ti .
+ ti = "b" .
+`,
 }
 
 
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index 77ff3a9..ee2f23d 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This package implements translation between
-// unsigned integer values and byte sequences.
+// Package binary implements translation between
+// unsigned integer values and byte sequences
+// and the reading and writing of fixed-size values.
 package binary
 
 import (
diff --git a/src/pkg/encoding/line/line.go b/src/pkg/encoding/line/line.go
index 779b575..f46ce1c 100644
--- a/src/pkg/encoding/line/line.go
+++ b/src/pkg/encoding/line/line.go
@@ -105,6 +105,9 @@ func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
 		l.buf = l.buf[:oldLen+n]
 		if readErr != nil {
 			l.err = readErr
+			if len(l.buf) == 0 {
+				return nil, false, readErr
+			}
 		}
 	}
 	panic("unreachable")
diff --git a/src/pkg/encoding/line/line_test.go b/src/pkg/encoding/line/line_test.go
index ff16d10..ff3d516 100644
--- a/src/pkg/encoding/line/line_test.go
+++ b/src/pkg/encoding/line/line_test.go
@@ -7,6 +7,7 @@ package line
 import (
 	"bytes"
 	"io"
+	"io/ioutil"
 	"os"
 	"testing"
 )
@@ -108,3 +109,25 @@ func TestReadAfterLines(t *testing.T) {
 		t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData)
 	}
 }
+
+func TestReadEmptyBuffer(t *testing.T) {
+	l := NewReader(bytes.NewBuffer(nil), 10)
+	line, isPrefix, err := l.ReadLine()
+	if err != os.EOF {
+		t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
+	}
+}
+
+func TestLinesAfterRead(t *testing.T) {
+	l := NewReader(bytes.NewBuffer([]byte("foo")), 10)
+	_, err := ioutil.ReadAll(l)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	line, isPrefix, err := l.ReadLine()
+	if err != os.EOF {
+		t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
+	}
+}
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index 4f4c8c7..80f6f3c 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -22,12 +22,12 @@ const (
 // Stdin, Stdout, and Stderr are Files representing pipes
 // connected to the running command's standard input, output, and error,
 // or else nil, depending on the arguments to Run.
-// Pid is the running command's operating system process ID.
+// Process represents the underlying operating system process.
 type Cmd struct {
-	Stdin  *os.File
-	Stdout *os.File
-	Stderr *os.File
-	Pid    int
+	Stdin   *os.File
+	Stdout  *os.File
+	Stderr  *os.File
+	Process *os.Process
 }
 
 // PathError records the name of a binary that was not
@@ -88,24 +88,24 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
 // If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
 // of the returned Cmd is the other end of the pipe.
 // Otherwise the field in Cmd is nil.
-func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
-	p = new(Cmd)
+func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
+	c = new(Cmd)
 	var fd [3]*os.File
 
-	if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil {
+	if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
 		goto Error
 	}
-	if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil {
+	if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
 		goto Error
 	}
 	if stderr == MergeWithStdout {
 		fd[2] = fd[1]
-	} else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil {
+	} else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
 		goto Error
 	}
 
 	// Run command.
-	p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
+	c.Process, err = os.StartProcess(name, argv, envv, dir, fd[0:])
 	if err != nil {
 		goto Error
 	}
@@ -118,7 +118,7 @@ func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int
 	if fd[2] != os.Stderr && fd[2] != fd[1] {
 		fd[2].Close()
 	}
-	return p, nil
+	return c, nil
 
 Error:
 	if fd[0] != os.Stdin && fd[0] != nil {
@@ -130,63 +130,67 @@ Error:
 	if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
 		fd[2].Close()
 	}
-	if p.Stdin != nil {
-		p.Stdin.Close()
+	if c.Stdin != nil {
+		c.Stdin.Close()
 	}
-	if p.Stdout != nil {
-		p.Stdout.Close()
+	if c.Stdout != nil {
+		c.Stdout.Close()
 	}
-	if p.Stderr != nil {
-		p.Stderr.Close()
+	if c.Stderr != nil {
+		c.Stderr.Close()
+	}
+	if c.Process != nil {
+		c.Process.Release()
 	}
 	return nil, err
 }
 
-// Wait waits for the running command p,
-// returning the Waitmsg returned by os.Wait and an error.
-// The options are passed through to os.Wait.
-// Setting options to 0 waits for p to exit;
+// Wait waits for the running command c,
+// returning the Waitmsg returned when the process exits.
+// The options are passed to the process's Wait method.
+// Setting options to 0 waits for c to exit;
 // other options cause Wait to return for other
 // process events; see package os for details.
-func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
-	if p.Pid <= 0 {
+func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
+	if c.Process == nil {
 		return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
 	}
-	w, err := os.Wait(p.Pid, options)
+	w, err := c.Process.Wait(options)
 	if w != nil && (w.Exited() || w.Signaled()) {
-		p.Pid = -1
+		c.Process.Release()
+		c.Process = nil
 	}
 	return w, err
 }
 
-// Close waits for the running command p to exit,
+// Close waits for the running command c to exit,
 // if it hasn't already, and then closes the non-nil file descriptors
-// p.Stdin, p.Stdout, and p.Stderr.
-func (p *Cmd) Close() os.Error {
-	if p.Pid > 0 {
+// c.Stdin, c.Stdout, and c.Stderr.
+func (c *Cmd) Close() os.Error {
+	if c.Process != nil {
 		// Loop on interrupt, but
 		// ignore other errors -- maybe
 		// caller has already waited for pid.
-		_, err := p.Wait(0)
+		_, err := c.Wait(0)
 		for err == os.EINTR {
-			_, err = p.Wait(0)
+			_, err = c.Wait(0)
 		}
 	}
 
 	// Close the FDs that are still open.
 	var err os.Error
-	if p.Stdin != nil && p.Stdin.Fd() >= 0 {
-		if err1 := p.Stdin.Close(); err1 != nil {
+	if c.Stdin != nil && c.Stdin.Fd() >= 0 {
+		if err1 := c.Stdin.Close(); err1 != nil {
 			err = err1
 		}
 	}
-	if p.Stdout != nil && p.Stdout.Fd() >= 0 {
-		if err1 := p.Stdout.Close(); err1 != nil && err != nil {
+	if c.Stdout != nil && c.Stdout.Fd() >= 0 {
+		if err1 := c.Stdout.Close(); err1 != nil && err != nil {
 			err = err1
 		}
 	}
-	if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 {
-		if err1 := p.Stderr.Close(); err1 != nil && err != nil {
+	if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
+		if err1 := c.Stderr.Close(); err1 != nil && err != nil {
 			err = err1
 		}
 	}
diff --git a/src/pkg/exp/eval/gen.go b/src/pkg/exp/eval/gen.go
index a2b1198..de98a5d 100644
--- a/src/pkg/exp/eval/gen.go
+++ b/src/pkg/exp/eval/gen.go
@@ -368,7 +368,7 @@ func main() {
 	if err != nil {
 		log.Exit(err)
 	}
-	err = t.Execute(data, os.Stdout)
+	err = t.Execute(os.Stdout, data)
 	if err != nil {
 		log.Exit(err)
 	}
diff --git a/src/pkg/exp/eval/stmt.go b/src/pkg/exp/eval/stmt.go
index 77ff066..5c5d433 100644
--- a/src/pkg/exp/eval/stmt.go
+++ b/src/pkg/exp/eval/stmt.go
@@ -908,7 +908,7 @@ func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
 		return
 
 	default:
-		log.Panic("Unexpected branch token %v", s.Tok)
+		log.Panicf("Unexpected branch token %v", s.Tok)
 	}
 
 	a.flow.put1(false, pc)
diff --git a/src/pkg/exp/wingui/gui.go b/src/pkg/exp/wingui/gui.go
index 41ee5b7..cf39293 100644
--- a/src/pkg/exp/wingui/gui.go
+++ b/src/pkg/exp/wingui/gui.go
@@ -51,7 +51,8 @@ func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr {
 	case WM_COMMAND:
 		switch uint32(lparam) {
 		case bh:
-			if ok, e := PostMessage(hwnd, WM_CLOSE, 0, 0); !ok {
+			e := PostMessage(hwnd, WM_CLOSE, 0, 0)
+			if e != 0 {
 				abortErrNo("PostMessage", e)
 			}
 		default:
@@ -125,7 +126,7 @@ func rungui() int {
 	ShowWindow(wh, SW_SHOWDEFAULT)
 
 	// UpdateWindow
-	if _, e := UpdateWindow(wh); e != 0 {
+	if e := UpdateWindow(wh); e != 0 {
 		abortErrNo("UpdateWindow", e)
 	}
 
diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go
index 2f480ec..c96f452 100644
--- a/src/pkg/exp/wingui/winapi.go
+++ b/src/pkg/exp/wingui/winapi.go
@@ -130,18 +130,18 @@ var (
 //sys	RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) = user32.RegisterClassExW
 //sys	CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) = user32.CreateWindowExW
 //sys	DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.DefWindowProcW
-//sys	DestroyWindow(hwnd uint32) (ok bool, errno int) = user32.DestroyWindow
+//sys	DestroyWindow(hwnd uint32) (errno int) = user32.DestroyWindow
 //sys	PostQuitMessage(exitcode int32) = user32.PostQuitMessage
-//sys	ShowWindow(hwnd uint32, cmdshow int32) (ok bool) = user32.ShowWindow
-//sys	UpdateWindow(hwnd uint32) (ok bool, errno int) = user32.UpdateWindow
+//sys	ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) = user32.ShowWindow
+//sys	UpdateWindow(hwnd uint32) (errno int) = user32.UpdateWindow
 //sys	GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) [failretval==-1] = user32.GetMessageW
-//sys	TranslateMessage(msg *Msg) (ok bool) = user32.TranslateMessage
+//sys	TranslateMessage(msg *Msg) (done bool) = user32.TranslateMessage
 //sys	DispatchMessage(msg *Msg) (ret int32) = user32.DispatchMessageW
 //sys	LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) = user32.LoadIconW
 //sys	LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) = user32.LoadCursorW
 //sys	SetCursor(cursor uint32) (precursor uint32, errno int) = user32.SetCursor
 //sys	SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.SendMessageW
-//sys	PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (ok bool, errno int) = user32.PostMessageW
+//sys	PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) = user32.PostMessageW
 
 func MakeIntResource(id uint16) *uint16 {
 	return (*uint16)(unsafe.Pointer(uintptr(id)))
diff --git a/src/pkg/exp/wingui/zwinapi.go b/src/pkg/exp/wingui/zwinapi.go
index 324bf17..60aaac6 100644
--- a/src/pkg/exp/wingui/zwinapi.go
+++ b/src/pkg/exp/wingui/zwinapi.go
@@ -79,10 +79,9 @@ func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult
 	return
 }
 
-func DestroyWindow(hwnd uint32) (ok bool, errno int) {
-	r0, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func DestroyWindow(hwnd uint32) (errno int) {
+	r1, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -99,16 +98,15 @@ func PostQuitMessage(exitcode int32) {
 	return
 }
 
-func ShowWindow(hwnd uint32, cmdshow int32) (ok bool) {
+func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) {
 	r0, _, _ := syscall.Syscall(procShowWindow, 2, uintptr(hwnd), uintptr(cmdshow), 0)
-	ok = bool(r0 != 0)
+	wasvisible = bool(r0 != 0)
 	return
 }
 
-func UpdateWindow(hwnd uint32) (ok bool, errno int) {
-	r0, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func UpdateWindow(hwnd uint32) (errno int) {
+	r1, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -135,9 +133,9 @@ func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32)
 	return
 }
 
-func TranslateMessage(msg *Msg) (ok bool) {
+func TranslateMessage(msg *Msg) (done bool) {
 	r0, _, _ := syscall.Syscall(procTranslateMessage, 1, uintptr(unsafe.Pointer(msg)), 0, 0)
-	ok = bool(r0 != 0)
+	done = bool(r0 != 0)
 	return
 }
 
@@ -198,10 +196,9 @@ func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult i
 	return
 }
 
-func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (ok bool, errno int) {
-	r0, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) {
+	r1, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index 143a106..be97205 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -96,7 +96,7 @@ func newIntValue(val int, p *int) *intValue {
 }
 
 func (i *intValue) Set(s string) bool {
-	v, err := strconv.Atoi(s)
+	v, err := strconv.Btoi64(s, 0)
 	*i = intValue(v)
 	return err == nil
 }
@@ -112,7 +112,7 @@ func newInt64Value(val int64, p *int64) *int64Value {
 }
 
 func (i *int64Value) Set(s string) bool {
-	v, err := strconv.Atoi64(s)
+	v, err := strconv.Btoi64(s, 0)
 	*i = int64Value(v)
 	return err == nil
 }
@@ -128,7 +128,7 @@ func newUintValue(val uint, p *uint) *uintValue {
 }
 
 func (i *uintValue) Set(s string) bool {
-	v, err := strconv.Atoui(s)
+	v, err := strconv.Btoui64(s, 0)
 	*i = uintValue(v)
 	return err == nil
 }
@@ -144,7 +144,7 @@ func newUint64Value(val uint64, p *uint64) *uint64Value {
 }
 
 func (i *uint64Value) Set(s string) bool {
-	v, err := strconv.Atoui64(s)
+	v, err := strconv.Btoui64(s, 0)
 	*i = uint64Value(v)
 	return err == nil
 }
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
index b91a8b5..30a21e6 100644
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -106,7 +106,7 @@ func TestParse(t *testing.T) {
 		"-bool",
 		"-bool2=true",
 		"--int", "22",
-		"--int64", "23",
+		"--int64", "0x23",
 		"-uint", "24",
 		"--uint64", "25",
 		"-string", "hello",
@@ -125,8 +125,8 @@ func TestParse(t *testing.T) {
 	if *intFlag != 22 {
 		t.Error("int flag should be 22, is ", *intFlag)
 	}
-	if *int64Flag != 23 {
-		t.Error("int64 flag should be 23, is ", *int64Flag)
+	if *int64Flag != 0x23 {
+		t.Error("int64 flag should be 0x23, is ", *int64Flag)
 	}
 	if *uintFlag != 24 {
 		t.Error("uint flag should be 24, is ", *uintFlag)
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 02c2938..b40e265 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -16,6 +16,7 @@
 			when printing structs, the plus flag (%+v) adds field names
 		%#v	a Go-syntax representation of the value
 		%T	a Go-syntax representation of the type of the value
+		%%	a literal percent sign; consumes no value
 
 	Boolean:
 		%t	the word true or false
@@ -28,6 +29,8 @@
 		%X	base 16, with upper-case letters for A-F
 		%U	Unicode format: U+1234; same as "U+%x" with 4 digits default
 	Floating-point and complex constituents:
+		%b	decimalless scientific notation with exponent a power
+			of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
 		%e	scientific notation, e.g. -1234.456e+78
 		%E	scientific notation, e.g. -1234.456E+78
 		%f	decimal point but no exponent, e.g. 123.456
@@ -136,6 +139,10 @@
 	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
 	%s and %v on strings scan a space-delimited token
 
+	The familiar base-setting prefixes 0 (octal) and 0x
+	(hexadecimal) are accepted when scanning integers without a
+	format or with the %v verb.
+
 	Width is interpreted in the input text (%5s means at most
 	five runes of input will be read to scan a string) but there
 	is no syntax for scanning with a precision (no %5.2f, just
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index a408c42..53d88d5 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -7,6 +7,7 @@ package fmt
 import (
 	"bytes"
 	"io"
+	"math"
 	"os"
 	"reflect"
 	"strconv"
@@ -15,18 +16,11 @@ import (
 	"utf8"
 )
 
-// readRuner is the interface to something that can read runes.  If
-// the object provided to Scan does not satisfy this interface, the
-// object will be wrapped by a readRune object.
-type readRuner interface {
-	ReadRune() (rune int, size int, err os.Error)
-}
-
-// unreadRuner is the interface to something that can unread runes.
+// runeUnreader is the interface to something that can unread runes.
 // If the object provided to Scan does not satisfy this interface,
 // a local buffer will be used to back up the input, but its contents
 // will be lost when Scan returns.
-type unreadRuner interface {
+type runeUnreader interface {
 	UnreadRune() os.Error
 }
 
@@ -36,7 +30,7 @@ type unreadRuner interface {
 type ScanState interface {
 	// GetRune reads the next rune (Unicode code point) from the input.
 	GetRune() (rune int, err os.Error)
-	// UngetRune causes the next call to GetRune to return the rune.
+	// UngetRune causes the next call to GetRune to return the same rune.
 	UngetRune()
 	// Width returns the value of the width option and whether it has been set.
 	// The unit is Unicode code points.
@@ -137,15 +131,15 @@ const EOF = -1
 
 // ss is the internal implementation of ScanState.
 type ss struct {
-	rr         readRuner    // where to read input
-	buf        bytes.Buffer // token accumulator
-	nlIsSpace  bool         // whether newline counts as white space
-	peekRune   int          // one-rune lookahead
-	prevRune   int          // last rune returned by GetRune
-	atEOF      bool         // already read EOF
-	maxWid     int          // max width of field, in runes
-	widPresent bool         // width was specified
-	wid        int          // width consumed so far; used in accept()
+	rr         io.RuneReader // where to read input
+	buf        bytes.Buffer  // token accumulator
+	nlIsSpace  bool          // whether newline counts as white space
+	peekRune   int           // one-rune lookahead
+	prevRune   int           // last rune returned by GetRune
+	atEOF      bool          // already read EOF
+	maxWid     int           // max width of field, in runes
+	widPresent bool          // width was specified
+	wid        int           // width consumed so far; used in accept()
 }
 
 func (s *ss) GetRune() (rune int, err os.Error) {
@@ -215,7 +209,7 @@ func (s *ss) mustGetRune() (rune int) {
 
 
 func (s *ss) UngetRune() {
-	if u, ok := s.rr.(unreadRuner); ok {
+	if u, ok := s.rr.(runeUnreader); ok {
 		u.UnreadRune()
 	} else {
 		s.peekRune = s.prevRune
@@ -246,7 +240,7 @@ func (s *ss) Token() (tok string, err os.Error) {
 
 // readRune is a structure to enable reading UTF-8 encoded code points
 // from an io.Reader.  It is used if the Reader given to the scanner does
-// not already implement ReadRuner.
+// not already implement io.RuneReader.
 type readRune struct {
 	reader  io.Reader
 	buf     [utf8.UTFMax]byte // used only inside ReadRune
@@ -308,7 +302,7 @@ var ssFree = newCache(func() interface{} { return new(ss) })
 // Allocate a new ss struct or grab a cached one.
 func newScanState(r io.Reader, nlIsSpace bool) *ss {
 	s := ssFree.get().(*ss)
-	if rr, ok := r.(readRuner); ok {
+	if rr, ok := r.(io.RuneReader); ok {
 		s.rr = rr
 	} else {
 		s.rr = &readRune{reader: r}
@@ -394,14 +388,12 @@ func (s *ss) consume(ok string, accept bool) bool {
 	if rune == EOF {
 		return false
 	}
-	for i := 0; i < len(ok); i++ {
-		if int(ok[i]) == rune {
-			if accept {
-				s.buf.WriteRune(rune)
-				s.wid++
-			}
-			return true
+	if strings.IndexRune(ok, rune) >= 0 {
+		if accept {
+			s.buf.WriteRune(rune)
+			s.wid++
 		}
+		return true
 	}
 	if rune != EOF && accept {
 		s.UngetRune()
@@ -409,6 +401,15 @@ func (s *ss) consume(ok string, accept bool) bool {
 	return false
 }
 
+// peek reports whether the next character is in the ok string, without consuming it.
+func (s *ss) peek(ok string) bool {
+	rune := s.getRune()
+	if rune != EOF {
+		s.UngetRune()
+	}
+	return strings.IndexRune(ok, rune) >= 0
+}
+
 // accept checks the next rune in the input.  If it's a byte (sic) in the string, it puts it in the
 // buffer and returns true. Otherwise it return false.
 func (s *ss) accept(ok string) bool {
@@ -459,7 +460,7 @@ const (
 	hexadecimalDigits = "0123456789aAbBcCdDeEfF"
 	sign              = "+-"
 	period            = "."
-	exponent          = "eE"
+	exponent          = "eEp"
 )
 
 // getBase returns the numeric base represented by the verb and its digit string.
@@ -482,8 +483,8 @@ func (s *ss) getBase(verb int) (base int, digits string) {
 }
 
 // scanNumber returns the numerical string with specified digits starting here.
-func (s *ss) scanNumber(digits string) string {
-	if !s.accept(digits) {
+func (s *ss) scanNumber(digits string, haveDigits bool) string {
+	if !haveDigits && !s.accept(digits) {
 		s.errorString("expected integer")
 	}
 	for s.accept(digits) {
@@ -502,22 +503,44 @@ func (s *ss) scanRune(bitSize int) int64 {
 	return rune
 }
 
+// scanBasePrefix reports whether the integer begins with a 0 or 0x,
+// and returns the base, digit string, and whether a zero was found.
+// It is called only if the verb is %v.
+func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
+	if !s.peek("0") {
+		return 10, decimalDigits, false
+	}
+	s.accept("0")
+	found = true // We've put a digit into the token buffer.
+	// Special cases for '0' && '0x'
+	base, digits = 8, octalDigits
+	if s.peek("xX") {
+		s.consume("xX", false)
+		base, digits = 16, hexadecimalDigits
+	}
+	return
+}
+
 // scanInt returns the value of the integer represented by the next
 // token, checking for overflow.  Any error is stored in s.err.
 func (s *ss) scanInt(verb int, bitSize int) int64 {
 	if verb == 'c' {
 		return s.scanRune(bitSize)
 	}
-	base, digits := s.getBase(verb)
 	s.skipSpace(false)
+	base, digits := s.getBase(verb)
+	haveDigits := false
 	if verb == 'U' {
 		if !s.consume("U", false) || !s.consume("+", false) {
 			s.errorString("bad unicode format ")
 		}
 	} else {
 		s.accept(sign) // If there's a sign, it will be left in the token buffer.
+		if verb == 'v' {
+			base, digits, haveDigits = s.scanBasePrefix()
+		}
 	}
-	tok := s.scanNumber(digits)
+	tok := s.scanNumber(digits, haveDigits)
 	i, err := strconv.Btoi64(tok, base)
 	if err != nil {
 		s.error(err)
@@ -536,14 +559,17 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
 	if verb == 'c' {
 		return uint64(s.scanRune(bitSize))
 	}
-	base, digits := s.getBase(verb)
 	s.skipSpace(false)
+	base, digits := s.getBase(verb)
+	haveDigits := false
 	if verb == 'U' {
 		if !s.consume("U", false) || !s.consume("+", false) {
 			s.errorString("bad unicode format ")
 		}
+	} else if verb == 'v' {
+		base, digits, haveDigits = s.scanBasePrefix()
 	}
-	tok := s.scanNumber(digits)
+	tok := s.scanNumber(digits, haveDigits)
 	i, err := strconv.Btoui64(tok, base)
 	if err != nil {
 		s.error(err)
@@ -617,6 +643,27 @@ func (s *ss) complexTokens() (real, imag string) {
 
 // convertFloat converts the string to a float64value.
 func (s *ss) convertFloat(str string, n int) float64 {
+	if p := strings.Index(str, "p"); p >= 0 {
+		// Atof doesn't handle power-of-2 exponents,
+		// but they're easy to evaluate.
+		f, err := strconv.AtofN(str[:p], n)
+		if err != nil {
+			// Put full string into error.
+			if e, ok := err.(*strconv.NumError); ok {
+				e.Num = str
+			}
+			s.error(err)
+		}
+		n, err := strconv.Atoi(str[p+1:])
+		if err != nil {
+			// Put full string into error.
+			if e, ok := err.(*strconv.NumError); ok {
+				e.Num = str
+			}
+			s.error(err)
+		}
+		return math.Ldexp(f, n)
+	}
 	f, err := strconv.AtofN(str, n)
 	if err != nil {
 		s.error(err)
@@ -747,7 +794,7 @@ func (s *ss) hexString() string {
 	return s.buf.String()
 }
 
-const floatVerbs = "eEfFgGv"
+const floatVerbs = "beEfFgGv"
 
 // scanOne scans a single value, deriving the scanner from the type of the argument.
 func (s *ss) scanOne(verb int, field interface{}) {
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 78b9fbb..478b109 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -129,10 +129,20 @@ func newReader(s string) *myStringReader {
 }
 
 var scanTests = []ScanTest{
-	// Numbers
+	// Basic types
 	{"T\n", &boolVal, true},  // boolean test vals toggle to be sure they are written
 	{"F\n", &boolVal, false}, // restored to zero value
 	{"21\n", &intVal, 21},
+	{"0\n", &intVal, 0},
+	{"000\n", &intVal, 0},
+	{"0x10\n", &intVal, 0x10},
+	{"-0x10\n", &intVal, -0x10},
+	{"0377\n", &intVal, 0377},
+	{"-0377\n", &intVal, -0377},
+	{"0\n", &uintVal, uint(0)},
+	{"000\n", &uintVal, uint(0)},
+	{"0x10\n", &uintVal, uint(0x10)},
+	{"0377\n", &uintVal, uint(0377)},
 	{"22\n", &int8Val, int8(22)},
 	{"23\n", &int16Val, int16(23)},
 	{"24\n", &int32Val, int32(24)},
@@ -160,6 +170,10 @@ var scanTests = []ScanTest{
 	{"2.3\n", &float64Val, 2.3},
 	{"2.3e1\n", &float32Val, float32(2.3e1)},
 	{"2.3e2\n", &float64Val, 2.3e2},
+	{"2.3p2\n", &float64Val, 2.3 * 4},
+	{"2.3p+2\n", &float64Val, 2.3 * 4},
+	{"2.3p+66\n", &float64Val, 2.3 * (1 << 32) * (1 << 32) * 4},
+	{"2.3p-66\n", &float64Val, 2.3 / ((1 << 32) * (1 << 32) * 4)},
 	{"2.35\n", &stringVal, "2.35"},
 	{"2345678\n", &bytesVal, []byte("2345678")},
 	{"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i},
@@ -197,6 +211,8 @@ var scanfTests = []ScanfTest{
 	{"%v", "TRUE\n", &boolVal, true},
 	{"%t", "false\n", &boolVal, false},
 	{"%v", "-71\n", &intVal, -71},
+	{"%v", "0377\n", &intVal, 0377},
+	{"%v", "0x44\n", &intVal, 0x44},
 	{"%d", "72\n", &intVal, 72},
 	{"%c", "a\n", &intVal, 'a'},
 	{"%c", "\u5072\n", &intVal, 0x5072},
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 34b0c4e..48e2af1 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -34,18 +34,18 @@ const (
 )
 
 
+const (
+	esc2 = '\xfe'                        // an escape byte that cannot occur in regular UTF-8
+	_    = 1 / (esc2 - tabwriter.Escape) // cause compiler error if esc2 == tabwriter.Escape
+)
+
+
 var (
 	esc       = []byte{tabwriter.Escape}
 	htab      = []byte{'\t'}
 	htabs     = []byte("\t\t\t\t\t\t\t\t")
 	newlines  = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
 	formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
-
-	esc_quot = []byte("&#34;") // shorter than "&quot;"
-	esc_apos = []byte("&#39;") // shorter than "&apos;"
-	esc_amp  = []byte("&amp;")
-	esc_lt   = []byte("&lt;")
-	esc_gt   = []byte("&gt;")
 )
 
 
@@ -145,18 +145,20 @@ func (p *printer) nlines(n, min int) int {
 // write0 does not indent after newlines, and does not HTML-escape or update p.pos.
 //
 func (p *printer) write0(data []byte) {
-	n, err := p.output.Write(data)
-	p.written += n
-	if err != nil {
-		p.errors <- err
-		runtime.Goexit()
+	if len(data) > 0 {
+		n, err := p.output.Write(data)
+		p.written += n
+		if err != nil {
+			p.errors <- err
+			runtime.Goexit()
+		}
 	}
 }
 
 
 // write interprets data and writes it to p.output. It inserts indentation
-// after a line break unless in a tabwriter escape sequence, and it HTML-
-// escapes characters if GenHTML is set. It updates p.pos as a side-effect.
+// after a line break unless in a tabwriter escape sequence.
+// It updates p.pos as a side-effect.
 //
 func (p *printer) write(data []byte) {
 	i0 := 0
@@ -189,36 +191,6 @@ func (p *printer) write(data []byte) {
 			// next segment start
 			i0 = i + 1
 
-		case '"', '\'', '&', '<', '>':
-			if p.Mode&GenHTML != 0 {
-				// write segment ending in b
-				p.write0(data[i0:i])
-
-				// write HTML-escaped b
-				var esc []byte
-				switch b {
-				case '"':
-					esc = esc_quot
-				case '\'':
-					esc = esc_apos
-				case '&':
-					esc = esc_amp
-				case '<':
-					esc = esc_lt
-				case '>':
-					esc = esc_gt
-				}
-				p.write0(esc)
-
-				// update p.pos
-				d := i + 1 - i0
-				p.pos.Offset += d
-				p.pos.Column += d
-
-				// next segment start
-				i0 = i + 1
-			}
-
 		case tabwriter.Escape:
 			p.mode ^= inLiteral
 
@@ -251,29 +223,13 @@ func (p *printer) writeNewlines(n int, useFF bool) {
 }
 
 
-func (p *printer) writeTaggedItem(data []byte, tag HTMLTag) {
-	// write start tag, if any
-	// (no html-escaping and no p.pos update for tags - use write0)
-	if tag.Start != "" {
-		p.write0([]byte(tag.Start))
-	}
-	p.write(data)
-	// write end tag, if any
-	if tag.End != "" {
-		p.write0([]byte(tag.End))
-	}
-}
-
-
 // writeItem writes data at position pos. data is the text corresponding to
 // a single lexical token, but may also be comment text. pos is the actual
 // (or at least very accurately estimated) position of the data in the original
-// source text. If tags are present and GenHTML is set, the tags are written
-// before and after the data. writeItem updates p.last to the position
-// immediately following the data.
+// source text. writeItem updates p.last to the position immediately following
+// the data.
 //
-func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
-	fileChanged := false
+func (p *printer) writeItem(pos token.Position, data []byte) {
 	if pos.IsValid() {
 		// continue with previous position if we don't have a valid pos
 		if p.last.IsValid() && p.last.Filename != pos.Filename {
@@ -283,7 +239,6 @@ func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
 			p.indent = 0
 			p.mode = 0
 			p.buffer = p.buffer[0:0]
-			fileChanged = true
 		}
 		p.pos = pos
 	}
@@ -292,18 +247,7 @@ func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
 		_, filename := path.Split(pos.Filename)
 		p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
 	}
-	if p.Mode&GenHTML != 0 {
-		// write line tag if on a new line
-		// TODO(gri): should write line tags on each line at the start
-		//            will be more useful (e.g. to show line numbers)
-		if p.Styler != nil && (pos.Line != p.lastTaggedLine || fileChanged) {
-			p.writeTaggedItem(p.Styler.LineTag(pos.Line))
-			p.lastTaggedLine = pos.Line
-		}
-		p.writeTaggedItem(data, tag)
-	} else {
-		p.write(data)
-	}
+	p.write(data)
 	p.last = p.pos
 }
 
@@ -312,14 +256,13 @@ func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) {
 // If there is any pending whitespace, it consumes as much of
 // it as is likely to help position the comment nicely.
 // pos is the comment position, next the position of the item
-// after all pending comments, isFirst indicates if this is the
-// first comment in a group of comments, and isKeyword indicates
-// if the next item is a keyword.
+// after all pending comments, prev is the previous comment in
+// a group of comments (or nil), and isKeyword indicates if the
+// next item is a keyword.
 //
-func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeyword bool) {
-	if !p.last.IsValid() {
-		// there was no preceeding item and the comment is the
-		// first item to be printed - don't write any whitespace
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
+	if p.written == 0 {
+		// the comment is the first item to be printed - don't write any whitespace
 		return
 	}
 
@@ -329,11 +272,12 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
 		return
 	}
 
-	if pos.IsValid() && pos.Line == p.last.Line {
+	if pos.Line == p.last.Line && (prev == nil || prev.Text[1] != '/') {
 		// comment on the same line as last item:
 		// separate with at least one separator
 		hasSep := false
-		if isFirst {
+		if prev == nil {
+			// first comment of a comment group
 			j := 0
 			for i, ch := range p.buffer {
 				switch ch {
@@ -370,7 +314,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
 	} else {
 		// comment on a different line:
 		// separate with at least one line break
-		if isFirst {
+		if prev == nil {
+			// first comment of a comment group
 			j := 0
 			for i, ch := range p.buffer {
 				switch ch {
@@ -402,10 +347,14 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
 		}
 		// use formfeeds to break columns before a comment;
 		// this is analogous to using formfeeds to separate
-		// individual lines of /*-style comments
-		// (if !pos.IsValid(), pos.Line == 0, and this will
-		// print no newlines)
-		p.writeNewlines(pos.Line-p.last.Line, true)
+		// individual lines of /*-style comments - but make
+		// sure there is at least one line break if the previous
+		// comment was a line comment
+		n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
+		if n <= 0 && prev != nil && prev.Text[1] == '/' {
+			n = 1
+		}
+		p.writeNewlines(n, true)
 	}
 }
 
@@ -413,21 +362,10 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
 func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, line []byte) {
 	// line must pass through unchanged, bracket it with tabwriter.Escape
 	line = bytes.Join([][]byte{esc, line, esc}, nil)
-
-	// apply styler, if any
-	var tag HTMLTag
-	if p.Styler != nil {
-		line, tag = p.Styler.Comment(comment, line)
-	}
-
-	p.writeItem(pos, line, tag)
+	p.writeItem(pos, line)
 }
 
 
-// TODO(gri): Similar (but not quite identical) functionality for
-//            comment processing can be found in go/doc/comment.go.
-//            Perhaps this can be factored eventually.
-
 // Split comment text into lines
 func split(text []byte) [][]byte {
 	// count lines (comment text never ends in a newline)
@@ -680,7 +618,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
 	var last *ast.Comment
 	for ; p.commentBefore(next); p.cindex++ {
 		for _, c := range p.comments[p.cindex].List {
-			p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last == nil, tok.IsKeyword())
+			p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, tok.IsKeyword())
 			p.writeComment(c)
 			last = c
 		}
@@ -796,7 +734,6 @@ func (p *printer) print(args ...interface{}) {
 	for _, f := range args {
 		next := p.pos // estimated position of next item
 		var data []byte
-		var tag HTMLTag
 		var tok token.Token
 
 		switch x := f.(type) {
@@ -821,28 +758,31 @@ func (p *printer) print(args ...interface{}) {
 			p.buffer = p.buffer[0 : i+1]
 			p.buffer[i] = x
 		case *ast.Ident:
-			if p.Styler != nil {
-				data, tag = p.Styler.Ident(x)
-			} else {
-				data = []byte(x.Name)
-			}
+			data = []byte(x.Name)
 			tok = token.IDENT
 		case *ast.BasicLit:
-			if p.Styler != nil {
-				data, tag = p.Styler.BasicLit(x)
-			} else {
-				data = x.Value
-			}
 			// escape all literals so they pass through unchanged
 			// (note that valid Go programs cannot contain
 			// tabwriter.Escape bytes since they do not appear in
 			// legal UTF-8 sequences)
-			escData := make([]byte, 0, len(data)+2)
-			escData = append(escData, tabwriter.Escape)
-			escData = append(escData, data...)
-			escData = append(escData, tabwriter.Escape)
-			data = escData
+			data = make([]byte, 0, len(x.Value)+2)
+			data = append(data, tabwriter.Escape)
+			data = append(data, x.Value...)
+			data = append(data, tabwriter.Escape)
 			tok = x.Kind
+			// If we have a raw string that spans multiple lines and
+			// the opening quote (`) is on a line preceded only by
+			// indentation, we don't want to write that indentation
+			// because the following lines of the raw string are not
+			// indented. It's easiest to correct the output at the end
+			// via the trimmer (because of the complex handling of
+			// white space).
+			// Mark multi-line raw strings by replacing the opening
+			// quote with esc2 and have the trimmer take care of fixing
+			// it up. (Do this _after_ making a copy of data!)
+			if data[1] == '`' && bytes.IndexByte(data, '\n') > 0 {
+				data[1] = esc2
+			}
 		case token.Token:
 			s := x.String()
 			if mayCombine(p.lastTok, s[0]) {
@@ -858,11 +798,7 @@ func (p *printer) print(args ...interface{}) {
 				p.buffer = p.buffer[0:1]
 				p.buffer[0] = ' '
 			}
-			if p.Styler != nil {
-				data, tag = p.Styler.Token(x)
-			} else {
-				data = []byte(s)
-			}
+			data = []byte(s)
 			tok = x
 		case token.Pos:
 			if x.IsValid() {
@@ -885,7 +821,7 @@ func (p *printer) print(args ...interface{}) {
 			// before
 			p.writeNewlines(next.Line-p.pos.Line, droppedFF)
 
-			p.writeItem(next, data, tag)
+			p.writeItem(next, data)
 		}
 	}
 }
@@ -927,21 +863,26 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
 // through unchanged.
 //
 type trimmer struct {
-	output io.Writer
-	space  bytes.Buffer
-	state  int
+	output  io.Writer
+	state   int
+	space   bytes.Buffer
+	hasText bool
 }
 
 
 // trimmer is implemented as a state machine.
 // It can be in one of the following states:
 const (
-	inSpace = iota
-	inEscape
-	inText
+	inSpace  = iota // inside space
+	atEscape        // inside space and the last char was an opening tabwriter.Escape
+	inEscape        // inside text bracketed by tabwriter.Escapes
+	inText          // inside text
 )
 
 
+var backquote = []byte{'`'}
+
+
 // Design note: It is tempting to eliminate extra blanks occurring in
 //              whitespace in this function as it could simplify some
 //              of the blanks logic in the node printing functions.
@@ -949,7 +890,13 @@ const (
 //              the tabwriter.
 
 func (p *trimmer) Write(data []byte) (n int, err os.Error) {
-	m := 0 // if p.state != inSpace, data[m:n] is unwritten
+	// invariants:
+	// p.state == inSpace, atEscape:
+	//	p.space is unwritten
+	//	p.hasText indicates if there is any text on this line
+	// p.state == inEscape, inText:
+	//	data[m:n] is unwritten
+	m := 0
 	var b byte
 	for n, b = range data {
 		if b == '\v' {
@@ -960,37 +907,55 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 			switch b {
 			case '\t', ' ':
 				p.space.WriteByte(b) // WriteByte returns no errors
-			case '\f', '\n':
+			case '\n', '\f':
 				p.space.Reset()                        // discard trailing space
 				_, err = p.output.Write(newlines[0:1]) // write newline
+				p.hasText = false
 			case tabwriter.Escape:
-				_, err = p.output.Write(p.space.Bytes())
-				p.space.Reset()
-				p.state = inEscape
-				m = n + 1 // drop tabwriter.Escape
+				p.state = atEscape
 			default:
 				_, err = p.output.Write(p.space.Bytes())
-				p.space.Reset()
 				p.state = inText
 				m = n
 			}
+		case atEscape:
+			// discard indentation if we have a multi-line raw string
+			// (see printer.print for details)
+			if b != esc2 || p.hasText {
+				_, err = p.output.Write(p.space.Bytes())
+			}
+			p.state = inEscape
+			m = n
+			if b == esc2 {
+				_, err = p.output.Write(backquote) // convert back
+				m++
+			}
 		case inEscape:
 			if b == tabwriter.Escape {
 				_, err = p.output.Write(data[m:n])
 				p.state = inSpace
+				p.space.Reset()
+				p.hasText = true
 			}
 		case inText:
 			switch b {
 			case '\t', ' ':
 				_, err = p.output.Write(data[m:n])
 				p.state = inSpace
+				p.space.Reset()
 				p.space.WriteByte(b) // WriteByte returns no errors
-			case '\f':
-				data[n] = '\n' // convert to newline
+				p.hasText = true
+			case '\n', '\f':
+				_, err = p.output.Write(data[m:n])
+				p.state = inSpace
+				p.space.Reset()
+				_, err = p.output.Write(newlines[0:1]) // write newline
+				p.hasText = false
 			case tabwriter.Escape:
 				_, err = p.output.Write(data[m:n])
-				p.state = inEscape
-				m = n + 1 // drop tabwriter.Escape
+				p.state = atEscape
+				p.space.Reset()
+				p.hasText = true
 			}
 		}
 		if err != nil {
@@ -999,9 +964,12 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 	}
 	n = len(data)
 
-	if p.state != inSpace {
+	switch p.state {
+	case inEscape, inText:
 		_, err = p.output.Write(data[m:n])
 		p.state = inSpace
+		p.space.Reset()
+		p.hasText = true
 	}
 
 	return
@@ -1013,36 +981,16 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 
 // General printing is controlled with these Config.Mode flags.
 const (
-	GenHTML   uint = 1 << iota // generate HTML
-	RawFormat                  // do not use a tabwriter; if set, UseSpaces is ignored
+	RawFormat uint = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
 	TabIndent                  // use tabs for indentation independent of UseSpaces
 	UseSpaces                  // use spaces instead of tabs for alignment
 )
 
 
-// An HTMLTag specifies a start and end tag.
-type HTMLTag struct {
-	Start, End string // empty if tags are absent
-}
-
-
-// A Styler specifies formatting of line tags and elementary Go words.
-// A format consists of text and a (possibly empty) surrounding HTML tag.
-//
-type Styler interface {
-	LineTag(line int) ([]byte, HTMLTag)
-	Comment(c *ast.Comment, line []byte) ([]byte, HTMLTag)
-	BasicLit(x *ast.BasicLit) ([]byte, HTMLTag)
-	Ident(id *ast.Ident) ([]byte, HTMLTag)
-	Token(tok token.Token) ([]byte, HTMLTag)
-}
-
-
 // A Config node controls the output of Fprint.
 type Config struct {
-	Mode     uint   // default: 0
-	Tabwidth int    // default: 8
-	Styler   Styler // default: nil
+	Mode     uint // default: 0
+	Tabwidth int  // default: 8
 }
 
 
@@ -1070,9 +1018,6 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
 		}
 
 		twmode := tabwriter.DiscardEmptyColumns
-		if cfg.Mode&GenHTML != 0 {
-			twmode |= tabwriter.FilterHTML
-		}
 		if cfg.Mode&TabIndent != 0 {
 			minwidth = 0
 			twmode |= tabwriter.TabIndent
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index c66471b..565075a 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -127,7 +127,7 @@ var data = []entry{
 }
 
 
-func Test(t *testing.T) {
+func TestFiles(t *testing.T) {
 	for _, e := range data {
 		source := path.Join(dataDir, e.source)
 		golden := path.Join(dataDir, e.golden)
@@ -136,3 +136,38 @@ func Test(t *testing.T) {
 		//check(t, golden, golden, e.mode);
 	}
 }
+
+
+// TestLineComments, using a simple test case, checks that consequtive line
+// comments are properly terminated with a newline even if the AST position
+// information is incorrect.
+//
+func TestLineComments(t *testing.T) {
+	const src = `// comment 1
+	// comment 2
+	// comment 3
+	package main
+	`
+
+	fset := token.NewFileSet()
+	ast1, err1 := parser.ParseFile(fset, "", src, parser.ParseComments)
+	if err1 != nil {
+		panic(err1)
+	}
+
+	var buf bytes.Buffer
+	fset = token.NewFileSet() // use the wrong file set
+	Fprint(&buf, fset, ast1)
+
+	nlines := 0
+	for _, ch := range buf.Bytes() {
+		if ch == '\n' {
+			nlines++
+		}
+	}
+
+	const expected = 3
+	if nlines < expected {
+		t.Errorf("got %d, expected %d\n", nlines, expected)
+	}
+}
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
index 882c762..7f18f33 100644
--- a/src/pkg/go/printer/testdata/expressions.golden
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -248,6 +248,77 @@ they must not be removed`
 
 
 func _() {
+	// smart handling of indentation for multi-line raw strings
+	var _ = ``
+	var _ = `foo`
+	var _ = `foo
+bar`
+
+	var _ = ``
+	var _ = `foo`
+	var _ =
+	// the next line should not be indented
+`foo
+bar`
+
+	var _ =	// comment
+	``
+	var _ =	// comment
+	`foo`
+	var _ =	// comment
+	// the next line should not be indented
+`foo
+bar`
+
+	var _ = /* comment */ ``
+	var _ = /* comment */ `foo`
+	var _ = /* comment */ `foo
+bar`
+
+	var _ =	/* comment */
+	``
+	var _ =	/* comment */
+	`foo`
+	var _ =	/* comment */
+	// the next line should not be indented
+`foo
+bar`
+
+	var board = []int(
+`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+	var state = S{
+		"foo",
+		// the next line should not be indented
+`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+		"bar",
+	}
+}
+
+
+func _() {
 	// one-line function literals (body is on a single line)
 	_ = func() {}
 	_ = func() int { return 0 }
diff --git a/src/pkg/go/printer/testdata/expressions.input b/src/pkg/go/printer/testdata/expressions.input
index 647706b..6bcd9b5 100644
--- a/src/pkg/go/printer/testdata/expressions.input
+++ b/src/pkg/go/printer/testdata/expressions.input
@@ -244,6 +244,85 @@ they must not be removed`
 
 
 func _() {
+	// smart handling of indentation for multi-line raw strings
+	var _ = ``
+	var _ = `foo`
+	var _ = `foo
+bar`
+
+
+var _ =
+	``
+var _ =
+	`foo`
+var _ =
+	// the next line should not be indented
+	`foo
+bar`
+
+
+	var _ = // comment
+		``
+	var _ = // comment
+		`foo`
+	var _ = // comment
+		// the next line should not be indented
+		`foo
+bar`
+
+
+var _ = /* comment */ ``
+var _ = /* comment */ `foo`
+var _ = /* comment */ `foo
+bar`
+
+
+	var _ = /* comment */
+		``
+	var _ = /* comment */
+		`foo`
+	var _ = /* comment */
+		// the next line should not be indented
+		`foo
+bar`
+
+
+var board = []int(
+	`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+
+	var state = S{
+		"foo",
+		// the next line should not be indented
+		`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+		"bar",
+	}
+}
+
+
+func _() {
 	// one-line function literals (body is on a single line)
 	_ = func() {}
 	_ = func() int { return 0 }
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
index 62be00c..f1944c9 100644
--- a/src/pkg/go/printer/testdata/expressions.raw
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -243,7 +243,77 @@ func _() {
 	_ = `foo
 		bar`
 	_ = `three spaces before the end of the line starting here:   
-they must not be removed`
+they must not be removed`}
+
+
+func _() {
+	// smart handling of indentation for multi-line raw strings
+	var _ = ``
+	var _ = `foo`
+	var _ = `foo
+bar`
+
+	var _ = ``
+	var _ = `foo`
+	var _ =
+	// the next line should not be indented
+`foo
+bar`
+
+	var _ =	// comment
+	``
+	var _ =	// comment
+	`foo`
+	var _ =	// comment
+	// the next line should not be indented
+`foo
+bar`
+
+	var _ = /* comment */ ``
+	var _ = /* comment */ `foo`
+	var _ = /* comment */ `foo
+bar`
+
+	var _ =	/* comment */
+	``
+	var _ =	/* comment */
+	`foo`
+	var _ =	/* comment */
+	// the next line should not be indented
+`foo
+bar`
+
+	var board = []int(
+`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+	var state = S{
+		"foo",
+		// the next line should not be indented
+`...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`,
+		"bar",
+	}
 }
 
 
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index db8b968..9667f61 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -481,6 +481,19 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
 	return nil
 }
 
+func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
+	defer catchError(&err)
+	state := newDecodeState(dec, &dec.buf)
+	state.fieldnum = singletonField
+	delta := int(state.decodeUint())
+	if delta != 0 {
+		errorf("gob decode: corrupted data: non-zero delta for singleton")
+	}
+	instr := &engine.instr[singletonField]
+	instr.op(instr, state, unsafe.Pointer(nil))
+	return nil
+}
+
 func (dec *Decoder) decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
 	instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
 	for i := 0; i < length; i++ {
@@ -653,8 +666,8 @@ func (dec *Decoder) ignoreInterface(state *decodeState) {
 	if id < 0 {
 		error(dec.err)
 	}
-	// At this point, the decoder buffer contains the value. Just toss it.
-	state.b.Reset()
+	// At this point, the decoder buffer contains a delimited value. Just toss it.
+	state.b.Next(int(state.decodeUint()))
 }
 
 // Index by Go types.
@@ -901,6 +914,16 @@ func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *dec
 	return
 }
 
+func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err os.Error) {
+	engine = new(decEngine)
+	engine.instr = make([]decInstr, 1) // one item
+	op := dec.decIgnoreOpFor(remoteId)
+	ovfl := overflow(dec.typeString(remoteId))
+	engine.instr[0] = decInstr{op, 0, 0, 0, ovfl}
+	engine.numInstr = 1
+	return
+}
+
 // Is this an exported - upper case - name?
 func isExported(name string) bool {
 	rune, _ := utf8.DecodeRuneInString(name)
@@ -984,7 +1007,12 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
 		// To handle recursive types, mark this engine as underway before compiling.
 		enginePtr = new(*decEngine)
 		dec.ignorerCache[wireId] = enginePtr
-		*enginePtr, err = dec.compileDec(wireId, emptyStructType)
+		wire := dec.wireType[wireId]
+		if wire != nil && wire.StructT != nil {
+			*enginePtr, err = dec.compileDec(wireId, emptyStructType)
+		} else {
+			*enginePtr, err = dec.compileIgnoreSingle(wireId)
+		}
 		if err != nil {
 			dec.ignorerCache[wireId] = nil, false
 		}
@@ -993,6 +1021,10 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
 }
 
 func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) os.Error {
+	// If the value is nil, it means we should just ignore this item.
+	if val == nil {
+		return dec.decodeIgnoredValue(wireId)
+	}
 	// Dereference down to the underlying struct type.
 	rt, indir := indirect(val.Type())
 	enginePtr, err := dec.getDecEnginePtr(wireId, rt)
@@ -1010,6 +1042,18 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) os.Error {
 	return dec.decodeSingle(engine, rt, uintptr(val.Addr()), indir)
 }
 
+func (dec *Decoder) decodeIgnoredValue(wireId typeId) os.Error {
+	enginePtr, err := dec.getIgnoreEnginePtr(wireId)
+	if err != nil {
+		return err
+	}
+	wire := dec.wireType[wireId]
+	if wire != nil && wire.StructT != nil {
+		return dec.ignoreStruct(*enginePtr)
+	}
+	return dec.ignoreSingle(*enginePtr)
+}
+
 func init() {
 	var iop, uop decOp
 	switch reflect.Typeof(int(0)).Bits() {
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
index 7527c5f..f7c994f 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/gob/decoder.go
@@ -153,9 +153,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
 
 // Decode reads the next value from the connection and stores
 // it in the data represented by the empty interface value.
-// The value underlying e must be the correct type for the next
+// If e is nil, the value will be discarded. Otherwise,
+// the value underlying e must either be the correct type for the next
 // data item received, and must be a pointer.
 func (dec *Decoder) Decode(e interface{}) os.Error {
+	if e == nil {
+		return dec.DecodeValue(nil)
+	}
 	value := reflect.NewValue(e)
 	// If e represents a value as opposed to a pointer, the answer won't
 	// get back to the caller.  Make sure it's a pointer.
@@ -169,7 +173,8 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
 // DecodeValue reads the next value from the connection and stores
 // it in the data represented by the reflection value.
 // The value must be the correct type for the next
-// data item received.
+// data item received, or it may be nil, which means the
+// value will be discarded.
 func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
 	// Make sure we're single-threaded through here.
 	dec.mutex.Lock()
@@ -178,7 +183,7 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
 	dec.buf.Reset() // In case data lingers from previous invocation.
 	dec.err = nil
 	id := dec.decodeTypeSequence(false)
-	if id >= 0 {
+	if dec.err == nil {
 		dec.err = dec.decodeValue(id, value)
 	}
 	return dec.err
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
index 1456ca0..3e06db7 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/gob/encoder_test.go
@@ -6,6 +6,7 @@ package gob
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"os"
 	"reflect"
@@ -120,7 +121,7 @@ func corruptDataCheck(s string, err os.Error, t *testing.T) {
 	dec := NewDecoder(b)
 	err1 := dec.Decode(new(ET2))
 	if err1 != err {
-		t.Error("expected error", err, "got", err1)
+		t.Errorf("from %q expected error %s; got %s", s, err, err1)
 	}
 }
 
@@ -384,6 +385,75 @@ func TestInterfaceIndirect(t *testing.T) {
 	}
 }
 
+// Now follow various tests that decode into things that can't represent the
+// encoded value, all of which should be legal.
+
+// Also, when the ignored object contains an interface value, it may define
+// types. Make sure that skipping the value still defines the types by using
+// the encoder/decoder pair to send a value afterwards.  If an interface
+// is sent, its type in the test is always NewType0, so this checks that the
+// encoder and decoder don't skew with respect to type definitions.
+
+type Struct0 struct {
+	I interface{}
+}
+
+type NewType0 struct {
+	S string
+}
+
+type ignoreTest struct {
+	in, out interface{}
+}
+
+var ignoreTests = []ignoreTest{
+	// Decode normal struct into an empty struct
+	{&struct{ A int }{23}, &struct{}{}},
+	// Decode normal struct into a nil.
+	{&struct{ A int }{23}, nil},
+	// Decode singleton string into a nil.
+	{"hello, world", nil},
+	// Decode singleton slice into a nil.
+	{[]int{1, 2, 3, 4}, nil},
+	// Decode struct containing an interface into a nil.
+	{&Struct0{&NewType0{"value0"}}, nil},
+	// Decode singleton slice of interfaces into a nil.
+	{[]interface{}{"hi", &NewType0{"value1"}, 23}, nil},
+}
+
+func TestDecodeIntoNothing(t *testing.T) {
+	Register(new(NewType0))
+	for i, test := range ignoreTests {
+		b := new(bytes.Buffer)
+		enc := NewEncoder(b)
+		err := enc.Encode(test.in)
+		if err != nil {
+			t.Errorf("%d: encode error %s:", i, err)
+			continue
+		}
+		dec := NewDecoder(b)
+		err = dec.Decode(test.out)
+		if err != nil {
+			t.Errorf("%d: decode error: %s", i, err)
+			continue
+		}
+		// Now see if the encoder and decoder are in a consistent state.
+		str := fmt.Sprintf("Value %d", i)
+		err = enc.Encode(&NewType0{str})
+		if err != nil {
+			t.Fatalf("%d: NewType0 encode error: %s", i, err)
+		}
+		ns := new(NewType0)
+		err = dec.Decode(ns)
+		if err != nil {
+			t.Fatalf("%d: NewType0 decode error: %s", i, err)
+		}
+		if ns.S != str {
+			t.Fatalf("%d: expected %q got %q", i, str, ns.S)
+		}
+	}
+}
+
 // Another bug from golang-nuts, involving nested interfaces.
 type Bug0Outer struct {
 	Bug0Field interface{}
diff --git a/src/pkg/http/persist.go b/src/pkg/http/persist.go
index 8bfc097..000a420 100644
--- a/src/pkg/http/persist.go
+++ b/src/pkg/http/persist.go
@@ -6,14 +6,17 @@ package http
 
 import (
 	"bufio"
-	"container/list"
 	"io"
 	"net"
+	"net/textproto"
 	"os"
 	"sync"
 )
 
-var ErrPersistEOF = &ProtocolError{"persistent connection closed"}
+var (
+	ErrPersistEOF = &ProtocolError{"persistent connection closed"}
+	ErrPipeline   = &ProtocolError{"pipeline error"}
+)
 
 // A ServerConn reads requests and sends responses over an underlying
 // connection, until the HTTP keepalive logic commands an end. ServerConn
@@ -26,8 +29,10 @@ type ServerConn struct {
 	r               *bufio.Reader
 	clsd            bool     // indicates a graceful close
 	re, we          os.Error // read/write errors
-	lastBody        io.ReadCloser
+	lastbody        io.ReadCloser
 	nread, nwritten int
+	pipe            textproto.Pipeline
+	pipereq         map[*Request]uint
 	lk              sync.Mutex // protected read/write to re,we
 }
 
@@ -37,7 +42,7 @@ func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
 	if r == nil {
 		r = bufio.NewReader(c)
 	}
-	return &ServerConn{c: c, r: r}
+	return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
 }
 
 // Close detaches the ServerConn and returns the underlying connection as well
@@ -57,10 +62,25 @@ func (sc *ServerConn) Close() (c net.Conn, r *bufio.Reader) {
 // Read returns the next request on the wire. An ErrPersistEOF is returned if
 // it is gracefully determined that there are no more requests (e.g. after the
 // first request on an HTTP/1.0 connection, or after a Connection:close on a
-// HTTP/1.1 connection). Read can be called concurrently with Write, but not
-// with another Read.
+// HTTP/1.1 connection).
 func (sc *ServerConn) Read() (req *Request, err os.Error) {
 
+	// Ensure ordered execution of Reads and Writes
+	id := sc.pipe.Next()
+	sc.pipe.StartRequest(id)
+	defer func() {
+		sc.pipe.EndRequest(id)
+		if req == nil {
+			sc.pipe.StartResponse(id)
+			sc.pipe.EndResponse(id)
+		} else {
+			// Remember the pipeline id of this request
+			sc.lk.Lock()
+			sc.pipereq[req] = id
+			sc.lk.Unlock()
+		}
+	}()
+
 	sc.lk.Lock()
 	if sc.we != nil { // no point receiving if write-side broken or closed
 		defer sc.lk.Unlock()
@@ -73,12 +93,12 @@ func (sc *ServerConn) Read() (req *Request, err os.Error) {
 	sc.lk.Unlock()
 
 	// Make sure body is fully consumed, even if user does not call body.Close
-	if sc.lastBody != nil {
+	if sc.lastbody != nil {
 		// body.Close is assumed to be idempotent and multiple calls to
 		// it should return the error that its first invokation
 		// returned.
-		err = sc.lastBody.Close()
-		sc.lastBody = nil
+		err = sc.lastbody.Close()
+		sc.lastbody = nil
 		if err != nil {
 			sc.lk.Lock()
 			defer sc.lk.Unlock()
@@ -102,7 +122,7 @@ func (sc *ServerConn) Read() (req *Request, err os.Error) {
 			return
 		}
 	}
-	sc.lastBody = req.Body
+	sc.lastbody = req.Body
 	sc.nread++
 	if req.Close {
 		sc.lk.Lock()
@@ -121,11 +141,24 @@ func (sc *ServerConn) Pending() int {
 	return sc.nread - sc.nwritten
 }
 
-// Write writes a repsonse. To close the connection gracefully, set the
+// Write writes resp in response to req. To close the connection gracefully, set the
 // Response.Close field to true. Write should be considered operational until
 // it returns an error, regardless of any errors returned on the Read side.
-// Write can be called concurrently with Read, but not with another Write.
-func (sc *ServerConn) Write(resp *Response) os.Error {
+func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
+
+	// Retrieve the pipeline ID of this request/response pair
+	sc.lk.Lock()
+	id, ok := sc.pipereq[req]
+	sc.pipereq[req] = 0, false
+	if !ok {
+		sc.lk.Unlock()
+		return ErrPipeline
+	}
+	sc.lk.Unlock()
+
+	// Ensure pipeline order
+	sc.pipe.StartResponse(id)
+	defer sc.pipe.EndResponse(id)
 
 	sc.lk.Lock()
 	if sc.we != nil {
@@ -166,10 +199,11 @@ type ClientConn struct {
 	c               net.Conn
 	r               *bufio.Reader
 	re, we          os.Error // read/write errors
-	lastBody        io.ReadCloser
+	lastbody        io.ReadCloser
 	nread, nwritten int
-	reqm            list.List  // request methods in order of execution
-	lk              sync.Mutex // protects read/write to reqm,re,we
+	pipe            textproto.Pipeline
+	pipereq         map[*Request]uint
+	lk              sync.Mutex // protects read/write to re,we,pipereq,etc.
 }
 
 // NewClientConn returns a new ClientConn reading and writing c.  If r is not
@@ -178,7 +212,7 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	if r == nil {
 		r = bufio.NewReader(c)
 	}
-	return &ClientConn{c: c, r: r}
+	return &ClientConn{c: c, r: r, pipereq: make(map[*Request]uint)}
 }
 
 // Close detaches the ClientConn and returns the underlying connection as well
@@ -191,7 +225,6 @@ func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
 	r = cc.r
 	cc.c = nil
 	cc.r = nil
-	cc.reqm.Init()
 	cc.lk.Unlock()
 	return
 }
@@ -201,8 +234,23 @@ func (cc *ClientConn) Close() (c net.Conn, r *bufio.Reader) {
 // keepalive connection is logically closed after this request and the opposing
 // server is informed. An ErrUnexpectedEOF indicates the remote closed the
 // underlying TCP connection, which is usually considered as graceful close.
-// Write can be called concurrently with Read, but not with another Write.
-func (cc *ClientConn) Write(req *Request) os.Error {
+func (cc *ClientConn) Write(req *Request) (err os.Error) {
+
+	// Ensure ordered execution of Writes
+	id := cc.pipe.Next()
+	cc.pipe.StartRequest(id)
+	defer func() {
+		cc.pipe.EndRequest(id)
+		if err != nil {
+			cc.pipe.StartResponse(id)
+			cc.pipe.EndResponse(id)
+		} else {
+			// Remember the pipeline id of this request
+			cc.lk.Lock()
+			cc.pipereq[req] = id
+			cc.lk.Unlock()
+		}
+	}()
 
 	cc.lk.Lock()
 	if cc.re != nil { // no point sending if read-side closed or broken
@@ -223,7 +271,7 @@ func (cc *ClientConn) Write(req *Request) os.Error {
 		cc.lk.Unlock()
 	}
 
-	err := req.Write(cc.c)
+	err = req.Write(cc.c)
 	if err != nil {
 		cc.lk.Lock()
 		defer cc.lk.Unlock()
@@ -231,9 +279,6 @@ func (cc *ClientConn) Write(req *Request) os.Error {
 		return err
 	}
 	cc.nwritten++
-	cc.lk.Lock()
-	cc.reqm.PushBack(req.Method)
-	cc.lk.Unlock()
 
 	return nil
 }
@@ -250,7 +295,21 @@ func (cc *ClientConn) Pending() int {
 // returned together with an ErrPersistEOF, which means that the remote
 // requested that this be the last request serviced. Read can be called
 // concurrently with Write, but not with another Read.
-func (cc *ClientConn) Read() (resp *Response, err os.Error) {
+func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {
+
+	// Retrieve the pipeline ID of this request/response pair
+	cc.lk.Lock()
+	id, ok := cc.pipereq[req]
+	cc.pipereq[req] = 0, false
+	if !ok {
+		cc.lk.Unlock()
+		return nil, ErrPipeline
+	}
+	cc.lk.Unlock()
+
+	// Ensure pipeline order
+	cc.pipe.StartResponse(id)
+	defer cc.pipe.EndResponse(id)
 
 	cc.lk.Lock()
 	if cc.re != nil {
@@ -259,17 +318,13 @@ func (cc *ClientConn) Read() (resp *Response, err os.Error) {
 	}
 	cc.lk.Unlock()
 
-	if cc.nread >= cc.nwritten {
-		return nil, os.NewError("persist client pipe count")
-	}
-
 	// Make sure body is fully consumed, even if user does not call body.Close
-	if cc.lastBody != nil {
+	if cc.lastbody != nil {
 		// body.Close is assumed to be idempotent and multiple calls to
 		// it should return the error that its first invokation
 		// returned.
-		err = cc.lastBody.Close()
-		cc.lastBody = nil
+		err = cc.lastbody.Close()
+		cc.lastbody = nil
 		if err != nil {
 			cc.lk.Lock()
 			defer cc.lk.Unlock()
@@ -278,18 +333,14 @@ func (cc *ClientConn) Read() (resp *Response, err os.Error) {
 		}
 	}
 
-	cc.lk.Lock()
-	m := cc.reqm.Front()
-	cc.reqm.Remove(m)
-	cc.lk.Unlock()
-	resp, err = ReadResponse(cc.r, m.Value.(string))
+	resp, err = ReadResponse(cc.r, req.Method)
 	if err != nil {
 		cc.lk.Lock()
 		defer cc.lk.Unlock()
 		cc.re = err
 		return
 	}
-	cc.lastBody = resp.Body
+	cc.lastbody = resp.Body
 
 	cc.nread++
 
@@ -301,3 +352,12 @@ func (cc *ClientConn) Read() (resp *Response, err os.Error) {
 	}
 	return
 }
+
+// Do is convenience method that writes a request and reads a response.
+func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
+	err = cc.Write(req)
+	if err != nil {
+		return
+	}
+	return cc.Read(req)
+}
diff --git a/src/pkg/http/response_test.go b/src/pkg/http/response_test.go
index 89a8c3b..11bfdd0 100644
--- a/src/pkg/http/response_test.go
+++ b/src/pkg/http/response_test.go
@@ -44,6 +44,47 @@ var respTests = []respTest{
 		"Body here\n",
 	},
 
+	// Unchunked HTTP/1.1 response without Content-Length or
+	// Connection headers.
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"\r\n" +
+			"Body here\n",
+
+		Response{
+			Status:        "200 OK",
+			StatusCode:    200,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			RequestMethod: "GET",
+			Close:         true,
+			ContentLength: -1,
+		},
+
+		"Body here\n",
+	},
+
+	// Unchunked HTTP/1.1 204 response without Content-Length.
+	{
+		"HTTP/1.1 204 No Content\r\n" +
+			"\r\n" +
+			"Body should not be read!\n",
+
+		Response{
+			Status:        "204 No Content",
+			StatusCode:    204,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			RequestMethod: "GET",
+			Close:         false,
+			ContentLength: 0,
+		},
+
+		"",
+	},
+
 	// Unchunked response with Content-Length.
 	{
 		"HTTP/1.0 200 OK\r\n" +
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index 7da3fc6..5594d51 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -9,10 +9,13 @@ package http
 import (
 	"bufio"
 	"bytes"
+	"fmt"
 	"io"
+	"io/ioutil"
 	"os"
 	"net"
 	"testing"
+	"time"
 )
 
 type dummyAddr string
@@ -189,7 +192,7 @@ func TestHostHandlers(t *testing.T) {
 			t.Errorf("writing request: %v", err)
 			continue
 		}
-		r, err := cc.Read()
+		r, err := cc.Read(&req)
 		if err != nil {
 			t.Errorf("reading response: %v", err)
 			continue
@@ -283,3 +286,66 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
 		}
 	}
 }
+
+func TestServerTimeouts(t *testing.T) {
+	l, err := net.ListenTCP("tcp", &net.TCPAddr{Port: 0})
+	if err != nil {
+		t.Fatalf("listen error: %v", err)
+	}
+	addr, _ := l.Addr().(*net.TCPAddr)
+
+	reqNum := 0
+	handler := HandlerFunc(func(res ResponseWriter, req *Request) {
+		reqNum++
+		fmt.Fprintf(res, "req=%d", reqNum)
+	})
+
+	const second = 1000000000 /* nanos */
+	server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+	go server.Serve(l)
+
+	url := fmt.Sprintf("http://localhost:%d/", addr.Port)
+
+	// Hit the HTTP server successfully.
+	r, _, err := Get(url)
+	if err != nil {
+		t.Fatalf("http Get #1: %v", err)
+	}
+	got, _ := ioutil.ReadAll(r.Body)
+	expected := "req=1"
+	if string(got) != expected {
+		t.Errorf("Unexpected response for request #1; got %q; expected %q",
+			string(got), expected)
+	}
+
+	// Slow client that should timeout.
+	t1 := time.Nanoseconds()
+	conn, err := net.Dial("tcp", "", fmt.Sprintf("localhost:%d", addr.Port))
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	buf := make([]byte, 1)
+	n, err := conn.Read(buf)
+	latency := time.Nanoseconds() - t1
+	if n != 0 || err != os.EOF {
+		t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, os.EOF)
+	}
+	if latency < second*0.20 /* fudge from 0.25 above */ {
+		t.Errorf("got EOF after %d ns, want >= %d", latency, second*0.20)
+	}
+
+	// Hit the HTTP server successfully again, verifying that the
+	// previous slow connection didn't run our handler.  (that we
+	// get "req=2", not "req=3")
+	r, _, err = Get(url)
+	if err != nil {
+		t.Fatalf("http Get #2: %v", err)
+	}
+	got, _ = ioutil.ReadAll(r.Body)
+	expected = "req=2"
+	if string(got) != expected {
+		t.Errorf("Get #2 got %q, want %q", string(got), expected)
+	}
+
+	l.Close()
+}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 6672c49..0be270a 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -670,6 +670,39 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
 // read requests and then call handler to reply to them.
 // Handler is typically nil, in which case the DefaultServeMux is used.
 func Serve(l net.Listener, handler Handler) os.Error {
+	srv := &Server{Handler: handler}
+	return srv.Serve(l)
+}
+
+// A Server defines parameters for running an HTTP server.
+type Server struct {
+	Addr         string  // TCP address to listen on, ":http" if empty
+	Handler      Handler // handler to invoke, http.DefaultServeMux if nil
+	ReadTimeout  int64   // the net.Conn.SetReadTimeout value for new connections
+	WriteTimeout int64   // the net.Conn.SetWriteTimeout value for new connections
+}
+
+// ListenAndServe listens on the TCP network address srv.Addr and then
+// calls Serve to handle requests on incoming connections.  If
+// srv.Addr is blank, ":http" is used.
+func (srv *Server) ListenAndServe() os.Error {
+	addr := srv.Addr
+	if addr == "" {
+		addr = ":http"
+	}
+	l, e := net.Listen("tcp", addr)
+	if e != nil {
+		return e
+	}
+	return srv.Serve(l)
+}
+
+// Serve accepts incoming connections on the Listener l, creating a
+// new service thread for each.  The service threads read requests and
+// then call srv.Handler to reply to them.
+func (srv *Server) Serve(l net.Listener) os.Error {
+	defer l.Close()
+	handler := srv.Handler
 	if handler == nil {
 		handler = DefaultServeMux
 	}
@@ -678,6 +711,12 @@ func Serve(l net.Listener, handler Handler) os.Error {
 		if e != nil {
 			return e
 		}
+		if srv.ReadTimeout != 0 {
+			rw.SetReadTimeout(srv.ReadTimeout)
+		}
+		if srv.WriteTimeout != 0 {
+			rw.SetWriteTimeout(srv.WriteTimeout)
+		}
 		c, err := newConn(rw, handler)
 		if err != nil {
 			continue
@@ -715,13 +754,8 @@ func Serve(l net.Listener, handler Handler) os.Error {
 //		}
 //	}
 func ListenAndServe(addr string, handler Handler) os.Error {
-	l, e := net.Listen("tcp", addr)
-	if e != nil {
-		return e
-	}
-	e = Serve(l, handler)
-	l.Close()
-	return e
+	server := &Server{Addr: addr, Handler: handler}
+	return server.ListenAndServe()
 }
 
 // ListenAndServeTLS acts identically to ListenAndServe, except that it
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index e62885d..f80f0ac 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -172,6 +172,20 @@ type transferReader struct {
 	Trailer          map[string]string
 }
 
+// bodyAllowedForStatus returns whether a given response status code
+// permits a body.  See RFC2616, section 4.4.
+func bodyAllowedForStatus(status int) bool {
+	switch {
+	case status >= 100 && status <= 199:
+		return false
+	case status == 204:
+		return false
+	case status == 304:
+		return false
+	}
+	return true
+}
+
 // msg is *Request or *Response.
 func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 	t := &transferReader{}
@@ -217,6 +231,19 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
 		return err
 	}
 
+	// If there is no Content-Length or chunked Transfer-Encoding on a *Response
+	// and the status is not 1xx, 204 or 304, then the body is unbounded.
+	// See RFC2616, section 4.4.
+	switch msg.(type) {
+	case *Response:
+		if t.ContentLength == -1 &&
+			!chunked(t.TransferEncoding) &&
+			bodyAllowedForStatus(t.StatusCode) {
+			// Unbounded body.
+			t.Close = true
+		}
+	}
+
 	// Prepare body reader.  ContentLength < 0 means chunked encoding
 	// or close connection when finished, since multipart is not supported yet
 	switch {
diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go
index 03cfafa..52d521d 100644
--- a/src/pkg/http/triv.go
+++ b/src/pkg/http/triv.go
@@ -99,15 +99,16 @@ func DateServer(rw http.ResponseWriter, req *http.Request) {
 		fmt.Fprintf(rw, "pipe: %s\n", err)
 		return
 	}
-	pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
+	p, err := os.StartProcess("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
 	defer r.Close()
 	w.Close()
 	if err != nil {
 		fmt.Fprintf(rw, "fork/exec: %s\n", err)
 		return
 	}
+	defer p.Release()
 	io.Copy(rw, r)
-	wait, err := os.Wait(pid, 0)
+	wait, err := p.Wait(0)
 	if err != nil {
 		fmt.Fprintf(rw, "wait: %s\n", err)
 		return
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index 1a6eca9..3b87918 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -150,14 +150,23 @@ type WriterAt interface {
 	WriteAt(p []byte, off int64) (n int, err os.Error)
 }
 
-// ReadByter is the interface that wraps the ReadByte method.
+// ByteReader is the interface that wraps the ReadByte method.
 //
 // ReadByte reads and returns the next byte from the input.
 // If no byte is available, err will be set.
-type ReadByter interface {
+type ByteReader interface {
 	ReadByte() (c byte, err os.Error)
 }
 
+// RuneReader is the interface that wraps the ReadRune method.
+//
+// ReadRune reads a single UTF-8 encoded Unicode character
+// and returns the rune and its size in bytes. If no character is
+// available, err will be set.
+type RuneReader interface {
+	ReadRune() (rune int, size int, err os.Error)
+}
+
 // WriteString writes the contents of the string s to w, which accepts an array of bytes.
 func WriteString(w Writer, s string) (n int, err os.Error) {
 	return w.Write([]byte(s))
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
index 759b49d..0fcc78a 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/json/encode.go
@@ -35,9 +35,8 @@ import (
 //
 // Struct values encode as JSON objects.  Each struct field becomes
 // a member of the object.  By default the object's key name is the
-// struct field name converted to lower case.  If the struct field
-// has a tag, that tag will be used as the name instead.
-// Only exported fields will be encoded.
+// struct field name.  If the struct field has a tag, that tag will 
+// be used as the name instead.  Only exported fields will be encoded.
 //
 // Map values encode as JSON objects.
 // The map's key type must be string; the object keys are used directly
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 9b91eb3..d9c8383 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -85,7 +85,7 @@ type ioPacket struct {
 func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
 	var r ioResult
 	var o *syscall.Overlapped
-	_, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
+	e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
 	switch {
 	case e == 0:
 		// Dequeued successfully completed io packet.
@@ -270,7 +270,7 @@ func timeoutIO() {
 		case writeto:
 			e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil)
 		case cancel:
-			_, e = syscall.CancelIo(uint32(o.fd.sysfd))
+			e = syscall.CancelIo(uint32(o.fd.sysfd))
 		}
 		o.c <- e
 	}
diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go
index 0b28536..675e252 100644
--- a/src/pkg/netchan/export.go
+++ b/src/pkg/netchan/export.go
@@ -118,7 +118,9 @@ func (client *expClient) run() {
 	for {
 		*hdr = header{}
 		if err := client.decode(hdrValue); err != nil {
-			expLog("error decoding client header:", err)
+			if err != os.EOF {
+				expLog("error decoding client header:", err)
+			}
 			break
 		}
 		switch hdr.PayloadType {
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index f6caf08..3a81afe 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -22,21 +22,25 @@ GOFILES_freebsd=\
 	env_unix.go\
 	file_unix.go\
 	sys_bsd.go\
+	exec_unix.go\
 
 GOFILES_darwin=\
 	env_unix.go\
 	file_unix.go\
 	sys_bsd.go\
+	exec_unix.go\
 
 GOFILES_linux=\
 	env_unix.go\
 	file_unix.go\
 	sys_linux.go\
+	exec_unix.go\
 
 GOFILES_windows=\
 	env_windows.go\
 	file_windows.go\
 	sys_windows.go\
+	exec_windows.go\
 
 GOFILES+=$(GOFILES_$(GOOS))
 
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
index d2b159d..a45d79b 100644
--- a/src/pkg/os/env_windows.go
+++ b/src/pkg/os/env_windows.go
@@ -50,8 +50,8 @@ func Setenv(key, value string) Error {
 	if len(value) > 0 {
 		v = syscall.StringToUTF16Ptr(value)
 	}
-	ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
-	if !ok {
+	e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+	if e != 0 {
 		return NewSyscallError("SetEnvironmentVariable", e)
 	}
 	return nil
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
index 100d984..dbdfacc 100644
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -5,17 +5,29 @@
 package os
 
 import (
+	"runtime"
 	"syscall"
 )
 
-// ForkExec forks the current process and invokes Exec with the program, arguments,
-// and environment specified by name, argv, and envv.  It returns the process
-// id of the forked process and an Error, if any.  The fd array specifies the
+// Process stores the information about a process created by StartProcess.
+type Process struct {
+	Pid    int
+	handle int
+}
+
+func newProcess(pid, handle int) *Process {
+	p := &Process{pid, handle}
+	runtime.SetFinalizer(p, (*Process).Release)
+	return p
+}
+
+// StartProcess starts a new process with the program, arguments,
+// and environment specified by name, argv, and envv. The fd array specifies the
 // file descriptors to be set up in the new process: fd[0] will be Unix file
 // descriptor 0 (standard input), fd[1] descriptor 1, and so on.  A nil entry
 // will cause the child to have no open file descriptor with that index.
 // If dir is not empty, the child chdirs into the directory before execing the program.
-func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
+func StartProcess(name string, argv []string, envv []string, dir string, fd []*File) (p *Process, err Error) {
 	if envv == nil {
 		envv = Environ()
 	}
@@ -29,17 +41,17 @@ func ForkExec(name string, argv []string, envv []string, dir string, fd []*File)
 		}
 	}
 
-	p, e := syscall.ForkExec(name, argv, envv, dir, intfd)
+	pid, h, e := syscall.StartProcess(name, argv, envv, dir, intfd)
 	if e != 0 {
-		return 0, &PathError{"fork/exec", name, Errno(e)}
+		return nil, &PathError{"fork/exec", name, Errno(e)}
 	}
-	return p, nil
+	return newProcess(pid, h), nil
 }
 
 // Exec replaces the current process with an execution of the
 // named binary, with arguments argv and environment envv.
 // If successful, Exec never returns.  If it fails, it returns an Error.
-// ForkExec is almost always a better way to execute a program.
+// StartProcess is almost always a better way to execute a program.
 func Exec(name string, argv []string, envv []string) Error {
 	if envv == nil {
 		envv = Environ()
@@ -65,37 +77,18 @@ type Waitmsg struct {
 	Rusage             *syscall.Rusage // System-dependent resource usage info.
 }
 
-// Options for Wait.
-const (
-	WNOHANG   = syscall.WNOHANG   // Don't wait if no process has exited.
-	WSTOPPED  = syscall.WSTOPPED  // If set, status of stopped subprocesses is also reported.
-	WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
-	WRUSAGE   = 1 << 20           // Record resource usage.
-)
-
-// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
-// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
-// the options
-
 // Wait waits for process pid to exit or stop, and then returns a
 // Waitmsg describing its status and an Error, if any. The options
 // (WNOHANG etc.) affect the behavior of the Wait call.
+// Wait is equivalent to calling FindProcess and then Wait
+// and Release on the result.
 func Wait(pid int, options int) (w *Waitmsg, err Error) {
-	var status syscall.WaitStatus
-	var rusage *syscall.Rusage
-	if options&WRUSAGE != 0 {
-		rusage = new(syscall.Rusage)
-		options ^= WRUSAGE
-	}
-	pid1, e := syscall.Wait4(pid, &status, options, rusage)
-	if e != 0 {
-		return nil, NewSyscallError("wait", e)
+	p, e := FindProcess(pid)
+	if e != nil {
+		return nil, e
 	}
-	w = new(Waitmsg)
-	w.Pid = pid1
-	w.WaitStatus = status
-	w.Rusage = rusage
-	return w, nil
+	defer p.Release()
+	return p.Wait(options)
 }
 
 // Convert i to decimal string.
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
new file mode 100644
index 0000000..8990d6a
--- /dev/null
+++ b/src/pkg/os/exec_unix.go
@@ -0,0 +1,63 @@
+// Copyright 2009 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 os
+
+import (
+	"runtime"
+	"syscall"
+)
+
+// Options for Wait.
+const (
+	WNOHANG   = syscall.WNOHANG   // Don't wait if no process has exited.
+	WSTOPPED  = syscall.WSTOPPED  // If set, status of stopped subprocesses is also reported.
+	WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
+	WRUSAGE   = 1 << 20           // Record resource usage.
+)
+
+// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
+// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
+// the options
+
+// Wait waits for the Process to exit or stop, and then returns a
+// Waitmsg describing its status and an Error, if any. The options
+// (WNOHANG etc.) affect the behavior of the Wait call.
+func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+	if p.Pid == -1 {
+		return nil, EINVAL
+	}
+	var status syscall.WaitStatus
+	var rusage *syscall.Rusage
+	if options&WRUSAGE != 0 {
+		rusage = new(syscall.Rusage)
+		options ^= WRUSAGE
+	}
+	pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
+	if e != 0 {
+		return nil, NewSyscallError("wait", e)
+	}
+	w = new(Waitmsg)
+	w.Pid = pid1
+	w.WaitStatus = status
+	w.Rusage = rusage
+	return w, nil
+}
+
+// Release releases any resources associated with the Process.
+func (p *Process) Release() Error {
+	// NOOP for unix.
+	p.Pid = -1
+	// no need for a finalizer anymore
+	runtime.SetFinalizer(p, nil)
+	return nil
+}
+
+// FindProcess looks for a running process by its pid.
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+func FindProcess(pid int) (p *Process, err Error) {
+	// NOOP for unix.
+	return newProcess(pid, 0), nil
+}
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
new file mode 100644
index 0000000..ae8ffea
--- /dev/null
+++ b/src/pkg/os/exec_windows.go
@@ -0,0 +1,52 @@
+// Copyright 2009 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 os
+
+import (
+	"runtime"
+	"syscall"
+)
+
+func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+	s, e := syscall.WaitForSingleObject(int32(p.handle), syscall.INFINITE)
+	switch s {
+	case syscall.WAIT_OBJECT_0:
+		break
+	case syscall.WAIT_FAILED:
+		return nil, NewSyscallError("WaitForSingleObject", e)
+	default:
+		return nil, ErrorString("os: unexpected result from WaitForSingleObject")
+	}
+	var ec uint32
+	e = syscall.GetExitCodeProcess(uint32(p.handle), &ec)
+	if e != 0 {
+		return nil, NewSyscallError("GetExitCodeProcess", e)
+	}
+	return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
+}
+
+func (p *Process) Release() Error {
+	if p.handle == -1 {
+		return EINVAL
+	}
+	e := syscall.CloseHandle(int32(p.handle))
+	if e != 0 {
+		return NewSyscallError("CloseHandle", e)
+	}
+	p.handle = -1
+	// no need for a finalizer anymore
+	runtime.SetFinalizer(p, nil)
+	return nil
+}
+
+func FindProcess(pid int) (p *Process, err Error) {
+	const da = syscall.STANDARD_RIGHTS_READ |
+		syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
+	h, e := syscall.OpenProcess(da, false, uint32(pid))
+	if e != 0 {
+		return nil, NewSyscallError("OpenProcess", e)
+	}
+	return newProcess(pid, int(h)), nil
+}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index bf710bb..d14c38e 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -83,9 +83,9 @@ func (file *File) Close() Error {
 	}
 	var e int
 	if file.isdir() {
-		_, e = syscall.FindClose(int32(file.fd))
+		e = syscall.FindClose(int32(file.fd))
 	} else {
-		_, e = syscall.CloseHandle(int32(file.fd))
+		e = syscall.CloseHandle(int32(file.fd))
 	}
 	var err Error
 	if e != 0 {
@@ -100,7 +100,8 @@ func (file *File) Close() Error {
 
 func (file *File) statFile(name string) (fi *FileInfo, err Error) {
 	var stat syscall.ByHandleFileInformation
-	if ok, e := syscall.GetFileInformationByHandle(int32(file.fd), &stat); !ok {
+	e := syscall.GetFileInformationByHandle(int32(file.fd), &stat)
+	if e != 0 {
 		return nil, &PathError{"stat", file.name, Errno(e)}
 	}
 	return fileInfoFromByHandleInfo(new(FileInfo), file.name, &stat), nil
@@ -142,7 +143,7 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
 		if di.usefirststat {
 			di.usefirststat = false
 		} else {
-			_, e := syscall.FindNextFile(int32(file.fd), &di.stat.Windata)
+			e := syscall.FindNextFile(int32(file.fd), &di.stat.Windata)
 			if e != 0 {
 				if e == syscall.ERROR_NO_MORE_FILES {
 					break
diff --git a/src/pkg/os/inotify/inotify_linux.go b/src/pkg/os/inotify/inotify_linux.go
index 9d7a074..96c229e 100644
--- a/src/pkg/os/inotify/inotify_linux.go
+++ b/src/pkg/os/inotify/inotify_linux.go
@@ -8,11 +8,11 @@ This package implements a wrapper for the Linux inotify system.
 Example:
     watcher, err := inotify.NewWatcher()
     if err != nil {
-        log.Exit(err)
+        log.Fatal(err)
     }
     err = watcher.Watch("/tmp")
     if err != nil {
-        log.Exit(err)
+        log.Fatal(err)
     }
     for {
         select {
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 49b58c8..2ea8acd 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -427,10 +427,11 @@ func TestForkExec(t *testing.T) {
 		adir = "/"
 		expect = "/\n"
 	}
-	pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr})
+	p, err := StartProcess(cmd, args, nil, adir, []*File{nil, w, Stderr})
 	if err != nil {
-		t.Fatalf("ForkExec: %v", err)
+		t.Fatalf("StartProcess: %v", err)
 	}
+	defer p.Release()
 	w.Close()
 
 	var b bytes.Buffer
@@ -440,7 +441,7 @@ func TestForkExec(t *testing.T) {
 		args[0] = cmd
 		t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect)
 	}
-	Wait(pid, 0)
+	p.Wait(0)
 }
 
 func checkMode(t *testing.T, path string, mode uint32) {
@@ -750,15 +751,16 @@ func run(t *testing.T, cmd []string) string {
 	if err != nil {
 		t.Fatal(err)
 	}
-	pid, err := ForkExec("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
+	p, err := StartProcess("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr})
 	if err != nil {
 		t.Fatal(err)
 	}
+	defer p.Release()
 	w.Close()
 
 	var b bytes.Buffer
 	io.Copy(&b, r)
-	Wait(pid, 0)
+	p.Wait(0)
 	output := b.String()
 	if n := len(output); n > 0 && output[n-1] == '\n' {
 		output = output[0 : n-1]
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index aed7330..c7ee4c8 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -316,9 +316,9 @@ func TestNumSubexp(t *testing.T) {
 }
 
 func BenchmarkLiteral(b *testing.B) {
-	x := strings.Repeat("x", 50)
+	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
-	re := MustCompile(x)
+	re := MustCompile("y")
 	b.StartTimer()
 	for i := 0; i < b.N; i++ {
 		if !re.MatchString(x) {
@@ -329,9 +329,9 @@ func BenchmarkLiteral(b *testing.B) {
 }
 
 func BenchmarkNotLiteral(b *testing.B) {
-	x := strings.Repeat("x", 49)
+	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
-	re := MustCompile("^" + x)
+	re := MustCompile(".y")
 	b.StartTimer()
 	for i := 0; i < b.N; i++ {
 		if !re.MatchString(x) {
diff --git a/src/pkg/regexp/find_test.go b/src/pkg/regexp/find_test.go
index 1690711..83b249e 100644
--- a/src/pkg/regexp/find_test.go
+++ b/src/pkg/regexp/find_test.go
@@ -6,6 +6,7 @@ package regexp
 
 import (
 	"fmt"
+	"strings"
 	"testing"
 )
 
@@ -191,6 +192,12 @@ func TestFindStringIndex(t *testing.T) {
 	}
 }
 
+func TestFindReaderIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
+	}
+}
+
 // Now come the simple All cases.
 
 func TestFindAll(t *testing.T) {
@@ -381,12 +388,18 @@ func TestFindSubmatchIndex(t *testing.T) {
 	}
 }
 
-func TestFindStringSubmatchndex(t *testing.T) {
+func TestFindStringSubmatchIndex(t *testing.T) {
 	for _, test := range findTests {
 		testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
 	}
 }
 
+func TestFindReaderSubmatchIndex(t *testing.T) {
+	for _, test := range findTests {
+		testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
+	}
+}
+
 // Now come the monster AllSubmatch cases.
 
 func TestFindAllSubmatch(t *testing.T) {
@@ -452,7 +465,7 @@ func TestFindAllSubmatchIndex(t *testing.T) {
 	}
 }
 
-func TestFindAllStringSubmatchndex(t *testing.T) {
+func TestFindAllStringSubmatchIndex(t *testing.T) {
 	for _, test := range findTests {
 		testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
 	}
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index d274ccd..e3221ac 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -54,6 +54,16 @@
 // text of the match/submatch.  If an index is negative, it means that
 // subexpression did not match any string in the input.
 //
+// There is also a subset of the methods that can be applied to text read
+// from a RuneReader:
+//
+//	MatchReader, FindReaderIndex, FindReaderSubmatchIndex
+//
+// This set may grow.  Note that regular expression matches may need to
+// examine text beyond the text returned by a match, so the methods that
+// match text from a RuneReader may read arbitrarily far into the input
+// before returning.
+//
 // (There are a few other methods that do not match this pattern.)
 //
 package regexp
@@ -231,13 +241,13 @@ func (p *parser) error(err Error) {
 	panic(err)
 }
 
-const endOfFile = -1
+const endOfText = -1
 
 func (p *parser) c() int { return p.ch }
 
 func (p *parser) nextc() int {
 	if p.pos >= len(p.re.expr) {
-		p.ch = endOfFile
+		p.ch = endOfText
 	} else {
 		c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
 		p.ch = c
@@ -288,7 +298,7 @@ func (p *parser) checkBackslash() int {
 	if c == '\\' {
 		c = p.nextc()
 		switch {
-		case c == endOfFile:
+		case c == endOfText:
 			p.error(ErrExtraneousBackslash)
 		case ispunct(c):
 			// c is as delivered
@@ -311,7 +321,7 @@ func (p *parser) charClass() *instr {
 	left := -1
 	for {
 		switch c := p.c(); c {
-		case ']', endOfFile:
+		case ']', endOfText:
 			if left >= 0 {
 				p.error(ErrBadRange)
 			}
@@ -356,7 +366,7 @@ func (p *parser) charClass() *instr {
 
 func (p *parser) term() (start, end *instr) {
 	switch c := p.c(); c {
-	case '|', endOfFile:
+	case '|', endOfText:
 		return nil, nil
 	case '*', '+', '?':
 		p.error(ErrBareClosure)
@@ -638,8 +648,11 @@ func (re *Regexp) NumSubexp() int { return re.nbra }
 // match vectors away as we execute.  Matches are ref counted and returned
 // to a free list when no longer active.  Increases a simple benchmark by 22X.
 type matchArena struct {
-	head *matchVec
-	len  int // length of match vector
+	head  *matchVec
+	len   int // length of match vector
+	pos   int
+	atBOT bool // whether we're at beginning of text
+	atEOT bool // whether we're at end of text
 }
 
 type matchVec struct {
@@ -699,21 +712,21 @@ type state struct {
 // Append new state to to-do list.  Leftmost-longest wins so avoid
 // adding a state that's already active.  The matchVec will be inc-ref'ed
 // if it is assigned to a state.
-func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec, pos, end int) []state {
+func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec) []state {
 	switch inst.kind {
 	case iBOT:
-		if pos == 0 {
-			s = a.addState(s, inst.next, prefixed, match, pos, end)
+		if a.atBOT {
+			s = a.addState(s, inst.next, prefixed, match)
 		}
 		return s
 	case iEOT:
-		if pos == end {
-			s = a.addState(s, inst.next, prefixed, match, pos, end)
+		if a.atEOT {
+			s = a.addState(s, inst.next, prefixed, match)
 		}
 		return s
 	case iBra:
-		match.m[inst.braNum] = pos
-		s = a.addState(s, inst.next, prefixed, match, pos, end)
+		match.m[inst.braNum] = a.pos
+		s = a.addState(s, inst.next, prefixed, match)
 		return s
 	}
 	l := len(s)
@@ -727,62 +740,157 @@ func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matc
 	s = append(s, state{inst, prefixed, match})
 	match.ref++
 	if inst.kind == iAlt {
-		s = a.addState(s, inst.left, prefixed, a.copy(match), pos, end)
+		s = a.addState(s, inst.left, prefixed, a.copy(match))
 		// give other branch a copy of this match vector
-		s = a.addState(s, inst.next, prefixed, a.copy(match), pos, end)
+		s = a.addState(s, inst.next, prefixed, a.copy(match))
 	}
 	return s
 }
 
-// Accepts either string or bytes - the logic is identical either way.
-// If bytes == nil, scan str.
-func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
+// input abstracts different representations of the input text. It provides
+// one-character lookahead.
+type input interface {
+	step(pos int) (rune int, width int) // advance one rune
+	canCheckPrefix() bool               // can we look ahead without losing info?
+	hasPrefix(re *Regexp) bool
+	index(re *Regexp, pos int) int
+}
+
+// inputString scans a string.
+type inputString struct {
+	str string
+}
+
+func newInputString(str string) *inputString {
+	return &inputString{str: str}
+}
+
+func (i *inputString) step(pos int) (int, int) {
+	if pos < len(i.str) {
+		return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+	}
+	return endOfText, 0
+}
+
+func (i *inputString) canCheckPrefix() bool {
+	return true
+}
+
+func (i *inputString) hasPrefix(re *Regexp) bool {
+	return strings.HasPrefix(i.str, re.prefix)
+}
+
+func (i *inputString) index(re *Regexp, pos int) int {
+	return strings.Index(i.str[pos:], re.prefix)
+}
+
+// inputBytes scans a byte slice.
+type inputBytes struct {
+	str []byte
+}
+
+func newInputBytes(str []byte) *inputBytes {
+	return &inputBytes{str: str}
+}
+
+func (i *inputBytes) step(pos int) (int, int) {
+	if pos < len(i.str) {
+		return utf8.DecodeRune(i.str[pos:len(i.str)])
+	}
+	return endOfText, 0
+}
+
+func (i *inputBytes) canCheckPrefix() bool {
+	return true
+}
+
+func (i *inputBytes) hasPrefix(re *Regexp) bool {
+	return bytes.HasPrefix(i.str, re.prefixBytes)
+}
+
+func (i *inputBytes) index(re *Regexp, pos int) int {
+	return bytes.Index(i.str[pos:], re.prefixBytes)
+}
+
+// inputReader scans a RuneReader.
+type inputReader struct {
+	r     io.RuneReader
+	atEOT bool
+	pos   int
+}
+
+func newInputReader(r io.RuneReader) *inputReader {
+	return &inputReader{r: r}
+}
+
+func (i *inputReader) step(pos int) (int, int) {
+	if !i.atEOT && pos != i.pos {
+		return endOfText, 0
+
+	}
+	r, w, err := i.r.ReadRune()
+	if err != nil {
+		i.atEOT = true
+		return endOfText, 0
+	}
+	i.pos += w
+	return r, w
+}
+
+func (i *inputReader) canCheckPrefix() bool {
+	return false
+}
+
+func (i *inputReader) hasPrefix(re *Regexp) bool {
+	return false
+}
+
+func (i *inputReader) index(re *Regexp, pos int) int {
+	return -1
+}
+
+// Search match starting from pos bytes into the input.
+func (re *Regexp) doExecute(i input, pos int) []int {
 	var s [2][]state
 	s[0] = make([]state, 0, 10)
 	s[1] = make([]state, 0, 10)
 	in, out := 0, 1
 	var final state
 	found := false
-	end := len(str)
-	if bytestr != nil {
-		end = len(bytestr)
-	}
 	anchored := re.inst[0].next.kind == iBOT
 	if anchored && pos > 0 {
 		return nil
 	}
 	// fast check for initial plain substring
-	if re.prefix != "" {
+	if i.canCheckPrefix() && re.prefix != "" {
 		advance := 0
 		if anchored {
-			if bytestr == nil {
-				if !strings.HasPrefix(str, re.prefix) {
-					return nil
-				}
-			} else {
-				if !bytes.HasPrefix(bytestr, re.prefixBytes) {
-					return nil
-				}
+			if !i.hasPrefix(re) {
+				return nil
 			}
 		} else {
-			if bytestr == nil {
-				advance = strings.Index(str[pos:], re.prefix)
-			} else {
-				advance = bytes.Index(bytestr[pos:], re.prefixBytes)
+			advance = i.index(re, pos)
+			if advance == -1 {
+				return nil
 			}
 		}
-		if advance == -1 {
-			return nil
-		}
 		pos += advance
 	}
-	arena := &matchArena{nil, 2 * (re.nbra + 1)}
-	for startPos := pos; pos <= end; {
+	// We look one character ahead so we can match $, which checks whether
+	// we are at EOT.
+	nextChar, nextWidth := i.step(pos)
+	arena := &matchArena{
+		len:   2 * (re.nbra + 1),
+		pos:   pos,
+		atBOT: pos == 0,
+		atEOT: nextChar == endOfText,
+	}
+	for c, startPos := 0, pos; c != endOfText; {
 		if !found && (pos == startPos || !anchored) {
 			// prime the pump if we haven't seen a match yet
 			match := arena.noMatch()
 			match.m[0] = pos
-			s[out] = arena.addState(s[out], re.start.next, false, match, pos, end)
+			s[out] = arena.addState(s[out], re.start.next, false, match)
 			arena.free(match) // if addState saved it, ref was incremented
 		} else if len(s[out]) == 0 {
 			// machine has completed
@@ -795,35 +903,32 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
 			arena.free(state.match)
 		}
 		s[out] = old[0:0] // truncate state vector
-		charwidth := 1
-		c := endOfFile
-		if pos < end {
-			if bytestr == nil {
-				c, charwidth = utf8.DecodeRuneInString(str[pos:end])
-			} else {
-				c, charwidth = utf8.DecodeRune(bytestr[pos:end])
-			}
-		}
-		pos += charwidth
+		c = nextChar
+		thisPos := pos
+		pos += nextWidth
+		nextChar, nextWidth = i.step(pos)
+		arena.atEOT = nextChar == endOfText
+		arena.atBOT = false
+		arena.pos = pos
 		for _, st := range s[in] {
 			switch st.inst.kind {
 			case iBOT:
 			case iEOT:
 			case iChar:
 				if c == st.inst.char {
-					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 				}
 			case iCharClass:
 				if st.inst.cclass.matches(c) {
-					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 				}
 			case iAny:
-				if c != endOfFile {
-					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+				if c != endOfText {
+					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 				}
 			case iNotNL:
-				if c != endOfFile && c != '\n' {
-					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
+				if c != endOfText && c != '\n' {
+					s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
 				}
 			case iBra:
 			case iAlt:
@@ -831,13 +936,13 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
 				// choose leftmost longest
 				if !found || // first
 					st.match.m[0] < final.match.m[0] || // leftmost
-					(st.match.m[0] == final.match.m[0] && pos-charwidth > final.match.m[1]) { // longest
+					(st.match.m[0] == final.match.m[0] && thisPos > final.match.m[1]) { // longest
 					if final.match != nil {
 						arena.free(final.match)
 					}
 					final = st
 					final.match.ref++
-					final.match.m[1] = pos - charwidth
+					final.match.m[1] = thisPos
 				}
 				found = true
 			default:
@@ -874,14 +979,31 @@ func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
 	return string(c[:i]), true
 }
 
+// MatchReader returns whether the Regexp matches the text read by the
+// RuneReader.  The return value is a boolean: true for match, false for no
+// match.
+func (re *Regexp) MatchReader(r io.RuneReader) bool {
+	return len(re.doExecute(newInputReader(r), 0)) > 0
+}
+
 // MatchString returns whether the Regexp matches the string s.
 // The return value is a boolean: true for match, false for no match.
-func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(s, nil, 0)) > 0 }
+func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(newInputString(s), 0)) > 0 }
 
 // Match returns whether the Regexp matches the byte slice b.
 // The return value is a boolean: true for match, false for no match.
-func (re *Regexp) Match(b []byte) bool { return len(re.doExecute("", b, 0)) > 0 }
+func (re *Regexp) Match(b []byte) bool { return len(re.doExecute(newInputBytes(b), 0)) > 0 }
 
+// MatchReader checks whether a textual regular expression matches the text
+// read by the RuneReader.  More complicated queries need to use Compile and
+// the full Regexp interface.
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) {
+	re, err := Compile(pattern)
+	if err != nil {
+		return false, err
+	}
+	return re.MatchReader(r), nil
+}
 
 // MatchString checks whether a textual regular expression
 // matches a string.  More complicated queries need
@@ -921,7 +1043,7 @@ func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) str
 	searchPos := 0    // position where we next look for a match
 	buf := new(bytes.Buffer)
 	for searchPos <= len(src) {
-		a := re.doExecute(src, nil, searchPos)
+		a := re.doExecute(newInputString(src), searchPos)
 		if len(a) == 0 {
 			break // no more matches
 		}
@@ -973,7 +1095,7 @@ func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
 	searchPos := 0    // position where we next look for a match
 	buf := new(bytes.Buffer)
 	for searchPos <= len(src) {
-		a := re.doExecute("", src, searchPos)
+		a := re.doExecute(newInputBytes(src), searchPos)
 		if len(a) == 0 {
 			break // no more matches
 		}
@@ -1038,7 +1160,13 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
 	}
 
 	for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
-		matches := re.doExecute(s, b, pos)
+		var in input
+		if b == nil {
+			in = newInputString(s)
+		} else {
+			in = newInputBytes(b)
+		}
+		matches := re.doExecute(in, pos)
 		if len(matches) == 0 {
 			break
 		}
@@ -1052,6 +1180,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
 				accept = false
 			}
 			var width int
+			// TODO: use step()
 			if b == nil {
 				_, width = utf8.DecodeRuneInString(s[pos:end])
 			} else {
@@ -1077,7 +1206,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
 // Find returns a slice holding the text of the leftmost match in b of the regular expression.
 // A return value of nil indicates no match.
 func (re *Regexp) Find(b []byte) []byte {
-	a := re.doExecute("", b, 0)
+	a := re.doExecute(newInputBytes(b), 0)
 	if a == nil {
 		return nil
 	}
@@ -1089,7 +1218,7 @@ func (re *Regexp) Find(b []byte) []byte {
 // b[loc[0]:loc[1]].
 // A return value of nil indicates no match.
 func (re *Regexp) FindIndex(b []byte) (loc []int) {
-	a := re.doExecute("", b, 0)
+	a := re.doExecute(newInputBytes(b), 0)
 	if a == nil {
 		return nil
 	}
@@ -1102,7 +1231,7 @@ func (re *Regexp) FindIndex(b []byte) (loc []int) {
 // an empty string.  Use FindStringIndex or FindStringSubmatch if it is
 // necessary to distinguish these cases.
 func (re *Regexp) FindString(s string) string {
-	a := re.doExecute(s, nil, 0)
+	a := re.doExecute(newInputString(s), 0)
 	if a == nil {
 		return ""
 	}
@@ -1114,7 +1243,19 @@ func (re *Regexp) FindString(s string) string {
 // itself is at s[loc[0]:loc[1]].
 // A return value of nil indicates no match.
 func (re *Regexp) FindStringIndex(s string) []int {
-	a := re.doExecute(s, nil, 0)
+	a := re.doExecute(newInputString(s), 0)
+	if a == nil {
+		return nil
+	}
+	return a[0:2]
+}
+
+// FindReaderIndex returns a two-element slice of integers defining the
+// location of the leftmost match of the regular expression in text read from
+// the RuneReader.  The match itself is at s[loc[0]:loc[1]].  A return
+// value of nil indicates no match.
+func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
+	a := re.doExecute(newInputReader(r), 0)
 	if a == nil {
 		return nil
 	}
@@ -1127,7 +1268,7 @@ func (re *Regexp) FindStringIndex(s string) []int {
 // comment.
 // A return value of nil indicates no match.
 func (re *Regexp) FindSubmatch(b []byte) [][]byte {
-	a := re.doExecute("", b, 0)
+	a := re.doExecute(newInputBytes(b), 0)
 	if a == nil {
 		return nil
 	}
@@ -1146,7 +1287,7 @@ func (re *Regexp) FindSubmatch(b []byte) [][]byte {
 // in the package comment.
 // A return value of nil indicates no match.
 func (re *Regexp) FindSubmatchIndex(b []byte) []int {
-	return re.doExecute("", b, 0)
+	return re.doExecute(newInputBytes(b), 0)
 }
 
 // FindStringSubmatch returns a slice of strings holding the text of the
@@ -1155,7 +1296,7 @@ func (re *Regexp) FindSubmatchIndex(b []byte) []int {
 // package comment.
 // A return value of nil indicates no match.
 func (re *Regexp) FindStringSubmatch(s string) []string {
-	a := re.doExecute(s, nil, 0)
+	a := re.doExecute(newInputString(s), 0)
 	if a == nil {
 		return nil
 	}
@@ -1174,7 +1315,16 @@ func (re *Regexp) FindStringSubmatch(s string) []string {
 // 'Index' descriptions in the package comment.
 // A return value of nil indicates no match.
 func (re *Regexp) FindStringSubmatchIndex(s string) []int {
-	return re.doExecute(s, nil, 0)
+	return re.doExecute(newInputString(s), 0)
+}
+
+// FindReaderSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression of text read by
+// the RuneReader, and the matches, if any, of its subexpressions, as defined
+// by the 'Submatch' and 'Index' descriptions in the package comment.  A
+// return value of nil indicates no match.
+func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
+	return re.doExecute(newInputReader(r), 0)
 }
 
 const startSize = 10 // The size at which to start a slice in the 'All' routines.
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
index 6f028c1..6de6d13 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/rpc/client.go
@@ -15,6 +15,16 @@ import (
 	"sync"
 )
 
+// ServerError represents an error that has been returned from
+// the remote side of the RPC connection.
+type ServerError string
+
+func (e ServerError) String() string {
+	return string(e)
+}
+
+const ErrShutdown = os.ErrorString("connection is shut down")
+
 // Call represents an active RPC.
 type Call struct {
 	ServiceMethod string      // The name of the service and method to call.
@@ -30,12 +40,12 @@ type Call struct {
 // with a single Client.
 type Client struct {
 	mutex    sync.Mutex // protects pending, seq
-	shutdown os.Error   // non-nil if the client is shut down
 	sending  sync.Mutex
 	seq      uint64
 	codec    ClientCodec
 	pending  map[uint64]*Call
 	closing  bool
+	shutdown bool
 }
 
 // A ClientCodec implements writing of RPC requests and
@@ -43,7 +53,9 @@ type Client struct {
 // The client calls WriteRequest to write a request to the connection
 // and calls ReadResponseHeader and ReadResponseBody in pairs
 // to read responses.  The client calls Close when finished with the
-// connection.
+// connection. ReadResponseBody may be called with a nil
+// argument to force the body of the response to be read and then
+// discarded.
 type ClientCodec interface {
 	WriteRequest(*Request, interface{}) os.Error
 	ReadResponseHeader(*Response) os.Error
@@ -55,8 +67,8 @@ type ClientCodec interface {
 func (client *Client) send(c *Call) {
 	// Register this call.
 	client.mutex.Lock()
-	if client.shutdown != nil {
-		c.Error = client.shutdown
+	if client.shutdown {
+		c.Error = ErrShutdown
 		client.mutex.Unlock()
 		c.done()
 		return
@@ -93,20 +105,27 @@ func (client *Client) input() {
 		c := client.pending[seq]
 		client.pending[seq] = c, false
 		client.mutex.Unlock()
-		err = client.codec.ReadResponseBody(c.Reply)
-		if response.Error != "" {
-			c.Error = os.ErrorString(response.Error)
-		} else if err != nil {
-			c.Error = err
+
+		if response.Error == "" {
+			err = client.codec.ReadResponseBody(c.Reply)
+			if err != nil {
+				c.Error = os.ErrorString("reading body " + err.String())
+			}
 		} else {
-			// Empty strings should turn into nil os.Errors
-			c.Error = nil
+			// We've got an error response. Give this to the request;
+			// any subsequent requests will get the ReadResponseBody
+			// error if there is one.
+			c.Error = ServerError(response.Error)
+			err = client.codec.ReadResponseBody(nil)
+			if err != nil {
+				err = os.ErrorString("reading error body: " + err.String())
+			}
 		}
 		c.done()
 	}
 	// Terminate pending calls.
 	client.mutex.Lock()
-	client.shutdown = err
+	client.shutdown = true
 	for _, call := range client.pending {
 		call.Error = err
 		call.done()
@@ -209,10 +228,11 @@ func Dial(network, address string) (*Client, os.Error) {
 }
 
 func (client *Client) Close() os.Error {
-	if client.shutdown != nil || client.closing {
-		return os.ErrorString("rpc: already closed")
-	}
 	client.mutex.Lock()
+	if client.shutdown || client.closing {
+		client.mutex.Unlock()
+		return ErrShutdown
+	}
 	client.closing = true
 	client.mutex.Unlock()
 	return client.codec.Close()
@@ -239,8 +259,8 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
 		}
 	}
 	c.Done = done
-	if client.shutdown != nil {
-		c.Error = client.shutdown
+	if client.shutdown {
+		c.Error = ErrShutdown
 		c.done()
 		return c
 	}
@@ -250,8 +270,8 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
 
 // Call invokes the named function, waits for it to complete, and returns its error status.
 func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) os.Error {
-	if client.shutdown != nil {
-		return client.shutdown
+	if client.shutdown {
+		return ErrShutdown
 	}
 	call := <-client.Go(serviceMethod, args, reply, nil).Done
 	return call.Error
diff --git a/src/pkg/rpc/debug.go b/src/pkg/rpc/debug.go
index 44b32e0..32dc8a1 100644
--- a/src/pkg/rpc/debug.go
+++ b/src/pkg/rpc/debug.go
@@ -83,7 +83,7 @@ func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	}
 	server.Unlock()
 	sort.Sort(services)
-	err := debug.Execute(services, w)
+	err := debug.Execute(w, services)
 	if err != nil {
 		fmt.Fprintln(w, "rpc: error executing template:", err.String())
 	}
diff --git a/src/pkg/rpc/jsonrpc/client.go b/src/pkg/rpc/jsonrpc/client.go
index dcaa69f..5b806bd 100644
--- a/src/pkg/rpc/jsonrpc/client.go
+++ b/src/pkg/rpc/jsonrpc/client.go
@@ -98,6 +98,9 @@ func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
 }
 
 func (c *clientCodec) ReadResponseBody(x interface{}) os.Error {
+	if x == nil {
+		return nil
+	}
 	return json.Unmarshal(*c.resp.Result, x)
 }
 
diff --git a/src/pkg/rpc/jsonrpc/server.go b/src/pkg/rpc/jsonrpc/server.go
index bf53bda..9c6b8b4 100644
--- a/src/pkg/rpc/jsonrpc/server.go
+++ b/src/pkg/rpc/jsonrpc/server.go
@@ -85,6 +85,9 @@ func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
 }
 
 func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
+	if x == nil {
+		return nil
+	}
 	// JSON params is array value.
 	// RPC params is struct.
 	// Unmarshal into array containing struct for now.
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
index 91e9cd5..9dcda41 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/rpc/server.go
@@ -299,10 +299,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
 
 // A value sent as a placeholder for the response when the server receives an invalid request.
 type InvalidRequest struct {
-	marker int
+	Marker int
 }
 
-var invalidRequest = InvalidRequest{1}
+var invalidRequest = InvalidRequest{}
 
 func _new(t *reflect.PtrType) *reflect.PtrValue {
 	v := reflect.MakeZero(t).(*reflect.PtrValue)
@@ -316,6 +316,7 @@ func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec Se
 	resp.ServiceMethod = req.ServiceMethod
 	if errmsg != "" {
 		resp.Error = errmsg
+		reply = invalidRequest
 	}
 	resp.Seq = req.Seq
 	sending.Lock()
@@ -389,54 +390,74 @@ func (server *Server) ServeConn(conn io.ReadWriteCloser) {
 func (server *Server) ServeCodec(codec ServerCodec) {
 	sending := new(sync.Mutex)
 	for {
-		// Grab the request header.
-		req := new(Request)
-		err := codec.ReadRequestHeader(req)
+		req, service, mtype, err := server.readRequest(codec)
 		if err != nil {
+			if err != os.EOF {
+				log.Println("rpc:", err)
+			}
 			if err == os.EOF || err == io.ErrUnexpectedEOF {
-				if err == io.ErrUnexpectedEOF {
-					log.Println("rpc:", err)
-				}
 				break
 			}
-			s := "rpc: server cannot decode request: " + err.String()
-			sendResponse(sending, req, invalidRequest, codec, s)
-			break
-		}
-		serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
-		if len(serviceMethod) != 2 {
-			s := "rpc: service/method request ill-formed: " + req.ServiceMethod
-			sendResponse(sending, req, invalidRequest, codec, s)
-			continue
-		}
-		// Look up the request.
-		server.Lock()
-		service, ok := server.serviceMap[serviceMethod[0]]
-		server.Unlock()
-		if !ok {
-			s := "rpc: can't find service " + req.ServiceMethod
-			sendResponse(sending, req, invalidRequest, codec, s)
-			continue
-		}
-		mtype, ok := service.method[serviceMethod[1]]
-		if !ok {
-			s := "rpc: can't find method " + req.ServiceMethod
-			sendResponse(sending, req, invalidRequest, codec, s)
+			// discard body
+			codec.ReadRequestBody(nil)
+
+			// send a response if we actually managed to read a header.
+			if req != nil {
+				sendResponse(sending, req, invalidRequest, codec, err.String())
+			}
 			continue
 		}
+
 		// Decode the argument value.
 		argv := _new(mtype.ArgType)
 		replyv := _new(mtype.ReplyType)
 		err = codec.ReadRequestBody(argv.Interface())
 		if err != nil {
-			log.Println("rpc: tearing down", serviceMethod[0], "connection:", err)
+			if err == os.EOF || err == io.ErrUnexpectedEOF {
+				if err == io.ErrUnexpectedEOF {
+					log.Println("rpc:", err)
+				}
+				break
+			}
 			sendResponse(sending, req, replyv.Interface(), codec, err.String())
-			break
+			continue
 		}
 		go service.call(sending, mtype, req, argv, replyv, codec)
 	}
 	codec.Close()
 }
+func (server *Server) readRequest(codec ServerCodec) (req *Request, service *service, mtype *methodType, err os.Error) {
+	// Grab the request header.
+	req = new(Request)
+	err = codec.ReadRequestHeader(req)
+	if err != nil {
+		req = nil
+		if err == os.EOF || err == io.ErrUnexpectedEOF {
+			return
+		}
+		err = os.ErrorString("rpc: server cannot decode request: " + err.String())
+		return
+	}
+
+	serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
+	if len(serviceMethod) != 2 {
+		err = os.ErrorString("rpc: service/method request ill-formed: " + req.ServiceMethod)
+		return
+	}
+	// Look up the request.
+	server.Lock()
+	service = server.serviceMap[serviceMethod[0]]
+	server.Unlock()
+	if service == nil {
+		err = os.ErrorString("rpc: can't find service " + req.ServiceMethod)
+		return
+	}
+	mtype = service.method[serviceMethod[1]]
+	if mtype == nil {
+		err = os.ErrorString("rpc: can't find method " + req.ServiceMethod)
+	}
+	return
+}
 
 // Accept accepts connections on the listener and serves requests
 // for each incoming connection.  Accept blocks; the caller typically
@@ -465,7 +486,8 @@ func RegisterName(name string, rcvr interface{}) os.Error {
 // The server calls ReadRequestHeader and ReadRequestBody in pairs
 // to read requests from the connection, and it calls WriteResponse to
 // write a response back.  The server calls Close when finished with the
-// connection.
+// connection. ReadRequestBody may be called with a nil
+// argument to force the body of the request to be read and discarded.
 type ServerCodec interface {
 	ReadRequestHeader(*Request) os.Error
 	ReadRequestBody(interface{}) os.Error
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
index 1f080fa..05aaebc 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/rpc/server_test.go
@@ -134,14 +134,25 @@ func testRPC(t *testing.T, addr string) {
 		t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
 	}
 
-	args = &Args{7, 8}
+	// Nonexistent method
+	args = &Args{7, 0}
 	reply = new(Reply)
-	err = client.Call("Arith.Mul", args, reply)
-	if err != nil {
-		t.Errorf("Mul: expected no error but got string %q", err.String())
+	err = client.Call("Arith.BadOperation", args, reply)
+	// expect an error
+	if err == nil {
+		t.Error("BadOperation: expected error")
+	} else if !strings.HasPrefix(err.String(), "rpc: can't find method ") {
+		t.Errorf("BadOperation: expected can't find method error; got %q", err)
 	}
-	if reply.C != args.A*args.B {
-		t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+
+	// Unknown service
+	args = &Args{7, 8}
+	reply = new(Reply)
+	err = client.Call("Arith.Unknown", args, reply)
+	if err == nil {
+		t.Error("expected error calling unknown service")
+	} else if strings.Index(err.String(), "method") < 0 {
+		t.Error("expected error about method; got", err)
 	}
 
 	// Out of order.
@@ -178,6 +189,15 @@ func testRPC(t *testing.T, addr string) {
 		t.Error("Div: expected divide by zero error; got", err)
 	}
 
+	// Bad type.
+	reply = new(Reply)
+	err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
+	if err == nil {
+		t.Error("expected error calling Arith.Add with wrong arg type")
+	} else if strings.Index(err.String(), "type") < 0 {
+		t.Error("expected error about type; got", err)
+	}
+
 	// Non-struct argument
 	const Val = 12345
 	str := fmt.Sprint(Val)
@@ -200,9 +220,19 @@ func testRPC(t *testing.T, addr string) {
 	if str != expect {
 		t.Errorf("String: expected %s got %s", expect, str)
 	}
+
+	args = &Args{7, 8}
+	reply = new(Reply)
+	err = client.Call("Arith.Mul", args, reply)
+	if err != nil {
+		t.Errorf("Mul: expected no error but got string %q", err.String())
+	}
+	if reply.C != args.A*args.B {
+		t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
+	}
 }
 
-func TestHTTPRPC(t *testing.T) {
+func TestHTTP(t *testing.T) {
 	once.Do(startServer)
 	testHTTPRPC(t, "")
 	newOnce.Do(startNewServer)
@@ -233,65 +263,6 @@ func testHTTPRPC(t *testing.T, path string) {
 	}
 }
 
-func TestCheckUnknownService(t *testing.T) {
-	once.Do(startServer)
-
-	conn, err := net.Dial("tcp", "", serverAddr)
-	if err != nil {
-		t.Fatal("dialing:", err)
-	}
-
-	client := NewClient(conn)
-
-	args := &Args{7, 8}
-	reply := new(Reply)
-	err = client.Call("Unknown.Add", args, reply)
-	if err == nil {
-		t.Error("expected error calling unknown service")
-	} else if strings.Index(err.String(), "service") < 0 {
-		t.Error("expected error about service; got", err)
-	}
-}
-
-func TestCheckUnknownMethod(t *testing.T) {
-	once.Do(startServer)
-
-	conn, err := net.Dial("tcp", "", serverAddr)
-	if err != nil {
-		t.Fatal("dialing:", err)
-	}
-
-	client := NewClient(conn)
-
-	args := &Args{7, 8}
-	reply := new(Reply)
-	err = client.Call("Arith.Unknown", args, reply)
-	if err == nil {
-		t.Error("expected error calling unknown service")
-	} else if strings.Index(err.String(), "method") < 0 {
-		t.Error("expected error about method; got", err)
-	}
-}
-
-func TestCheckBadType(t *testing.T) {
-	once.Do(startServer)
-
-	conn, err := net.Dial("tcp", "", serverAddr)
-	if err != nil {
-		t.Fatal("dialing:", err)
-	}
-
-	client := NewClient(conn)
-
-	reply := new(Reply)
-	err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
-	if err == nil {
-		t.Error("expected error calling Arith.Add with wrong arg type")
-	} else if strings.Index(err.String(), "type") < 0 {
-		t.Error("expected error about type; got", err)
-	}
-}
-
 type ArgNotPointer int
 type ReplyNotPointer int
 type ArgNotPublic int
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 63d5826..74e1df0 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -5,6 +5,14 @@
 #include "386/asm.h"
 
 TEXT _rt0_386(SB),7,$0
+	// Linux, Windows start the FPU in extended double precision.
+	// Other operating systems use double precision.
+	// Change to double precision to match them,
+	// and to match other hardware that only has double.
+	PUSHL $0x27F
+	FLDCW	0(SP)
+	POPL AX
+
 	// copy arguments forward on an even stack
 	MOVL	0(SP), AX		// argc
 	LEAL	4(SP), BX		// argv
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index e9488cf..521c095 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -26,8 +26,12 @@ GOFILES=\
 	softfloat64.go\
 	type.go\
 	version.go\
+	version_$(GOOS).go\
+	version_$(GOARCH).go\
 	runtime_defs.go\
 
+CLEANFILES+=version.go version_*.go
+
 OFILES_windows=\
 	syscall.$O\
 
@@ -107,7 +111,7 @@ include ../../Make.pkg
 
 $(pkgdir)/%.h: %.h
 	@test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)
-	cp $< $@
+	cp $< "$@"
 
 clean: clean-local
 
@@ -127,8 +131,14 @@ mkversion: mkversion.c
 version.go: mkversion
 	./mkversion >version.go
 
+version_$(GOARCH).go:
+	(echo 'package runtime'; echo 'const theGoarch = "$(GOARCH)"') >$@
+
+version_$(GOOS).go:
+	(echo 'package runtime'; echo 'const theGoos = "$(GOOS)"') >$@
+
 %.c:	%.goc goc2c
-	./goc2c `pwd`/$< > $@.tmp
+	./goc2c "`pwd`/$<" > $@.tmp
 	mv -f $@.tmp $@
 
 %.$O:	$(GOARCH)/%.c
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c
index 86e96f3..d3aae0d 100644
--- a/src/pkg/runtime/amd64/traceback.c
+++ b/src/pkg/runtime/amd64/traceback.c
@@ -8,6 +8,8 @@
 static uintptr isclosureentry(uintptr);
 void runtime·deferproc(void);
 void runtime·newproc(void);
+void runtime·newstack(void);
+void runtime·morestack(void);
 
 // This code is also used for the 386 tracebacks.
 // Use uintptr for an appropriate word-sized integer.
@@ -17,15 +19,32 @@ void runtime·newproc(void);
 // A little clunky to merge the two but avoids duplicating
 // the code and all its subtlety.
 static int32
-gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
+gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 max)
 {
 	byte *p;
-	int32 i, n, iter, nascent;
-	uintptr pc, tracepc, *fp;
+	int32 i, n, iter, sawnewstack;
+	uintptr pc, lr, tracepc;
+	byte *fp;
 	Stktop *stk;
 	Func *f;
-	
+
 	pc = (uintptr)pc0;
+	lr = 0;
+	fp = nil;
+	
+	// If the PC is goexit, the goroutine hasn't started yet.
+	if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
+		fp = sp;
+		lr = pc;
+		pc = (uintptr)g->entry;
+	}
+	
+	// If the PC is zero, it's likely a nil function call.
+	// Start in the caller's frame.
+	if(pc == 0) {
+		pc = lr;
+		lr = 0;
+	}
 
 	// If the PC is zero, it's likely a nil function call.
 	// Start in the caller's frame.
@@ -33,26 +52,29 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
 		pc = *(uintptr*)sp;
 		sp += sizeof(uintptr);
 	}
-	
-	nascent = 0;
-	if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
-		// Hasn't started yet.  g->sched is set up for goexit
-		// but goroutine will start at g->entry.
-		nascent = 1;
-		pc = (uintptr)g->entry;
-	}
-	
+
 	n = 0;
+	sawnewstack = 0;
 	stk = (Stktop*)g->stackbase;
-	for(iter = 0; iter < 100 && n < m; iter++) {	// iter avoids looping forever
+	for(iter = 0; iter < 100 && n < max; iter++) {	// iter avoids looping forever
+		// Typically:
+		//	pc is the PC of the running function.
+		//	sp is the stack pointer at that program counter.
+		//	fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
+		//	stk is the stack containing sp.
+		//	The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
+	
 		if(pc == (uintptr)runtime·lessstack) {
 			// Hit top of stack segment.  Unwind to next segment.
 			pc = (uintptr)stk->gobuf.pc;
 			sp = stk->gobuf.sp;
+			lr = 0;
+			fp = nil;
+			if(pcbuf == nil)
+				runtime·printf("----- stack segment boundary -----\n");
 			stk = (Stktop*)stk->stackbase;
 			continue;
 		}
-
 		if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
 			// Dangerous, but worthwhile: see if this is a closure:
 			//	ADDQ $wwxxyyzz, SP; RET
@@ -66,17 +88,32 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
 				sp += *(uint32*)(p+2);
 				pc = *(uintptr*)sp;
 				sp += sizeof(uintptr);
+				lr = 0;
+				fp = nil;
 				continue;
 			}
 			
-			if(nascent && (pc = isclosureentry(pc)) != 0)
+			// Closure at top of stack, not yet started.
+			if(lr == (uintptr)runtime·goexit && (pc = isclosureentry(pc)) != 0) {
+				fp = sp;
 				continue;
+			}
 
-			// Unknown pc; stop.
+			// Unknown pc: stop.
 			break;
 		}
 
-		// Found an actual function worth reporting.
+		// Found an actual function.
+		if(fp == nil) {
+			fp = sp;
+			if(pc > f->entry && f->frame >= sizeof(uintptr))
+				fp += f->frame - sizeof(uintptr);
+			if(lr == 0)
+				lr = *(uintptr*)fp;
+			fp += sizeof(uintptr);
+		} else if(lr == 0)
+			lr = *(uintptr*)fp;
+
 		if(skip > 0)
 			skip--;
 		else if(pcbuf != nil)
@@ -93,15 +130,10 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
 				tracepc--;
 			runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
 			runtime·printf("\t%S(", f->name);
-			fp = (uintptr*)sp;
-			if(f->frame < sizeof(uintptr))
-				fp++;
-			else
-				fp += f->frame/sizeof(uintptr);
 			for(i = 0; i < f->args; i++) {
 				if(i != 0)
 					runtime·prints(", ");
-				runtime·printhex(fp[i]);
+				runtime·printhex(((uintptr*)fp)[i]);
 				if(i >= 4) {
 					runtime·prints(", ...");
 					break;
@@ -111,20 +143,32 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
 			n++;
 		}
 		
-		if(nascent) {
-			pc = (uintptr)g->sched.pc;
-			sp = g->sched.sp;
-			nascent = 0;
+		if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
+			fp += 2*sizeof(uintptr);
+
+		if(f->entry == (uintptr)runtime·newstack)
+			sawnewstack = 1;
+
+		if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && g == m->g0 && sawnewstack) {
+			// The fact that we saw newstack means that morestack
+			// has managed to record its information in m, so we can
+			// use it to keep unwinding the stack.
+			runtime·printf("----- morestack called from goroutine %d -----\n", m->curg->goid);
+			pc = (uintptr)m->morepc;
+			sp = m->morebuf.sp - sizeof(void*);
+			lr = (uintptr)m->morebuf.pc;
+			fp = m->morebuf.sp;
+			sawnewstack = 0;
+			g = m->curg;
+			stk = (Stktop*)g->stackbase;
 			continue;
 		}
 
-		if(f->frame < sizeof(uintptr))	// assembly functions lie
-			sp += sizeof(uintptr);
-		else
-			sp += f->frame;
-		pc = *((uintptr*)sp - 1);
-		if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
-			sp += 2*sizeof(uintptr);
+		// Unwind to next frame.
+		pc = lr;
+		lr = 0;
+		sp = fp;
+		fp = nil;
 	}
 	return n;
 }
@@ -156,7 +200,17 @@ isclosureentry(uintptr pc)
 	p = (byte*)pc;
 	if(p < runtime·mheap.arena_start || p+32 > runtime·mheap.arena_used)
 		return 0;
+
+	if(*p == 0xe8) {
+		// CALL fn
+		return pc+5+*(int32*)(p+1);
+	}
 	
+	if(sizeof(uintptr) == 8 && p[0] == 0x48 && p[1] == 0xb9 && p[10] == 0xff && p[11] == 0xd1) {
+		// MOVQ $fn, CX; CALL *CX
+		return *(uintptr*)(p+2);
+	}
+
 	// SUBQ $siz, SP
 	if((sizeof(uintptr) == 8 && *p++ != 0x48) || *p++ != 0x81 || *p++ != 0xec)
 		return 0;
diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c
index 8289fdb..2307e98 100644
--- a/src/pkg/runtime/arm/traceback.c
+++ b/src/pkg/runtime/arm/traceback.c
@@ -3,19 +3,27 @@
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "malloc.h"
+
+void runtime·deferproc(void);
+void runtime·newproc(void);
+void runtime·newstack(void);
+void runtime·morestack(void);
 
 static int32
-gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 m)
+gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 max)
 {
 	int32 i, n, iter;
-	uintptr pc, lr, tracepc;
+	uintptr pc, lr, tracepc, x;
+	byte *fp, *p;
 	Stktop *stk;
 	Func *f;
 	
 	pc = (uintptr)pc0;
 	lr = (uintptr)lr0;
-	
-	// If the PC is goexit, it hasn't started yet.
+	fp = nil;
+
+	// If the PC is goexit, the goroutine hasn't started yet.
 	if(pc == (uintptr)runtime·goexit) {
 		pc = (uintptr)g->entry;
 		lr = (uintptr)runtime·goexit;
@@ -30,21 +38,73 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
 
 	n = 0;
 	stk = (Stktop*)g->stackbase;
-	for(iter = 0; iter < 100 && n < m; iter++) {	// iter avoids looping forever
+	for(iter = 0; iter < 100 && n < max; iter++) {	// iter avoids looping forever
+		// Typically:
+		//	pc is the PC of the running function.
+		//	sp is the stack pointer at that program counter.
+		//	fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown.
+		//	stk is the stack containing sp.
+		//	The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
+		
 		if(pc == (uintptr)runtime·lessstack) {
 			// Hit top of stack segment.  Unwind to next segment.
 			pc = (uintptr)stk->gobuf.pc;
 			sp = stk->gobuf.sp;
-			lr = *(uintptr*)sp;
+			lr = 0;
+			fp = nil;
+			if(pcbuf == nil)
+				runtime·printf("----- stack segment boundary -----\n");
 			stk = (Stktop*)stk->stackbase;
 			continue;
 		}
-		if(pc <= 0x1000 || (f = runtime·findfunc(pc-4)) == nil) {
-			// TODO: Check for closure.
+		
+		if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
+			// Dangerous, but worthwhile: see if this is a closure by
+			// decoding the instruction stream.
+			//
+			// We check p < p+4 to avoid wrapping and faulting if
+			// we have lost track of where we are.
+			p = (byte*)pc;
+			if((pc&3) == 0 && p < p+4 &&
+			   runtime·mheap.arena_start < p &&
+			   p+4 < runtime·mheap.arena_used) {
+			   	x = *(uintptr*)p;
+				if((x&0xfffff000) == 0xe49df000) {
+					// End of closure:
+					// MOVW.P frame(R13), R15
+					pc = *(uintptr*)sp;
+					lr = 0;
+					sp += x & 0xfff;
+					fp = nil;
+					continue;
+				}
+				if((x&0xfffff000) == 0xe52de000 && lr == (uintptr)runtime·goexit) {
+					// Beginning of closure.
+					// Closure at top of stack, not yet started.
+					p += 5*4;
+					if((x&0xfff) != 4) {
+						// argument copying
+						p += 7*4;
+					}
+					if((byte*)pc < p && p < p+4 && p+4 < runtime·mheap.arena_used) {
+						pc = *(uintptr*)p;
+						fp = nil;
+						continue;
+					}
+				}
+			}
 			break;
 		}
 		
-		// Found an actual function worth reporting.
+		// Found an actual function.
+		if(lr == 0)
+			lr = *(uintptr*)sp;
+		if(fp == nil) {
+			fp = sp;
+			if(pc > f->entry && f->frame >= 0)
+				fp += f->frame;
+		}
+
 		if(skip > 0)
 			skip--;
 		else if(pcbuf != nil)
@@ -64,7 +124,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
 			for(i = 0; i < f->args; i++) {
 				if(i != 0)
 					runtime·prints(", ");
-				runtime·printhex(((uintptr*)sp)[1+i]);
+				runtime·printhex(((uintptr*)fp)[1+i]);
 				if(i >= 4) {
 					runtime·prints(", ...");
 					break;
@@ -73,17 +133,28 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
 			runtime·prints(")\n");
 			n++;
 		}
+
+		if(pcbuf == nil && f->entry == (uintptr)runtime·newstack && g == m->g0) {
+			runtime·printf("----- newstack called from goroutine %d -----\n", m->curg->goid);
+			pc = (uintptr)m->morepc;
+			sp = (byte*)m->moreargp - sizeof(void*);
+			lr = (uintptr)m->morebuf.pc;
+			fp = m->morebuf.sp;
+			g = m->curg;
+			stk = (Stktop*)g->stackbase;
+			continue;
+		}
 		
-		if(lr == 0)
-			lr = *(uintptr*)sp;
+		// Unwind to next frame.
 		pc = lr;
 		lr = 0;
-		if(f->frame >= 0)
-			sp += f->frame;
+		sp = fp;
+		fp = nil;
 	}
 	return n;		
 }
 
+
 void
 runtime·traceback(byte *pc0, byte *sp, byte *lr, G *g)
 {
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index e6ece95..74e5a30 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -53,13 +53,12 @@ runtime·cgocall(void (*fn)(void*), void *arg)
 // (arg/argsize) on to the stack, calls the function, copies the
 // arguments back where they came from, and finally returns to the old
 // stack.
-uintptr
+void
 runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
 {
 	Gobuf oldsched, oldg1sched;
 	G *g1;
 	void *sp;
-	uintptr ret;
 
 	if(g != m->g0)
 		runtime·throw("bad g in cgocallback");
@@ -71,11 +70,11 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
 	runtime·startcgocallback(g1);
 
 	sp = g1->sched.sp - argsize;
-	if(sp < g1->stackguard - StackGuard + 4) // +4 for return address
+	if(sp < g1->stackguard - StackGuard + 8) // +8 for return address
 		runtime·throw("g stack overflow in cgocallback");
 	runtime·mcpy(sp, arg, argsize);
 
-	ret = runtime·runcgocallback(g1, sp, fn);
+	runtime·runcgocallback(g1, sp, fn);
 
 	runtime·mcpy(arg, sp, argsize);
 
@@ -83,8 +82,6 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
 
 	m->sched = oldsched;
 	g1->sched = oldg1sched;
-
-	return ret;
 }
 
 void
diff --git a/src/pkg/runtime/cgocall.h b/src/pkg/runtime/cgocall.h
index 7c24e16..1ad954e 100644
--- a/src/pkg/runtime/cgocall.h
+++ b/src/pkg/runtime/cgocall.h
@@ -7,6 +7,6 @@
  */
 
 void runtime·cgocall(void (*fn)(void*), void*);
-uintptr runtime·cgocallback(void (*fn)(void), void*, int32);
+void runtime·cgocallback(void (*fn)(void), void*, int32);
 void *runtime·cmalloc(uintptr);
 void runtime·cfree(void*);
diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go
index d09db1b..5117e1a 100644
--- a/src/pkg/runtime/debug.go
+++ b/src/pkg/runtime/debug.go
@@ -69,7 +69,8 @@ type MemStatsType struct {
 
 	// Per-size allocation statistics.
 	// Not locked during update; approximate.
-	BySize [67]struct {
+	// 61 is NumSizeClasses in the C code.
+	BySize [61]struct {
 		Size    uint32
 		Mallocs uint64
 		Frees   uint64
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index dba2832..c6e664a 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -60,31 +60,47 @@ func (f *Func) Entry() uintptr { return f.entry }
 // counter within f.
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
 	// NOTE(rsc): If you edit this function, also edit
-	// symtab.c:/^funcline.
+	// symtab.c:/^funcline.  That function also has the
+	// comments explaining the logic.
+	targetpc := pc
+
 	var pcQuant uintptr = 1
 	if GOARCH == "arm" {
 		pcQuant = 4
 	}
 
-	targetpc := pc
 	p := f.pcln
 	pc = f.pc0
 	line = int(f.ln0)
-	file = f.src
-	for i := 0; i < len(p) && pc <= targetpc; i++ {
-		switch {
-		case p[i] == 0:
+	i := 0
+	//print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line,
+	//	" tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n")
+	for {
+		for i < len(p) && p[i] > 128 {
+			pc += pcQuant * uintptr(p[i]-128)
+			i++
+		}
+		//print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n")
+		if pc > targetpc || i >= len(p) {
+			break
+		}
+		if p[i] == 0 {
+			if i+5 > len(p) {
+				break
+			}
 			line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
-			i += 4
-		case p[i] <= 64:
+			i += 5
+		} else if p[i] <= 64 {
 			line += int(p[i])
-		case p[i] <= 128:
+			i++
+		} else {
 			line -= int(p[i] - 64)
-		default:
-			pc += pcQuant * uintptr(p[i]-129)
+			i++
 		}
+		//print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n")
 		pc += pcQuant
 	}
+	file = f.src
 	return
 }
 
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
index cbae187..f5bbfa6 100644
--- a/src/pkg/runtime/freebsd/mem.c
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -33,6 +33,12 @@ runtime·SysFree(void *v, uintptr n)
 void*
 runtime·SysReserve(void *v, uintptr n)
 {
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if(sizeof(void*) == 8)
+		return v;
+	
 	return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 }
 
@@ -42,6 +48,17 @@ runtime·SysMap(void *v, uintptr n)
 	void *p;
 	
 	mstats.sys += n;
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if(sizeof(void*) == 8) {
+		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if(p != v) {
+			runtime·printf("runtime: address space conflict: map(%v) = %v\n", v, p);
+			runtime·throw("runtime: address space conflict");
+		}
+		return;
+	}
+
 	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
 	if(p != v)
 		runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index aa36df6..3dec45e 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -702,7 +702,7 @@ unsafe·New(Eface typ, void *ret)
 	t = (Type*)((Eface*)typ.data-1);
 
 	if(t->kind&KindNoPointers)
-		ret = runtime·mallocgc(t->size, RefNoPointers, 1, 1);
+		ret = runtime·mallocgc(t->size, FlagNoPointers, 1, 1);
 	else
 		ret = runtime·mal(t->size);
 	FLUSH(&ret);
@@ -722,7 +722,7 @@ unsafe·NewArray(Eface typ, uint32 n, void *ret)
 	
 	size = n*t->size;
 	if(t->kind&KindNoPointers)
-		ret = runtime·mallocgc(size, RefNoPointers, 1, 1);
+		ret = runtime·mallocgc(size, FlagNoPointers, 1, 1);
 	else
 		ret = runtime·mal(size);
 	FLUSH(&ret);
diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s
index 0f82d6a..223e6d2 100644
--- a/src/pkg/runtime/linux/386/rt0.s
+++ b/src/pkg/runtime/linux/386/rt0.s
@@ -5,13 +5,5 @@
 // Darwin and Linux use the same linkage to main
 
 TEXT _rt0_386_linux(SB),7,$0
-	// Linux starts the FPU in extended double precision.
-	// Other operating systems use double precision.
-	// Change to double precision to match them,
-	// and to match other hardware that only has double.
-	PUSHL $0x27F
-	FLDCW	0(SP)
-	POPL AX
-
 	JMP	_rt0_386(SB)
 
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index 3a83e73..633ad0c 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -39,6 +39,12 @@ runtime·SysFree(void *v, uintptr n)
 void*
 runtime·SysReserve(void *v, uintptr n)
 {
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if(sizeof(void*) == 8)
+		return v;
+	
 	return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 }
 
@@ -48,6 +54,17 @@ runtime·SysMap(void *v, uintptr n)
 	void *p;
 	
 	mstats.sys += n;
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if(sizeof(void*) == 8) {
+		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if(p != v) {
+			runtime·printf("runtime: address space conflict: map(%v) = %v\n", v, p);
+			runtime·throw("runtime: address space conflict");
+		}
+		return;
+	}
+
 	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
 	if(p != v)
 		runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index cc28b94..70b85d6 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -36,14 +36,13 @@ fastrand1(void)
 // Small objects are allocated from the per-thread cache's free lists.
 // Large objects (> 32 kB) are allocated straight from the heap.
 void*
-runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
+runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
 {
 	int32 sizeclass, rate;
 	MCache *c;
 	uintptr npages;
 	MSpan *s;
 	void *v;
-	uint32 *ref;
 
 	if(runtime·gcwaiting && g != m->g0 && m->locks == 0)
 		runtime·gosched();
@@ -65,12 +64,6 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
 		mstats.alloc += size;
 		mstats.total_alloc += size;
 		mstats.by_size[sizeclass].nmalloc++;
-
-		if(!runtime·mlookup(v, nil, nil, nil, &ref)) {
-			runtime·printf("malloc %D; runtime·mlookup failed\n", (uint64)size);
-			runtime·throw("malloc runtime·mlookup");
-		}
-		*ref = RefNone | refflag;
 	} else {
 		// TODO(rsc): Report tracebacks for very large allocations.
 
@@ -87,13 +80,14 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
 		v = (void*)(s->start << PageShift);
 
 		// setup for mark sweep
-		s->gcref0 = RefNone | refflag;
-		ref = &s->gcref0;
+		runtime·markspan(v, 0, 0, true);
 	}
+	if(!(flag & FlagNoGC))
+		runtime·markallocated(v, size, (flag&FlagNoPointers) != 0);
 
 	m->mallocing = 0;
 
-	if(!(refflag & RefNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
+	if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
 		if(size >= rate)
 			goto profile;
 		if(m->mcache->next_sample > size)
@@ -104,7 +98,7 @@ runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
 				rate = 0x3fffffff;
 			m->mcache->next_sample = fastrand1() % (2*rate);
 		profile:
-			*ref |= RefProfiled;
+			runtime·setblockspecial(v);
 			runtime·MProf_Malloc(v, size);
 		}
 	}
@@ -124,33 +118,35 @@ runtime·malloc(uintptr size)
 void
 runtime·free(void *v)
 {
-	int32 sizeclass, size;
+	int32 sizeclass;
 	MSpan *s;
 	MCache *c;
-	uint32 prof, *ref;
+	uint32 prof;
+	uintptr size;
 
 	if(v == nil)
 		return;
+	
+	// If you change this also change mgc0.c:/^sweepspan,
+	// which has a copy of the guts of free.
 
 	if(m->mallocing)
 		runtime·throw("malloc/free - deadlock");
 	m->mallocing = 1;
 
-	if(!runtime·mlookup(v, nil, nil, &s, &ref)) {
+	if(!runtime·mlookup(v, nil, nil, &s)) {
 		runtime·printf("free %p: not an allocated block\n", v);
 		runtime·throw("free runtime·mlookup");
 	}
-	prof = *ref & RefProfiled;
-	*ref = RefFree;
+	prof = runtime·blockspecial(v);
 
 	// Find size class for v.
 	sizeclass = s->sizeclass;
 	if(sizeclass == 0) {
 		// Large object.
-		if(prof)
-			runtime·MProf_Free(v, s->npages<<PageShift);
-		mstats.alloc -= s->npages<<PageShift;
-		runtime·memclr(v, s->npages<<PageShift);
+		size = s->npages<<PageShift;
+		*(uintptr*)(s->start<<PageShift) = 1;	// mark as "needs to be zeroed"
+		runtime·unmarkspan(v, 1<<PageShift);
 		runtime·MHeap_Free(&runtime·mheap, s, 1);
 	} else {
 		// Small object.
@@ -158,19 +154,20 @@ runtime·free(void *v)
 		size = runtime·class_to_size[sizeclass];
 		if(size > sizeof(uintptr))
 			((uintptr*)v)[1] = 1;	// mark as "needs to be zeroed"
-		if(prof)
-			runtime·MProf_Free(v, size);
-		mstats.alloc -= size;
 		mstats.by_size[sizeclass].nfree++;
 		runtime·MCache_Free(c, v, sizeclass, size);
 	}
+	runtime·markfreed(v, size);
+	mstats.alloc -= size;
+	if(prof)
+		runtime·MProf_Free(v, size);
 	m->mallocing = 0;
 }
 
 int32
-runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
+runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 {
-	uintptr n, nobj, i;
+	uintptr n, i;
 	byte *p;
 	MSpan *s;
 
@@ -179,12 +176,11 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
 	if(sp)
 		*sp = s;
 	if(s == nil) {
+		runtime·checkfreed(v, 1);
 		if(base)
 			*base = nil;
 		if(size)
 			*size = 0;
-		if(ref)
-			*ref = 0;
 		return 0;
 	}
 
@@ -195,14 +191,11 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
 			*base = p;
 		if(size)
 			*size = s->npages<<PageShift;
-		if(ref)
-			*ref = &s->gcref0;
 		return 1;
 	}
 
-	if((byte*)v >= (byte*)s->gcref) {
-		// pointers into the gc ref counts
-		// do not count as pointers.
+	if((byte*)v >= (byte*)s->limit) {
+		// pointers past the last block do not count as pointers.
 		return 0;
 	}
 
@@ -213,21 +206,6 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
 	if(size)
 		*size = n;
 
-	// good for error checking, but expensive
-	if(0) {
-		nobj = (s->npages << PageShift) / (n + RefcountOverhead);
-		if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) {
-			runtime·printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
-				s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
-			runtime·printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
-				s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
-				(uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
-			runtime·throw("bad gcref");
-		}
-	}
-	if(ref)
-		*ref = &s->gcref[i];
-
 	return 1;
 }
 
@@ -246,14 +224,20 @@ runtime·allocmcache(void)
 
 int32 runtime·sizeof_C_MStats = sizeof(MStats);
 
+#define MaxArena32 (2U<<30)
+
 void
 runtime·mallocinit(void)
 {
 	byte *p;
-	uintptr arena_size;
+	uintptr arena_size, bitmap_size;
+	extern byte end[];
 
 	runtime·InitSizes();
 
+	// Set up the allocation arena, a contiguous area of memory where
+	// allocated data will be found.  The arena begins with a bitmap large
+	// enough to hold 4 bits per allocated word.
 	if(sizeof(void*) == 8) {
 		// On a 64-bit machine, allocate from a single contiguous reservation.
 		// 16 GB should be big enough for now.
@@ -273,19 +257,53 @@ runtime·mallocinit(void)
 		// odds of the conservative garbage collector not collecting memory
 		// because some non-pointer block of memory had a bit pattern
 		// that matched a memory address.
+		//
+		// Actually we reserve 17 GB (because the bitmap ends up being 1 GB)
+		// but it hardly matters: fc is not valid UTF-8 either, and we have to
+		// allocate 15 GB before we get that far.
 		arena_size = 16LL<<30;
-		p = runtime·SysReserve((void*)(0x00f8ULL<<32), arena_size);
+		bitmap_size = arena_size / (sizeof(void*)*8/4);
+		p = runtime·SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size);
 		if(p == nil)
 			runtime·throw("runtime: cannot reserve arena virtual address space");
-		runtime·mheap.arena_start = p;
-		runtime·mheap.arena_used = p;
-		runtime·mheap.arena_end = p + arena_size;
 	} else {
-		// On a 32-bit machine, we'll take what we can get for each allocation
-		// and maintain arena_start and arena_end as min, max we've seen.
-		runtime·mheap.arena_start = (byte*)0xffffffff;
-		runtime·mheap.arena_end = 0;
+		// On a 32-bit machine, we can't typically get away
+		// with a giant virtual address space reservation.
+		// Instead we map the memory information bitmap
+		// immediately after the data segment, large enough
+		// to handle another 2GB of mappings (256 MB),
+		// along with a reservation for another 512 MB of memory.
+		// When that gets used up, we'll start asking the kernel
+		// for any memory anywhere and hope it's in the 2GB
+		// following the bitmap (presumably the executable begins
+		// near the bottom of memory, so we'll have to use up
+		// most of memory before the kernel resorts to giving out
+		// memory before the beginning of the text segment).
+		//
+		// Alternatively we could reserve 512 MB bitmap, enough
+		// for 4GB of mappings, and then accept any memory the
+		// kernel threw at us, but normally that's a waste of 512 MB
+		// of address space, which is probably too much in a 32-bit world.
+		bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
+		arena_size = 512<<20;
+		
+		// SysReserve treats the address we ask for, end, as a hint,
+		// not as an absolute requirement.  If we ask for the end
+		// of the data segment but the operating system requires
+		// a little more space before we can start allocating, it will
+		// give out a slightly higher pointer.  That's fine.  
+		// Run with what we get back.
+		p = runtime·SysReserve(end, bitmap_size + arena_size);
+		if(p == nil)
+			runtime·throw("runtime: cannot reserve arena virtual address space");
 	}
+	if((uintptr)p & (((uintptr)1<<PageShift)-1))
+		runtime·throw("runtime: SysReserve returned unaligned address");
+
+	runtime·mheap.bitmap = p;
+	runtime·mheap.arena_start = p + bitmap_size;
+	runtime·mheap.arena_used = runtime·mheap.arena_start;
+	runtime·mheap.arena_end = runtime·mheap.arena_start + arena_size;
 
 	// Initialize the rest of the allocator.	
 	runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc);
@@ -299,26 +317,41 @@ void*
 runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
 {
 	byte *p;
-	
-	if(sizeof(void*) == 8) {
+
+	if(n <= h->arena_end - h->arena_used) {
 		// Keep taking from our reservation.
-		if(h->arena_end - h->arena_used < n)
-			return nil;
 		p = h->arena_used;
 		runtime·SysMap(p, n);
 		h->arena_used += n;
+		runtime·MHeap_MapBits(h);
 		return p;
-	} else {
-		// Take what we can get from the OS.
-		p = runtime·SysAlloc(n);
-		if(p == nil)
-			return nil;
-		if(p+n > h->arena_used)
-			h->arena_used = p+n;
-		if(p > h->arena_end)
-			h->arena_end = p;
-		return p;		
 	}
+	
+	// On 64-bit, our reservation is all we have.
+	if(sizeof(void*) == 8)
+		return nil;
+
+	// On 32-bit, once the reservation is gone we can
+	// try to get memory at a location chosen by the OS
+	// and hope that it is in the range we allocated bitmap for.
+	p = runtime·SysAlloc(n);
+	if(p == nil)
+		return nil;
+
+	if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
+		runtime·printf("runtime: memory allocated by OS not in usable range");
+		runtime·SysFree(p, n);
+		return nil;
+	}
+
+	if(p+n > h->arena_used) {
+		h->arena_used = p+n;
+		if(h->arena_used > h->arena_end)
+			h->arena_end = h->arena_used;
+		runtime·MHeap_MapBits(h);
+	}
+	
+	return p;
 }
 
 // Runtime stubs.
@@ -353,7 +386,6 @@ void*
 runtime·stackalloc(uint32 n)
 {
 	void *v;
-	uint32 *ref;
 
 	if(m->mallocing || m->gcing || n == FixedStack) {
 		runtime·lock(&stacks);
@@ -369,11 +401,7 @@ runtime·stackalloc(uint32 n)
 		runtime·unlock(&stacks);
 		return v;
 	}
-	v = runtime·mallocgc(n, RefNoProfiling, 0, 0);
-	if(!runtime·mlookup(v, nil, nil, nil, &ref))
-		runtime·throw("stackalloc runtime·mlookup");
-	*ref = RefStack;
-	return v;
+	return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
 }
 
 void
@@ -399,7 +427,7 @@ func Free(p *byte) {
 }
 
 func Lookup(p *byte) (base *byte, size uintptr) {
-	runtime·mlookup(p, &base, &size, nil, nil);
+	runtime·mlookup(p, &base, &size, nil);
 }
 
 func GC() {
@@ -422,7 +450,7 @@ func SetFinalizer(obj Eface, finalizer Eface) {
 		runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
 		goto throw;
 	}
-	if(!runtime·mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) {
+	if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) {
 		runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
 		goto throw;
 	}
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index e2472e8..4e27945 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -97,8 +97,14 @@ typedef	uintptr	PageID;		// address >> PageShift
 
 enum
 {
+	// Computed constant.  The definition of MaxSmallSize and the
+	// algorithm in msize.c produce some number of different allocation
+	// size classes.  NumSizeClasses is that number.  It's needed here
+	// because there are static arrays of this length; when msize runs its
+	// size choosing algorithm it double-checks that NumSizeClasses agrees.
+	NumSizeClasses = 61,
+
 	// Tunable constants.
-	NumSizeClasses = 67,		// Number of size classes (must match msize.c)
 	MaxSmallSize = 32<<10,
 
 	FixAllocChunk = 128<<10,	// Chunk size for FixAlloc
@@ -290,10 +296,7 @@ struct MSpan
 	uint32	ref;		// number of allocated objects in this span
 	uint32	sizeclass;	// size class
 	uint32	state;		// MSpanInUse etc
-	union {
-		uint32	*gcref;	// sizeclass > 0
-		uint32	gcref0;	// sizeclass == 0
-	};
+	byte	*limit;	// end of data in span
 };
 
 void	runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
@@ -336,6 +339,7 @@ struct MHeap
 
 	// range of addresses we might see in the heap
 	byte *bitmap;
+	uintptr bitmap_mapped;
 	byte *arena_start;
 	byte *arena_used;
 	byte *arena_end;
@@ -359,26 +363,29 @@ MSpan*	runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct
 void	runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
 MSpan*	runtime·MHeap_Lookup(MHeap *h, void *v);
 MSpan*	runtime·MHeap_LookupMaybe(MHeap *h, void *v);
-void	runtime·MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
+void	runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *size, int32 *npages, int32 *nobj);
 void*	runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
+void	runtime·MHeap_MapBits(MHeap *h);
 
 void*	runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
-int32	runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
+int32	runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
 void	runtime·gc(int32 force);
+void	runtime·markallocated(void *v, uintptr n, bool noptr);
+void	runtime·checkallocated(void *v, uintptr n);
+void	runtime·markfreed(void *v, uintptr n);
+void	runtime·checkfreed(void *v, uintptr n);
+int32	runtime·checking;
+void	runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
+void	runtime·unmarkspan(void *v, uintptr size);
+bool	runtime·blockspecial(void*);
+void	runtime·setblockspecial(void*);
 
 enum
 {
-	RefcountOverhead = 4,	// one uint32 per object
-
-	RefFree = 0,	// must be zero
-	RefStack,		// stack segment - don't free and don't scan for pointers
-	RefNone,		// no references
-	RefSome,		// some references
-	RefNoPointers = 0x80000000U,	// flag - no pointers here
-	RefHasFinalizer = 0x40000000U,	// flag - has finalizer
-	RefProfiled = 0x20000000U,	// flag - is in profiling table
-	RefNoProfiling = 0x10000000U,	// flag - must not profile
-	RefFlags = 0xFFFF0000U,
+	// flags to malloc
+	FlagNoPointers = 1<<0,	// no pointers here
+	FlagNoProfiling = 1<<1,	// must not profile
+	FlagNoGC = 1<<2,	// must not free or scan for pointers
 };
 
 void	runtime·MProf_Malloc(void*, uintptr);
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index f1ad119..29b03b5 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -113,8 +113,7 @@ static void
 MCentral_Free(MCentral *c, void *v)
 {
 	MSpan *s;
-	PageID page;
-	MLink *p, *next;
+	MLink *p;
 	int32 size;
 
 	// Find span for v.
@@ -138,16 +137,8 @@ MCentral_Free(MCentral *c, void *v)
 	if(--s->ref == 0) {
 		size = runtime·class_to_size[c->sizeclass];
 		runtime·MSpanList_Remove(s);
-		// The second word of each freed block indicates
-		// whether it needs to be zeroed.  The first word
-		// is the link pointer and must always be cleared.
-		for(p=s->freelist; p; p=next) {
-			next = p->next;
-			if(size > sizeof(uintptr) && ((uintptr*)p)[1] != 0)
-				runtime·memclr((byte*)p, size);
-			else
-				p->next = nil;
-		}
+		runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+		*(uintptr*)(s->start<<PageShift) = 1;  // needs zeroing
 		s->freelist = nil;
 		c->nfree -= (s->npages << PageShift) / size;
 		runtime·unlock(c);
@@ -157,7 +148,7 @@ MCentral_Free(MCentral *c, void *v)
 }
 
 void
-runtime·MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
+runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *sizep, int32 *npagesp, int32 *nobj)
 {
 	int32 size;
 	int32 npages;
@@ -166,7 +157,7 @@ runtime·MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32
 	size = runtime·class_to_size[sizeclass];
 	*npagesp = npages;
 	*sizep = size;
-	*nobj = (npages << PageShift) / (size + RefcountOverhead);
+	*nobj = (npages << PageShift) / size;
 }
 
 // Fetch a new span from the heap and
@@ -174,7 +165,8 @@ runtime·MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32
 static bool
 MCentral_Grow(MCentral *c)
 {
-	int32 i, n, npages, size;
+	int32 i, n, npages;
+	uintptr size;
 	MLink **tailp, *v;
 	byte *p;
 	MSpan *s;
@@ -191,7 +183,7 @@ MCentral_Grow(MCentral *c)
 	// Carve span into sequence of blocks.
 	tailp = &s->freelist;
 	p = (byte*)(s->start << PageShift);
-	s->gcref = (uint32*)(p + size*n);
+	s->limit = p + size*n;
 	for(i=0; i<n; i++) {
 		v = (MLink*)p;
 		*tailp = v;
@@ -199,6 +191,7 @@ MCentral_Grow(MCentral *c)
 		p += size;
 	}
 	*tailp = nil;
+	runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
 
 	runtime·lock(c);
 	c->nfree += n;
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
index f73561b..03ee777 100644
--- a/src/pkg/runtime/mfinal.c
+++ b/src/pkg/runtime/mfinal.c
@@ -5,6 +5,7 @@
 #include "runtime.h"
 #include "malloc.h"
 
+// TODO(rsc): Why not just use mheap.Lock?
 static Lock finlock;
 
 // Finalizer hash table.  Direct hash, linear scan, at most 3/4 full.
@@ -101,24 +102,21 @@ runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
 	}
 
 	runtime·lock(&finlock);
-	if(!runtime·mlookup(p, &base, nil, nil, &ref) || p != base) {
+	if(!runtime·mlookup(p, &base, nil, nil) || p != base) {
 		runtime·unlock(&finlock);
 		runtime·throw("addfinalizer on invalid pointer");
 	}
 	if(f == nil) {
-		if(*ref & RefHasFinalizer) {
-			lookfintab(&fintab, p, 1);
-			*ref &= ~RefHasFinalizer;
-		}
+		lookfintab(&fintab, p, 1);
 		runtime·unlock(&finlock);
 		return;
 	}
 
-	if(*ref & RefHasFinalizer) {
+	if(lookfintab(&fintab, p, 0)) {
 		runtime·unlock(&finlock);
 		runtime·throw("double finalizer");
 	}
-	*ref |= RefHasFinalizer;
+	runtime·setblockspecial(p);
 
 	if(fintab.nkey >= fintab.max/2+fintab.max/4) {
 		// keep table at most 3/4 full:
@@ -134,7 +132,7 @@ runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
 			newtab.max *= 3;
 		}
 
-		newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
+		newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1);
 		newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
 
 		for(i=0; i<fintab.max; i++) {
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index af1c721..232c6cd 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2,28 +2,66 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Garbage collector -- step 0.
-//
-// Stop the world, mark and sweep garbage collector.
-// NOT INTENDED FOR PRODUCTION USE.
-//
-// A mark and sweep collector provides a way to exercise
-// and test the memory allocator and the stack walking machinery
-// without also needing to get reference counting
-// exactly right.
+// Garbage collector.
 
 #include "runtime.h"
 #include "malloc.h"
 
 enum {
-	Debug = 0
+	Debug = 0,
+	UseCas = 1,
+	PtrSize = sizeof(void*),
+	
+	// Four bits per word (see #defines below).
+	wordsPerBitmapWord = sizeof(void*)*8/4,
+	bitShift = sizeof(void*)*8/4,
 };
 
-typedef struct BlockList BlockList;
-struct BlockList
+// Bits in per-word bitmap.
+// #defines because enum might not be able to hold the values.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory.  There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+// The bits in the word are packed together by type first, then by
+// heap location, so each 64-bit bitmap word consists of, from top to bottom,
+// the 16 bitSpecial bits for the corresponding heap words, then the 16 bitMarked bits,
+// then the 16 bitNoPointers/bitBlockBoundary bits, then the 16 bitAllocated bits.
+// This layout makes it easier to iterate over the bits of a given type.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there.  On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start.  (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+//
+// To pull out the bits corresponding to a given pointer p, we use:
+//
+//	off = p - (uintptr*)mheap.arena_start;  // word offset
+//	b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
+//	shift = off % wordsPerBitmapWord
+//	bits = *b >> shift;
+//	/* then test bits & bitAllocated, bits & bitMarked, etc. */
+//
+#define bitAllocated		((uintptr)1<<(bitShift*0))
+#define bitNoPointers		((uintptr)1<<(bitShift*1))	/* when bitAllocated is set */
+#define bitMarked		((uintptr)1<<(bitShift*2))	/* when bitAllocated is set */
+#define bitSpecial		((uintptr)1<<(bitShift*3))	/* when bitAllocated is set - has finalizer or being profiled */
+#define bitBlockBoundary	((uintptr)1<<(bitShift*1))	/* when bitAllocated is NOT set */
+
+#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+
+static uint64 nlookup;
+static uint64 nsizelookup;
+static uint64 naddrlookup;
+static uint64 nhandoff;
+static int32 gctrace;
+
+typedef struct Workbuf Workbuf;
+struct Workbuf
 {
-	byte *obj;
-	uintptr size;
+	Workbuf *next;
+	uintptr nw;
+	byte *w[2048-2];
 };
 
 extern byte data[];
@@ -33,72 +71,258 @@ extern byte end[];
 static G *fing;
 static Finalizer *finq;
 static int32 fingwait;
-static BlockList *bl, *ebl;
+static uint32 nfullwait;
 
 static void runfinq(void);
-
-enum {
-	PtrSize = sizeof(void*)
-};
-
+static bool bitlookup(void*, uintptr**, uintptr*, int32*);
+static Workbuf* getempty(Workbuf*);
+static Workbuf* getfull(Workbuf*);
+
+// scanblock scans a block of n bytes starting at pointer b for references
+// to other objects, scanning any it finds recursively until there are no
+// unscanned objects left.  Instead of using an explicit recursion, it keeps
+// a work list in the Workbuf* structures and loops in the main function
+// body.  Keeping an explicit work list is easier on the stack allocator and
+// more efficient.
 static void
 scanblock(byte *b, int64 n)
 {
-	int32 off;
-	void *obj;
-	uintptr size;
-	uint32 *refp, ref;
+	byte *obj, *arena_start, *p;
 	void **vp;
-	int64 i;
-	BlockList *w;
-
-	w = bl;
-	w->obj = b;
-	w->size = n;
-	w++;
+	uintptr size, *bitp, bits, shift, i, j, x, xbits, off;
+	MSpan *s;
+	PageID k;
+	void **bw, **w, **ew;
+	Workbuf *wbuf;
 
-	while(w > bl) {
-		w--;
-		b = w->obj;
-		n = w->size;
+	// Memory arena parameters.
+	arena_start = runtime·mheap.arena_start;
+	
+	wbuf = nil;  // current work buffer
+	ew = nil;  // end of work buffer
+	bw = nil;  // beginning of work buffer
+	w = nil;  // current pointer into work buffer
+
+	// Align b to a word boundary.
+	off = (uintptr)b & (PtrSize-1);
+	if(off != 0) {
+		b += PtrSize - off;
+		n -= PtrSize - off;
+	}
 
+	for(;;) {
+		// Each iteration scans the block b of length n, queueing pointers in
+		// the work buffer.
 		if(Debug > 1)
 			runtime·printf("scanblock %p %D\n", b, n);
-		off = (uint32)(uintptr)b & (PtrSize-1);
-		if(off) {
-			b += PtrSize - off;
-			n -= PtrSize - off;
-		}
-	
+
 		vp = (void**)b;
 		n /= PtrSize;
 		for(i=0; i<n; i++) {
-			obj = vp[i];
-			if(obj == nil)
+			obj = (byte*)vp[i];
+			
+			// Words outside the arena cannot be pointers.
+			if((byte*)obj < arena_start || (byte*)obj >= runtime·mheap.arena_used)
 				continue;
-			if(runtime·mheap.arena_start <= (byte*)obj && (byte*)obj < runtime·mheap.arena_end) {
-				if(runtime·mlookup(obj, &obj, &size, nil, &refp)) {
-					ref = *refp;
-					switch(ref & ~RefFlags) {
-					case RefNone:
-						if(Debug > 1)
-							runtime·printf("found at %p: ", &vp[i]);
-						*refp = RefSome | (ref & RefFlags);
-						if(!(ref & RefNoPointers)) {
-							if(w >= ebl)
-								runtime·throw("scanblock: garbage collection stack overflow");
-							w->obj = obj;
-							w->size = size;
-							w++;
-						}
-						break;
-					}
+			
+			// obj may be a pointer to a live object.
+			// Try to find the beginning of the object.
+			
+			// Round down to word boundary.
+			obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+
+			// Find bits for this word.
+			off = (uintptr*)obj - (uintptr*)arena_start;
+			bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+			shift = off % wordsPerBitmapWord;
+			xbits = *bitp;
+			bits = xbits >> shift;
+
+			// Pointing at the beginning of a block?
+			if((bits & (bitAllocated|bitBlockBoundary)) != 0)
+				goto found;
+
+			// Pointing just past the beginning?
+			// Scan backward a little to find a block boundary.
+			for(j=shift; j-->0; ) {
+				if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
+					obj = (byte*)obj - (shift-j)*PtrSize;
+					shift = j;
+					bits = xbits>>shift;
+					goto found;
 				}
 			}
+
+			// Otherwise consult span table to find beginning.
+			// (Manually inlined copy of MHeap_LookupMaybe.)
+			nlookup++;
+			naddrlookup++;
+			k = (uintptr)obj>>PageShift;
+			x = k;
+			if(sizeof(void*) == 8)
+				x -= (uintptr)arena_start>>PageShift;
+			s = runtime·mheap.map[x];
+			if(s == nil || k < s->start || k - s->start >= s->npages || s->state != MSpanInUse)
+				continue;
+			p =  (byte*)((uintptr)s->start<<PageShift);
+			if(s->sizeclass == 0) {
+				obj = p;
+			} else {
+				if((byte*)obj >= (byte*)s->limit)
+					continue;
+				size = runtime·class_to_size[s->sizeclass];
+				int32 i = ((byte*)obj - p)/size;
+				obj = p+i*size;
+			}
+
+			// Now that we know the object header, reload bits.
+			off = (uintptr*)obj - (uintptr*)arena_start;
+			bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+			shift = off % wordsPerBitmapWord;
+			xbits = *bitp;
+			bits = xbits >> shift;
+
+		found:
+			// Now we have bits, bitp, and shift correct for
+			// obj pointing at the base of the object.
+			// If not allocated or already marked, done.
+			if((bits & bitAllocated) == 0 || (bits & bitMarked) != 0)
+				continue;
+			*bitp |= bitMarked<<shift;
+
+			// If object has no pointers, don't need to scan further.
+			if((bits & bitNoPointers) != 0)
+				continue;
+
+			// If buffer is full, get a new one.
+			if(w >= ew) {
+				wbuf = getempty(wbuf);
+				bw = wbuf->w;
+				w = bw;
+				ew = bw + nelem(wbuf->w);
+			}
+			*w++ = obj;
+		}
+		
+		// Done scanning [b, b+n).  Prepare for the next iteration of
+		// the loop by setting b and n to the parameters for the next block.
+
+		// Fetch b from the work buffers.
+		if(w <= bw) {
+			// Emptied our buffer: refill.
+			wbuf = getfull(wbuf);
+			if(wbuf == nil)
+				break;
+			bw = wbuf->w;
+			ew = wbuf->w + nelem(wbuf->w);
+			w = bw+wbuf->nw;
 		}
+		b = *--w;
+	
+		// Figure out n = size of b.  Start by loading bits for b.
+		off = (uintptr*)b - (uintptr*)arena_start;
+		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		xbits = *bitp;
+		bits = xbits >> shift;
+		
+		// Might be small; look for nearby block boundary.
+		// A block boundary is marked by either bitBlockBoundary
+		// or bitAllocated being set (see notes near their definition).
+		enum {
+			boundary = bitBlockBoundary|bitAllocated
+		};
+		// Look for a block boundary both after and before b
+		// in the same bitmap word.
+		//
+		// A block boundary j words after b is indicated by
+		//	bits>>j & boundary
+		// assuming shift+j < bitShift.  (If shift+j >= bitShift then
+		// we'll be bleeding other bit types like bitMarked into our test.)
+		// Instead of inserting the conditional shift+j < bitShift into the loop,
+		// we can let j range from 1 to bitShift as long as we first
+		// apply a mask to keep only the bits corresponding
+		// to shift+j < bitShift aka j < bitShift-shift.
+		bits &= (boundary<<(bitShift-shift)) - boundary;
+		
+		// A block boundary j words before b is indicated by
+		//	xbits>>(shift-j) & boundary
+		// (assuming shift >= j).  There is no cleverness here
+		// avoid the test, because when j gets too large the shift
+		// turns negative, which is undefined in C.		
+
+		for(j=1; j<bitShift; j++) {
+			if(((bits>>j)&boundary) != 0 || shift>=j && ((xbits>>(shift-j))&boundary) != 0) {
+				n = j*PtrSize;
+				goto scan;
+			}
+		}
+		
+		// Fall back to asking span about size class.
+		// (Manually inlined copy of MHeap_Lookup.)
+		nlookup++;
+		nsizelookup++;
+		x = (uintptr)b>>PageShift;
+		if(sizeof(void*) == 8)
+			x -= (uintptr)arena_start>>PageShift;
+		s = runtime·mheap.map[x];
+		if(s->sizeclass == 0)
+			n = s->npages<<PageShift;
+		else
+			n = runtime·class_to_size[s->sizeclass];
+	scan:;
+	}
+}
+
+static struct {
+	Workbuf	*full;
+	Workbuf	*empty;
+	byte	*chunk;
+	uintptr	nchunk;
+} work;
+
+// Get an empty work buffer off the work.empty list,
+// allocating new buffers as needed.
+static Workbuf*
+getempty(Workbuf *b)
+{
+	if(b != nil) {
+		b->nw = nelem(b->w);
+		b->next = work.full;
+		work.full = b;
+	}
+	b = work.empty;
+	if(b != nil) {
+		work.empty = b->next;
+		return b;
+	}
+	
+	if(work.nchunk < sizeof *b) {
+		work.nchunk = 1<<20;
+		work.chunk = runtime·SysAlloc(work.nchunk);
+	}
+	b = (Workbuf*)work.chunk;
+	work.chunk += sizeof *b;
+	work.nchunk -= sizeof *b;
+	return b;
+}
+
+// Get a full work buffer off the work.full list, or return nil.
+static Workbuf*
+getfull(Workbuf *b)
+{
+	if(b != nil) {
+		b->nw = 0;
+		b->next = work.empty;
+		work.empty = b;
 	}
+	b = work.full;
+	if(b != nil)
+		work.full = b->next;
+	return b;
 }
 
+// Scanstack calls scanblock on each of gp's stack segments.
 static void
 scanstack(G *gp)
 {
@@ -119,46 +343,26 @@ scanstack(G *gp)
 	}
 }
 
+// Markfin calls scanblock on the blocks that have finalizers:
+// the things pointed at cannot be freed until the finalizers have run.
 static void
 markfin(void *v)
 {
 	uintptr size;
-	uint32 *refp;
 
 	size = 0;
-	refp = nil;
-	if(!runtime·mlookup(v, &v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
+	if(!runtime·mlookup(v, &v, &size, nil) || !runtime·blockspecial(v))
 		runtime·throw("mark - finalizer inconsistency");
-	
+
 	// do not mark the finalizer block itself.  just mark the things it points at.
 	scanblock(v, size);
 }
 
+// Mark 
 static void
 mark(void)
 {
 	G *gp;
-	uintptr blsize, nobj;
-
-	// Figure out how big an object stack we need.
-	// Get a new one if we need more than we have
-	// or we need significantly less than we have.
-	nobj = mstats.heap_objects;
-	if(nobj > ebl - bl || nobj < (ebl-bl)/4) {
-		if(bl != nil)
-			runtime·SysFree(bl, (byte*)ebl - (byte*)bl);
-		
-		// While we're allocated a new object stack,
-		// add 20% headroom and also round up to
-		// the nearest page boundary, since mmap
-		// will anyway.
-		nobj = nobj * 12/10;
-		blsize = nobj * sizeof *bl;
-		blsize = (blsize + 4095) & ~4095;
-		nobj = blsize / sizeof *bl;
-		bl = runtime·SysAlloc(blsize);
-		ebl = bl + nobj;
-	}
 
 	// mark data+bss.
 	// skip runtime·mheap itself, which has no interesting pointers
@@ -192,97 +396,85 @@ mark(void)
 	runtime·walkfintab(markfin);
 }
 
-// free RefNone, free & queue finalizers for RefNone|RefHasFinalizer, reset RefSome
+// Sweep frees or calls finalizers for blocks not marked in the mark phase.
+// It clears the mark bits in preparation for the next GC round.
 static void
-sweepspan(MSpan *s)
+sweep(void)
 {
-	int32 n, npages, size;
+	MSpan *s;
+	int32 cl, n, npages;
+	uintptr size;
 	byte *p;
-	uint32 ref, *gcrefp, *gcrefep;
 	MCache *c;
 	Finalizer *f;
 
-	p = (byte*)(s->start << PageShift);
-	if(s->sizeclass == 0) {
-		// Large block.
-		ref = s->gcref0;
-		switch(ref & ~(RefFlags^RefHasFinalizer)) {
-		case RefNone:
-			// Free large object.
-			mstats.alloc -= s->npages<<PageShift;
-			mstats.nfree++;
-			runtime·memclr(p, s->npages<<PageShift);
-			if(ref & RefProfiled)
-				runtime·MProf_Free(p, s->npages<<PageShift);
-			s->gcref0 = RefFree;
-			runtime·MHeap_Free(&runtime·mheap, s, 1);
-			break;
-		case RefNone|RefHasFinalizer:
-			f = runtime·getfinalizer(p, 1);
-			if(f == nil)
-				runtime·throw("finalizer inconsistency");
-			f->arg = p;
-			f->next = finq;
-			finq = f;
-			ref &= ~RefHasFinalizer;
-			// fall through
-		case RefSome:
-		case RefSome|RefHasFinalizer:
-			s->gcref0 = RefNone | (ref&RefFlags);
-			break;
+	for(s = runtime·mheap.allspans; s != nil; s = s->allnext) {
+		if(s->state != MSpanInUse)
+			continue;
+
+		p = (byte*)(s->start << PageShift);
+		cl = s->sizeclass;
+		if(cl == 0) {
+			size = s->npages<<PageShift;
+			n = 1;
+		} else {
+			// Chunk full of small blocks.
+			size = runtime·class_to_size[cl];
+			npages = runtime·class_to_allocnpages[cl];
+			n = (npages << PageShift) / size;
 		}
-		return;
-	}
+	
+		// sweep through n objects of given size starting at p.
+		for(; n > 0; n--, p += size) {
+			uintptr off, *bitp, shift, bits;
 
-	// Chunk full of small blocks.
-	runtime·MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
-	gcrefp = s->gcref;
-	gcrefep = s->gcref + n;
-	for(; gcrefp < gcrefep; gcrefp++, p += size) {
-		ref = *gcrefp;
-		if(ref < RefNone)	// RefFree or RefStack
-			continue;
-		switch(ref & ~(RefFlags^RefHasFinalizer)) {
-		case RefNone:
-			// Free small object.
-			if(ref & RefProfiled)
+			off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;
+			bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+			shift = off % wordsPerBitmapWord;
+			bits = *bitp>>shift;
+
+			if((bits & bitAllocated) == 0)
+				continue;
+
+			if((bits & bitMarked) != 0) {
+				*bitp &= ~(bitMarked<<shift);
+				continue;
+			}
+
+			if((bits & bitSpecial) != 0) {
+				// Special means it has a finalizer or is being profiled.
+				f = runtime·getfinalizer(p, 1);
+				if(f != nil) {
+					f->arg = p;
+					f->next = finq;
+					finq = f;
+					continue;
+				}
 				runtime·MProf_Free(p, size);
-			*gcrefp = RefFree;
-			c = m->mcache;
-			if(size > sizeof(uintptr))
-				((uintptr*)p)[1] = 1;	// mark as "needs to be zeroed"
+			}
+
+			// Mark freed; restore block boundary bit.
+			*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+
+			if(s->sizeclass == 0) {
+				// Free large span.
+				runtime·unmarkspan(p, 1<<PageShift);
+				*(uintptr*)p = 1;	// needs zeroing
+				runtime·MHeap_Free(&runtime·mheap, s, 1);
+			} else {
+				// Free small object.
+				c = m->mcache;
+				if(size > sizeof(uintptr))
+					((uintptr*)p)[1] = 1;	// mark as "needs to be zeroed"
+				mstats.by_size[s->sizeclass].nfree++;
+				runtime·MCache_Free(c, p, s->sizeclass, size);
+			}
 			mstats.alloc -= size;
 			mstats.nfree++;
-			mstats.by_size[s->sizeclass].nfree++;
-			runtime·MCache_Free(c, p, s->sizeclass, size);
-			break;
-		case RefNone|RefHasFinalizer:
-			f = runtime·getfinalizer(p, 1);
-			if(f == nil)
-				runtime·throw("finalizer inconsistency");
-			f->arg = p;
-			f->next = finq;
-			finq = f;
-			ref &= ~RefHasFinalizer;
-			// fall through
-		case RefSome:
-		case RefSome|RefHasFinalizer:
-			*gcrefp = RefNone | (ref&RefFlags);
-			break;
 		}
 	}
 }
 
-static void
-sweep(void)
-{
-	MSpan *s;
-
-	for(s = runtime·mheap.allspans; s != nil; s = s->allnext)
-		if(s->state == MSpanInUse)
-			sweepspan(s);
-}
-
 // Semaphore, not Lock, so that the goroutine
 // reschedules when there is contention rather
 // than spinning.
@@ -326,7 +518,8 @@ cachestats(void)
 void
 runtime·gc(int32 force)
 {
-	int64 t0, t1;
+	int64 t0, t1, t2, t3;
+	uint64 heap0, heap1, obj0, obj1;
 	byte *p;
 	Finalizer *fp;
 
@@ -349,23 +542,41 @@ runtime·gc(int32 force)
 			gcpercent = -1;
 		else
 			gcpercent = runtime·atoi(p);
+		
+		p = runtime·getenv("GOGCTRACE");
+		if(p != nil)
+			gctrace = runtime·atoi(p);
 	}
 	if(gcpercent < 0)
 		return;
 
 	runtime·semacquire(&gcsema);
+	if(!force && mstats.heap_alloc < mstats.next_gc) {
+		runtime·semrelease(&gcsema);
+		return;
+	}
+
 	t0 = runtime·nanotime();
+	nlookup = 0;
+	nsizelookup = 0;
+	naddrlookup = 0;
+
 	m->gcing = 1;
 	runtime·stoptheworld();
 	if(runtime·mheap.Lock.key != 0)
 		runtime·throw("runtime·mheap locked during gc");
-	if(force || mstats.heap_alloc >= mstats.next_gc) {
-		cachestats();
-		mark();
-		sweep();
-		stealcache();
-		mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
-	}
+
+	cachestats();
+	heap0 = mstats.heap_alloc;
+	obj0 = mstats.nmalloc - mstats.nfree;
+
+	mark();
+	t1 = runtime·nanotime();
+	sweep();
+	t2 = runtime·nanotime();
+	stealcache();
+
+	mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
 	m->gcing = 0;
 
 	m->locks++;	// disable gc during the mallocs in newproc
@@ -381,18 +592,34 @@ runtime·gc(int32 force)
 	}
 	m->locks--;
 
-	t1 = runtime·nanotime();
+	cachestats();
+	heap1 = mstats.heap_alloc;
+	obj1 = mstats.nmalloc - mstats.nfree;
+
+	t3 = runtime·nanotime();
+	mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t3 - t0;
+	mstats.pause_total_ns += t3 - t0;
 	mstats.numgc++;
-	mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t1 - t0;
-	mstats.pause_total_ns += t1 - t0;
 	if(mstats.debuggc)
-		runtime·printf("pause %D\n", t1-t0);
+		runtime·printf("pause %D\n", t3-t0);
+	
+	if(gctrace) {
+		runtime·printf("gc%d: %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D pointer lookups (%D size, %D addr)\n",
+			mstats.numgc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
+			heap0>>20, heap1>>20, obj0, obj1,
+			mstats.nmalloc, mstats.nfree,
+			nlookup, nsizelookup, naddrlookup);
+	}
+
 	runtime·semrelease(&gcsema);
 	runtime·starttheworld();
 	
 	// give the queued finalizers, if any, a chance to run
 	if(fp != nil)
 		runtime·gosched();
+	
+	if(gctrace > 1 && !force)
+		runtime·gc(1);
 }
 
 static void
@@ -430,3 +657,157 @@ runfinq(void)
 		runtime·gc(1);	// trigger another gc to clean up the finalized objects, if possible
 	}
 }
+
+// mark the block at v of size n as allocated.
+// If noptr is true, mark it as having no pointers.
+void
+runtime·markallocated(void *v, uintptr n, bool noptr)
+{
+	uintptr *b, bits, off, shift;
+
+	if(0)
+		runtime·printf("markallocated %p+%p\n", v, n);
+
+	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markallocated: bad pointer");
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+
+	bits = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
+	if(noptr)
+		bits |= bitNoPointers<<shift;
+	*b = bits;
+}
+
+// mark the block at v of size n as freed.
+void
+runtime·markfreed(void *v, uintptr n)
+{
+	uintptr *b, off, shift;
+
+	if(0)
+		runtime·printf("markallocated %p+%p\n", v, n);
+
+	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markallocated: bad pointer");
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+
+	*b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+}
+
+// check that the block at v of size n is marked freed.
+void
+runtime·checkfreed(void *v, uintptr n)
+{
+	uintptr *b, bits, off, shift;
+
+	if(!runtime·checking)
+		return;
+
+	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		return;	// not allocated, so okay
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+
+	bits = *b>>shift;
+	if((bits & bitAllocated) != 0) {
+		runtime·printf("checkfreed %p+%p: off=%p have=%p\n",
+			v, n, off, bits & bitMask);
+		runtime·throw("checkfreed: not freed");
+	}
+}
+
+// mark the span of memory at v as having n blocks of the given size.
+// if leftover is true, there is left over space at the end of the span.
+void
+runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
+{
+	uintptr *b, off, shift;
+	byte *p;
+
+	if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markspan: bad pointer");
+
+	p = v;
+	if(leftover)	// mark a boundary just past end of last block too
+		n++;
+	for(; n-- > 0; p += size) {
+		off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;  // word offset
+		b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		*b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+	}
+}
+
+// unmark the span of memory at v of length n bytes.
+void
+runtime·unmarkspan(void *v, uintptr n)
+{
+	uintptr *p, *b, off;
+
+	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markspan: bad pointer");
+
+	p = v;
+	off = p - (uintptr*)runtime·mheap.arena_start;  // word offset
+	if(off % wordsPerBitmapWord != 0)
+		runtime·throw("markspan: unaligned pointer");
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	n /= PtrSize;
+	if(n%wordsPerBitmapWord != 0)
+		runtime·throw("unmarkspan: unaligned length");
+	n /= wordsPerBitmapWord;
+	while(n-- > 0)
+		*b-- = 0;
+}
+
+bool
+runtime·blockspecial(void *v)
+{
+	uintptr *b, off, shift;
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+
+	return (*b & (bitSpecial<<shift)) != 0;
+}
+
+void
+runtime·setblockspecial(void *v)
+{
+	uintptr *b, off, shift;
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+
+	*b |= bitSpecial<<shift;
+}
+ 
+void
+runtime·MHeap_MapBits(MHeap *h)
+{
+	// Caller has added extra mappings to the arena.
+	// Add extra mappings of bitmap words as needed.
+	// We allocate extra bitmap pieces in chunks of bitmapChunk.
+	enum {
+		bitmapChunk = 8192
+	};
+	uintptr n;
+	
+	n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
+	n = (n+bitmapChunk-1) & ~(bitmapChunk-1);
+	if(h->bitmap_mapped >= n)
+		return;
+
+	runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped);
+	h->bitmap_mapped = n;
+}
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index 0c9ac0a..8061b7c 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -180,7 +180,9 @@ MHeap_Grow(MHeap *h, uintptr npage)
 	// Allocate a multiple of 64kB (16 pages).
 	npage = (npage+15)&~15;
 	ask = npage<<PageShift;
-	if(ask < HeapAllocChunk)
+	if(ask > h->arena_end - h->arena_used)
+		return false;
+	if(ask < HeapAllocChunk && HeapAllocChunk <= h->arena_end - h->arena_used)
 		ask = HeapAllocChunk;
 
 	v = runtime·MHeap_SysAlloc(h, ask);
@@ -194,11 +196,6 @@ MHeap_Grow(MHeap *h, uintptr npage)
 	}
 	mstats.heap_sys += ask;
 
-	if((byte*)v < h->arena_start || h->arena_start == nil)
-		h->arena_start = v;
-	if((byte*)v+ask > h->arena_end)
-		h->arena_end = (byte*)v+ask;
-
 	// Create a fake "in use" span and free it, so that the
 	// right coalescing happens.
 	s = runtime·FixAlloc_Alloc(&h->spanalloc);
@@ -370,10 +367,14 @@ runtime·MSpanList_IsEmpty(MSpan *list)
 void
 runtime·MSpanList_Insert(MSpan *list, MSpan *span)
 {
-	if(span->next != nil || span->prev != nil)
+	if(span->next != nil || span->prev != nil) {
+		runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
 		runtime·throw("MSpanList_Insert");
+	}
 	span->next = list->next;
 	span->prev = list;
 	span->next->prev = span;
 	span->prev->next = span;
 }
+
+
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index 3ed5f74..91d1bbe 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -25,9 +25,9 @@ case "$GOARCH" in
 		echo '#define	m(r)	4(r)'
 		;;
 	plan9)
-		echo '#define	get_tls(r)'
-		echo '#define	g(r)	0xdfffefc0'
-		echo '#define	m(r)	0xdfffefc4'
+		echo '#define	get_tls(r)	MOVL _tos(SB), r '
+		echo '#define	g(r)	-8(r)'
+		echo '#define	m(r)	-4(r)'
 		;;
 	linux)
 		# On Linux systems, what we call 0(GS) and 4(GS) for g and m
@@ -84,6 +84,7 @@ esac
 echo
 
 awk '
+{ gsub(/\r/, ""); }
 /^aggr G$/ { aggr="g" }
 /^aggr M$/ { aggr = "m" }
 /^aggr Gobuf$/ { aggr = "gobuf" }
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
index 9790d3f..56afa18 100644
--- a/src/pkg/runtime/mkversion.c
+++ b/src/pkg/runtime/mkversion.c
@@ -5,13 +5,11 @@ char *template =
 	"// generated by mkversion.c; do not edit.\n"
 	"package runtime\n"
 	"const defaultGoroot = \"%s\"\n"
-	"const theVersion = \"%s\"\n"
-	"const theGoarch = \"%s\"\n"
-	"const theGoos = \"%s\"\n";
+	"const theVersion = \"%s\"\n";
 
 void
 main(void)
 {
-	print(template, getgoroot(), getgoversion(), getgoarch(), getgoos());
+	print(template, getgoroot(), getgoversion());
 	exits(0);
 }
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index f4581e9..aae3d18 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -65,7 +65,7 @@ stkbucket(uintptr *stk, int32 nstk)
 		   runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
 			return b;
 
-	b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
+	b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
 	bucketmem += sizeof *b + nstk*sizeof stk[0];
 	runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
 	b->hash = h;
@@ -132,7 +132,7 @@ setaddrbucket(uintptr addr, Bucket *b)
 		if(ah->addr == (addr>>20))
 			goto found;
 
-	ah = runtime·mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
+	ah = runtime·mallocgc(sizeof *ah, FlagNoProfiling, 0, 1);
 	addrmem += sizeof *ah;
 	ah->next = addrhash[h];
 	ah->addr = addr>>20;
@@ -140,7 +140,7 @@ setaddrbucket(uintptr addr, Bucket *b)
 
 found:
 	if((e = addrfree) == nil) {
-		e = runtime·mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
+		e = runtime·mallocgc(64*sizeof *e, FlagNoProfiling, 0, 0);
 		addrmem += 64*sizeof *e;
 		for(i=0; i+1<64; i++)
 			e[i].next = &e[i+1];
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index ec85eb3..770ef38 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -57,7 +57,7 @@ runtime·SizeToClass(int32 size)
 void
 runtime·InitSizes(void)
 {
-	int32 align, sizeclass, size, osize, nextsize, n;
+	int32 align, sizeclass, size, nextsize, n;
 	uint32 i;
 	uintptr allocsize, npages;
 
@@ -81,8 +81,7 @@ runtime·InitSizes(void)
 		// the leftover is less than 1/8 of the total,
 		// so wasted space is at most 12.5%.
 		allocsize = PageSize;
-		osize = size + RefcountOverhead;
-		while(allocsize%osize > (allocsize/8))
+		while(allocsize%size > allocsize/8)
 			allocsize += PageSize;
 		npages = allocsize >> PageShift;
 
@@ -93,7 +92,7 @@ runtime·InitSizes(void)
 		// different sizes.
 		if(sizeclass > 1
 		&& npages == runtime·class_to_allocnpages[sizeclass-1]
-		&& allocsize/osize == allocsize/(runtime·class_to_size[sizeclass-1]+RefcountOverhead)) {
+		&& allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
 			runtime·class_to_size[sizeclass-1] = size;
 			continue;
 		}
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h
index 5df7576..58fd9d9 100644
--- a/src/pkg/runtime/plan9/386/defs.h
+++ b/src/pkg/runtime/plan9/386/defs.h
@@ -1 +1,2 @@
 // nothing to see here
+#define tos_pid 48
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
index 867b894..f760b78 100644
--- a/src/pkg/runtime/plan9/386/sys.s
+++ b/src/pkg/runtime/plan9/386/sys.s
@@ -58,9 +58,10 @@ TEXT runtime·rfork(SB),7,$0
 	MOVL	BX, m(AX)
 
 	// Initialize AX from _tos->pid
-	MOVL	0xdfffeff8, AX
+	MOVL	_tos(SB), AX
+	MOVL	tos_pid(AX), AX
 	MOVL	AX, m_procid(BX)	// save pid as m->procid
-
+	
 	CALL	runtime·stackcheck(SB)	// smashes AX, CX
 	
 	MOVL	0(DX), DX	// paranoia; check they are not nil
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
index 651e672..b840de9 100644
--- a/src/pkg/runtime/plan9/mem.c
+++ b/src/pkg/runtime/plan9/mem.c
@@ -10,40 +10,47 @@ static byte *bloc = { end };
 
 enum
 {
-	Round = 7
+	Round = 4095
 };
 
 void*
-runtime·SysAlloc(uintptr ask)
+runtime·SysAlloc(uintptr nbytes)
 {
 	uintptr bl;
 	
 	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
 	bl = ((uintptr)bloc + Round) & ~Round;
-	if(runtime·brk_((void*)(bl + ask)) < 0)
+	if(runtime·brk_((void*)(bl + nbytes)) < 0)
 		return (void*)-1;
-	bloc = (byte*)bl + ask;
+	bloc = (byte*)bl + nbytes;
 	return (void*)bl;
 }
 
 void
-runtime·SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr nbytes)
 {
 	// from tiny/mem.c
 	// Push pointer back if this is a free
 	// of the most recent SysAlloc.
-	n += (n + Round) & ~Round;
-	if(bloc == (byte*)v+n)
-		bloc -= n;	
+	nbytes += (nbytes + Round) & ~Round;
+	if(bloc == (byte*)v+nbytes)
+		bloc -= nbytes;	
 }
 
 void
-runtime·SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr nbytes)
 {
-	USED(v, n);
+	USED(v, nbytes);
 }
 
 void
-runtime·SysMemInit(void)
+runtime·SysMap(void *v, uintptr nbytes)
 {
+	USED(v, nbytes);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr nbytes)
+{
+	return runtime·SysAlloc(nbytes);
 }
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 998cbc7..26c1f13 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -752,8 +752,8 @@ runtime·newstack(void)
 		free = framesize;
 	}
 
-//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n",
-//frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
+//runtime·printf("newstack framesize=%d argsize=%d morepc=%p moreargp=%p gobuf=%p, %p top=%p old=%p\n",
+//framesize, argsize, m->morepc, m->moreargp, m->morebuf.pc, m->morebuf.sp, top, g1->stackbase);
 
 	top->stackbase = g1->stackbase;
 	top->stackguard = g1->stackguard;
@@ -761,7 +761,7 @@ runtime·newstack(void)
 	top->argp = m->moreargp;
 	top->argsize = argsize;
 	top->free = free;
-	
+
 	// copy flag from panic
 	top->panic = g1->ispanic;
 	g1->ispanic = false;
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 284b1e4..e3a20d4 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -528,14 +528,22 @@ void
 runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
 {
 	Func *f;
+	uintptr pc;
 
-	if(runtime·callers(1+skip, &retpc, 1) == 0 || (f = runtime·findfunc(retpc-1)) == nil) {
+	if(runtime·callers(1+skip, &retpc, 1) == 0) {
 		retfile = runtime·emptystring;
 		retline = 0;
 		retbool = false;
+	} else if((f = runtime·findfunc(retpc)) == nil) {
+		retfile = runtime·emptystring;
+		retline = 0;
+		retbool = true;  // have retpc at least
 	} else {
 		retfile = f->src;
-		retline = runtime·funcline(f, retpc-1);
+		pc = retpc;
+		if(pc > f->entry)
+			pc--;
+		retline = runtime·funcline(f, pc);
 		retbool = true;
 	}
 	FLUSH(&retfile);
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 2c19f85..cea07e4 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -419,7 +419,7 @@ void	runtime·signalstack(byte*, int32);
 G*	runtime·malg(int32);
 void	runtime·minit(void);
 Func*	runtime·findfunc(uintptr);
-int32	runtime·funcline(Func*, uint64);
+int32	runtime·funcline(Func*, uintptr);
 void*	runtime·stackalloc(uint32);
 void	runtime·stackfree(void*, uintptr);
 MCache*	runtime·allocmcache(void);
@@ -443,7 +443,7 @@ void	runtime·breakpoint(void);
 void	runtime·gosched(void);
 void	runtime·goexit(void);
 void	runtime·runcgo(void (*fn)(void*), void*);
-uintptr	runtime·runcgocallback(G*, void*, void (*fn)());
+void	runtime·runcgocallback(G*, void*, void (*fn)());
 void	runtime·entersyscall(void);
 void	runtime·exitsyscall(void);
 void	runtime·startcgocallback(G*);
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 0510754..1fee923 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -41,7 +41,7 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
 	ret->cap = cap;
 
 	if((t->elem->kind&KindNoPointers))
-		ret->array = runtime·mallocgc(size, RefNoPointers, 1, 1);
+		ret->array = runtime·mallocgc(size, FlagNoPointers, 1, 1);
 	else
 		ret->array = runtime·mal(size);
 }
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index 916559e..b72aa93 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -225,7 +225,7 @@ func slicebytetostring(b Slice) (s String) {
 }
 
 func stringtoslicebyte(s String) (b Slice) {
-	b.array = runtime·mallocgc(s.len, RefNoPointers, 1, 1);
+	b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 1);
 	b.len = s.len;
 	b.cap = s.len;
 	runtime·mcpy(b.array, s.str, s.len);
@@ -268,7 +268,7 @@ func stringtosliceint(s String) (b Slice) {
 		n++;
 	}
 
-	b.array = runtime·mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
+	b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 1);
 	b.len = n;
 	b.cap = n;
 	p = s.str;
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index b2cccd3..6f0eea0 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -258,28 +258,49 @@ splitpcln(void)
 	ef = func + nfunc;
 	pc = func[0].entry;	// text base
 	f->pcln.array = p;
-	f->pc0 = pc - pcquant;
+	f->pc0 = pc;
 	line = 0;
-	for(; p < ep; p++) {
-		if(f < ef && pc > (f+1)->entry) {
+	for(;;) {
+		while(p < ep && *p > 128)
+			pc += pcquant * (*p++ - 128);
+		// runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
+		if(*p == 0) {
+			if(p+5 > ep)
+				break;
+			// 4 byte add to line
+			line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
+			p += 5;
+		} else if(*p <= 64)
+			line += *p++;
+		else
+			line -= *p++ - 64;
+		
+		// pc, line now match.
+		// Because the state machine begins at pc==entry and line==0,
+		// it can happen - just at the beginning! - that the update may
+		// have updated line but left pc alone, to tell us the true line
+		// number for pc==entry.  In that case, update f->ln0.
+		// Having the correct initial line number is important for choosing
+		// the correct file in dosrcline above.
+		if(f == func && pc == f->pc0) {
+			f->pcln.array = p;
+			f->pc0 = pc + pcquant;
+			f->ln0 = line;
+		}
+
+		if(f < ef && pc >= (f+1)->entry) {
 			f->pcln.len = p - f->pcln.array;
 			f->pcln.cap = f->pcln.len;
 			f++;
 			f->pcln.array = p;
-			f->pc0 = pc;
+			// pc0 and ln0 are the starting values for
+			// the loop over f->pcln, so pc must be 
+			// adjusted by the same pcquant update
+			// that we're going to do as we continue our loop.
+			f->pc0 = pc + pcquant;
 			f->ln0 = line;
 		}
-		if(*p == 0) {
-			// 4 byte add to line
-			line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
-			p += 4;
-		} else if(*p <= 64) {
-			line += *p;
-		} else if(*p <= 128) {
-			line -= *p - 64;
-		} else {
-			pc += pcquant*(*p - 129);
-		}
+
 		pc += pcquant;
 	}
 	if(f < ef) {
@@ -293,13 +314,17 @@ splitpcln(void)
 // (Source file is f->src.)
 // NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
 int32
-runtime·funcline(Func *f, uint64 targetpc)
+runtime·funcline(Func *f, uintptr targetpc)
 {
 	byte *p, *ep;
 	uintptr pc;
 	int32 line;
 	int32 pcquant;
 	
+	enum {
+		debug = 0
+	};
+	
 	switch(thechar) {
 	case '5':
 		pcquant = 4;
@@ -313,17 +338,41 @@ runtime·funcline(Func *f, uint64 targetpc)
 	ep = p + f->pcln.len;
 	pc = f->pc0;
 	line = f->ln0;
-	for(; p < ep && pc <= targetpc; p++) {
+	if(debug && !runtime·panicking)
+		runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n",
+			pc, targetpc, line, p, (int32)f->pcln.len);
+	for(;;) {
+		// Table is a sequence of updates.
+
+		// Each update says first how to adjust the pc,
+		// in possibly multiple instructions...
+		while(p < ep && *p > 128)
+			pc += pcquant * (*p++ - 128);
+
+		if(debug && !runtime·panicking)
+			runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
+		
+		// If the pc has advanced too far or we're out of data,
+		// stop and the last known line number.
+		if(pc > targetpc || p >= ep)
+			break;
+
+		// ... and then how to adjust the line number,
+		// in a single instruction.
 		if(*p == 0) {
+			if(p+5 > ep)
+				break;
 			line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
-			p += 4;
-		} else if(*p <= 64) {
-			line += *p;
-		} else if(*p <= 128) {
-			line -= *p - 64;
-		} else {
-			pc += pcquant*(*p - 129);
-		}
+			p += 5;
+		} else if(*p <= 64)
+			line += *p++;
+		else
+			line -= *p++ - 64;
+		// Now pc, line pair is consistent.
+		if(debug && !runtime·panicking)
+			runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line);
+
+		// PC increments implicitly on each iteration.
 		pc += pcquant;
 	}
 	return line;
diff --git a/src/pkg/runtime/windows/386/defs.h b/src/pkg/runtime/windows/386/defs.h
index a2a8821..49fc195 100644
--- a/src/pkg/runtime/windows/386/defs.h
+++ b/src/pkg/runtime/windows/386/defs.h
@@ -10,6 +10,9 @@ enum {
 	PROT_EXEC = 0x4,
 	MAP_ANON = 0x1,
 	MAP_PRIVATE = 0x2,
+	SIGINT = 0x2,
+	CTRL_C_EVENT = 0,
+	CTRL_BREAK_EVENT = 0x1,
 	EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
 	EXCEPTION_BREAKPOINT = 0x80000003,
 	EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c
index 69178cd..9036369 100644
--- a/src/pkg/runtime/windows/386/signal.c
+++ b/src/pkg/runtime/windows/386/signal.c
@@ -27,12 +27,7 @@ runtime·dumpregs(Context *r)
 void
 runtime·initsig(int32)
 {
-}
-
-String
-runtime·signame(int32)
-{
-	return runtime·emptystring;
+	runtime·siginit();
 }
 
 uint32
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s
index d1a8a49..bca48fe 100644
--- a/src/pkg/runtime/windows/386/sys.s
+++ b/src/pkg/runtime/windows/386/sys.s
@@ -99,6 +99,45 @@ TEXT runtime·sigtramp1(SB),0,$16-28
 sigdone:
 	RET
 
+// Windows runs the ctrl handler in a new thread.
+TEXT runtime·ctrlhandler(SB),7,$0
+	PUSHL	BP
+	MOVL	SP, BP
+	PUSHL	BX
+	PUSHL	SI
+	PUSHL	DI
+	PUSHL	0x2c(FS)
+	MOVL	SP, BX
+
+	// setup dummy m, g
+	SUBL	$(m_sehframe+4), SP	// at least space for m_sehframe
+	LEAL	m_tls(SP), CX
+	MOVL	CX, 0x2c(FS)
+	MOVL	SP, m(CX)
+	MOVL	SP, DX
+	SUBL	$8, SP			// space for g_stack{guard,base}
+	MOVL	SP, g(CX)
+	MOVL	SP, m_g0(DX)
+	LEAL	-4096(SP), CX
+	MOVL	CX, g_stackguard(SP)
+	MOVL	BX, g_stackbase(SP)
+
+	PUSHL	8(BP)
+	CALL	runtime·ctrlhandler1(SB)
+	POPL	CX
+
+	get_tls(CX)
+	MOVL	g(CX), CX
+	MOVL	g_stackbase(CX), SP
+	POPL	0x2c(FS)
+	POPL	DI
+	POPL	SI
+	POPL	BX
+	POPL	BP
+	MOVL	0(SP), CX
+	ADDL	$8, SP
+	JMP	CX
+
 // Called from dynamic function created by ../thread.c compilecallback,
 // running on Windows stack (not Go stack).
 // BX, BP, SI, DI registers and DF flag are preserved
@@ -107,7 +146,11 @@ sigdone:
 // DX = total size of arguments
 //
 TEXT runtime·callbackasm+0(SB),7,$0
+	// preserve whatever's at the memory location that
+	// the callback will use to store the return value
 	LEAL	8(SP), CX
+	PUSHL	0(CX)(DX*1)
+	ADDL	$4, DX			// extend argsize by size of return value
 
 	// save registers as required for windows callback
 	PUSHL	0(FS)
@@ -129,7 +172,7 @@ TEXT runtime·callbackasm+0(SB),7,$0
 	CALL	runtime·cgocallback(SB)
 
 	// restore registers as required for windows callback
-	POPL	CX
+	POPL	AX
 	POPL	CX
 	POPL	DX
 	POPL	BX
@@ -139,6 +182,8 @@ TEXT runtime·callbackasm+0(SB),7,$0
 	POPL	0(FS)
 	CLD
 
+	MOVL	-4(CX)(DX*1), AX
+	POPL	-4(CX)(DX*1)
 	RET
 
 // void tstart(M *newm);
diff --git a/src/pkg/runtime/windows/defs.c b/src/pkg/runtime/windows/defs.c
index 5aac03c..3b28249 100644
--- a/src/pkg/runtime/windows/defs.c
+++ b/src/pkg/runtime/windows/defs.c
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+#include <signal.h>
 #include <stdarg.h>
 #include <windef.h>
 #include <winbase.h>
+#include <wincon.h>
 
 enum {
 	$PROT_NONE = 0,
@@ -15,6 +17,10 @@ enum {
 	$MAP_ANON = 1,
 	$MAP_PRIVATE = 2,
 
+	$SIGINT = SIGINT,
+	$CTRL_C_EVENT = CTRL_C_EVENT,
+	$CTRL_BREAK_EVENT = CTRL_BREAK_EVENT,
+
 	$EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
 	$EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
 	$EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c
index 19d11ce..54d77da 100644
--- a/src/pkg/runtime/windows/mem.c
+++ b/src/pkg/runtime/windows/mem.c
@@ -48,7 +48,14 @@ runtime·SysFree(void *v, uintptr n)
 void*
 runtime·SysReserve(void *v, uintptr n)
 {
-	return runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_RESERVE, 0);
+	// v is just a hint.
+	// First try at v.
+	v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+	if(v != nil)
+		return v;
+	
+	// Next let the kernel choose the address.
+	return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_RESERVE, PAGE_EXECUTE_READWRITE);
 }
 
 void
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
index 391eace..77881e8 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/windows/os.h
@@ -20,6 +20,7 @@ uint32 runtime·tstart_stdcall(M *newm);
 
 uint32 runtime·issigpanic(uint32);
 void runtime·sigpanic(void);
+uint32 runtime·ctrlhandler(uint32 type);
 
 // Windows dll function to go callback entry.
 byte *runtime·compilecallback(Eface fn, bool cleanstack);
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index 278a5da..aedd242 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -18,6 +18,7 @@
 #pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
 #pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
 #pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
+#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
 #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
 #pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
 #pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
@@ -33,6 +34,7 @@ extern void *runtime·GetStdHandle;
 extern void *runtime·LoadLibraryEx;
 extern void *runtime·QueryPerformanceCounter;
 extern void *runtime·QueryPerformanceFrequency;
+extern void *runtime·SetConsoleCtrlHandler;
 extern void *runtime·SetEvent;
 extern void *runtime·WaitForSingleObject;
 extern void *runtime·WriteFile;
@@ -43,6 +45,7 @@ void
 runtime·osinit(void)
 {
 	runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
+	runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, 1);
 }
 
 void
@@ -161,6 +164,7 @@ runtime·destroylock(Lock *l)
 void
 runtime·noteclear(Note *n)
 {
+	n->lock.key = 0;	// memset(n, 0, sizeof *n)
 	eventlock(&n->lock);
 }
 
@@ -180,11 +184,17 @@ runtime·notesleep(Note *n)
 void
 runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
 {
+	void *thandle;
+
 	USED(stk);
 	USED(g);	// assuming g = m->g0
 	USED(fn);	// assuming fn = mstart
 
-	runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
+	thandle = runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
+	if(thandle == 0) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
+		runtime·throw("runtime.newosproc");
+	}
 }
 
 // Called to initialize a new m (including the bootstrap m).
@@ -279,6 +289,41 @@ runtime·sigpanic(void)
 	runtime·throw("fault");
 }
 
+String
+runtime·signame(int32 sig)
+{
+	int8 *s;
+
+	switch(sig) {
+	case SIGINT:
+		s = "SIGINT: interrupt";
+		break;
+	default:
+		return runtime·emptystring;
+	}
+	return runtime·gostringnocopy((byte*)s);
+}
+
+uint32
+runtime·ctrlhandler1(uint32 type)
+{
+	int32 s;
+
+	switch(type) {
+	case CTRL_C_EVENT:
+	case CTRL_BREAK_EVENT:
+		s = SIGINT;
+		break;
+	default:
+		return 0;
+	}
+
+	if(runtime·sigsend(s))
+		return 1;
+	runtime·exit(2);	// SIGINT, SIGTERM, etc
+	return 0;
+}
+
 // Call back from windows dll into go.
 byte *
 runtime·compilecallback(Eface fn, bool cleanstack)
diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go
index 4ec3cdb..b6049c5 100644
--- a/src/pkg/strconv/ftoa.go
+++ b/src/pkg/strconv/ftoa.go
@@ -64,7 +64,7 @@ func FtoaN(f float64, fmt byte, prec int, n int) string {
 }
 
 func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
-	neg := bits>>flt.expbits>>flt.mantbits != 0
+	neg := bits>>(flt.expbits+flt.mantbits) != 0
 	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
 	mant := bits & (uint64(1)<<flt.mantbits - 1)
 
diff --git a/src/pkg/strconv/ftoa_test.go b/src/pkg/strconv/ftoa_test.go
index bc32760..6d361a1 100644
--- a/src/pkg/strconv/ftoa_test.go
+++ b/src/pkg/strconv/ftoa_test.go
@@ -121,9 +121,8 @@ var ftoatests = []ftoaTest{
 
 	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
 	{2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
-	// TODO: uncomment after fixing issue 1463.
 	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
-	// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+	{2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
 }
 
 func TestFtoa(t *testing.T) {
diff --git a/src/pkg/sync/Makefile b/src/pkg/sync/Makefile
index f843795..fd8e5d9 100644
--- a/src/pkg/sync/Makefile
+++ b/src/pkg/sync/Makefile
@@ -9,6 +9,7 @@ GOFILES=\
 	mutex.go\
 	once.go \
 	rwmutex.go\
+	waitgroup.go\
 
 # 386-specific object files
 OFILES_386=\
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index c4d82af..2a1270b 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -3,10 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // The sync package provides basic synchronization primitives
-// such as mutual exclusion locks.  Other than the Once type,
-// most are intended for use by low-level library routines.
-// Higher-level synchronization is better done via channels
-// and communication.
+// such as mutual exclusion locks.  Other than the Once and
+// WaitGroup types, most are intended for use by low-level
+// library routines.  Higher-level synchronization is better
+// done via channels and communication.
 package sync
 
 import "runtime"
@@ -53,9 +53,14 @@ func (m *Mutex) Lock() {
 // It is allowed for one goroutine to lock a Mutex and then
 // arrange for another goroutine to unlock it.
 func (m *Mutex) Unlock() {
-	if xadd(&m.key, -1) == 0 {
+	switch v := xadd(&m.key, -1); {
+	case v == 0:
 		// changed from 1 to 0; no contention
 		return
+	case int32(v) == -1:
+		// changed from 0 to -1: wasn't locked
+		// (or there are 4 billion goroutines waiting)
+		panic("sync: unlock of unlocked mutex")
 	}
 	runtime.Semrelease(&m.sema)
 }
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index d0e048e..f5c20ca 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -89,3 +89,16 @@ func BenchmarkContendedMutex(b *testing.B) {
 	<-c
 	<-c
 }
+
+func TestMutexPanic(t *testing.T) {
+	defer func() {
+		if recover() == nil {
+			t.Fatalf("unlock of unlocked mutex did not panic")
+		}
+	}()
+
+	var mu Mutex
+	mu.Lock()
+	mu.Unlock()
+	mu.Unlock()
+}
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
index 06fd0b0..25696ac 100644
--- a/src/pkg/sync/rwmutex.go
+++ b/src/pkg/sync/rwmutex.go
@@ -64,12 +64,10 @@ func (rw *RWMutex) Lock() {
 	rw.r.Unlock()
 }
 
-// Unlock unlocks rw for writing.
-// It is a run-time error if rw is not locked for writing
-// on entry to Unlock.
+// Unlock unlocks rw for writing.  It is a run-time error if rw is
+// not locked for writing on entry to Unlock.
 //
-// Like for Mutexes,
-// a locked RWMutex is not associated with a particular goroutine.
-// It is allowed for one goroutine to RLock (Lock) an RWMutex and then
+// As with Mutexes, a locked RWMutex is not associated with a particular
+// goroutine.  One goroutine may RLock (Lock) an RWMutex and then
 // arrange for another goroutine to RUnlock (Unlock) it.
 func (rw *RWMutex) Unlock() { rw.w.Unlock() }
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
new file mode 100644
index 0000000..68e1d50
--- /dev/null
+++ b/src/pkg/sync/waitgroup.go
@@ -0,0 +1,86 @@
+// 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 sync
+
+import "runtime"
+
+// A WaitGroup waits for a collection of goroutines to finish.
+// The main goroutine calls Add to set the number of
+// goroutines to wait for.  Then each of the goroutines
+// runs and calls Done when finished.  At the same time,
+// Wait can be used to block until all goroutines have finished.
+//
+// For example:
+//
+//   for i := 0; i < n; i++ {
+//       if !condition(i) {
+//           continue
+//       }
+//       wg.Add(1)
+//       go func() {
+//           // Do something.
+//           wg.Done()
+//       }
+//   }
+//   wg.Wait()
+// 
+type WaitGroup struct {
+	m       Mutex
+	counter int
+	waiters int
+	sema    *uint32
+}
+
+// WaitGroup creates a new semaphore each time the old semaphore
+// is released. This is to avoid the following race:
+//
+// G1: Add(1)
+// G1: go G2()
+// G1: Wait() // Context switch after Unlock() and before Semacquire().
+// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
+// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
+// G3: Add(1) // Makes counter == 1, waiters == 0.
+// G3: go G4()
+// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
+
+// Add adds delta, which may be negative, to the WaitGroup counter.
+// If the counter becomes zero, all goroutines blocked on Wait() are released.
+func (wg *WaitGroup) Add(delta int) {
+	wg.m.Lock()
+	if delta < -wg.counter {
+		wg.m.Unlock()
+		panic("sync: negative WaitGroup count")
+	}
+	wg.counter += delta
+	if wg.counter == 0 && wg.waiters > 0 {
+		for i := 0; i < wg.waiters; i++ {
+			runtime.Semrelease(wg.sema)
+		}
+		wg.waiters = 0
+		wg.sema = nil
+	}
+	wg.m.Unlock()
+}
+
+// Done decrements the WaitGroup counter.
+func (wg *WaitGroup) Done() {
+	wg.Add(-1)
+}
+
+// Wait blocks until the WaitGroup counter is zero.
+func (wg *WaitGroup) Wait() {
+	wg.m.Lock()
+	if wg.counter == 0 {
+		wg.m.Unlock()
+		return
+	}
+	wg.waiters++
+	if wg.sema == nil {
+		wg.sema = new(uint32)
+	}
+	s := wg.sema
+	wg.m.Unlock()
+	runtime.Semacquire(s)
+}
diff --git a/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
new file mode 100644
index 0000000..fe35732
--- /dev/null
+++ b/src/pkg/sync/waitgroup_test.go
@@ -0,0 +1,60 @@
+// 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 sync_test
+
+import (
+	. "sync"
+	"testing"
+)
+
+func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
+	n := 16
+	wg1.Add(n)
+	wg2.Add(n)
+	exited := make(chan bool, n)
+	for i := 0; i != n; i++ {
+		go func(i int) {
+			wg1.Done()
+			wg2.Wait()
+			exited <- true
+		}(i)
+	}
+	wg1.Wait()
+	for i := 0; i != n; i++ {
+		select {
+		case <-exited:
+			t.Fatal("WaitGroup released group too soon")
+		default:
+		}
+		wg2.Done()
+	}
+	for i := 0; i != n; i++ {
+		<-exited // Will block if barrier fails to unlock someone.
+	}
+}
+
+func TestWaitGroup(t *testing.T) {
+	wg1 := &WaitGroup{}
+	wg2 := &WaitGroup{}
+
+	// Run the same test a few times to ensure barrier is in a proper state.
+	for i := 0; i != 8; i++ {
+		testWaitGroup(t, wg1, wg2)
+	}
+}
+
+func TestWaitGroupMisuse(t *testing.T) {
+	defer func() {
+		err := recover()
+		if err != "sync: negative WaitGroup count" {
+			t.Fatalf("Unexpected panic: %#v", err)
+		}
+	}()
+	wg := &WaitGroup{}
+	wg.Add(1)
+	wg.Done()
+	wg.Done()
+	t.Fatal("Should panic")
+}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index c7f7893..04c0669 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -310,3 +310,9 @@ func Exec(argv0 string, argv []string, envv []string) (err int) {
 		uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])))
 	return int(err1)
 }
+
+// StartProcess wraps ForkExec for package os.
+func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) {
+	pid, err = forkExec(argv0, argv, envv, false, dir, fd)
+	return pid, 0, err
+}
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
index c3ed3ba..7256c3a 100644
--- a/src/pkg/syscall/exec_windows.go
+++ b/src/pkg/syscall/exec_windows.go
@@ -107,7 +107,7 @@ func escapeAddQuotes(s string) string {
 
 
 func CloseOnExec(fd int) {
-	return
+	SetHandleInformation(int32(fd), HANDLE_FLAG_INHERIT, 0)
 }
 
 func SetNonblock(fd int, nonblocking bool) (errno int) {
@@ -117,13 +117,9 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
 
 // TODO(kardia): Add trace
 //The command and arguments are passed via the Command line parameter.
-func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
-	if traceme == true {
-		return 0, EWINDOWS
-	}
-
+func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) {
 	if len(fd) > 3 {
-		return 0, EWINDOWS
+		return 0, 0, EWINDOWS
 	}
 
 	//CreateProcess will throw an error if the dir is not set to a valid dir
@@ -144,22 +140,31 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
 	startupInfo.StdOutput = 0
 	startupInfo.StdErr = 0
 
+	// Acquire the fork lock so that no other threads
+	// create new fds that are not yet close-on-exec
+	// before we fork.
+	ForkLock.Lock()
+	defer ForkLock.Unlock()
+
 	var currentProc, _ = GetCurrentProcess()
 	if len(fd) > 0 && fd[0] > 0 {
-		if ok, err := DuplicateHandle(currentProc, int32(fd[0]), currentProc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
-			return 0, err
+		err := DuplicateHandle(currentProc, int32(fd[0]), currentProc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS)
+		if err != 0 {
+			return 0, 0, err
 		}
 		defer CloseHandle(int32(startupInfo.StdInput))
 	}
 	if len(fd) > 1 && fd[1] > 0 {
-		if ok, err := DuplicateHandle(currentProc, int32(fd[1]), currentProc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
-			return 0, err
+		err := DuplicateHandle(currentProc, int32(fd[1]), currentProc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS)
+		if err != 0 {
+			return 0, 0, err
 		}
 		defer CloseHandle(int32(startupInfo.StdOutput))
 	}
 	if len(fd) > 2 && fd[2] > 0 {
-		if ok, err := DuplicateHandle(currentProc, int32(fd[2]), currentProc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS); !ok {
-			return 0, err
+		err := DuplicateHandle(currentProc, int32(fd[2]), currentProc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS)
+		if err != 0 {
+			return 0, 0, err
 		}
 		defer CloseHandle(int32(startupInfo.StdErr))
 	}
@@ -168,7 +173,7 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
 	}
 	// argv0 must not be longer then 256 chars
 	// but the entire cmd line can have up to 32k chars (msdn)
-	ok, err := CreateProcess(
+	err = CreateProcess(
 		nil,
 		StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv[1:], " ", escapeAddQuotes)),
 		nil,  //ptr to struct lpProcessAttributes
@@ -180,23 +185,14 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri
 		startupInfo,
 		processInfo)
 
-	if ok {
+	if err != 0 {
 		pid = int(processInfo.ProcessId)
-		CloseHandle(processInfo.Process)
+		handle = int(processInfo.Process)
 		CloseHandle(processInfo.Thread)
 	}
 	return
 }
 
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
-	return forkExec(argv0, argv, envv, false, dir, fd)
-}
-
-// PtraceForkExec is like ForkExec, but starts the child in a traced state.
-func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
-	return forkExec(argv0, argv, envv, true, dir, fd)
-}
-
 // Ordinary exec.
 func Exec(argv0 string, argv []string, envv []string) (err int) {
 	return EWINDOWS
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 41acf95..a13c0e9 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -38,23 +38,28 @@ includes_Darwin='
 #define _DARWIN_C_SOURCE
 #define KERNEL
 #define _DARWIN_USE_64_BIT_INODE
-#include <sys/cdefs.h>
-#include <sys/wait.h>
+#include <sys/types.h>
 #include <sys/event.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
 #include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_mroute.h>
 '
 
 includes_FreeBSD='
-#include <sys/wait.h>
+#include <sys/types.h>
 #include <sys/event.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
-#include <net/route.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
 #include <net/if.h>
+#include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/ip_mroute.h>
@@ -105,16 +110,22 @@ done
 		$2 ~ /^(MAP_FAILED)$/ {next}
 
 		$2 !~ /^ETH_/ &&
+		$2 !~ /^EPROC_/ &&
+		$2 !~ /^EQUIV_/ &&
+		$2 !~ /^EXPR_/ &&
 		$2 ~ /^E[A-Z0-9_]+$/ ||
 		$2 ~ /^SIG[^_]/ ||
 		$2 ~ /^IN_/ ||
-		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|IFF)_/ ||
+		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|IFF|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
 		$2 == "SOMAXCONN" ||
 		$2 == "NAME_MAX" ||
 		$2 == "IFNAMSIZ" ||
+		$2 == "CTL_NET" ||
+		$2 == "CTL_MAXNAME" ||
 		$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
 		$2 ~ /^(O|F|FD|NAME|S|PTRACE)_/ ||
-		$2 ~ /^SIO/ ||
+		$2 ~ /^SIOC/ ||
+		$2 !~ "WMESGLEN" &&
 		$2 ~ /^W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", $2, $2)}
 		$2 ~ /^__WCOREFLAG$/ {next}
 		$2 ~ /^__W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", substr($2,3), $2)}
diff --git a/src/pkg/syscall/mksyscall.sh b/src/pkg/syscall/mksyscall.sh
index 79d19d0..0f80980 100755
--- a/src/pkg/syscall/mksyscall.sh
+++ b/src/pkg/syscall/mksyscall.sh
@@ -98,14 +98,11 @@ while(<>) {
 		} elsif($type =~ /^\[\](.*)/) {
 			# Convert slice into pointer, length.
 			# Have to be careful not to take address of &a[0] if len == 0:
-			# pass nil in that case.
+			# pass dummy pointer in that case.
+			# Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
 			$text .= "\tvar _p$n unsafe.Pointer\n";
 			$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
-			if($nacl) {
-				# NaCl rejects zero length write with nil pointer,
-				# so use non-nil pointer.
-				$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero[0])\n\t}";
-			}
+			$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
 			$text .= "\n";
 			push @args, "uintptr(_p$n)", "uintptr(len($name))";
 			$n++;
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
index 1647d69..9697537 100644
--- a/src/pkg/syscall/syscall.go
+++ b/src/pkg/syscall/syscall.go
@@ -24,3 +24,7 @@ func StringByteSlice(s string) []byte {
 // StringBytePtr returns a pointer to a NUL-terminated array of bytes
 // containing the text of s.
 func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
+
+// Single-word zero for use when we need a valid pointer to 0 bytes.
+// See mksyscall.sh.
+var _zero uintptr
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 3c4ac51..1f5b2ba 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -223,8 +223,40 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
 	return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
 }
 
+func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, int) {
+	if sa.Index == 0 {
+		return 0, 0, EINVAL
+	}
+	sa.raw.Len = sa.Len
+	sa.raw.Family = AF_LINK
+	sa.raw.Index = sa.Index
+	sa.raw.Type = sa.Type
+	sa.raw.Nlen = sa.Nlen
+	sa.raw.Alen = sa.Alen
+	sa.raw.Slen = sa.Slen
+	for i := 0; i < len(sa.raw.Data); i++ {
+		sa.raw.Data[i] = sa.Data[i]
+	}
+	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, 0
+}
+
 func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
 	switch rsa.Addr.Family {
+	case AF_LINK:
+		pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
+		sa := new(SockaddrDatalink)
+		sa.Len = pp.Len
+		sa.Family = pp.Family
+		sa.Index = pp.Index
+		sa.Type = pp.Type
+		sa.Nlen = pp.Nlen
+		sa.Alen = pp.Alen
+		sa.Slen = pp.Slen
+		for i := 0; i < len(sa.Data); i++ {
+			sa.Data[i] = pp.Data[i]
+		}
+		return sa, 0
+
 	case AF_UNIX:
 		pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
 		if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
@@ -343,6 +375,10 @@ func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
 	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
 }
 
+func SetsockoptIpMreq(fd, level, opt int, mreq *IpMreq) (errno int) {
+	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
 func SetsockoptString(fd, level, opt int, s string) (errno int) {
 	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), len(s))
 }
@@ -395,7 +431,6 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno
 
 // Translate "kern.hostname" to []_C_int{0,1,2,3}.
 func nametomib(name string) (mib []_C_int, errno int) {
-	const CTL_MAXNAME = 12
 	const siz = uintptr(unsafe.Sizeof(mib[0]))
 
 	// NOTE(rsc): It seems strange to set the buffer to have
@@ -467,6 +502,27 @@ func SysctlUint32(name string) (value uint32, errno int) {
 	return *(*uint32)(unsafe.Pointer(&buf[0])), 0
 }
 
+func SysctlNetRoute(fourth, fifth, sixth int) (value []byte, errno int) {
+	mib := []_C_int{CTL_NET, AF_ROUTE, 0, _C_int(fourth), _C_int(fifth), _C_int(sixth)}
+
+	// Find size.
+	n := uintptr(0)
+	if errno = sysctl(mib, nil, &n, nil, 0); errno != 0 {
+		return nil, errno
+	}
+	if n == 0 {
+		return nil, 0
+	}
+
+	// Read into buffer of that size.
+	b := make([]byte, n)
+	if errno = sysctl(mib, &b[0], &n, nil, 0); errno != 0 {
+		return nil, errno
+	}
+
+	return b[0:n], 0
+}
+
 //sys	utimes(path string, timeval *[2]Timeval) (errno int)
 func Utimes(path string, tv []Timeval) (errno int) {
 	if len(tv) != 2 {
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index ab83af5..552c9c1 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -14,6 +14,18 @@ package syscall
 
 const OS = "darwin"
 
+type SockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [12]int8
+	raw    RawSockaddrDatalink
+}
+
 /*
  * Wrapped
  */
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index ee947be..ed31066 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -14,6 +14,18 @@ package syscall
 
 const OS = "freebsd"
 
+type SockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [46]int8
+	raw    RawSockaddrDatalink
+}
+
 /*
  * Exposed directly
  */
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index d20c035..30ad896 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -428,6 +428,10 @@ func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
 	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
 }
 
+func SetsockoptIpMreq(fd, level, opt int, mreq *IpMreq) (errno int) {
+	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
 func SetsockoptString(fd, level, opt int, s string) (errno int) {
 	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), len(s))
 }
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 762ed53..0cd89d4 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -106,57 +106,59 @@ func NewCallback(fn interface{}) uintptr
 
 //sys	GetLastError() (lasterrno int)
 //sys	LoadLibrary(libname string) (handle uint32, errno int) = LoadLibraryW
-//sys	FreeLibrary(handle uint32) (ok bool, errno int)
+//sys	FreeLibrary(handle uint32) (errno int)
 //sys	GetProcAddress(module uint32, procname string) (proc uint32, errno int)
 //sys	GetVersion() (ver uint32, errno int)
 //sys	FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) = FormatMessageW
 //sys	ExitProcess(exitcode uint32)
-//sys	CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) [failretval==-1] = CreateFileW
-//sys	ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int)
-//sys	WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int)
+//sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) [failretval==-1] = CreateFileW
+//sys	ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
+//sys	WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
 //sys	SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
-//sys	CloseHandle(handle int32) (ok bool, errno int)
+//sys	CloseHandle(handle int32) (errno int)
 //sys	GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval==-1]
 //sys	FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) [failretval==-1] = FindFirstFileW
-//sys	FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) = FindNextFileW
-//sys	FindClose(handle int32) (ok bool, errno int)
-//sys	GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok bool, errno int)
+//sys	FindNextFile(handle int32, data *Win32finddata) (errno int) = FindNextFileW
+//sys	FindClose(handle int32) (errno int)
+//sys	GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (errno int)
 //sys	GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) = GetCurrentDirectoryW
-//sys	SetCurrentDirectory(path *uint16) (ok bool, errno int) = SetCurrentDirectoryW
-//sys	CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) = CreateDirectoryW
-//sys	RemoveDirectory(path *uint16) (ok bool, errno int) = RemoveDirectoryW
-//sys	DeleteFile(path *uint16) (ok bool, errno int) = DeleteFileW
-//sys	MoveFile(from *uint16, to *uint16) (ok bool, errno int) = MoveFileW
-//sys	GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) = GetComputerNameW
-//sys	SetEndOfFile(handle int32) (ok bool, errno int)
+//sys	SetCurrentDirectory(path *uint16) (errno int) = SetCurrentDirectoryW
+//sys	CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) = CreateDirectoryW
+//sys	RemoveDirectory(path *uint16) (errno int) = RemoveDirectoryW
+//sys	DeleteFile(path *uint16) (errno int) = DeleteFileW
+//sys	MoveFile(from *uint16, to *uint16) (errno int) = MoveFileW
+//sys	GetComputerName(buf *uint16, n *uint32) (errno int) = GetComputerNameW
+//sys	SetEndOfFile(handle int32) (errno int)
 //sys	GetSystemTimeAsFileTime(time *Filetime)
 //sys	sleep(msec uint32) = Sleep
 //sys	GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff]
 //sys	CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int)
-//sys	GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int)
-//sys	CancelIo(s uint32) (ok bool, errno int)
-//sys	CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation)  (ok bool, errno int) = CreateProcessW
-//sys	GetStartupInfo(startupInfo *StartupInfo)  (ok bool, errno int) = GetStartupInfoW
+//sys	GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
+//sys	CancelIo(s uint32) (errno int)
+//sys	CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW
+//sys	OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int)
+//sys	GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int)
+//sys	GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW
 //sys	GetCurrentProcess() (pseudoHandle int32, errno int)
-//sys	DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int)
+//sys	DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
 //sys	WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
 //sys	GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
-//sys	CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32) (ok bool, errno int)
+//sys	CreatePipe(readhandle *uint32, writehandle *uint32, sa *SecurityAttributes, size uint32) (errno int)
 //sys	GetFileType(filehandle uint32) (n uint32, errno int)
-//sys	CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) = advapi32.CryptAcquireContextW
-//sys	CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) = advapi32.CryptReleaseContext
-//sys	CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) = advapi32.CryptGenRandom
-//sys OpenProcess(da uint32,b int, pid uint32) (handle uint32, errno int)
-//sys GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int)
+//sys	CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) = advapi32.CryptAcquireContextW
+//sys	CryptReleaseContext(provhandle uint32, flags uint32) (errno int) = advapi32.CryptReleaseContext
+//sys	CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (errno int) = advapi32.CryptGenRandom
 //sys	GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
-//sys	FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) = kernel32.FreeEnvironmentStringsW
+//sys	FreeEnvironmentStrings(envs *uint16) (errno int) = kernel32.FreeEnvironmentStringsW
 //sys	GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
-//sys	SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) = kernel32.SetEnvironmentVariableW
-//sys	SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (ok bool, errno int)
+//sys	SetEnvironmentVariable(name *uint16, value *uint16) (errno int) = kernel32.SetEnvironmentVariableW
+//sys	SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int)
 //sys	GetFileAttributes(name *uint16) (attrs uint32, errno int) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
 //sys	GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
 //sys	CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) [failretval==nil] = shell32.CommandLineToArgvW
 //sys	LocalFree(hmem uint32) (handle uint32, errno int) [failretval!=0]
+//sys	SetHandleInformation(handle int32, mask uint32, flags uint32) (errno int)
+//sys	FlushFileBuffers(handle int32) (errno int)
 
 // syscall interface implementation for other packages
 
@@ -181,6 +183,13 @@ func Errstr(errno int) string {
 
 func Exit(code int) { ExitProcess(uint32(code)) }
 
+func makeInheritSa() *SecurityAttributes {
+	var sa SecurityAttributes
+	sa.Length = uint32(unsafe.Sizeof(sa))
+	sa.InheritHandle = 1
+	return &sa
+}
+
 func Open(path string, mode int, perm uint32) (fd int, errno int) {
 	if len(path) == 0 {
 		return -1, ERROR_FILE_NOT_FOUND
@@ -202,6 +211,10 @@ func Open(path string, mode int, perm uint32) (fd int, errno int) {
 		access |= FILE_APPEND_DATA
 	}
 	sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
+	var sa *SecurityAttributes
+	if mode&O_CLOEXEC == 0 {
+		sa = makeInheritSa()
+	}
 	var createmode uint32
 	switch {
 	case mode&O_CREAT != 0:
@@ -215,13 +228,14 @@ func Open(path string, mode int, perm uint32) (fd int, errno int) {
 	default:
 		createmode = OPEN_EXISTING
 	}
-	h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, nil, createmode, FILE_ATTRIBUTE_NORMAL, 0)
+	h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
 	return int(h), int(e)
 }
 
 func Read(fd int, p []byte) (n int, errno int) {
 	var done uint32
-	if ok, e := ReadFile(int32(fd), p, &done, nil); !ok {
+	e := ReadFile(int32(fd), p, &done, nil)
+	if e != 0 {
 		if e == ERROR_BROKEN_PIPE {
 			// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
 			return 0, 0
@@ -245,7 +259,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	o.OffsetHigh = uint32(offset >> 32)
 	o.Offset = uint32(offset)
 	var done uint32
-	if ok, e := ReadFile(int32(fd), p, &done, &o); !ok {
+	e = ReadFile(int32(fd), p, &done, &o)
+	if e != 0 {
 		return 0, e
 	}
 	return int(done), 0
@@ -253,7 +268,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 
 func Write(fd int, p []byte) (n int, errno int) {
 	var done uint32
-	if ok, e := WriteFile(int32(fd), p, &done, nil); !ok {
+	e := WriteFile(int32(fd), p, &done, nil)
+	if e != 0 {
 		return 0, e
 	}
 	return int(done), 0
@@ -269,7 +285,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	o.OffsetHigh = uint32(offset >> 32)
 	o.Offset = uint32(offset)
 	var done uint32
-	if ok, e := WriteFile(int32(fd), p, &done, &o); !ok {
+	e = WriteFile(int32(fd), p, &done, &o)
+	if e != 0 {
 		return 0, e
 	}
 	return int(done), 0
@@ -300,10 +317,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
 }
 
 func Close(fd int) (errno int) {
-	if ok, e := CloseHandle(int32(fd)); !ok {
-		return e
-	}
-	return 0
+	return CloseHandle(int32(fd))
 }
 
 var (
@@ -362,46 +376,32 @@ func Getwd() (wd string, errno int) {
 }
 
 func Chdir(path string) (errno int) {
-	if ok, e := SetCurrentDirectory(&StringToUTF16(path)[0]); !ok {
-		return e
-	}
-	return 0
+	return SetCurrentDirectory(&StringToUTF16(path)[0])
 }
 
 func Mkdir(path string, mode uint32) (errno int) {
-	if ok, e := CreateDirectory(&StringToUTF16(path)[0], nil); !ok {
-		return e
-	}
-	return 0
+	return CreateDirectory(&StringToUTF16(path)[0], nil)
 }
 
 func Rmdir(path string) (errno int) {
-	if ok, e := RemoveDirectory(&StringToUTF16(path)[0]); !ok {
-		return e
-	}
-	return 0
+	return RemoveDirectory(&StringToUTF16(path)[0])
 }
 
 func Unlink(path string) (errno int) {
-	if ok, e := DeleteFile(&StringToUTF16(path)[0]); !ok {
-		return e
-	}
-	return 0
+	return DeleteFile(&StringToUTF16(path)[0])
 }
 
 func Rename(oldpath, newpath string) (errno int) {
 	from := &StringToUTF16(oldpath)[0]
 	to := &StringToUTF16(newpath)[0]
-	if ok, e := MoveFile(from, to); !ok {
-		return e
-	}
-	return 0
+	return MoveFile(from, to)
 }
 
 func ComputerName() (name string, errno int) {
 	var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
 	b := make([]uint16, n)
-	if ok, e := GetComputerName(&b[0], &n); !ok {
+	e := GetComputerName(&b[0], &n)
+	if e != 0 {
 		return "", e
 	}
 	return string(utf16.Decode(b[0:n])), 0
@@ -413,10 +413,12 @@ func Ftruncate(fd int, length int64) (errno int) {
 		return e
 	}
 	defer Seek(fd, curoffset, 0)
-	if _, e := Seek(fd, length, 0); e != 0 {
+	_, e = Seek(fd, length, 0)
+	if e != 0 {
 		return e
 	}
-	if _, e := SetEndOfFile(int32(fd)); e != 0 {
+	e = SetEndOfFile(int32(fd))
+	if e != 0 {
 		return e
 	}
 	return 0
@@ -439,8 +441,9 @@ func Pipe(p []int) (errno int) {
 		return EINVAL
 	}
 	var r, w uint32
-	if ok, errno := CreatePipe(&r, &w, nil, 0); !ok {
-		return errno
+	e := CreatePipe(&r, &w, makeInheritSa(), 0)
+	if e != 0 {
+		return e
 	}
 	p[0] = int(r)
 	p[1] = int(w)
@@ -460,10 +463,11 @@ func Utimes(path string, tv []Timeval) (errno int) {
 	defer Close(int(h))
 	a := NsecToFiletime(tv[0].Nanoseconds())
 	w := NsecToFiletime(tv[1].Nanoseconds())
-	if ok, e := SetFileTime(h, nil, &a, &w); !ok {
-		return e
-	}
-	return 0
+	return SetFileTime(h, nil, &a, &w)
+}
+
+func Fsync(fd int) (errno int) {
+	return FlushFileBuffers(int32(fd))
 }
 
 // net api calls
@@ -479,7 +483,7 @@ func Utimes(path string, tv []Timeval) (errno int) {
 //sys	listen(s int32, backlog int32) (errno int) [failretval==-1] = wsock32.listen
 //sys	shutdown(s int32, how int32) (errno int) [failretval==-1] = wsock32.shutdown
 //sys	Closesocket(s int32) (errno int) [failretval==-1] = wsock32.closesocket
-//sys	AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, errno int) = wsock32.AcceptEx
+//sys	AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) = wsock32.AcceptEx
 //sys	GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = wsock32.GetAcceptExSockaddrs
 //sys	WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
 //sys	WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
@@ -637,7 +641,7 @@ func AcceptIOCP(iocpfd, fd int, o *Overlapped) (attrs *byte, errno int) {
 	attrs = (*byte)(unsafe.Pointer(&rsa[0]))
 	alen := uint32(unsafe.Sizeof(rsa[0]))
 	var done uint32
-	_, errno = AcceptEx(uint32(iocpfd), uint32(fd), attrs, 0, alen, alen, &done, o)
+	errno = AcceptEx(uint32(iocpfd), uint32(fd), attrs, 0, alen, alen, &done, o)
 	return
 }
 
@@ -660,6 +664,32 @@ func WSASendto(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
 	return
 }
 
+// Invented structures to support what package os expects.
+type Rusage struct{}
+
+type WaitStatus struct {
+	Status   uint32
+	ExitCode uint32
+}
+
+func (w WaitStatus) Exited() bool { return true }
+
+func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
+
+func (w WaitStatus) Signal() int { return -1 }
+
+func (w WaitStatus) CoreDump() bool { return false }
+
+func (w WaitStatus) Stopped() bool { return false }
+
+func (w WaitStatus) Continued() bool { return false }
+
+func (w WaitStatus) StopSignal() int { return -1 }
+
+func (w WaitStatus) Signaled() bool { return true }
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
 // TODO(brainman): fix all needed for net
 
 func Accept(fd int) (nfd int, sa Sockaddr, errno int)                        { return 0, nil, EWINDOWS }
@@ -694,9 +724,6 @@ func Chown(path string, uid int, gid int) (errno int)     { return EWINDOWS }
 func Lchown(path string, uid int, gid int) (errno int)    { return EWINDOWS }
 func Fchown(fd int, uid int, gid int) (errno int)         { return EWINDOWS }
 
-// TODO(brainman): use FlushFileBuffers Windows api to implement Fsync.
-func Fsync(fd int) (errno int) { return EWINDOWS }
-
 func Getuid() (uid int)                  { return -1 }
 func Geteuid() (euid int)                { return -1 }
 func Getgid() (gid int)                  { return -1 }
@@ -723,67 +750,3 @@ const (
 	SYS_EXIT
 	SYS_READ
 )
-
-type Rusage struct {
-	Utime    Timeval
-	Stime    Timeval
-	Maxrss   int32
-	Ixrss    int32
-	Idrss    int32
-	Isrss    int32
-	Minflt   int32
-	Majflt   int32
-	Nswap    int32
-	Inblock  int32
-	Oublock  int32
-	Msgsnd   int32
-	Msgrcv   int32
-	Nsignals int32
-	Nvcsw    int32
-	Nivcsw   int32
-}
-
-type WaitStatus struct {
-	Status   uint32
-	ExitCode uint32
-}
-
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
-	const da = STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | SYNCHRONIZE
-	handle, errno := OpenProcess(da, 0, uint32(pid))
-	if errno != 0 {
-		return 0, errno
-	}
-	defer CloseHandle(int32(handle))
-	e, errno := WaitForSingleObject(int32(handle), INFINITE)
-	var c uint32
-	if ok, errno := GetExitCodeProcess(handle, &c); !ok {
-		return 0, errno
-	}
-	*wstatus = WaitStatus{e, c}
-	return pid, 0
-}
-
-
-func (w WaitStatus) Exited() bool { return w.Status == WAIT_OBJECT_0 }
-
-func (w WaitStatus) ExitStatus() int {
-	if w.Status == WAIT_OBJECT_0 {
-		return int(w.ExitCode)
-	}
-	return -1
-}
-
-func (WaitStatus) Signal() int { return -1 }
-
-func (WaitStatus) CoreDump() bool { return false }
-
-func (WaitStatus) Stopped() bool { return false }
-
-func (WaitStatus) Continued() bool { return false }
-
-func (WaitStatus) StopSignal() int { return -1 }
-
-func (w WaitStatus) Signaled() bool { return w.Status == WAIT_OBJECT_0 }
-
-func (WaitStatus) TrapCause() int { return -1 }
diff --git a/src/pkg/syscall/types_darwin.c b/src/pkg/syscall/types_darwin.c
index d7f7a74..4096bcf 100644
--- a/src/pkg/syscall/types_darwin.c
+++ b/src/pkg/syscall/types_darwin.c
@@ -11,12 +11,10 @@ Input to godefs.  See also mkerrors.sh and mkall.sh
 #define _DARWIN_USE_64_BIT_INODE
 #include <dirent.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
 #include <mach/mach.h>
 #include <mach/message.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <signal.h>
-#include <stdio.h>
 #include <sys/event.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
@@ -25,12 +23,18 @@ Input to godefs.  See also mkerrors.sh and mkall.sh
 #include <sys/resource.h>
 #include <sys/select.h>
 #include <sys/signal.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
 #include <sys/wait.h>
-#include <unistd.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
 
 // Machine characteristics; for internal use.
 
@@ -89,6 +93,7 @@ union sockaddr_all {
 	struct sockaddr_in s2;	// these pad it out
 	struct sockaddr_in6 s3;
 	struct sockaddr_un s4;
+	struct sockaddr_dl s5;
 };
 
 struct sockaddr_any {
@@ -99,11 +104,13 @@ struct sockaddr_any {
 typedef struct sockaddr_in $RawSockaddrInet4;
 typedef struct sockaddr_in6 $RawSockaddrInet6;
 typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_dl $RawSockaddrDatalink;
 typedef struct sockaddr $RawSockaddr;
 typedef struct sockaddr_any $RawSockaddrAny;
 typedef socklen_t $_Socklen;
 typedef struct linger $Linger;
 typedef struct iovec $Iovec;
+typedef struct ip_mreq $IpMreq;
 typedef struct msghdr $Msghdr;
 typedef struct cmsghdr $Cmsghdr;
 
@@ -112,7 +119,9 @@ enum {
 	$SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
 	$SizeofSockaddrAny = sizeof(struct sockaddr_any),
 	$SizeofSockaddrUnix = sizeof(struct sockaddr_un),
+	$SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
 	$SizeofLinger = sizeof(struct linger),
+	$SizeofIpMreq = sizeof(struct ip_mreq),
 	$SizeofMsghdr = sizeof(struct msghdr),
 	$SizeofCmsghdr = sizeof(struct cmsghdr),
 };
@@ -132,3 +141,19 @@ typedef struct kevent $Kevent_t;
 // Select
 
 typedef fd_set $FdSet;
+
+// Routing and interface messages
+
+enum {
+	$SizeofIfMsghdr = sizeof(struct if_msghdr),
+	$SizeofIfData = sizeof(struct if_data),
+	$SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
+	$SizeofRtMsghdr = sizeof(struct rt_msghdr),
+	$SizeofRtMetrics = sizeof(struct rt_metrics),
+};
+
+typedef struct if_msghdr $IfMsghdr;
+typedef struct if_data $IfData;
+typedef struct ifa_msghdr $IfaMsghdr;
+typedef struct rt_msghdr $RtMsghdr;
+typedef struct rt_metrics $RtMetrics;
diff --git a/src/pkg/syscall/types_freebsd.c b/src/pkg/syscall/types_freebsd.c
index 13bec9f..6fc8141 100644
--- a/src/pkg/syscall/types_freebsd.c
+++ b/src/pkg/syscall/types_freebsd.c
@@ -7,14 +7,11 @@ Input to godefs.  See also mkerrors.sh and mkall.sh
  */
 
 #define KERNEL
-#include <sys/cdefs.h>
 #include <dirent.h>
 #include <fcntl.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
 #include <signal.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <sys/event.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
@@ -26,9 +23,14 @@ Input to godefs.  See also mkerrors.sh and mkall.sh
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
 #include <sys/un.h>
 #include <sys/wait.h>
-#include <unistd.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
 
 // Machine characteristics; for internal use.
 
@@ -101,6 +103,7 @@ union sockaddr_all {
 	struct sockaddr_in s2;	// these pad it out
 	struct sockaddr_in6 s3;
 	struct sockaddr_un s4;
+	struct sockaddr_dl s5;
 };
 
 struct sockaddr_any {
@@ -111,11 +114,13 @@ struct sockaddr_any {
 typedef struct sockaddr_in $RawSockaddrInet4;
 typedef struct sockaddr_in6 $RawSockaddrInet6;
 typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_dl $RawSockaddrDatalink;
 typedef struct sockaddr $RawSockaddr;
 typedef struct sockaddr_any $RawSockaddrAny;
 typedef socklen_t $_Socklen;
 typedef struct linger $Linger;
 typedef struct iovec $Iovec;
+typedef struct ip_mreq $IpMreq;
 typedef struct msghdr $Msghdr;
 typedef struct cmsghdr $Cmsghdr;
 
@@ -124,7 +129,9 @@ enum {
 	$SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
 	$SizeofSockaddrAny = sizeof(struct sockaddr_any),
 	$SizeofSockaddrUnix = sizeof(struct sockaddr_un),
+	$SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
 	$SizeofLinger = sizeof(struct linger),
+	$SizeofIpMreq = sizeof(struct ip_mreq),
 	$SizeofMsghdr = sizeof(struct msghdr),
 	$SizeofCmsghdr = sizeof(struct cmsghdr),
 };
@@ -144,3 +151,19 @@ typedef struct kevent $Kevent_t;
 // Select
 
 typedef fd_set $FdSet;
+
+// Routing and interface messages
+
+enum {
+	$SizeofIfMsghdr = sizeof(struct if_msghdr),
+	$SizeofIfData = sizeof(struct if_data),
+	$SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
+	$SizeofRtMsghdr = sizeof(struct rt_msghdr),
+	$SizeofRtMetrics = sizeof(struct rt_metrics),
+};
+
+typedef struct if_msghdr $IfMsghdr;
+typedef struct if_data $IfData;
+typedef struct ifa_msghdr $IfaMsghdr;
+typedef struct rt_msghdr $RtMsghdr;
+typedef struct rt_metrics $RtMetrics;
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
index 4752e31..ec94c84 100644
--- a/src/pkg/syscall/types_linux.c
+++ b/src/pkg/syscall/types_linux.c
@@ -109,6 +109,7 @@ typedef struct sockaddr_any $RawSockaddrAny;
 typedef socklen_t $_Socklen;
 typedef struct linger $Linger;
 typedef struct iovec $Iovec;
+typedef struct ip_mreq $IpMreq;
 typedef struct msghdr $Msghdr;
 typedef struct cmsghdr $Cmsghdr;
 typedef struct ucred $Ucred;
@@ -120,6 +121,7 @@ enum {
 	$SizeofSockaddrUnix = sizeof(struct sockaddr_un),
 	$SizeofSockaddrLinklayer = sizeof(struct sockaddr_ll),
 	$SizeofLinger = sizeof(struct linger),
+	$SizeofIpMreq = sizeof(struct ip_mreq),	
 	$SizeofMsghdr = sizeof(struct msghdr),
 	$SizeofCmsghdr = sizeof(struct cmsghdr),
 	$SizeofUcred = sizeof(struct ucred),
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index 8f5f69b..52b9862 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -45,6 +45,8 @@ const (
 	AF_SYSTEM                   = 0x20
 	AF_UNIX                     = 0x1
 	AF_UNSPEC                   = 0
+	CTL_MAXNAME                 = 0xc
+	CTL_NET                     = 0x4
 	E2BIG                       = 0x7
 	EACCES                      = 0xd
 	EADDRINUSE                  = 0x30
@@ -475,6 +477,15 @@ const (
 	MSG_TRUNC                   = 0x10
 	MSG_WAITALL                 = 0x40
 	MSG_WAITSTREAM              = 0x200
+	NAME_MAX                    = 0xff
+	NET_RT_DUMP                 = 0x1
+	NET_RT_DUMP2                = 0x7
+	NET_RT_FLAGS                = 0x2
+	NET_RT_IFLIST               = 0x3
+	NET_RT_IFLIST2              = 0x6
+	NET_RT_MAXID                = 0x8
+	NET_RT_STAT                 = 0x4
+	NET_RT_TRASH                = 0x5
 	O_ACCMODE                   = 0x3
 	O_ALERT                     = 0x20000000
 	O_APPEND                    = 0x8
@@ -498,6 +509,77 @@ const (
 	O_SYNC                      = 0x80
 	O_TRUNC                     = 0x400
 	O_WRONLY                    = 0x1
+	RTAX_AUTHOR                 = 0x6
+	RTAX_BRD                    = 0x7
+	RTAX_DST                    = 0
+	RTAX_GATEWAY                = 0x1
+	RTAX_GENMASK                = 0x3
+	RTAX_IFA                    = 0x5
+	RTAX_IFP                    = 0x4
+	RTAX_MAX                    = 0x8
+	RTAX_NETMASK                = 0x2
+	RTA_AUTHOR                  = 0x40
+	RTA_BRD                     = 0x80
+	RTA_DST                     = 0x1
+	RTA_GATEWAY                 = 0x2
+	RTA_GENMASK                 = 0x8
+	RTA_IFA                     = 0x20
+	RTA_IFP                     = 0x10
+	RTA_NETMASK                 = 0x4
+	RTF_BLACKHOLE               = 0x1000
+	RTF_BROADCAST               = 0x400000
+	RTF_CLONING                 = 0x100
+	RTF_CONDEMNED               = 0x2000000
+	RTF_DELCLONE                = 0x80
+	RTF_DONE                    = 0x40
+	RTF_DYNAMIC                 = 0x10
+	RTF_GATEWAY                 = 0x2
+	RTF_HOST                    = 0x4
+	RTF_IFREF                   = 0x4000000
+	RTF_IFSCOPE                 = 0x1000000
+	RTF_LLINFO                  = 0x400
+	RTF_LOCAL                   = 0x200000
+	RTF_MODIFIED                = 0x20
+	RTF_MULTICAST               = 0x800000
+	RTF_PINNED                  = 0x100000
+	RTF_PRCLONING               = 0x10000
+	RTF_PROTO1                  = 0x8000
+	RTF_PROTO2                  = 0x4000
+	RTF_PROTO3                  = 0x40000
+	RTF_REJECT                  = 0x8
+	RTF_STATIC                  = 0x800
+	RTF_UP                      = 0x1
+	RTF_WASCLONED               = 0x20000
+	RTF_XRESOLVE                = 0x200
+	RTM_ADD                     = 0x1
+	RTM_CHANGE                  = 0x3
+	RTM_DELADDR                 = 0xd
+	RTM_DELETE                  = 0x2
+	RTM_DELMADDR                = 0x10
+	RTM_GET                     = 0x4
+	RTM_GET2                    = 0x14
+	RTM_IFINFO                  = 0xe
+	RTM_IFINFO2                 = 0x12
+	RTM_LOCK                    = 0x8
+	RTM_LOSING                  = 0x5
+	RTM_MISS                    = 0x7
+	RTM_NEWADDR                 = 0xc
+	RTM_NEWMADDR                = 0xf
+	RTM_NEWMADDR2               = 0x13
+	RTM_OLDADD                  = 0x9
+	RTM_OLDDEL                  = 0xa
+	RTM_REDIRECT                = 0x6
+	RTM_RESOLVE                 = 0xb
+	RTM_RTTUNIT                 = 0xf4240
+	RTM_VERSION                 = 0x5
+	RTV_EXPIRE                  = 0x4
+	RTV_HOPCOUNT                = 0x2
+	RTV_MTU                     = 0x1
+	RTV_RPIPE                   = 0x8
+	RTV_RTT                     = 0x40
+	RTV_RTTVAR                  = 0x80
+	RTV_SPIPE                   = 0x10
+	RTV_SSTHRESH                = 0x20
 	SCM_CREDS                   = 0x3
 	SCM_RIGHTS                  = 0x1
 	SCM_TIMESTAMP               = 0x2
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index 75174a0..4e7a174 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -45,6 +45,8 @@ const (
 	AF_SYSTEM                   = 0x20
 	AF_UNIX                     = 0x1
 	AF_UNSPEC                   = 0
+	CTL_MAXNAME                 = 0xc
+	CTL_NET                     = 0x4
 	E2BIG                       = 0x7
 	EACCES                      = 0xd
 	EADDRINUSE                  = 0x30
@@ -475,6 +477,15 @@ const (
 	MSG_TRUNC                   = 0x10
 	MSG_WAITALL                 = 0x40
 	MSG_WAITSTREAM              = 0x200
+	NAME_MAX                    = 0xff
+	NET_RT_DUMP                 = 0x1
+	NET_RT_DUMP2                = 0x7
+	NET_RT_FLAGS                = 0x2
+	NET_RT_IFLIST               = 0x3
+	NET_RT_IFLIST2              = 0x6
+	NET_RT_MAXID                = 0x8
+	NET_RT_STAT                 = 0x4
+	NET_RT_TRASH                = 0x5
 	O_ACCMODE                   = 0x3
 	O_ALERT                     = 0x20000000
 	O_APPEND                    = 0x8
@@ -498,6 +509,77 @@ const (
 	O_SYNC                      = 0x80
 	O_TRUNC                     = 0x400
 	O_WRONLY                    = 0x1
+	RTAX_AUTHOR                 = 0x6
+	RTAX_BRD                    = 0x7
+	RTAX_DST                    = 0
+	RTAX_GATEWAY                = 0x1
+	RTAX_GENMASK                = 0x3
+	RTAX_IFA                    = 0x5
+	RTAX_IFP                    = 0x4
+	RTAX_MAX                    = 0x8
+	RTAX_NETMASK                = 0x2
+	RTA_AUTHOR                  = 0x40
+	RTA_BRD                     = 0x80
+	RTA_DST                     = 0x1
+	RTA_GATEWAY                 = 0x2
+	RTA_GENMASK                 = 0x8
+	RTA_IFA                     = 0x20
+	RTA_IFP                     = 0x10
+	RTA_NETMASK                 = 0x4
+	RTF_BLACKHOLE               = 0x1000
+	RTF_BROADCAST               = 0x400000
+	RTF_CLONING                 = 0x100
+	RTF_CONDEMNED               = 0x2000000
+	RTF_DELCLONE                = 0x80
+	RTF_DONE                    = 0x40
+	RTF_DYNAMIC                 = 0x10
+	RTF_GATEWAY                 = 0x2
+	RTF_HOST                    = 0x4
+	RTF_IFREF                   = 0x4000000
+	RTF_IFSCOPE                 = 0x1000000
+	RTF_LLINFO                  = 0x400
+	RTF_LOCAL                   = 0x200000
+	RTF_MODIFIED                = 0x20
+	RTF_MULTICAST               = 0x800000
+	RTF_PINNED                  = 0x100000
+	RTF_PRCLONING               = 0x10000
+	RTF_PROTO1                  = 0x8000
+	RTF_PROTO2                  = 0x4000
+	RTF_PROTO3                  = 0x40000
+	RTF_REJECT                  = 0x8
+	RTF_STATIC                  = 0x800
+	RTF_UP                      = 0x1
+	RTF_WASCLONED               = 0x20000
+	RTF_XRESOLVE                = 0x200
+	RTM_ADD                     = 0x1
+	RTM_CHANGE                  = 0x3
+	RTM_DELADDR                 = 0xd
+	RTM_DELETE                  = 0x2
+	RTM_DELMADDR                = 0x10
+	RTM_GET                     = 0x4
+	RTM_GET2                    = 0x14
+	RTM_IFINFO                  = 0xe
+	RTM_IFINFO2                 = 0x12
+	RTM_LOCK                    = 0x8
+	RTM_LOSING                  = 0x5
+	RTM_MISS                    = 0x7
+	RTM_NEWADDR                 = 0xc
+	RTM_NEWMADDR                = 0xf
+	RTM_NEWMADDR2               = 0x13
+	RTM_OLDADD                  = 0x9
+	RTM_OLDDEL                  = 0xa
+	RTM_REDIRECT                = 0x6
+	RTM_RESOLVE                 = 0xb
+	RTM_RTTUNIT                 = 0xf4240
+	RTM_VERSION                 = 0x5
+	RTV_EXPIRE                  = 0x4
+	RTV_HOPCOUNT                = 0x2
+	RTV_MTU                     = 0x1
+	RTV_RPIPE                   = 0x8
+	RTV_RTT                     = 0x40
+	RTV_RTTVAR                  = 0x80
+	RTV_SPIPE                   = 0x10
+	RTV_SSTHRESH                = 0x20
 	SCM_CREDS                   = 0x3
 	SCM_RIGHTS                  = 0x1
 	SCM_TIMESTAMP               = 0x2
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 5af1d4a..d3d46ce 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -94,6 +94,8 @@ const (
 	AF_VENDOR45                 = 0x81
 	AF_VENDOR46                 = 0x83
 	AF_VENDOR47                 = 0x85
+	CTL_MAXNAME                 = 0x18
+	CTL_NET                     = 0x4
 	E2BIG                       = 0x7
 	EACCES                      = 0xd
 	EADDRINUSE                  = 0x30
@@ -540,6 +542,11 @@ const (
 	MSG_PEEK                    = 0x2
 	MSG_TRUNC                   = 0x10
 	MSG_WAITALL                 = 0x40
+	NET_RT_DUMP                 = 0x1
+	NET_RT_FLAGS                = 0x2
+	NET_RT_IFLIST               = 0x3
+	NET_RT_IFMALIST             = 0x4
+	NET_RT_MAXID                = 0x5
 	O_ACCMODE                   = 0x3
 	O_APPEND                    = 0x8
 	O_ASYNC                     = 0x40
@@ -561,6 +568,75 @@ const (
 	O_TRUNC                     = 0x400
 	O_TTY_INIT                  = 0x80000
 	O_WRONLY                    = 0x1
+	RTAX_AUTHOR                 = 0x6
+	RTAX_BRD                    = 0x7
+	RTAX_DST                    = 0
+	RTAX_GATEWAY                = 0x1
+	RTAX_GENMASK                = 0x3
+	RTAX_IFA                    = 0x5
+	RTAX_IFP                    = 0x4
+	RTAX_MAX                    = 0x8
+	RTAX_NETMASK                = 0x2
+	RTA_AUTHOR                  = 0x40
+	RTA_BRD                     = 0x80
+	RTA_DST                     = 0x1
+	RTA_GATEWAY                 = 0x2
+	RTA_GENMASK                 = 0x8
+	RTA_IFA                     = 0x20
+	RTA_IFP                     = 0x10
+	RTA_NETMASK                 = 0x4
+	RTF_BLACKHOLE               = 0x1000
+	RTF_BROADCAST               = 0x400000
+	RTF_DONE                    = 0x40
+	RTF_DYNAMIC                 = 0x10
+	RTF_FMASK                   = 0x1004d808
+	RTF_GATEWAY                 = 0x2
+	RTF_HOST                    = 0x4
+	RTF_LLDATA                  = 0x400
+	RTF_LLINFO                  = 0x400
+	RTF_LOCAL                   = 0x200000
+	RTF_MODIFIED                = 0x20
+	RTF_MULTICAST               = 0x800000
+	RTF_PINNED                  = 0x100000
+	RTF_PRCLONING               = 0x10000
+	RTF_PROTO1                  = 0x8000
+	RTF_PROTO2                  = 0x4000
+	RTF_PROTO3                  = 0x40000
+	RTF_REJECT                  = 0x8
+	RTF_RNH_LOCKED              = 0x40000000
+	RTF_STATIC                  = 0x800
+	RTF_STICKY                  = 0x10000000
+	RTF_UP                      = 0x1
+	RTF_XRESOLVE                = 0x200
+	RTM_ADD                     = 0x1
+	RTM_CHANGE                  = 0x3
+	RTM_DELADDR                 = 0xd
+	RTM_DELETE                  = 0x2
+	RTM_DELMADDR                = 0x10
+	RTM_GET                     = 0x4
+	RTM_IEEE80211               = 0x12
+	RTM_IFANNOUNCE              = 0x11
+	RTM_IFINFO                  = 0xe
+	RTM_LOCK                    = 0x8
+	RTM_LOSING                  = 0x5
+	RTM_MISS                    = 0x7
+	RTM_NEWADDR                 = 0xc
+	RTM_NEWMADDR                = 0xf
+	RTM_OLDADD                  = 0x9
+	RTM_OLDDEL                  = 0xa
+	RTM_REDIRECT                = 0x6
+	RTM_RESOLVE                 = 0xb
+	RTM_RTTUNIT                 = 0xf4240
+	RTM_VERSION                 = 0x5
+	RTV_EXPIRE                  = 0x4
+	RTV_HOPCOUNT                = 0x2
+	RTV_MTU                     = 0x1
+	RTV_RPIPE                   = 0x8
+	RTV_RTT                     = 0x40
+	RTV_RTTVAR                  = 0x80
+	RTV_SPIPE                   = 0x10
+	RTV_SSTHRESH                = 0x20
+	RTV_WEIGHT                  = 0x100
 	SCM_BINTIME                 = 0x4
 	SCM_CREDS                   = 0x3
 	SCM_RIGHTS                  = 0x1
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 7e9d857..ce3ff54 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -94,6 +94,8 @@ const (
 	AF_VENDOR45                 = 0x81
 	AF_VENDOR46                 = 0x83
 	AF_VENDOR47                 = 0x85
+	CTL_MAXNAME                 = 0x18
+	CTL_NET                     = 0x4
 	E2BIG                       = 0x7
 	EACCES                      = 0xd
 	EADDRINUSE                  = 0x30
@@ -540,6 +542,11 @@ const (
 	MSG_PEEK                    = 0x2
 	MSG_TRUNC                   = 0x10
 	MSG_WAITALL                 = 0x40
+	NET_RT_DUMP                 = 0x1
+	NET_RT_FLAGS                = 0x2
+	NET_RT_IFLIST               = 0x3
+	NET_RT_IFMALIST             = 0x4
+	NET_RT_MAXID                = 0x5
 	O_ACCMODE                   = 0x3
 	O_APPEND                    = 0x8
 	O_ASYNC                     = 0x40
@@ -561,6 +568,75 @@ const (
 	O_TRUNC                     = 0x400
 	O_TTY_INIT                  = 0x80000
 	O_WRONLY                    = 0x1
+	RTAX_AUTHOR                 = 0x6
+	RTAX_BRD                    = 0x7
+	RTAX_DST                    = 0
+	RTAX_GATEWAY                = 0x1
+	RTAX_GENMASK                = 0x3
+	RTAX_IFA                    = 0x5
+	RTAX_IFP                    = 0x4
+	RTAX_MAX                    = 0x8
+	RTAX_NETMASK                = 0x2
+	RTA_AUTHOR                  = 0x40
+	RTA_BRD                     = 0x80
+	RTA_DST                     = 0x1
+	RTA_GATEWAY                 = 0x2
+	RTA_GENMASK                 = 0x8
+	RTA_IFA                     = 0x20
+	RTA_IFP                     = 0x10
+	RTA_NETMASK                 = 0x4
+	RTF_BLACKHOLE               = 0x1000
+	RTF_BROADCAST               = 0x400000
+	RTF_DONE                    = 0x40
+	RTF_DYNAMIC                 = 0x10
+	RTF_FMASK                   = 0x1004d808
+	RTF_GATEWAY                 = 0x2
+	RTF_HOST                    = 0x4
+	RTF_LLDATA                  = 0x400
+	RTF_LLINFO                  = 0x400
+	RTF_LOCAL                   = 0x200000
+	RTF_MODIFIED                = 0x20
+	RTF_MULTICAST               = 0x800000
+	RTF_PINNED                  = 0x100000
+	RTF_PRCLONING               = 0x10000
+	RTF_PROTO1                  = 0x8000
+	RTF_PROTO2                  = 0x4000
+	RTF_PROTO3                  = 0x40000
+	RTF_REJECT                  = 0x8
+	RTF_RNH_LOCKED              = 0x40000000
+	RTF_STATIC                  = 0x800
+	RTF_STICKY                  = 0x10000000
+	RTF_UP                      = 0x1
+	RTF_XRESOLVE                = 0x200
+	RTM_ADD                     = 0x1
+	RTM_CHANGE                  = 0x3
+	RTM_DELADDR                 = 0xd
+	RTM_DELETE                  = 0x2
+	RTM_DELMADDR                = 0x10
+	RTM_GET                     = 0x4
+	RTM_IEEE80211               = 0x12
+	RTM_IFANNOUNCE              = 0x11
+	RTM_IFINFO                  = 0xe
+	RTM_LOCK                    = 0x8
+	RTM_LOSING                  = 0x5
+	RTM_MISS                    = 0x7
+	RTM_NEWADDR                 = 0xc
+	RTM_NEWMADDR                = 0xf
+	RTM_OLDADD                  = 0x9
+	RTM_OLDDEL                  = 0xa
+	RTM_REDIRECT                = 0x6
+	RTM_RESOLVE                 = 0xb
+	RTM_RTTUNIT                 = 0xf4240
+	RTM_VERSION                 = 0x5
+	RTV_EXPIRE                  = 0x4
+	RTV_HOPCOUNT                = 0x2
+	RTV_MTU                     = 0x1
+	RTV_RPIPE                   = 0x8
+	RTV_RTT                     = 0x40
+	RTV_RTTVAR                  = 0x80
+	RTV_SPIPE                   = 0x10
+	RTV_SSTHRESH                = 0x20
+	RTV_WEIGHT                  = 0x100
 	SCM_BINTIME                 = 0x4
 	SCM_CREDS                   = 0x3
 	SCM_RIGHTS                  = 0x1
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index fe45d23..43d2782 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -640,7 +640,6 @@ const (
 	SIOCSIFTXQLEN                    = 0x8943
 	SIOCSPGRP                        = 0x8902
 	SIOCSRARP                        = 0x8962
-	SIOGIFINDEX                      = 0x8933
 	SOCK_CLOEXEC                     = 0x80000
 	SOCK_DCCP                        = 0x6
 	SOCK_DGRAM                       = 0x2
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index f9404d0..04f4dad 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -641,7 +641,6 @@ const (
 	SIOCSIFTXQLEN                    = 0x8943
 	SIOCSPGRP                        = 0x8902
 	SIOCSRARP                        = 0x8962
-	SIOGIFINDEX                      = 0x8933
 	SOCK_CLOEXEC                     = 0x80000
 	SOCK_DCCP                        = 0x6
 	SOCK_DGRAM                       = 0x2
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 9718e5d..973f00e 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -121,6 +121,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -134,6 +136,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
@@ -155,6 +159,8 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	var _p0 unsafe.Pointer
 	if len(mib) > 0 {
 		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	errno = int(e1)
@@ -377,6 +383,8 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
@@ -414,6 +422,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
 	n = int(r0)
@@ -601,6 +611,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
@@ -614,6 +626,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
@@ -627,6 +641,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -640,6 +656,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -871,6 +889,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index 6dca198..f7a37b6 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -121,6 +121,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -134,6 +136,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
@@ -155,6 +159,8 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	var _p0 unsafe.Pointer
 	if len(mib) > 0 {
 		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	errno = int(e1)
@@ -377,6 +383,8 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
@@ -414,6 +422,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
 	n = int(r0)
@@ -601,6 +611,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -614,6 +626,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -627,6 +641,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -640,6 +656,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -871,6 +889,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 627a9a2..1fab5e2 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -121,6 +121,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -134,6 +136,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
@@ -155,6 +159,8 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	var _p0 unsafe.Pointer
 	if len(mib) > 0 {
 		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	errno = int(e1)
@@ -361,6 +367,8 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
@@ -398,6 +406,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
 	n = int(r0)
@@ -609,6 +619,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
@@ -622,6 +634,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
@@ -635,6 +649,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -648,6 +664,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -871,6 +889,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 8872367..53434b2 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -121,6 +121,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -134,6 +136,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
@@ -155,6 +159,8 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	var _p0 unsafe.Pointer
 	if len(mib) > 0 {
 		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	errno = int(e1)
@@ -361,6 +367,8 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
@@ -398,6 +406,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
 	n = int(r0)
@@ -609,6 +619,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -622,6 +634,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -635,6 +649,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -648,6 +664,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -871,6 +889,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_linux_386.go b/src/pkg/syscall/zsyscall_linux_386.go
index aa8c41a..005cc15 100644
--- a/src/pkg/syscall/zsyscall_linux_386.go
+++ b/src/pkg/syscall/zsyscall_linux_386.go
@@ -53,6 +53,8 @@ func Getcwd(buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
@@ -184,6 +186,8 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(events) > 0 {
 		_p0 = unsafe.Pointer(&events[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
@@ -277,6 +281,8 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -391,6 +397,8 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -468,6 +476,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -481,6 +491,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -518,6 +530,8 @@ func Setdomainname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -530,6 +544,8 @@ func Sethostname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -688,6 +704,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -823,6 +841,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
@@ -836,6 +856,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index 2759c5c..d449a3b 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -53,6 +53,8 @@ func Getcwd(buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
@@ -184,6 +186,8 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(events) > 0 {
 		_p0 = unsafe.Pointer(&events[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
@@ -277,6 +281,8 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -391,6 +397,8 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -468,6 +476,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -481,6 +491,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -518,6 +530,8 @@ func Setdomainname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -530,6 +544,8 @@ func Sethostname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -688,6 +704,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -839,6 +857,8 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -852,6 +872,8 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
@@ -1071,6 +1093,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -1084,6 +1108,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 7111085..22b736b 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -53,6 +53,8 @@ func Getcwd(buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
@@ -184,6 +186,8 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(events) > 0 {
 		_p0 = unsafe.Pointer(&events[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
@@ -277,6 +281,8 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -391,6 +397,8 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -468,6 +476,8 @@ func Read(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -481,6 +491,8 @@ func Readlink(path string, buf []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
@@ -518,6 +530,8 @@ func Setdomainname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -530,6 +544,8 @@ func Sethostname(p []byte) (errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	errno = int(e1)
@@ -688,6 +704,8 @@ func Write(fd int, p []byte) (n int, errno int) {
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
@@ -802,6 +820,8 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	var _p0 unsafe.Pointer
 	if len(p) > 0 {
 		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
@@ -815,6 +835,8 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index b71177e..46e16f4 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -45,6 +45,8 @@ var (
 	procGetQueuedCompletionStatus  = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
 	procCancelIo                   = getSysProcAddr(modkernel32, "CancelIo")
 	procCreateProcessW             = getSysProcAddr(modkernel32, "CreateProcessW")
+	procOpenProcess                = getSysProcAddr(modkernel32, "OpenProcess")
+	procGetExitCodeProcess         = getSysProcAddr(modkernel32, "GetExitCodeProcess")
 	procGetStartupInfoW            = getSysProcAddr(modkernel32, "GetStartupInfoW")
 	procGetCurrentProcess          = getSysProcAddr(modkernel32, "GetCurrentProcess")
 	procDuplicateHandle            = getSysProcAddr(modkernel32, "DuplicateHandle")
@@ -55,8 +57,6 @@ var (
 	procCryptAcquireContextW       = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
 	procCryptReleaseContext        = getSysProcAddr(modadvapi32, "CryptReleaseContext")
 	procCryptGenRandom             = getSysProcAddr(modadvapi32, "CryptGenRandom")
-	procOpenProcess                = getSysProcAddr(modkernel32, "OpenProcess")
-	procGetExitCodeProcess         = getSysProcAddr(modkernel32, "GetExitCodeProcess")
 	procGetEnvironmentStringsW     = getSysProcAddr(modkernel32, "GetEnvironmentStringsW")
 	procFreeEnvironmentStringsW    = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW")
 	procGetEnvironmentVariableW    = getSysProcAddr(modkernel32, "GetEnvironmentVariableW")
@@ -66,6 +66,8 @@ var (
 	procGetCommandLineW            = getSysProcAddr(modkernel32, "GetCommandLineW")
 	procCommandLineToArgvW         = getSysProcAddr(modshell32, "CommandLineToArgvW")
 	procLocalFree                  = getSysProcAddr(modkernel32, "LocalFree")
+	procSetHandleInformation       = getSysProcAddr(modkernel32, "SetHandleInformation")
+	procFlushFileBuffers           = getSysProcAddr(modkernel32, "FlushFileBuffers")
 	procWSAStartup                 = getSysProcAddr(modwsock32, "WSAStartup")
 	procWSACleanup                 = getSysProcAddr(modwsock32, "WSACleanup")
 	procsocket                     = getSysProcAddr(modwsock32, "socket")
@@ -111,10 +113,9 @@ func LoadLibrary(libname string) (handle uint32, errno int) {
 	return
 }
 
-func FreeLibrary(handle uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procFreeLibrary, 1, uintptr(handle), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func FreeLibrary(handle uint32) (errno int) {
+	r1, _, e1 := Syscall(procFreeLibrary, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -180,7 +181,7 @@ func ExitProcess(exitcode uint32) {
 	return
 }
 
-func CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) {
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) {
 	r0, _, e1 := Syscall9(procCreateFileW, 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
 	handle = int32(r0)
 	if handle == -1 {
@@ -195,14 +196,13 @@ func CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode u
 	return
 }
 
-func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int) {
+func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
 	var _p0 *byte
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r0, _, e1 := Syscall6(procReadFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+	r1, _, e1 := Syscall6(procReadFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -214,14 +214,13 @@ func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (o
 	return
 }
 
-func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int) {
+func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
 	var _p0 *byte
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r0, _, e1 := Syscall6(procWriteFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+	r1, _, e1 := Syscall6(procWriteFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -248,10 +247,9 @@ func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence
 	return
 }
 
-func CloseHandle(handle int32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procCloseHandle, 1, uintptr(handle), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func CloseHandle(handle int32) (errno int) {
+	r1, _, e1 := Syscall(procCloseHandle, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -293,10 +291,9 @@ func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int)
 	return
 }
 
-func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procFindNextFileW, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func FindNextFile(handle int32, data *Win32finddata) (errno int) {
+	r1, _, e1 := Syscall(procFindNextFileW, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -308,10 +305,9 @@ func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) {
 	return
 }
 
-func FindClose(handle int32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procFindClose, 1, uintptr(handle), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func FindClose(handle int32) (errno int) {
+	r1, _, e1 := Syscall(procFindClose, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -323,10 +319,9 @@ func FindClose(handle int32) (ok bool, errno int) {
 	return
 }
 
-func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procGetFileInformationByHandle, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (errno int) {
+	r1, _, e1 := Syscall(procGetFileInformationByHandle, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -353,10 +348,9 @@ func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
 	return
 }
 
-func SetCurrentDirectory(path *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procSetCurrentDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func SetCurrentDirectory(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procSetCurrentDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -368,10 +362,9 @@ func SetCurrentDirectory(path *uint16) (ok bool, errno int) {
 	return
 }
 
-func CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procCreateDirectoryW, 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+	r1, _, e1 := Syscall(procCreateDirectoryW, 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -383,10 +376,9 @@ func CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) {
 	return
 }
 
-func RemoveDirectory(path *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procRemoveDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func RemoveDirectory(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procRemoveDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -398,10 +390,9 @@ func RemoveDirectory(path *uint16) (ok bool, errno int) {
 	return
 }
 
-func DeleteFile(path *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procDeleteFileW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func DeleteFile(path *uint16) (errno int) {
+	r1, _, e1 := Syscall(procDeleteFileW, 1, uintptr(unsafe.Pointer(path)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -413,10 +404,9 @@ func DeleteFile(path *uint16) (ok bool, errno int) {
 	return
 }
 
-func MoveFile(from *uint16, to *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procMoveFileW, 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func MoveFile(from *uint16, to *uint16) (errno int) {
+	r1, _, e1 := Syscall(procMoveFileW, 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -428,10 +418,9 @@ func MoveFile(from *uint16, to *uint16) (ok bool, errno int) {
 	return
 }
 
-func GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procGetComputerNameW, 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func GetComputerName(buf *uint16, n *uint32) (errno int) {
+	r1, _, e1 := Syscall(procGetComputerNameW, 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -443,10 +432,9 @@ func GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) {
 	return
 }
 
-func SetEndOfFile(handle int32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procSetEndOfFile, 1, uintptr(handle), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func SetEndOfFile(handle int32) (errno int) {
+	r1, _, e1 := Syscall(procSetEndOfFile, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -498,10 +486,9 @@ func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, thread
 	return
 }
 
-func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall6(procGetQueuedCompletionStatus, 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+	r1, _, e1 := Syscall6(procGetQueuedCompletionStatus, 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -513,10 +500,9 @@ func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlap
 	return
 }
 
-func CancelIo(s uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procCancelIo, 1, uintptr(s), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func CancelIo(s uint32) (errno int) {
+	r1, _, e1 := Syscall(procCancelIo, 1, uintptr(s), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -528,16 +514,15 @@ func CancelIo(s uint32) (ok bool, errno int) {
 	return
 }
 
-func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) {
+func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
 	var _p0 uint32
 	if inheritHandles {
 		_p0 = 1
 	} else {
 		_p0 = 0
 	}
-	r0, _, e1 := Syscall12(procCreateProcessW, 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+	r1, _, e1 := Syscall12(procCreateProcessW, 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -549,10 +534,16 @@ func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, thr
 	return
 }
 
-func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) {
+	var _p0 uint32
+	if inheritHandle {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid))
+	handle = uint32(r0)
+	if handle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -564,10 +555,9 @@ func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) {
 	return
 }
 
-func GetCurrentProcess() (pseudoHandle int32, errno int) {
-	r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0, 0)
-	pseudoHandle = int32(r0)
-	if pseudoHandle == 0 {
+func GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int) {
+	r1, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -579,16 +569,9 @@ func GetCurrentProcess() (pseudoHandle int32, errno int) {
 	return
 }
 
-func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int) {
-	var _p0 uint32
-	if bInheritHandle {
-		_p0 = 1
-	} else {
-		_p0 = 0
-	}
-	r0, _, e1 := Syscall9(procDuplicateHandle, 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+	r1, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -600,10 +583,10 @@ func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetPro
 	return
 }
 
-func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) {
-	r0, _, e1 := Syscall(procWaitForSingleObject, 2, uintptr(handle), uintptr(waitMilliseconds), 0)
-	event = uint32(r0)
-	if event == 0xffffffff {
+func GetCurrentProcess() (pseudoHandle int32, errno int) {
+	r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0, 0)
+	pseudoHandle = int32(r0)
+	if pseudoHandle == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -615,10 +598,15 @@ func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, e
 	return
 }
 
-func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
-	r0, _, e1 := Syscall(procGetTempPathW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
-	n = uint32(r0)
-	if n == 0 {
+func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+	var _p0 uint32
+	if bInheritHandle {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r1, _, e1 := Syscall9(procDuplicateHandle, 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -630,10 +618,10 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
 	return
 }
 
-func CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall6(procCreatePipe, 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(lpsa)), uintptr(size), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) {
+	r0, _, e1 := Syscall(procWaitForSingleObject, 2, uintptr(handle), uintptr(waitMilliseconds), 0)
+	event = uint32(r0)
+	if event == 0xffffffff {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -645,8 +633,8 @@ func CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32
 	return
 }
 
-func GetFileType(filehandle uint32) (n uint32, errno int) {
-	r0, _, e1 := Syscall(procGetFileType, 1, uintptr(filehandle), 0, 0)
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetTempPathW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
 	n = uint32(r0)
 	if n == 0 {
 		if e1 != 0 {
@@ -660,10 +648,9 @@ func GetFileType(filehandle uint32) (n uint32, errno int) {
 	return
 }
 
-func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall6(procCryptAcquireContextW, 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func CreatePipe(readhandle *uint32, writehandle *uint32, sa *SecurityAttributes, size uint32) (errno int) {
+	r1, _, e1 := Syscall6(procCreatePipe, 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -675,10 +662,10 @@ func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16
 	return
 }
 
-func CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procCryptReleaseContext, 2, uintptr(provhandle), uintptr(flags), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func GetFileType(filehandle uint32) (n uint32, errno int) {
+	r0, _, e1 := Syscall(procGetFileType, 1, uintptr(filehandle), 0, 0)
+	n = uint32(r0)
+	if n == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -690,10 +677,9 @@ func CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) {
 	return
 }
 
-func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procCryptGenRandom, 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
-	ok = bool(r0 != 0)
-	if !ok {
+func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+	r1, _, e1 := Syscall6(procCryptAcquireContextW, 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -705,10 +691,9 @@ func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno
 	return
 }
 
-func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) {
-	r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(b), uintptr(pid))
-	handle = uint32(r0)
-	if handle == 0 {
+func CryptReleaseContext(provhandle uint32, flags uint32) (errno int) {
+	r1, _, e1 := Syscall(procCryptReleaseContext, 2, uintptr(provhandle), uintptr(flags), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -720,10 +705,9 @@ func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) {
 	return
 }
 
-func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(h), uintptr(unsafe.Pointer(c)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (errno int) {
+	r1, _, e1 := Syscall(procCryptGenRandom, 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -750,10 +734,9 @@ func GetEnvironmentStrings() (envs *uint16, errno int) {
 	return
 }
 
-func FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procFreeEnvironmentStringsW, 1, uintptr(unsafe.Pointer(envs)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func FreeEnvironmentStrings(envs *uint16) (errno int) {
+	r1, _, e1 := Syscall(procFreeEnvironmentStringsW, 1, uintptr(unsafe.Pointer(envs)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -780,10 +763,9 @@ func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32
 	return
 }
 
-func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) {
-	r0, _, e1 := Syscall(procSetEnvironmentVariableW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func SetEnvironmentVariable(name *uint16, value *uint16) (errno int) {
+	r1, _, e1 := Syscall(procSetEnvironmentVariableW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -795,10 +777,9 @@ func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) {
 	return
 }
 
-func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (ok bool, errno int) {
-	r0, _, e1 := Syscall6(procSetFileTime, 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+	r1, _, e1 := Syscall6(procSetFileTime, 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
@@ -861,6 +842,34 @@ func LocalFree(hmem uint32) (handle uint32, errno int) {
 	return
 }
 
+func SetHandleInformation(handle int32, mask uint32, flags uint32) (errno int) {
+	r1, _, e1 := Syscall(procSetHandleInformation, 3, uintptr(handle), uintptr(mask), uintptr(flags))
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
+func FlushFileBuffers(handle int32) (errno int) {
+	r1, _, e1 := Syscall(procFlushFileBuffers, 1, uintptr(handle), 0, 0)
+	if int(r1) == 0 {
+		if e1 != 0 {
+			errno = int(e1)
+		} else {
+			errno = EINVAL
+		}
+	} else {
+		errno = 0
+	}
+	return
+}
+
 func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
 	r0, _, _ := Syscall(procWSAStartup, 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
 	sockerrno = int(r0)
@@ -1008,10 +1017,9 @@ func Closesocket(s int32) (errno int) {
 	return
 }
 
-func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, errno int) {
-	r0, _, e1 := Syscall9(procAcceptEx, 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
-	ok = bool(r0 != 0)
-	if !ok {
+func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+	r1, _, e1 := Syscall9(procAcceptEx, 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
+	if int(r1) == 0 {
 		if e1 != 0 {
 			errno = int(e1)
 		} else {
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
index 708bba4..736c654 100644
--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -6,22 +6,29 @@ package syscall
 
 // Constants
 const (
-	sizeofPtr           = 0x4
-	sizeofShort         = 0x2
-	sizeofInt           = 0x4
-	sizeofLong          = 0x4
-	sizeofLongLong      = 0x8
-	O_CLOEXEC           = 0
-	SizeofSockaddrInet4 = 0x10
-	SizeofSockaddrInet6 = 0x1c
-	SizeofSockaddrAny   = 0x6c
-	SizeofSockaddrUnix  = 0x6a
-	SizeofLinger        = 0x8
-	SizeofMsghdr        = 0x1c
-	SizeofCmsghdr       = 0xc
-	PTRACE_TRACEME      = 0
-	PTRACE_CONT         = 0x7
-	PTRACE_KILL         = 0x8
+	sizeofPtr              = 0x4
+	sizeofShort            = 0x2
+	sizeofInt              = 0x4
+	sizeofLong             = 0x4
+	sizeofLongLong         = 0x8
+	O_CLOEXEC              = 0
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x14
+	SizeofLinger           = 0x8
+	SizeofIpMreq           = 0x8
+	SizeofMsghdr           = 0x1c
+	SizeofCmsghdr          = 0xc
+	PTRACE_TRACEME         = 0
+	PTRACE_CONT            = 0x7
+	PTRACE_KILL            = 0x8
+	SizeofIfMsghdr         = 0x70
+	SizeofIfData           = 0x60
+	SizeofIfaMsghdr        = 0x14
+	SizeofRtMsghdr         = 0x5c
+	SizeofRtMetrics        = 0x38
 )
 
 // Types
@@ -144,13 +151,13 @@ type Log2phys_t struct {
 }
 
 type Dirent struct {
-	Ino     uint64
-	Seekoff uint64
-	Reclen  uint16
-	Namlen  uint16
-	Type    uint8
-	Name    [1024]int8
-	Pad0    [3]byte
+	Ino          uint64
+	Seekoff      uint64
+	Reclen       uint16
+	Namlen       uint16
+	Type         uint8
+	Name         [1024]int8
+	Pad_godefs_0 [3]byte
 }
 
 type RawSockaddrInet4 struct {
@@ -176,6 +183,17 @@ type RawSockaddrUnix struct {
 	Path   [104]int8
 }
 
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [12]int8
+}
+
 type RawSockaddr struct {
 	Len    uint8
 	Family uint8
@@ -199,6 +217,11 @@ type Iovec struct {
 	Len  uint32
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
 	Name       *byte
 	Namelen    uint32
@@ -227,3 +250,87 @@ type Kevent_t struct {
 type FdSet struct {
 	Bits [32]int32
 }
+
+type IfMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Data         IfData
+}
+
+type IfData struct {
+	Type       uint8
+	Typelen    uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Unused1    uint8
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Recvtiming uint32
+	Xmittiming uint32
+	Lastchange Timeval
+	Unused2    uint32
+	Hwassist   uint32
+	Reserved1  uint32
+	Reserved2  uint32
+}
+
+type IfaMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Metric       int32
+}
+
+type RtMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Flags        int32
+	Addrs        int32
+	Pid          int32
+	Seq          int32
+	Errno        int32
+	Use          int32
+	Inits        uint32
+	Rmx          RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint32
+	Mtu      uint32
+	Hopcount uint32
+	Expire   int32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Filler   [4]uint32
+}
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
index 5b27376..91ee457 100644
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -6,22 +6,29 @@ package syscall
 
 // Constants
 const (
-	sizeofPtr           = 0x8
-	sizeofShort         = 0x2
-	sizeofInt           = 0x4
-	sizeofLong          = 0x8
-	sizeofLongLong      = 0x8
-	O_CLOEXEC           = 0
-	SizeofSockaddrInet4 = 0x10
-	SizeofSockaddrInet6 = 0x1c
-	SizeofSockaddrAny   = 0x6c
-	SizeofSockaddrUnix  = 0x6a
-	SizeofLinger        = 0x8
-	SizeofMsghdr        = 0x30
-	SizeofCmsghdr       = 0xc
-	PTRACE_TRACEME      = 0
-	PTRACE_CONT         = 0x7
-	PTRACE_KILL         = 0x8
+	sizeofPtr              = 0x8
+	sizeofShort            = 0x2
+	sizeofInt              = 0x4
+	sizeofLong             = 0x8
+	sizeofLongLong         = 0x8
+	O_CLOEXEC              = 0
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x14
+	SizeofLinger           = 0x8
+	SizeofIpMreq           = 0x8
+	SizeofMsghdr           = 0x30
+	SizeofCmsghdr          = 0xc
+	PTRACE_TRACEME         = 0
+	PTRACE_CONT            = 0x7
+	PTRACE_KILL            = 0x8
+	SizeofIfMsghdr         = 0x70
+	SizeofIfData           = 0x60
+	SizeofIfaMsghdr        = 0x14
+	SizeofRtMsghdr         = 0x5c
+	SizeofRtMetrics        = 0x38
 )
 
 // Types
@@ -40,9 +47,9 @@ type Timespec struct {
 }
 
 type Timeval struct {
-	Sec  int64
-	Usec int32
-	Pad0 [4]byte
+	Sec          int64
+	Usec         int32
+	Pad_godefs_0 [4]byte
 }
 
 type Rusage struct {
@@ -79,7 +86,7 @@ type Stat_t struct {
 	Uid           uint32
 	Gid           uint32
 	Rdev          int32
-	Pad0          [4]byte
+	Pad_godefs_0  [4]byte
 	Atimespec     Timespec
 	Mtimespec     Timespec
 	Ctimespec     Timespec
@@ -129,9 +136,9 @@ type Fstore_t struct {
 }
 
 type Radvisory_t struct {
-	Offset int64
-	Count  int32
-	Pad0   [4]byte
+	Offset       int64
+	Count        int32
+	Pad_godefs_0 [4]byte
 }
 
 type Fbootstraptransfer_t struct {
@@ -147,13 +154,13 @@ type Log2phys_t struct {
 }
 
 type Dirent struct {
-	Ino     uint64
-	Seekoff uint64
-	Reclen  uint16
-	Namlen  uint16
-	Type    uint8
-	Name    [1024]int8
-	Pad0    [3]byte
+	Ino          uint64
+	Seekoff      uint64
+	Reclen       uint16
+	Namlen       uint16
+	Type         uint8
+	Name         [1024]int8
+	Pad_godefs_0 [3]byte
 }
 
 type RawSockaddrInet4 struct {
@@ -179,6 +186,17 @@ type RawSockaddrUnix struct {
 	Path   [104]int8
 }
 
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [12]int8
+}
+
 type RawSockaddr struct {
 	Len    uint8
 	Family uint8
@@ -202,16 +220,21 @@ type Iovec struct {
 	Len  uint64
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
-	Name       *byte
-	Namelen    uint32
-	Pad0       [4]byte
-	Iov        *Iovec
-	Iovlen     int32
-	Pad1       [4]byte
-	Control    *byte
-	Controllen uint32
-	Flags      int32
+	Name         *byte
+	Namelen      uint32
+	Pad_godefs_0 [4]byte
+	Iov          *Iovec
+	Iovlen       int32
+	Pad_godefs_1 [4]byte
+	Control      *byte
+	Controllen   uint32
+	Flags        int32
 }
 
 type Cmsghdr struct {
@@ -232,3 +255,87 @@ type Kevent_t struct {
 type FdSet struct {
 	Bits [32]int32
 }
+
+type IfMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Data         IfData
+}
+
+type IfData struct {
+	Type       uint8
+	Typelen    uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Unused1    uint8
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Recvtiming uint32
+	Xmittiming uint32
+	Lastchange [8]byte /* timeval32 */
+	Unused2    uint32
+	Hwassist   uint32
+	Reserved1  uint32
+	Reserved2  uint32
+}
+
+type IfaMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Metric       int32
+}
+
+type RtMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Flags        int32
+	Addrs        int32
+	Pid          int32
+	Seq          int32
+	Errno        int32
+	Use          int32
+	Inits        uint32
+	Rmx          RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint32
+	Mtu      uint32
+	Hopcount uint32
+	Expire   int32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Filler   [4]uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
index 39e7452..0f8e37a 100644
--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -6,36 +6,43 @@ package syscall
 
 // Constants
 const (
-	sizeofPtr           = 0x4
-	sizeofShort         = 0x2
-	sizeofInt           = 0x4
-	sizeofLong          = 0x4
-	sizeofLongLong      = 0x8
-	O_CLOEXEC           = 0
-	S_IFMT              = 0xf000
-	S_IFIFO             = 0x1000
-	S_IFCHR             = 0x2000
-	S_IFDIR             = 0x4000
-	S_IFBLK             = 0x6000
-	S_IFREG             = 0x8000
-	S_IFLNK             = 0xa000
-	S_IFSOCK            = 0xc000
-	S_ISUID             = 0x800
-	S_ISGID             = 0x400
-	S_ISVTX             = 0x200
-	S_IRUSR             = 0x100
-	S_IWUSR             = 0x80
-	S_IXUSR             = 0x40
-	SizeofSockaddrInet4 = 0x10
-	SizeofSockaddrInet6 = 0x1c
-	SizeofSockaddrAny   = 0x6c
-	SizeofSockaddrUnix  = 0x6a
-	SizeofLinger        = 0x8
-	SizeofMsghdr        = 0x1c
-	SizeofCmsghdr       = 0xc
-	PTRACE_TRACEME      = 0
-	PTRACE_CONT         = 0x7
-	PTRACE_KILL         = 0x8
+	sizeofPtr              = 0x4
+	sizeofShort            = 0x2
+	sizeofInt              = 0x4
+	sizeofLong             = 0x4
+	sizeofLongLong         = 0x8
+	O_CLOEXEC              = 0
+	S_IFMT                 = 0xf000
+	S_IFIFO                = 0x1000
+	S_IFCHR                = 0x2000
+	S_IFDIR                = 0x4000
+	S_IFBLK                = 0x6000
+	S_IFREG                = 0x8000
+	S_IFLNK                = 0xa000
+	S_IFSOCK               = 0xc000
+	S_ISUID                = 0x800
+	S_ISGID                = 0x400
+	S_ISVTX                = 0x200
+	S_IRUSR                = 0x100
+	S_IWUSR                = 0x80
+	S_IXUSR                = 0x40
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x36
+	SizeofLinger           = 0x8
+	SizeofIpMreq           = 0x8
+	SizeofMsghdr           = 0x1c
+	SizeofCmsghdr          = 0xc
+	PTRACE_TRACEME         = 0
+	PTRACE_CONT            = 0x7
+	PTRACE_KILL            = 0x8
+	SizeofIfMsghdr         = 0x60
+	SizeofIfData           = 0x50
+	SizeofIfaMsghdr        = 0x14
+	SizeofRtMsghdr         = 0x5c
+	SizeofRtMetrics        = 0x38
 )
 
 // Types
@@ -102,8 +109,8 @@ type Stat_t struct {
 	Gen           uint32
 	Lspare        int32
 	Birthtimespec Timespec
-	Pad0          uint32
-	Pad1          uint32
+	Pad_godefs_0  uint32
+	Pad_godefs_1  uint32
 }
 
 type Statfs_t struct {
@@ -171,6 +178,17 @@ type RawSockaddrUnix struct {
 	Path   [104]int8
 }
 
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [46]int8
+}
+
 type RawSockaddr struct {
 	Len    uint8
 	Family uint8
@@ -194,6 +212,11 @@ type Iovec struct {
 	Len  uint32
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
 	Name       *byte
 	Namelen    uint32
@@ -222,3 +245,84 @@ type Kevent_t struct {
 type FdSet struct {
 	X__fds_bits [32]uint32
 }
+
+type IfMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Data         IfData
+}
+
+type IfData struct {
+	Type        uint8
+	Physical    uint8
+	Addrlen     uint8
+	Hdrlen      uint8
+	Link_state  uint8
+	Spare_char1 uint8
+	Spare_char2 uint8
+	Datalen     uint8
+	Mtu         uint32
+	Metric      uint32
+	Baudrate    uint32
+	Ipackets    uint32
+	Ierrors     uint32
+	Opackets    uint32
+	Oerrors     uint32
+	Collisions  uint32
+	Ibytes      uint32
+	Obytes      uint32
+	Imcasts     uint32
+	Omcasts     uint32
+	Iqdrops     uint32
+	Noproto     uint32
+	Hwassist    uint32
+	Epoch       int32
+	Lastchange  Timeval
+}
+
+type IfaMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Metric       int32
+}
+
+type RtMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Flags        int32
+	Addrs        int32
+	Pid          int32
+	Seq          int32
+	Errno        int32
+	Fmask        int32
+	Inits        uint32
+	Rmx          RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint32
+	Mtu      uint32
+	Hopcount uint32
+	Expire   uint32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Weight   uint32
+	Filler   [3]uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
index eea7a05..83a54f6 100644
--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -6,36 +6,43 @@ package syscall
 
 // Constants
 const (
-	sizeofPtr           = 0x8
-	sizeofShort         = 0x2
-	sizeofInt           = 0x4
-	sizeofLong          = 0x8
-	sizeofLongLong      = 0x8
-	O_CLOEXEC           = 0
-	S_IFMT              = 0xf000
-	S_IFIFO             = 0x1000
-	S_IFCHR             = 0x2000
-	S_IFDIR             = 0x4000
-	S_IFBLK             = 0x6000
-	S_IFREG             = 0x8000
-	S_IFLNK             = 0xa000
-	S_IFSOCK            = 0xc000
-	S_ISUID             = 0x800
-	S_ISGID             = 0x400
-	S_ISVTX             = 0x200
-	S_IRUSR             = 0x100
-	S_IWUSR             = 0x80
-	S_IXUSR             = 0x40
-	SizeofSockaddrInet4 = 0x10
-	SizeofSockaddrInet6 = 0x1c
-	SizeofSockaddrAny   = 0x6c
-	SizeofSockaddrUnix  = 0x6a
-	SizeofLinger        = 0x8
-	SizeofMsghdr        = 0x30
-	SizeofCmsghdr       = 0xc
-	PTRACE_TRACEME      = 0
-	PTRACE_CONT         = 0x7
-	PTRACE_KILL         = 0x8
+	sizeofPtr              = 0x8
+	sizeofShort            = 0x2
+	sizeofInt              = 0x4
+	sizeofLong             = 0x8
+	sizeofLongLong         = 0x8
+	O_CLOEXEC              = 0
+	S_IFMT                 = 0xf000
+	S_IFIFO                = 0x1000
+	S_IFCHR                = 0x2000
+	S_IFDIR                = 0x4000
+	S_IFBLK                = 0x6000
+	S_IFREG                = 0x8000
+	S_IFLNK                = 0xa000
+	S_IFSOCK               = 0xc000
+	S_ISUID                = 0x800
+	S_ISGID                = 0x400
+	S_ISVTX                = 0x200
+	S_IRUSR                = 0x100
+	S_IWUSR                = 0x80
+	S_IXUSR                = 0x40
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x36
+	SizeofLinger           = 0x8
+	SizeofIpMreq           = 0x8
+	SizeofMsghdr           = 0x30
+	SizeofCmsghdr          = 0xc
+	PTRACE_TRACEME         = 0
+	PTRACE_CONT            = 0x7
+	PTRACE_KILL            = 0x8
+	SizeofIfMsghdr         = 0xa8
+	SizeofIfData           = 0x98
+	SizeofIfaMsghdr        = 0x14
+	SizeofRtMsghdr         = 0x98
+	SizeofRtMetrics        = 0x70
 )
 
 // Types
@@ -102,8 +109,8 @@ type Stat_t struct {
 	Gen           uint32
 	Lspare        int32
 	Birthtimespec Timespec
-	Pad0          uint8
-	Pad1          uint8
+	Pad_godefs_0  uint8
+	Pad_godefs_1  uint8
 }
 
 type Statfs_t struct {
@@ -132,13 +139,13 @@ type Statfs_t struct {
 }
 
 type Flock_t struct {
-	Start  int64
-	Len    int64
-	Pid    int32
-	Type   int16
-	Whence int16
-	Sysid  int32
-	Pad0   [4]byte
+	Start        int64
+	Len          int64
+	Pid          int32
+	Type         int16
+	Whence       int16
+	Sysid        int32
+	Pad_godefs_0 [4]byte
 }
 
 type Dirent struct {
@@ -172,6 +179,17 @@ type RawSockaddrUnix struct {
 	Path   [104]int8
 }
 
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [46]int8
+}
+
 type RawSockaddr struct {
 	Len    uint8
 	Family uint8
@@ -195,16 +213,21 @@ type Iovec struct {
 	Len  uint64
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
-	Name       *byte
-	Namelen    uint32
-	Pad0       [4]byte
-	Iov        *Iovec
-	Iovlen     int32
-	Pad1       [4]byte
-	Control    *byte
-	Controllen uint32
-	Flags      int32
+	Name         *byte
+	Namelen      uint32
+	Pad_godefs_0 [4]byte
+	Iov          *Iovec
+	Iovlen       int32
+	Pad_godefs_1 [4]byte
+	Control      *byte
+	Controllen   uint32
+	Flags        int32
 }
 
 type Cmsghdr struct {
@@ -225,3 +248,84 @@ type Kevent_t struct {
 type FdSet struct {
 	X__fds_bits [16]uint64
 }
+
+type IfMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Data         IfData
+}
+
+type IfData struct {
+	Type        uint8
+	Physical    uint8
+	Addrlen     uint8
+	Hdrlen      uint8
+	Link_state  uint8
+	Spare_char1 uint8
+	Spare_char2 uint8
+	Datalen     uint8
+	Mtu         uint64
+	Metric      uint64
+	Baudrate    uint64
+	Ipackets    uint64
+	Ierrors     uint64
+	Opackets    uint64
+	Oerrors     uint64
+	Collisions  uint64
+	Ibytes      uint64
+	Obytes      uint64
+	Imcasts     uint64
+	Omcasts     uint64
+	Iqdrops     uint64
+	Noproto     uint64
+	Hwassist    uint64
+	Epoch       int64
+	Lastchange  Timeval
+}
+
+type IfaMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Addrs        int32
+	Flags        int32
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Metric       int32
+}
+
+type RtMsghdr struct {
+	Msglen       uint16
+	Version      uint8
+	Type         uint8
+	Index        uint16
+	Pad_godefs_0 [2]byte
+	Flags        int32
+	Addrs        int32
+	Pid          int32
+	Seq          int32
+	Errno        int32
+	Fmask        int32
+	Inits        uint64
+	Rmx          RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint64
+	Mtu      uint64
+	Hopcount uint64
+	Expire   uint64
+	Recvpipe uint64
+	Sendpipe uint64
+	Ssthresh uint64
+	Rtt      uint64
+	Rttvar   uint64
+	Pksent   uint64
+	Weight   uint64
+	Filler   [3]uint64
+}
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 0603168..d98d6af 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -18,6 +18,7 @@ const (
 	SizeofSockaddrUnix      = 0x6e
 	SizeofSockaddrLinklayer = 0x14
 	SizeofLinger            = 0x8
+	SizeofIpMreq            = 0x8
 	SizeofMsghdr            = 0x1c
 	SizeofCmsghdr           = 0xc
 	SizeofUcred             = 0xc
@@ -45,37 +46,37 @@ type Timeval struct {
 }
 
 type Timex struct {
-	Modes     uint32
-	Offset    int32
-	Freq      int32
-	Maxerror  int32
-	Esterror  int32
-	Status    int32
-	Constant  int32
-	Precision int32
-	Tolerance int32
-	Time      Timeval
-	Tick      int32
-	Ppsfreq   int32
-	Jitter    int32
-	Shift     int32
-	Stabil    int32
-	Jitcnt    int32
-	Calcnt    int32
-	Errcnt    int32
-	Stbcnt    int32
-	Tai       int32
-	Pad0      int32
-	Pad1      int32
-	Pad2      int32
-	Pad3      int32
-	Pad4      int32
-	Pad5      int32
-	Pad6      int32
-	Pad7      int32
-	Pad8      int32
-	Pad9      int32
-	Pad10     int32
+	Modes         uint32
+	Offset        int32
+	Freq          int32
+	Maxerror      int32
+	Esterror      int32
+	Status        int32
+	Constant      int32
+	Precision     int32
+	Tolerance     int32
+	Time          Timeval
+	Tick          int32
+	Ppsfreq       int32
+	Jitter        int32
+	Shift         int32
+	Stabil        int32
+	Jitcnt        int32
+	Calcnt        int32
+	Errcnt        int32
+	Stbcnt        int32
+	Tai           int32
+	Pad_godefs_0  int32
+	Pad_godefs_1  int32
+	Pad_godefs_2  int32
+	Pad_godefs_3  int32
+	Pad_godefs_4  int32
+	Pad_godefs_5  int32
+	Pad_godefs_6  int32
+	Pad_godefs_7  int32
+	Pad_godefs_8  int32
+	Pad_godefs_9  int32
+	Pad_godefs_10 int32
 }
 
 type Time_t int32
@@ -119,24 +120,24 @@ type Rlimit struct {
 type _Gid_t uint32
 
 type Stat_t struct {
-	Dev       uint64
-	X__pad1   uint16
-	Pad0      [2]byte
-	X__st_ino uint32
-	Mode      uint32
-	Nlink     uint32
-	Uid       uint32
-	Gid       uint32
-	Rdev      uint64
-	X__pad2   uint16
-	Pad1      [2]byte
-	Size      int64
-	Blksize   int32
-	Blocks    int64
-	Atim      Timespec
-	Mtim      Timespec
-	Ctim      Timespec
-	Ino       uint64
+	Dev          uint64
+	X__pad1      uint16
+	Pad_godefs_0 [2]byte
+	X__st_ino    uint32
+	Mode         uint32
+	Nlink        uint32
+	Uid          uint32
+	Gid          uint32
+	Rdev         uint64
+	X__pad2      uint16
+	Pad_godefs_1 [2]byte
+	Size         int64
+	Blksize      int32
+	Blocks       int64
+	Atim         Timespec
+	Mtim         Timespec
+	Ctim         Timespec
+	Ino          uint64
 }
 
 type Statfs_t struct {
@@ -154,12 +155,12 @@ type Statfs_t struct {
 }
 
 type Dirent struct {
-	Ino    uint64
-	Off    int64
-	Reclen uint16
-	Type   uint8
-	Name   [256]int8
-	Pad0   [1]byte
+	Ino          uint64
+	Off          int64
+	Reclen       uint16
+	Type         uint8
+	Name         [256]int8
+	Pad_godefs_0 [1]byte
 }
 
 type RawSockaddrInet4 struct {
@@ -214,6 +215,11 @@ type Iovec struct {
 	Len  uint32
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
 	Name       *byte
 	Namelen    uint32
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index b975a87..db5c32c 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -18,6 +18,7 @@ const (
 	SizeofSockaddrUnix      = 0x6e
 	SizeofSockaddrLinklayer = 0x14
 	SizeofLinger            = 0x8
+	SizeofIpMreq            = 0x8
 	SizeofMsghdr            = 0x38
 	SizeofCmsghdr           = 0x10
 	SizeofUcred             = 0xc
@@ -45,40 +46,40 @@ type Timeval struct {
 }
 
 type Timex struct {
-	Modes     uint32
-	Pad0      [4]byte
-	Offset    int64
-	Freq      int64
-	Maxerror  int64
-	Esterror  int64
-	Status    int32
-	Pad1      [4]byte
-	Constant  int64
-	Precision int64
-	Tolerance int64
-	Time      Timeval
-	Tick      int64
-	Ppsfreq   int64
-	Jitter    int64
-	Shift     int32
-	Pad2      [4]byte
-	Stabil    int64
-	Jitcnt    int64
-	Calcnt    int64
-	Errcnt    int64
-	Stbcnt    int64
-	Tai       int32
-	Pad3      int32
-	Pad4      int32
-	Pad5      int32
-	Pad6      int32
-	Pad7      int32
-	Pad8      int32
-	Pad9      int32
-	Pad10     int32
-	Pad11     int32
-	Pad12     int32
-	Pad13     int32
+	Modes         uint32
+	Pad_godefs_0  [4]byte
+	Offset        int64
+	Freq          int64
+	Maxerror      int64
+	Esterror      int64
+	Status        int32
+	Pad_godefs_1  [4]byte
+	Constant      int64
+	Precision     int64
+	Tolerance     int64
+	Time          Timeval
+	Tick          int64
+	Ppsfreq       int64
+	Jitter        int64
+	Shift         int32
+	Pad_godefs_2  [4]byte
+	Stabil        int64
+	Jitcnt        int64
+	Calcnt        int64
+	Errcnt        int64
+	Stbcnt        int64
+	Tai           int32
+	Pad_godefs_3  int32
+	Pad_godefs_4  int32
+	Pad_godefs_5  int32
+	Pad_godefs_6  int32
+	Pad_godefs_7  int32
+	Pad_godefs_8  int32
+	Pad_godefs_9  int32
+	Pad_godefs_10 int32
+	Pad_godefs_11 int32
+	Pad_godefs_12 int32
+	Pad_godefs_13 int32
 }
 
 type Time_t int64
@@ -154,12 +155,12 @@ type Statfs_t struct {
 }
 
 type Dirent struct {
-	Ino    uint64
-	Off    int64
-	Reclen uint16
-	Type   uint8
-	Name   [256]int8
-	Pad0   [5]byte
+	Ino          uint64
+	Off          int64
+	Reclen       uint16
+	Type         uint8
+	Name         [256]int8
+	Pad_godefs_0 [5]byte
 }
 
 type RawSockaddrInet4 struct {
@@ -214,16 +215,21 @@ type Iovec struct {
 	Len  uint64
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
-	Name       *byte
-	Namelen    uint32
-	Pad0       [4]byte
-	Iov        *Iovec
-	Iovlen     uint64
-	Control    *byte
-	Controllen uint64
-	Flags      int32
-	Pad1       [4]byte
+	Name         *byte
+	Namelen      uint32
+	Pad_godefs_0 [4]byte
+	Iov          *Iovec
+	Iovlen       uint64
+	Control      *byte
+	Controllen   uint64
+	Flags        int32
+	Pad_godefs_1 [4]byte
 }
 
 type Cmsghdr struct {
@@ -280,22 +286,22 @@ type FdSet struct {
 }
 
 type Sysinfo_t struct {
-	Uptime    int64
-	Loads     [3]uint64
-	Totalram  uint64
-	Freeram   uint64
-	Sharedram uint64
-	Bufferram uint64
-	Totalswap uint64
-	Freeswap  uint64
-	Procs     uint16
-	Pad       uint16
-	Pad0      [4]byte
-	Totalhigh uint64
-	Freehigh  uint64
-	Unit      uint32
-	X_f       [2]int8
-	Pad1      [4]byte
+	Uptime       int64
+	Loads        [3]uint64
+	Totalram     uint64
+	Freeram      uint64
+	Sharedram    uint64
+	Bufferram    uint64
+	Totalswap    uint64
+	Freeswap     uint64
+	Procs        uint16
+	Pad          uint16
+	Pad_godefs_0 [4]byte
+	Totalhigh    uint64
+	Freehigh     uint64
+	Unit         uint32
+	X_f          [0]int8
+	Pad_godefs_1 [4]byte
 }
 
 type Utsname struct {
@@ -308,12 +314,12 @@ type Utsname struct {
 }
 
 type Ustat_t struct {
-	Tfree  int32
-	Pad0   [4]byte
-	Tinode uint64
-	Fname  [6]int8
-	Fpack  [6]int8
-	Pad1   [4]byte
+	Tfree        int32
+	Pad_godefs_0 [4]byte
+	Tinode       uint64
+	Fname        [6]int8
+	Fpack        [6]int8
+	Pad_godefs_1 [4]byte
 }
 
 type EpollEvent struct {
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 450f200..236155b 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -23,6 +23,7 @@ const (
 	SizeofSockaddrUnix      = 0x6e
 	SizeofSockaddrLinklayer = 0x14
 	SizeofLinger            = 0x8
+	SizeofIpMreq            = 0x8
 	SizeofMsghdr            = 0x1c
 	SizeofCmsghdr           = 0xc
 	SizeofUcred             = 0xc
@@ -221,6 +222,11 @@ type Iovec struct {
 	Len  uint32
 }
 
+type IpMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
 type Msghdr struct {
 	Name       *byte
 	Namelen    uint32
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index b1271af..e9ab354 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -74,6 +74,7 @@ const (
 	OPEN_ALWAYS       = 4
 	TRUNCATE_EXISTING = 5
 
+	HANDLE_FLAG_INHERIT    = 0x00000001
 	STARTF_USESTDHANDLES   = 0x00000100
 	DUPLICATE_CLOSE_SOURCE = 0x00000001
 	DUPLICATE_SAME_ACCESS  = 0x00000002
@@ -172,6 +173,12 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
+type SecurityAttributes struct {
+	Length             uint32
+	SecurityDescriptor uintptr
+	InheritHandle      uint32
+}
+
 type Overlapped struct {
 	Internal     uint32
 	InternalHigh uint32
diff --git a/src/pkg/template/template.go b/src/pkg/template/template.go
index 078463a..36fd06d 100644
--- a/src/pkg/template/template.go
+++ b/src/pkg/template/template.go
@@ -47,12 +47,20 @@
 		{field1 field2 ...}
 		{field|formatter}
 		{field1 field2...|formatter}
+		{field|formatter1|formatter2}
 
 	Insert the value of the fields into the output. Each field is
 	first looked for in the cursor, as in .section and .repeated.
 	If it is not found, the search continues in outer sections
 	until the top level is reached.
 
+	If the field value is a pointer, leading asterisks indicate
+	that the value to be inserted should be evaluated through the
+	pointer.  For example, if x.p is of type *int, {x.p} will
+	insert the value of the pointer but {*x.p} will insert the
+	value of the underlying integer.  If the value is nil or not a
+	pointer, asterisks have no effect.
+
 	If a formatter is specified, it must be named in the formatter
 	map passed to the template set up routines or in the default
 	set ("html","str","") and is used to process the data for
@@ -62,10 +70,15 @@
 	values at the instantiation, and formatter is its name at
 	the invocation site.  The default formatter just concatenates
 	the string representations of the fields.
+
+	Multiple formatters separated by the pipeline character | are
+	executed sequentially, with each formatter receiving the bytes
+	emitted by the one to its left.
 */
 package template
 
 import (
+	"bytes"
 	"container/vector"
 	"fmt"
 	"io"
@@ -131,9 +144,9 @@ type literalElement struct {
 
 // A variable invocation to be evaluated
 type variableElement struct {
-	linenum   int
-	word      []string // The fields in the invocation.
-	formatter string   // TODO(r): implement pipelines
+	linenum int
+	word    []string // The fields in the invocation.
+	fmts    []string // Names of formatters to apply. len(fmts) > 0
 }
 
 // A .section block, possibly with a .or
@@ -169,13 +182,14 @@ type Template struct {
 // the data item descends into the fields associated with sections, etc.
 // Parent is used to walk upwards to find variables higher in the tree.
 type state struct {
-	parent *state        // parent in hierarchy
-	data   reflect.Value // the driver data for this section etc.
-	wr     io.Writer     // where to send output
+	parent *state          // parent in hierarchy
+	data   reflect.Value   // the driver data for this section etc.
+	wr     io.Writer       // where to send output
+	buf    [2]bytes.Buffer // alternating buffers used when chaining formatters
 }
 
 func (parent *state) clone(data reflect.Value) *state {
-	return &state{parent, data, parent.wr}
+	return &state{parent: parent, data: data, wr: parent.wr}
 }
 
 // New creates a new template with the specified formatter map (which
@@ -402,38 +416,43 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
 	return
 }
 
+// formatter returns the Formatter with the given name in the Template, or nil if none exists.
+func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
+	if t.fmap != nil {
+		if fn := t.fmap[name]; fn != nil {
+			return fn
+		}
+	}
+	return builtins[name]
+}
+
 // -- Parsing
 
 // Allocate a new variable-evaluation element.
-func (t *Template) newVariable(words []string) (v *variableElement) {
-	// The words are tokenized elements from the {item}. The last one may be of
-	// the form "|fmt".  For example: {a b c|d}
-	formatter := ""
+func (t *Template) newVariable(words []string) *variableElement {
+	// After the final space-separated argument, formatters may be specified separated
+	// by pipe symbols, for example: {a b c|d|e}
+
+	// Until we learn otherwise, formatters contains a single name: "", the default formatter.
+	formatters := []string{""}
 	lastWord := words[len(words)-1]
-	bar := strings.Index(lastWord, "|")
+	bar := strings.IndexRune(lastWord, '|')
 	if bar >= 0 {
 		words[len(words)-1] = lastWord[0:bar]
-		formatter = lastWord[bar+1:]
+		formatters = strings.Split(lastWord[bar+1:], "|", -1)
 	}
-	// Probably ok, so let's build it.
-	v = &variableElement{t.linenum, words, formatter}
 
 	// We could remember the function address here and avoid the lookup later,
 	// but it's more dynamic to let the user change the map contents underfoot.
 	// We do require the name to be present, though.
 
 	// Is it in user-supplied map?
-	if t.fmap != nil {
-		if _, ok := t.fmap[formatter]; ok {
-			return
+	for _, f := range formatters {
+		if t.formatter(f) == nil {
+			t.parseError("unknown formatter: %q", f)
 		}
 	}
-	// Is it in builtin map?
-	if _, ok := builtins[formatter]; ok {
-		return
-	}
-	t.parseError("unknown formatter: %s", formatter)
-	return
+	return &variableElement{t.linenum, words, formatters}
 }
 
 // Grab the next item.  If it's simple, just append it to the template.
@@ -633,6 +652,23 @@ func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value
 	return v
 }
 
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error.  If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+	for i := numLevels; v != nil && i > 0; i++ {
+		if p, ok := v.(*reflect.PtrValue); ok {
+			if p.IsNil() {
+				return v
+			}
+			v = p.Elem()
+		} else {
+			break
+		}
+	}
+	return v
+}
+
 // Walk v through pointers and interfaces, extracting the elements within.
 func indirect(v reflect.Value) reflect.Value {
 loop:
@@ -654,12 +690,16 @@ loop:
 // The special name "@" (the "cursor") denotes the current data.
 // The value coming in (st.data) might need indirecting to reach
 // a struct while the return value is not indirected - that is,
-// it represents the actual named field.
+// it represents the actual named field. Leading stars indicate
+// levels of indirection to be applied to the value.
 func (t *Template) findVar(st *state, s string) reflect.Value {
+	data := st.data
+	flattenedName := strings.TrimLeft(s, "*")
+	numStars := len(s) - len(flattenedName)
+	s = flattenedName
 	if s == "@" {
-		return st.data
+		return indirectPtr(data, numStars)
 	}
-	data := st.data
 	for _, elem := range strings.Split(s, ".", -1) {
 		// Look up field; data must be a struct or map.
 		data = t.lookup(st, data, elem)
@@ -667,7 +707,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
 			return nil
 		}
 	}
-	return data
+	return indirectPtr(data, numStars)
 }
 
 // Is there no data to look at?
@@ -705,28 +745,31 @@ func (t *Template) varValue(name string, st *state) reflect.Value {
 	return field
 }
 
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+	fn := t.formatter(fmt)
+	if fn == nil {
+		t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
+	}
+	fn(wr, fmt, val...)
+}
+
 // Evaluate a variable, looking up through the parent if necessary.
 // If it has a formatter attached ({var|formatter}) run that too.
 func (t *Template) writeVariable(v *variableElement, st *state) {
-	formatter := v.formatter
 	// Turn the words of the invocation into values.
 	val := make([]interface{}, len(v.word))
 	for i, word := range v.word {
 		val[i] = t.varValue(word, st).Interface()
 	}
-	// is it in user-supplied map?
-	if t.fmap != nil {
-		if fn, ok := t.fmap[formatter]; ok {
-			fn(st.wr, formatter, val...)
-			return
-		}
-	}
-	// is it in builtin map?
-	if fn, ok := builtins[formatter]; ok {
-		fn(st.wr, formatter, val...)
-		return
+
+	for i, fmt := range v.fmts[:len(v.fmts)-1] {
+		b := &st.buf[i&1]
+		b.Reset()
+		t.format(b, fmt, val, v, st)
+		val = val[0:1]
+		val[0] = b.Bytes()
 	}
-	t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.word[0])
+	t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
 }
 
 // Execute element i.  Return next index to execute.
@@ -929,12 +972,12 @@ func (t *Template) ParseFile(filename string) (err os.Error) {
 
 // Execute applies a parsed template to the specified data object,
 // generating output to wr.
-func (t *Template) Execute(data interface{}, wr io.Writer) (err os.Error) {
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
 	// Extract the driver data.
 	val := reflect.NewValue(data)
 	defer checkError(&err)
 	t.p = 0
-	t.execute(0, t.elems.Len(), &state{nil, val, wr})
+	t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
 	return nil
 }
 
diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go
index 3842b6d..d21a539 100644
--- a/src/pkg/template/template_test.go
+++ b/src/pkg/template/template_test.go
@@ -31,8 +31,10 @@ type U struct {
 
 type S struct {
 	Header        string
+	HeaderPtr     *string
 	Integer       int
-	Raw           string
+	IntegerPtr    *int
+	NilPtr        *int
 	InnerT        T
 	InnerPointerT *T
 	Data          []T
@@ -47,7 +49,7 @@ type S struct {
 	JSON          interface{}
 	Innermap      U
 	Stringmap     map[string]string
-	Bytes         []byte
+	Ptrmap        map[string]*string
 	Iface         interface{}
 	Ifaceptr      interface{}
 }
@@ -118,6 +120,24 @@ var tests = []*Test{
 		out: "Header=77\n",
 	},
 
+	&Test{
+		in: "Pointers: {*HeaderPtr}={*IntegerPtr}\n",
+
+		out: "Pointers: Header=77\n",
+	},
+
+	&Test{
+		in: "Stars but not pointers: {*Header}={*Integer}\n",
+
+		out: "Stars but not pointers: Header=77\n",
+	},
+
+	&Test{
+		in: "nil pointer: {*NilPtr}={*Integer}\n",
+
+		out: "nil pointer: <nil>=77\n",
+	},
+
 	// Method at top level
 	&Test{
 		in: "ptrmethod={PointerMethod}\n",
@@ -312,38 +332,6 @@ var tests = []*Test{
 		out: "ItemNumber1=ValueNumber1\n",
 	},
 
-
-	// Formatters
-	&Test{
-		in: "{.section Pdata }\n" +
-			"{Header|uppercase}={Integer|+1}\n" +
-			"{Header|html}={Integer|str}\n" +
-			"{.end}\n",
-
-		out: "HEADER=78\n" +
-			"Header=77\n",
-	},
-
-	&Test{
-		in: "{.section Pdata }\n" +
-			"{Header|uppercase}={Integer Header|multiword}\n" +
-			"{Header|html}={Header Integer|multiword}\n" +
-			"{Header|html}={Header Integer}\n" +
-			"{.end}\n",
-
-		out: "HEADER=<77><Header>\n" +
-			"Header=<Header><77>\n" +
-			"Header=Header77\n",
-	},
-
-	&Test{
-		in: "{Raw}\n" +
-			"{Raw|html}\n",
-
-		out: "&<>!@ #$%^\n" +
-			"&amp;&lt;&gt;!@ #$%^\n",
-	},
-
 	&Test{
 		in: "{.section Emptystring}emptystring{.end}\n" +
 			"{.section Header}header{.end}\n",
@@ -358,12 +346,6 @@ var tests = []*Test{
 		out: "1\n4\n",
 	},
 
-	&Test{
-		in: "{Bytes}",
-
-		out: "hello",
-	},
-
 	// Maps
 
 	&Test{
@@ -407,6 +389,20 @@ var tests = []*Test{
 		out: "\tstringresult\n" +
 			"\tstringresult\n",
 	},
+	&Test{
+		in: "{*Ptrmap.stringkey1}\n",
+
+		out: "pointedToString\n",
+	},
+	&Test{
+		in: "{.repeated section Ptrmap}\n" +
+			"{*@}\n" +
+			"{.end}",
+
+		out: "pointedToString\n" +
+			"pointedToString\n",
+	},
+
 
 	// Interface values
 
@@ -460,8 +456,9 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
 	s := new(S)
 	// initialized by hand for clarity.
 	s.Header = "Header"
+	s.HeaderPtr = &s.Header
 	s.Integer = 77
-	s.Raw = "&<>!@ #$%^"
+	s.IntegerPtr = &s.Integer
 	s.InnerT = t1
 	s.Data = []T{t1, t2}
 	s.Pdata = []*T{&t1, &t2}
@@ -480,7 +477,10 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
 	s.Stringmap = make(map[string]string)
 	s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
 	s.Stringmap["stringkey2"] = "stringresult"
-	s.Bytes = []byte("hello")
+	s.Ptrmap = make(map[string]*string)
+	x := "pointedToString"
+	s.Ptrmap["stringkey1"] = &x // the same value so repeated section is order-independent
+	s.Ptrmap["stringkey2"] = &x
 	s.Iface = []int{1, 2, 3}
 	s.Ifaceptr = &T{"Item", "Value"}
 
@@ -492,7 +492,7 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
 			t.Error("unexpected parse error: ", err)
 			continue
 		}
-		err = tmpl.Execute(s, &buf)
+		err = tmpl.Execute(&buf, s)
 		if test.err == "" {
 			if err != nil {
 				t.Error("unexpected execute error:", err)
@@ -517,7 +517,7 @@ func TestMapDriverType(t *testing.T) {
 		t.Error("unexpected parse error:", err)
 	}
 	var b bytes.Buffer
-	err = tmpl.Execute(mp, &b)
+	err = tmpl.Execute(&b, mp)
 	if err != nil {
 		t.Error("unexpected execute error:", err)
 	}
@@ -535,7 +535,7 @@ func TestMapNoEntry(t *testing.T) {
 		t.Error("unexpected parse error:", err)
 	}
 	var b bytes.Buffer
-	err = tmpl.Execute(mp, &b)
+	err = tmpl.Execute(&b, mp)
 	if err != nil {
 		t.Error("unexpected execute error:", err)
 	}
@@ -552,7 +552,7 @@ func TestStringDriverType(t *testing.T) {
 		t.Error("unexpected parse error:", err)
 	}
 	var b bytes.Buffer
-	err = tmpl.Execute("hello", &b)
+	err = tmpl.Execute(&b, "hello")
 	if err != nil {
 		t.Error("unexpected execute error:", err)
 	}
@@ -569,7 +569,7 @@ func TestTwice(t *testing.T) {
 		t.Error("unexpected parse error:", err)
 	}
 	var b bytes.Buffer
-	err = tmpl.Execute("hello", &b)
+	err = tmpl.Execute(&b, "hello")
 	if err != nil {
 		t.Error("unexpected parse error:", err)
 	}
@@ -578,7 +578,7 @@ func TestTwice(t *testing.T) {
 	if s != expect {
 		t.Errorf("failed passing string as data: expected %q got %q", expect, s)
 	}
-	err = tmpl.Execute("hello", &b)
+	err = tmpl.Execute(&b, "hello")
 	if err != nil {
 		t.Error("unexpected parse error:", err)
 	}
@@ -614,7 +614,7 @@ func TestCustomDelims(t *testing.T) {
 				continue
 			}
 			var b bytes.Buffer
-			err = tmpl.Execute("hello", &b)
+			err = tmpl.Execute(&b, "hello")
 			s := b.String()
 			if s != "template: hello"+ldelim+rdelim {
 				t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
@@ -635,7 +635,7 @@ func TestVarIndirection(t *testing.T) {
 	if err != nil {
 		t.Fatal("unexpected parse error:", err)
 	}
-	err = tmpl.Execute(s, &buf)
+	err = tmpl.Execute(&buf, s)
 	if err != nil {
 		t.Fatal("unexpected execute error:", err)
 	}
@@ -669,7 +669,7 @@ func TestReferenceToUnexported(t *testing.T) {
 	if err != nil {
 		t.Fatal("unexpected parse error:", err)
 	}
-	err = tmpl.Execute(u, &buf)
+	err = tmpl.Execute(&buf, u)
 	if err == nil {
 		t.Fatal("expected execute error, got none")
 	}
@@ -677,3 +677,87 @@ func TestReferenceToUnexported(t *testing.T) {
 		t.Fatal("expected unexported error; got", err)
 	}
 }
+
+var formatterTests = []Test{
+	{
+		in: "{Header|uppercase}={Integer|+1}\n" +
+			"{Header|html}={Integer|str}\n",
+
+		out: "HEADER=78\n" +
+			"Header=77\n",
+	},
+
+	{
+		in: "{Header|uppercase}={Integer Header|multiword}\n" +
+			"{Header|html}={Header Integer|multiword}\n" +
+			"{Header|html}={Header Integer}\n",
+
+		out: "HEADER=<77><Header>\n" +
+			"Header=<Header><77>\n" +
+			"Header=Header77\n",
+	},
+	{
+		in: "{Raw}\n" +
+			"{Raw|html}\n",
+
+		out: "a <&> b\n" +
+			"a &lt;&amp;&gt; b\n",
+	},
+	{
+		in:  "{Bytes}",
+		out: "hello",
+	},
+	{
+		in:  "{Raw|uppercase|html|html}",
+		out: "A &amp;lt;&amp;amp;&amp;gt; B",
+	},
+	{
+		in:  "{Header Integer|multiword|html}",
+		out: "&lt;Header&gt;&lt;77&gt;",
+	},
+	{
+		in:  "{Integer|no_formatter|html}",
+		err: `unknown formatter: "no_formatter"`,
+	},
+	{
+		in:  "{Integer|||||}", // empty string is a valid formatter
+		out: "77",
+	},
+}
+
+func TestFormatters(t *testing.T) {
+	data := map[string]interface{}{
+		"Header":  "Header",
+		"Integer": 77,
+		"Raw":     "a <&> b",
+		"Bytes":   []byte("hello"),
+	}
+	for _, c := range formatterTests {
+		tmpl, err := Parse(c.in, formatters)
+		if err != nil {
+			if c.err == "" {
+				t.Error("unexpected parse error:", err)
+				continue
+			}
+			if strings.Index(err.String(), c.err) < 0 {
+				t.Errorf("unexpected error: expected %q, got %q", c.err, err.String())
+				continue
+			}
+		} else {
+			if c.err != "" {
+				t.Errorf("For %q, expected error, got none.", c.in)
+				continue
+			}
+			buf := bytes.NewBuffer(nil)
+			err = tmpl.Execute(buf, data)
+			if err != nil {
+				t.Error("unexpected Execute error: ", err)
+				continue
+			}
+			actual := buf.String()
+			if actual != c.out {
+				t.Errorf("for %q: expected %q but got %q.", c.in, c.out, actual)
+			}
+		}
+	}
+}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 0e04935..edbf084 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -43,6 +43,7 @@ import (
 	"fmt"
 	"os"
 	"runtime"
+	"time"
 )
 
 // Report as tests are run; default is silent for success.
@@ -153,16 +154,19 @@ func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTe
 		if *chatty {
 			println("=== RUN ", tests[i].Name)
 		}
+		ns := -time.Nanoseconds()
 		t := new(T)
 		t.ch = make(chan *T)
 		go tRunner(t, &tests[i])
 		<-t.ch
+		ns += time.Nanoseconds()
+		tstr := fmt.Sprintf("(%.1f seconds)", float64(ns)/1e9)
 		if t.failed {
-			println("--- FAIL:", tests[i].Name)
+			println("--- FAIL:", tests[i].Name, tstr)
 			print(t.errors)
 			ok = false
 		} else if *chatty {
-			println("--- PASS:", tests[i].Name)
+			println("--- PASS:", tests[i].Name, tstr)
 			print(t.errors)
 		}
 	}
diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go
index 4d9c672..417b4ed 100644
--- a/src/pkg/xml/xml.go
+++ b/src/pkg/xml/xml.go
@@ -163,7 +163,7 @@ type Parser struct {
 	//	"quot": `"`,
 	Entity map[string]string
 
-	r         io.ReadByter
+	r         io.ByteReader
 	buf       bytes.Buffer
 	saved     *bytes.Buffer
 	stk       *stack
@@ -191,7 +191,7 @@ func NewParser(r io.Reader) *Parser {
 	// Assume that if reader has its own
 	// ReadByte, it's efficient enough.
 	// Otherwise, use bufio.
-	if rb, ok := r.(io.ReadByter); ok {
+	if rb, ok := r.(io.ByteReader); ok {
 		p.r = rb
 	} else {
 		p.r = bufio.NewReader(r)
diff --git a/src/run.bash b/src/run.bash
index 731e07e..a3e90cc 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -30,26 +30,17 @@ xcd() {
 	builtin cd "$GOROOT"/src/$1
 }
 
-maketest() {
-	for i
-	do
-		(
-			xcd $i
-			if $rebuild; then
-				gomake clean
-				time gomake
-				gomake install
-			fi
-			gomake test
-		) || exit $?
-	done
-}
-
-maketest \
-	pkg \
+if $rebuild; then
+	(xcd pkg
+		gomake clean
+		time gomake
+		gomake install
+	) || exit $i
+fi
 
-# all of these are subtly different
-# from what maketest does.
+(xcd pkg
+gomake test
+) || exit $?
 
 (xcd pkg/sync;
 if $rebuild; then
@@ -77,19 +68,17 @@ time gomake test
 ) || exit $?
 
 [ "$GOARCH" == arm ] ||
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../misc/cgo/stdio
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	gomake clean
-	./test.bash
-fi
+gomake clean
+./test.bash
 ) || exit $?
 
 [ "$GOARCH" == arm ] ||
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../misc/cgo/life
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	gomake clean
-	./test.bash
-fi
+gomake clean
+./test.bash
 ) || exit $?
 
 (xcd pkg/exp/ogle
@@ -97,16 +86,16 @@ gomake clean
 time gomake ogle
 ) || exit $?
 
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../doc/progs
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	time ./run
-fi
+time ./run
 ) || exit $?
 
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../doc/codelab/wiki
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	gomake test
-fi
+gomake clean
+gomake
+gomake test
 ) || exit $?
 
 for i in ../misc/dashboard/builder ../misc/goplay
@@ -118,15 +107,15 @@ do
 done
 
 [ "$GOARCH" == arm ] ||
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../test/bench
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	./timing.sh -test
-fi
+./timing.sh -test
 ) || exit $?
 
+[ "$GOHOSTOS" == windows ] ||
 (xcd ../test
-if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
-	./run
-fi
+./run
 ) || exit $?
 
+echo
+echo ALL TESTS PASSED
diff --git a/src/version.bash b/src/version.bash
index 2d29825..0e64831 100755
--- a/src/version.bash
+++ b/src/version.bash
@@ -11,17 +11,16 @@ fi
 
 # Get numerical revision
 VERSION=$(hg identify -n 2>/dev/null)
-if [ $? = 0 ]; then
-	TAG=$(hg identify -t | sed 's!/release!!')
-else
+if [ $? != 0 ]; then
 	OLD=$(hg identify | sed 1q)
 	VERSION=$(echo $OLD | awk '{print $1}')
-	TAG=$(echo $OLD | awk '{print $2}' | sed 's!/release!!')
 fi
 
-# Append tag if not 'tip'
-if [[ "$TAG" != "tip" ]]; then
-	VERSION="$VERSION $TAG"
+# Find most recent known release tag.
+TAG=$(hg tags | awk '$1~/^release\./ {print $1}' | sed -n 1p)
+
+if [ "$TAG" != "" ]; then
+	VERSION="$TAG $VERSION"
 fi
 
 echo $VERSION
diff --git a/test/bugs/bug322.dir/lib.go b/test/bugs/bug322.dir/lib.go
new file mode 100644
index 0000000..0de56d3
--- /dev/null
+++ b/test/bugs/bug322.dir/lib.go
@@ -0,0 +1,15 @@
+// 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 lib
+
+type T struct {
+	x int  // non-exported field
+}
+
+func (t T) M() {
+}
+
+func (t *T) PM() {
+}
diff --git a/test/bugs/bug322.dir/main.go b/test/bugs/bug322.dir/main.go
new file mode 100644
index 0000000..a99ed3b
--- /dev/null
+++ b/test/bugs/bug322.dir/main.go
@@ -0,0 +1,47 @@
+// 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 "./lib"
+
+type I interface {
+	M()
+}
+
+type PI interface {
+	PM()
+}
+
+func main() {
+	var t lib.T
+	t.M()
+	t.PM()
+
+	var i1 I = t
+	i1.M()
+	
+	// This combination is illegal because
+	// PM requires a pointer receiver.
+	// var pi1 PI = t
+	// pi1.PM()
+
+	var pt = &t
+	pt.M()
+	pt.PM()
+
+	var i2 I = pt
+	i2.M()
+
+	var pi2 PI = pt
+	pi2.PM()
+}
+
+/*
+These should not be errors anymore:
+
+bug322.dir/main.go:19: implicit assignment of unexported field 'x' of lib.T in method receiver
+bug322.dir/main.go:22: implicit assignment of unexported field 'x' of lib.T in assignment
+bug322.dir/main.go:31: implicit assignment of unexported field 'x' of lib.T in method receiver
+*/
\ No newline at end of file
diff --git a/test/bugs/bug322.go b/test/bugs/bug322.go
new file mode 100644
index 0000000..ad0e62d
--- /dev/null
+++ b/test/bugs/bug322.go
@@ -0,0 +1,8 @@
+// $G $D/$F.dir/lib.go && $G $D/$F.dir/main.go && $L main.$A && ./$A.out || echo BUG: fails incorrectly
+
+// 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.
+
+// Test case for issue 1402.
+ignored
diff --git a/test/chan/select5.go b/test/chan/select5.go
index 0678b8d..e7ca9e0 100644
--- a/test/chan/select5.go
+++ b/test/chan/select5.go
@@ -49,7 +49,7 @@ func main() {
 }
 
 func run(t *template.Template, a interface{}, out io.Writer) {
-	if err := t.Execute(a, out); err != nil {
+	if err := t.Execute(out, a); err != nil {
 		panic(err)
 	}
 }
diff --git a/test/fixedbugs/bug320.go b/test/fixedbugs/bug320.go
new file mode 100644
index 0000000..06d41f2
--- /dev/null
+++ b/test/fixedbugs/bug320.go
@@ -0,0 +1,45 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// 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 main() {
+	c := make(chan int, 1)
+	dummy := make(chan int)
+	v := 0x12345678
+	for i := 0; i < 10; i++ {
+		// 6g had a bug that caused select to pass &t to
+		// selectrecv before allocating the memory for t,
+		// which caused non-deterministic crashes.
+		// This test looks for the bug by checking that the
+		// value received actually ends up in t.
+		// If the allocation happens after storing through
+		// whatever garbage &t holds, the later reference
+		// to t in the case body will use the new pointer and
+		// not see the received value.
+		v += 0x1020304
+		c <- v
+		select {
+		case t := <-c:
+			go func() {
+				f(t)
+			}()
+			escape(&t)
+			if t != v {
+				println(i, v, t)
+				panic("wrong values")
+			}
+		case dummy <- 1:
+		}
+	}
+}
+
+func escape(*int) {
+}
+
+func f(int) {
+}
+
diff --git a/test/fixedbugs/bug321.go b/test/fixedbugs/bug321.go
new file mode 100644
index 0000000..d0595ff
--- /dev/null
+++ b/test/fixedbugs/bug321.go
@@ -0,0 +1,30 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug321
+
+// 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.
+
+// Troublesome floating point constants. Issue 1463.
+
+package main
+
+import "fmt"
+
+func check(test string, got, want float64) bool {
+	if got != want {
+		fmt.Println(test, "got", got, "want", want)
+		return false
+	}
+	return true
+}
+
+func main() {
+	good := true
+	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+	good = good && check("2.2250738585072012e-308", 2.2250738585072012e-308, 2.2250738585072014e-308)
+	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	good = good && check("2.2250738585072011e-308", 2.2250738585072011e-308, 2.225073858507201e-308)
+	if !good {
+		panic("fail")
+	}
+}
diff --git a/test/fixedbugs/bug322.go b/test/fixedbugs/bug322.go
new file mode 100644
index 0000000..bfb5283
--- /dev/null
+++ b/test/fixedbugs/bug322.go
@@ -0,0 +1,20 @@
+// errchk $G $D/$F.go
+
+// 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
+
+type T struct{}
+type P *T
+
+func (t *T) Meth() {}
+func (t T) Meth2() {}
+
+func main() {
+	t := &T{}
+	p := P(t)
+	p.Meth()  // ERROR "undefined \(type P"
+	p.Meth2() // ERROR "undefined \(type P"
+}
\ No newline at end of file
diff --git a/test/golden.out b/test/golden.out
index 425771b..7883973 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -158,3 +158,9 @@ panic: interface conversion: interface is main.T, not main.T
 
 
 == bugs/
+
+=========== bugs/bug322.go
+bugs/bug322.dir/main.go:19: implicit assignment of unexported field 'x' of lib.T in method receiver
+bugs/bug322.dir/main.go:22: implicit assignment of unexported field 'x' of lib.T in assignment
+bugs/bug322.dir/main.go:31: implicit assignment of unexported field 'x' of lib.T in method receiver
+BUG: fails incorrectly
diff --git a/test/run b/test/run
index ec01952..28d0caa 100755
--- a/test/run
+++ b/test/run
@@ -42,9 +42,7 @@ TMP2FILE=/tmp/gotest2-$$-$USER
 
 # don't run the machine out of memory: limit individual processes to 4GB.
 # on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
-# Linux charges reserved but not mapped addresses to ulimit -v
-# so we have to use ulimit -m.
-ulimit -m 4000000
+ulimit -v 4000000
 
 # no core files please
 ulimit -c 0

-- 
Packaging for Google Go



More information about the Pkg-google-commits mailing list