mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
68 Commits
dev.corety
...
go1.2rc5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4abdb873be | ||
|
|
1ca6226dda | ||
|
|
6d8aa1bcbb | ||
|
|
0bb20c6189 | ||
|
|
3409e2a2e6 | ||
|
|
a5940dddba | ||
|
|
8a28f58bc9 | ||
|
|
af4b9ae6e1 | ||
|
|
61af4f905b | ||
|
|
cd618b24a6 | ||
|
|
268d4631ae | ||
|
|
2b6571cdfa | ||
|
|
02c5ab4f87 | ||
|
|
9af8f45258 | ||
|
|
021476db3b | ||
|
|
1c961995ae | ||
|
|
1bca9371e7 | ||
|
|
6ec8f31510 | ||
|
|
f0189653ca | ||
|
|
f7edec22f7 | ||
|
|
9cb593dc89 | ||
|
|
db1c08e7a1 | ||
|
|
4f8794d3e7 | ||
|
|
065f8fd5a7 | ||
|
|
e491f0c376 | ||
|
|
2eb51b1ba8 | ||
|
|
4708b76f84 | ||
|
|
1d78c86897 | ||
|
|
28c1081208 | ||
|
|
8648d26c5f | ||
|
|
63ff715a55 | ||
|
|
6d10afd9e5 | ||
|
|
89f0148955 | ||
|
|
842a18c28f | ||
|
|
6ab0f588a8 | ||
|
|
71b3aca9fa | ||
|
|
a4085fdf10 | ||
|
|
d4bc355c56 | ||
|
|
2737f274f5 | ||
|
|
744d53cdeb | ||
|
|
2cce16c4a0 | ||
|
|
153283b74b | ||
|
|
038ff9dca1 | ||
|
|
724d28a03d | ||
|
|
7097ed7337 | ||
|
|
5962673984 | ||
|
|
efb3af3d5c | ||
|
|
7191e08599 | ||
|
|
0911539937 | ||
|
|
ce1a9fcbf5 | ||
|
|
cc10ac750d | ||
|
|
df3e05d37c | ||
|
|
407b1130cd | ||
|
|
194b6a4bf2 | ||
|
|
f17adc0765 | ||
|
|
645a023474 | ||
|
|
77ac7fdcc8 | ||
|
|
bf5d7c6713 | ||
|
|
6cbfe8df5c | ||
|
|
34250ab212 | ||
|
|
11f1f82b30 | ||
|
|
e3597e3920 | ||
|
|
265ff83af6 | ||
|
|
c57029d43d | ||
|
|
287fa600ed | ||
|
|
000c1c5127 | ||
|
|
c1792398d4 | ||
|
|
309e16554a |
4
AUTHORS
4
AUTHORS
@@ -47,6 +47,7 @@ Anthony Starks <ajstarks@gmail.com>
|
||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
@@ -149,6 +150,7 @@ Hong Ruiqi <hongruiqi@gmail.com>
|
||||
Icarus Sparry <golang@icarus.freeuk.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
James Gray <james@james4k.com>
|
||||
@@ -218,6 +220,7 @@ Mats Lidell <mats.lidell@cag.se>
|
||||
Matt Jibson <matt.jibson@gmail.com>
|
||||
Matt Joiner <anacrolix@gmail.com>
|
||||
Matt Reiferson <mreiferson@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
Michael Chaten <mchaten@gmail.com>
|
||||
@@ -277,6 +280,7 @@ Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au>
|
||||
|
||||
@@ -80,6 +80,7 @@ Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||
Aron Nopanen <aron.nopanen@gmail.com>
|
||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||
Asim Shankar <asimshankar@gmail.com>
|
||||
Ato Araki <ato.araki@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
Austin Clements <aclements@csail.mit.edu>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
@@ -97,6 +98,7 @@ Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
Blake Mizerany <blake.mizerany@gmail.com>
|
||||
Bobby Powers <bobbypowers@gmail.com>
|
||||
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
||||
Brad Garcia <bgarcia@golang.org>
|
||||
Brendan O'Dea <bod@golang.org>
|
||||
Brian Dellisanti <briandellisanti@gmail.com>
|
||||
Brian G. Merrell <bgmerrell@gmail.com>
|
||||
@@ -220,6 +222,7 @@ Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Ivan Krasin <krasin@golang.org>
|
||||
Jacob Baskin <jbaskin@google.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
James Aguilar <jaguilar@google.com>
|
||||
James David Chalfant <james.chalfant@gmail.com>
|
||||
James Fysh <james.fysh@gmail.com>
|
||||
@@ -311,6 +314,7 @@ Marcel van Lohuizen <mpvl@golang.org>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Mark Zavislak <zavislak@google.com>
|
||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||
Marko Mikulicic <mkm@google.com>
|
||||
Markus Duft <markus.duft@salomon.at>
|
||||
Markus Sonderegger <marraison@gmail.com>
|
||||
Martin Neubauer <m.ne@gmx.net>
|
||||
@@ -322,6 +326,7 @@ Matt Jibson <matt.jibson@gmail.com>
|
||||
Matt Joiner <anacrolix@gmail.com>
|
||||
Matt Jones <mrjones@google.com>
|
||||
Matt Reiferson <mreiferson@gmail.com>
|
||||
Matthew Cottingham <mattcottingham@gmail.com>
|
||||
Matthew Dempsky <mdempsky@google.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Maxim Pimenov <mpimenov@google.com>
|
||||
@@ -398,6 +403,7 @@ Raif S. Naffah <go@naffah-raif.name>
|
||||
Raph Levien <raph@google.com>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Rob Pike <r@golang.org>
|
||||
@@ -407,6 +413,7 @@ Robert Figueiredo <robfig@gmail.com>
|
||||
Robert Griesemer <gri@golang.org>
|
||||
Robert Hencke <robert.hencke@gmail.com>
|
||||
Robert Obryk <robryk@gmail.com>
|
||||
Robert Snedegar <roberts@google.com>
|
||||
Robin Eklind <r.eklind.87@gmail.com>
|
||||
Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
|
||||
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
|
||||
|
||||
439
doc/asm.html
Normal file
439
doc/asm.html
Normal file
@@ -0,0 +1,439 @@
|
||||
<!--{
|
||||
"Title": "A Quick Guide to Go's Assembler",
|
||||
"Path": "/doc/asm"
|
||||
}-->
|
||||
|
||||
<h2 id="introduction">A Quick Guide to Go's Assembler</h2>
|
||||
|
||||
<p>
|
||||
This document is a quick outline of the unusual form of assembly language used by the <code>gc</code>
|
||||
suite of Go compilers (<code>6g</code>, <code>8g</code>, etc.).
|
||||
It is based on the input to the Plan 9 assemblers, which is documented in detail
|
||||
<a href="http://plan9.bell-labs.com/sys/doc/asm.html">on the Plan 9 site</a>.
|
||||
If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.
|
||||
This document provides a summary of the syntax and
|
||||
describes the peculiarities that apply when writing assembly code to interact with Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most important thing to know about Go's assembler is that it is not a direct representation of the underlying machine.
|
||||
Some of the details map precisely to the machine, but some do not.
|
||||
This is because the compiler suite (see
|
||||
<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">this description</a>)
|
||||
needs no assembler pass in the usual pipeline.
|
||||
Instead, the compiler emits a kind of incompletely defined instruction set, in binary form, which the linker
|
||||
then completes.
|
||||
In particular, the linker does instruction selection, so when you see an instruction like <code>MOV</code>
|
||||
what the linker actually generates for that operation might not be a move instruction at all, perhaps a clear or load.
|
||||
Or it might correspond exactly to the machine instruction with that name.
|
||||
In general, machine-specific operations tend to appear as themselves, while more general concepts like
|
||||
memory move and subroutine call and return are more abstract.
|
||||
The details vary with architecture, and we apologize for the imprecision; the situation is not well-defined.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The assembler program is a way to generate that intermediate, incompletely defined instruction sequence
|
||||
as input for the linker.
|
||||
If you want to see what the instructions look like in assembly for a given architecture, say amd64, there
|
||||
are many examples in the sources of the standard library, in packages such as
|
||||
<a href="/pkg/runtime/"><code>runtime</code></a> and
|
||||
<a href="/pkg/math/big/"><code>math/big</code></a>.
|
||||
You can also examine what the compiler emits as assembly code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cat x.go
|
||||
package main
|
||||
|
||||
func main() {
|
||||
println(3)
|
||||
}
|
||||
$ go tool 6g -S x.go # or: go build -gcflags -S x.go
|
||||
|
||||
--- prog list "main" ---
|
||||
0000 (x.go:3) TEXT main+0(SB),$8-0
|
||||
0001 (x.go:3) FUNCDATA $0,gcargs·0+0(SB)
|
||||
0002 (x.go:3) FUNCDATA $1,gclocals·0+0(SB)
|
||||
0003 (x.go:4) MOVQ $3,(SP)
|
||||
0004 (x.go:4) PCDATA $0,$8
|
||||
0005 (x.go:4) CALL ,runtime.printint+0(SB)
|
||||
0006 (x.go:4) PCDATA $0,$-1
|
||||
0007 (x.go:4) PCDATA $0,$0
|
||||
0008 (x.go:4) CALL ,runtime.printnl+0(SB)
|
||||
0009 (x.go:4) PCDATA $0,$-1
|
||||
0010 (x.go:5) RET ,
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
|
||||
for use by the garbage collector; they are introduced by the compiler.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To see what gets put in the binary after linking, add the <code>-a</code> flag to the linker:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go tool 6l -a x.6 # or: go build -ldflags -a x.go
|
||||
codeblk [0x2000,0x1d059) at offset 0x1000
|
||||
002000 main.main | (3) TEXT main.main+0(SB),$8
|
||||
002000 65488b0c25a0080000 | (3) MOVQ 2208(GS),CX
|
||||
002009 483b21 | (3) CMPQ SP,(CX)
|
||||
00200c 7707 | (3) JHI ,2015
|
||||
00200e e83da20100 | (3) CALL ,1c250+runtime.morestack00
|
||||
002013 ebeb | (3) JMP ,2000
|
||||
002015 4883ec08 | (3) SUBQ $8,SP
|
||||
002019 | (3) FUNCDATA $0,main.gcargs·0+0(SB)
|
||||
002019 | (3) FUNCDATA $1,main.gclocals·0+0(SB)
|
||||
002019 48c7042403000000 | (4) MOVQ $3,(SP)
|
||||
002021 | (4) PCDATA $0,$8
|
||||
002021 e8aad20000 | (4) CALL ,f2d0+runtime.printint
|
||||
002026 | (4) PCDATA $0,$-1
|
||||
002026 | (4) PCDATA $0,$0
|
||||
002026 e865d40000 | (4) CALL ,f490+runtime.printnl
|
||||
00202b | (4) PCDATA $0,$-1
|
||||
00202b 4883c408 | (5) ADDQ $8,SP
|
||||
00202f c3 | (5) RET ,
|
||||
...
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="symbols">Symbols</h3>
|
||||
|
||||
<p>
|
||||
Some symbols, such as <code>PC</code>, <code>R0</code> and <code>SP</code>, are predeclared and refer to registers.
|
||||
There are two other predeclared symbols, <code>SB</code> (static base) and <code>FP</code> (frame pointer).
|
||||
All user-defined symbols other than jump labels are written as offsets to these pseudo-registers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
|
||||
is the name <code>foo</code> as an address in memory.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>FP</code> pseudo-register is a virtual frame pointer
|
||||
used to refer to function arguments.
|
||||
The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.
|
||||
Thus <code>0(FP)</code> is the first argument to the function,
|
||||
<code>8(FP)</code> is the second (on a 64-bit machine), and so on.
|
||||
When referring to a function argument this way, it is conventional to place the name
|
||||
at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
|
||||
Some of the assemblers enforce this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
|
||||
For assembly functions with Go prototypes, <code>go vet</code> will check that the argument names
|
||||
and offsets match.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>SP</code> pseudo-register is a virtual stack pointer
|
||||
used to refer to frame-local variables and the arguments being
|
||||
prepared for function calls.
|
||||
It points to the top of the local stack frame, so references should use negative offsets
|
||||
in the range [−framesize, 0):
|
||||
<code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.
|
||||
On architectures with a real register named <code>SP</code>, the name prefix distinguishes
|
||||
references to the virtual stack pointer from references to the architectural <code>SP</code> register.
|
||||
That is, <code>x-8(SP)</code> and <code>-8(SP)</code> are different memory locations:
|
||||
the first refers to the virtual stack pointer pseudo-register, while the second refers to the
|
||||
hardware's <code>SP</code> register.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Instructions, registers, and assembler directives are always in UPPER CASE to remind you
|
||||
that assembly programming is a fraught endeavor.
|
||||
(Exceptions: the <code>m</code> and <code>g</code> register renamings on ARM.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In Go object files and binaries, the full name of a symbol is the
|
||||
package path followed by a period and the symbol name:
|
||||
<code>fmt.Printf</code> or <code>math/rand.Int</code>.
|
||||
Because the assembler's parser treats period and slash as punctuation,
|
||||
those strings cannot be used directly as identifier names.
|
||||
Instead, the assembler allows the middle dot character U+00B7
|
||||
and the division slash U+2215 in identifiers and rewrites them to
|
||||
plain period and slash.
|
||||
Within an assembler source file, the symbols above are written as
|
||||
<code>fmt·Printf</code> and <code>math∕rand·Int</code>.
|
||||
The assembly listings generated by the compilers when using the <code>-S</code> flag
|
||||
show the period and slash directly instead of the Unicode replacements
|
||||
required by the assemblers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Most hand-written assembly files do not include the full package path
|
||||
in symbol names, because the linker inserts the package path of the current
|
||||
object file at the beginning of any name starting with a period:
|
||||
in an assembly source file within the math/rand package implementation,
|
||||
the package's Int function can be referred to as <code>·Int</code>.
|
||||
This convention avoids the need to hard-code a package's import path in its
|
||||
own source code, making it easier to move the code from one location to another.
|
||||
</p>
|
||||
|
||||
<h3 id="directives">Directives</h3>
|
||||
|
||||
<p>
|
||||
The assembler uses various directives to bind text and data to symbol names.
|
||||
For example, here is a simple complete function definition. The <code>TEXT</code>
|
||||
directive declares the symbol <code>runtime·profileloop</code> and the instructions
|
||||
that follow form the body of the function.
|
||||
The last instruction in a <code>TEXT</code> block must be some sort of jump, usually a <code>RET</code> (pseudo-)instruction.
|
||||
(If it's not, the linker will append a jump-to-itself instruction; there is no fallthrough in <code>TEXTs</code>.)
|
||||
After the symbol, the arguments are flags (see below)
|
||||
and the frame size, a constant (but see below):
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
TEXT runtime·profileloop(SB),NOSPLIT,$8
|
||||
MOVQ $runtime·profileloop1(SB), CX
|
||||
MOVQ CX, 0(SP)
|
||||
CALL runtime·externalthreadhandler(SB)
|
||||
RET
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In the general case, the frame size is followed by an argument size, separated by a minus sign.
|
||||
(It's not an subtraction, just idiosyncratic syntax.)
|
||||
The frame size <code>$24-8</code> states that the function has a 24-byte frame
|
||||
and is called with 8 bytes of argument, which live on the caller's frame.
|
||||
If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
|
||||
the argument size must be provided.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that the symbol name uses a middle dot to separate the components and is specified as an offset from the
|
||||
static base pseudo-register <code>SB</code>.
|
||||
This function would be called from Go source for package <code>runtime</code> using the
|
||||
simple name <code>profileloop</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For <code>DATA</code> directives, the symbol is followed by a slash and the number
|
||||
of bytes the memory associated with the symbol occupies.
|
||||
The arguments are optional flags and the data itself.
|
||||
For instance,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
DATA runtime·isplan9(SB)/4, $1
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
declares the local symbol <code>runtime·isplan9</code> of size 4 and value 1.
|
||||
Again the symbol has the middle dot and is offset from <code>SB</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>GLOBL</code> directive declares a symbol to be global.
|
||||
The arguments are optional flags and the size of the data being declared as a global,
|
||||
which will have initial value all zeros unless a <code>DATA</code> directive
|
||||
has initialized it.
|
||||
The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.
|
||||
This example
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
GLOBL runtime·tlsoffset(SB),$4
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
declares <code>runtime·tlsoffset</code> to have size 4.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There may be one or two arguments to the directives.
|
||||
If there are two, the first is a bit mask of flags,
|
||||
which can be written as numeric expressions, added or or-ed together,
|
||||
or can be set symbolically for easier absorption by a human.
|
||||
Their values, defined in the file <code>src/cmd/ld/textflag.h</code>, are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>NOPROF</code> = 1
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
Don't profile the marked function. This flag is deprecated.
|
||||
</li>
|
||||
<li>
|
||||
<code>DUPOK</code> = 2
|
||||
<br>
|
||||
It is legal to have multiple instances of this symbol in a single binary.
|
||||
The linker will choose one of the duplicates to use.
|
||||
</li>
|
||||
<li>
|
||||
<code>NOSPLIT</code> = 4
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
Don't insert the preamble to check if the stack must be split.
|
||||
The frame for the routine, plus anything it calls, must fit in the
|
||||
spare space at the top of the stack segment.
|
||||
Used to protect routines such as the stack splitting code itself.
|
||||
</li>
|
||||
<li>
|
||||
<code>RODATA</code> = 8
|
||||
<br>
|
||||
(For <code>DATA</code> and <code>GLOBL</code> items.)
|
||||
Put this data in a read-only section.
|
||||
</li>
|
||||
<li>
|
||||
<code>NOPTR</code> = 16
|
||||
<br>
|
||||
(For <code>DATA</code> and <code>GLOBL</code> items.)
|
||||
This data contains no pointers and therefore does not need to be
|
||||
scanned by the garbage collector.
|
||||
</li>
|
||||
<li>
|
||||
<code>WRAPPER</code> = 32
|
||||
<br>
|
||||
(For <code>TEXT</code> items.)
|
||||
This is a wrapper function and should not count as disabling <code>recover</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="architectures">Architecture-specific details</h2>
|
||||
|
||||
<p>
|
||||
It is impractical to list all the instructions and other details for each machine.
|
||||
To see what instructions are defined for a given machine, say 32-bit Intel x86,
|
||||
look in the top-level header file for the corresponding linker, in this case <code>8l</code>.
|
||||
That is, the file <code>$GOROOT/src/cmd/8l/8.out.h</code> contains a C enumeration, called <code>as</code>,
|
||||
of the instructions and their spellings as known to the assembler and linker for that architecture.
|
||||
In that file you'll find a declaration that begins
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
enum as
|
||||
{
|
||||
AXXX,
|
||||
AAAA,
|
||||
AAAD,
|
||||
AAAM,
|
||||
AAAS,
|
||||
AADCB,
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Each instruction begins with a initial capital <code>A</code> in this list, so <code>AADCB</code>
|
||||
represents the <code>ADCB</code> (add carry byte) instruction.
|
||||
The enumeration is in alphabetical order, plus some late additions (<code>AXXX</code> occupies
|
||||
the zero slot as an invalid instruction).
|
||||
The sequence has nothing to do with the actual encoding of the machine instructions.
|
||||
Again, the linker takes care of that detail.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:
|
||||
<code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.
|
||||
This convention applies even on architectures where the usual mode is the opposite direction.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here follows some descriptions of key Go-specific details for the supported architectures.
|
||||
</p>
|
||||
|
||||
<h3 id="x86">32-bit Intel 386</h3>
|
||||
|
||||
<p>
|
||||
The runtime pointers to the <code>m</code> and <code>g</code> structures are maintained
|
||||
through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
|
||||
A OS-dependent macro <code>get_tls</code> is defined for the assembler if the source includes
|
||||
an architecture-dependent header file, like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include "zasm_GOOS_GOARCH.h"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Within the runtime, the <code>get_tls</code> macro loads its argument register
|
||||
with a pointer to a pair of words representing the <code>g</code> and <code>m</code> pointers.
|
||||
The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> looks like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
get_tls(CX)
|
||||
MOVL g(CX), AX // Move g into AX.
|
||||
MOVL m(CX), BX // Move m into BX.
|
||||
</pre>
|
||||
|
||||
<h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
|
||||
|
||||
<p>
|
||||
The assembly code to access the <code>m</code> and <code>g</code>
|
||||
pointers is the same as on the 386, except it uses <code>MOVQ</code> rather than
|
||||
<code>MOVL</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
get_tls(CX)
|
||||
MOVQ g(CX), AX // Move g into AX.
|
||||
MOVQ m(CX), BX // Move m into BX.
|
||||
</pre>
|
||||
|
||||
<h3 id="arm">ARM</h3>
|
||||
|
||||
<p>
|
||||
The registers <code>R9</code>, <code>R10</code>, and <code>R11</code>
|
||||
are reserved by the compiler and linker.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>R9</code> and <code>R10</code> point to the <code>m</code> (machine) and <code>g</code>
|
||||
(goroutine) structures, respectively.
|
||||
Within assembler source code, these pointers must be referred to as <code>m</code> and <code>g</code>;
|
||||
the names <code>R9</code> and <code>R10</code> are not recognized.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To make it easier for people and compilers to write assembly, the ARM linker
|
||||
allows general addressing forms and pseudo-operations like <code>DIV</code> or <code>MOD</code>
|
||||
that may not be expressible using a single hardware instruction.
|
||||
It implements these forms as multiple instructions, often using the <code>R11</code> register
|
||||
to hold temporary values.
|
||||
Hand-written assembly can use <code>R11</code>, but doing so requires
|
||||
being sure that the linker is not also using it to implement any of the other
|
||||
instructions in the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When defining a <code>TEXT</code>, specifying frame size <code>$-4</code>
|
||||
tells the linker that this is a leaf function that does not need to save <code>LR</code> on entry.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The name <code>SP</code> always refers to the virtual stack pointer described earlier.
|
||||
For the hardware register, use <code>R13</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
|
||||
|
||||
<p>
|
||||
The assemblers are designed to support the compiler so not all hardware instructions
|
||||
are defined for all architectures: if the compiler doesn't generate it, it might not be there.
|
||||
If you need to use a missing instruction, there are two ways to proceed.
|
||||
One is to update the assembler to support that instruction, which is straightforward
|
||||
but only worthwhile if it's likely the instruction will be used again.
|
||||
Instead, for simple one-off cases, it's possible to use the <code>BYTE</code>
|
||||
and <code>WORD</code> directives
|
||||
to lay down explicit data into the instruction stream within a <code>TEXT</code>.
|
||||
Here's how the 386 runtime defines the 64-bit atomic load function.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// uint64 atomicload64(uint64 volatile* addr);
|
||||
// so actually
|
||||
// void atomicload64(uint64 *res, uint64 volatile *addr);
|
||||
TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
|
||||
MOVL 4(SP), BX
|
||||
MOVL 8(SP), AX
|
||||
// MOVQ (%EAX), %MM0
|
||||
BYTE $0x0f; BYTE $0x6f; BYTE $0x00
|
||||
// MOVQ %MM0, 0(%EBX)
|
||||
BYTE $0x0f; BYTE $0x7f; BYTE $0x03
|
||||
// EMMS
|
||||
BYTE $0x0F; BYTE $0x77
|
||||
RET
|
||||
</pre>
|
||||
@@ -38,8 +38,8 @@ The GCC 4.7.1 release and all later 4.7 releases include a complete
|
||||
|
||||
<p>
|
||||
Due to timing, the GCC 4.8.0 and 4.8.1 releases are close to but not
|
||||
identical to Go 1.1. The GCC 4.8.2 release is expected to include a
|
||||
complete Go 1.1.1 implementation.
|
||||
identical to Go 1.1. The GCC 4.8.2 release includes a complete Go
|
||||
1.1.2 implementation.
|
||||
</p>
|
||||
|
||||
<h2 id="Source_code">Source code</h2>
|
||||
|
||||
@@ -137,12 +137,61 @@ This means that any loop that includes a (non-inlined) function call can
|
||||
be pre-empted, allowing other goroutines to run on the same thread.
|
||||
</p>
|
||||
|
||||
<h3 id="thread_limit">Limit on the number of threads</h3>
|
||||
|
||||
<p>
|
||||
Go 1.2 introduces a configurable limit (default 10,000) to the total number of threads
|
||||
a single program may have in its address space, to avoid resource starvation
|
||||
issues in some environments.
|
||||
Note that goroutines are multiplexed onto threads so this limit does not directly
|
||||
limit the number of goroutines, only the number that may be simultaneously blocked
|
||||
in a system call.
|
||||
In practice, the limit is hard to reach.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The new <a href="/pkg/runtime/debug/#SetMaxThreads"><code>SetMaxThreads</code></a> function in the
|
||||
<a href="/pkg/runtime/debug/"><code>runtime/debug</code></a> package controls the thread count limit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Few functions will be affected by the limit, but if a program dies because it hits the
|
||||
limit, it could be modified to call <code>SetMaxThreads</code> to set a higher count.
|
||||
Even better would be to refactor the program to need fewer threads, reducing consumption
|
||||
of kernel resources.
|
||||
</p>
|
||||
|
||||
<h3 id="stack_size">Stack size</h3>
|
||||
|
||||
<p>
|
||||
In Go 1.2, the minimum size of the stack when a goroutine is created has been lifted from 4KB to 8KB.
|
||||
Many programs were suffering performance problems with the old size, which had a tendency
|
||||
to introduce expensive stack-segment switching in performance-critical sections.
|
||||
The new number was determined by empirical testing.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At the other end, the new function <a href="/pkg/runtime/debug/#SetMaxStack"><code>SetMaxStack</code></a>
|
||||
in the <a href="/pkg/runtime/debug"><code>runtime/debug</code></a> package controls
|
||||
the <em>maximum</em> size of a single goroutine's stack.
|
||||
The default is 1GB on 64-bit systems and 250MB on 32-bit systems.
|
||||
Before Go 1.2, it was too easy for a runaway recursion to consume all the memory on a machine.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
The increased minimum stack size may cause programs with many goroutines to use
|
||||
more memory. There is no workaround, but plans for future releases
|
||||
include new stack management technology that should address the problem better.
|
||||
</p>
|
||||
|
||||
<h3 id="cgo_and_cpp">Cgo and C++</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/cgo/"><code>cgo</code></a> command will now invoke the C++
|
||||
compiler to build any pieces of the linked-to library that are written in C++; the
|
||||
documentation has more detail.
|
||||
compiler to build any pieces of the linked-to library that are written in C++;
|
||||
<a href="/cmd/cgo/">the documentation</a> has more detail.
|
||||
</p>
|
||||
|
||||
<h3 id="go_tools_godoc">Godoc and vet moved to the go.tools subrepository</h3>
|
||||
@@ -687,7 +736,8 @@ now treats channel and function fields of structures as if they were unexported,
|
||||
even if they are not. That is, it ignores them completely. Previously they would
|
||||
trigger an error, which could cause unexpected compatibility problems if an
|
||||
embedded structure added such a field.
|
||||
The package also now supports the generic encoding interfaces of the
|
||||
The package also now supports the generic <code>BinaryMarshaler</code> and
|
||||
<code>BinaryUnmarshaler</code> interfaces of the
|
||||
<a href="/pkg/encoding/"><code>encoding</code></a> package
|
||||
described above.
|
||||
</li>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of Oct 16, 2013",
|
||||
"Subtitle": "Version of Nov 13, 2013",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -1456,10 +1456,6 @@ by a value of type <code>T</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Any value may be assigned to the <a href="#Blank_identifier">blank identifier</a>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Blocks">Blocks</h2>
|
||||
|
||||
@@ -1516,6 +1512,11 @@ No identifier may be declared twice in the same block, and
|
||||
no identifier may be declared in both the file and package block.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="#Blank_identifier">blank identifier</a> may be used like any other identifier
|
||||
in a declaration, but it does not introduce a binding and thus is not declared.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Declaration = ConstDecl | TypeDecl | VarDecl .
|
||||
TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
|
||||
@@ -1585,8 +1586,10 @@ the body of any nested function.
|
||||
<h3 id="Blank_identifier">Blank identifier</h3>
|
||||
|
||||
<p>
|
||||
The <i>blank identifier</i>, represented by the underscore character <code>_</code>, may be used in a declaration like
|
||||
any other identifier but the declaration does not introduce a new <a href="#Declarations_and_scope">binding</a>.
|
||||
The <i>blank identifier</i> is represented by the underscore character <code>_</code>.
|
||||
It serves as an anonymous placeholder instead of a regular (non-blank)
|
||||
identifier and has special meaning in <a href="#Declarations_and_scope">declarations</a>,
|
||||
as an <a href="#Operands">operand</a>, and in <a href="#Assignments">assignments</a>.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -2077,8 +2080,8 @@ operators and functions to operands.
|
||||
|
||||
<p>
|
||||
Operands denote the elementary values in an expression. An operand may be a
|
||||
literal, a (possibly <a href="#Qualified_identifiers">qualified</a>) identifier
|
||||
denoting a
|
||||
literal, a (possibly <a href="#Qualified_identifiers">qualified</a>)
|
||||
non-<a href="#Blank_identifier">blank</a> identifier denoting a
|
||||
<a href="#Constant_declarations">constant</a>,
|
||||
<a href="#Variable_declarations">variable</a>, or
|
||||
<a href="#Function_declarations">function</a>,
|
||||
@@ -2086,6 +2089,11 @@ a <a href="#Method_expressions">method expression</a> yielding a function,
|
||||
or a parenthesized expression.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="#Blank_identifier">blank identifier</a> may appear as an
|
||||
operand only on the left-hand side of an <a href="#Assignments">assignment</a>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Operand = Literal | OperandName | MethodExpr | "(" Expression ")" .
|
||||
Literal = BasicLit | CompositeLit | FunctionLit .
|
||||
@@ -4255,7 +4263,8 @@ assign_op = [ add_op | mul_op ] "=" .
|
||||
|
||||
<p>
|
||||
Each left-hand side operand must be <a href="#Address_operators">addressable</a>,
|
||||
a map index expression, or the <a href="#Blank_identifier">blank identifier</a>.
|
||||
a map index expression, or (for <code>=</code> assignments only) the
|
||||
<a href="#Blank_identifier">blank identifier</a>.
|
||||
Operands may be parenthesized.
|
||||
</p>
|
||||
|
||||
@@ -4268,12 +4277,13 @@ a[i] = 23
|
||||
|
||||
<p>
|
||||
An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
|
||||
<code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
|
||||
<code>y</code> where <i>op</i> is a binary arithmetic operation equivalent
|
||||
to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
|
||||
<code>y</code> but evaluates <code>x</code>
|
||||
only once. The <i>op</i><code>=</code> construct is a single token.
|
||||
In assignment operations, both the left- and right-hand expression lists
|
||||
must contain exactly one single-valued expression.
|
||||
must contain exactly one single-valued expression, and the left-hand
|
||||
expression must not be the blank identifier.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -4298,21 +4308,26 @@ x, y = f()
|
||||
|
||||
<p>
|
||||
assigns the first value to <code>x</code> and the second to <code>y</code>.
|
||||
The <a href="#Blank_identifier">blank identifier</a> provides a
|
||||
way to ignore values returned by a multi-valued expression:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
x, _ = f() // ignore second value returned by f()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In the second form, the number of operands on the left must equal the number
|
||||
of expressions on the right, each of which must be single-valued, and the
|
||||
<i>n</i>th expression on the right is assigned to the <i>n</i>th
|
||||
operand on the left.
|
||||
operand on the left:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
one, two, three = '一', '二', '三'
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <a href="#Blank_identifier">blank identifier</a> provides a way to
|
||||
ignore right-hand side values in an assignment:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
_ = x // evaluate x but ignore it
|
||||
x, _ = f() // evaluate f() but ignore second result value
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The assignment proceeds in two phases.
|
||||
First, the operands of <a href="#Index_expressions">index expressions</a>
|
||||
@@ -4350,16 +4365,29 @@ for i, x[i] = range x { // set i, x[2] = 0, x[0]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In assignments, each value must be
|
||||
<a href="#Assignability">assignable</a> to the type of the
|
||||
operand to which it is assigned. If an untyped <a href="#Constants">constant</a>
|
||||
is assigned to a variable of interface type, the constant is <a href="#Conversions">converted</a>
|
||||
to type <code>bool</code>, <code>rune</code>, <code>int</code>, <code>float64</code>,
|
||||
<code>complex128</code> or <code>string</code>
|
||||
respectively, depending on whether the value is a
|
||||
boolean, rune, integer, floating-point, complex, or string constant.
|
||||
In assignments, each value must be <a href="#Assignability">assignable</a>
|
||||
to the type of the operand to which it is assigned, with the following special cases:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li><p>
|
||||
If an untyped <a href="#Constants">constant</a>
|
||||
is assigned to a variable of interface type or the blank identifier,
|
||||
the constant is first <a href="#Conversions">converted</a> to type
|
||||
<code>bool</code>, <code>rune</code>, <code>int</code>, <code>float64</code>,
|
||||
<code>complex128</code> or <code>string</code> respectively, depending on
|
||||
whether the value is a boolean, rune, integer, floating-point, complex, or
|
||||
string constant.
|
||||
</p></li>
|
||||
|
||||
<li><p>
|
||||
<!-- Note that the result of a comparison is an untyped bool that may not be constant. -->
|
||||
If a left-hand side is the blank identifier, any typed or non-constant
|
||||
value except for the predeclared identifier
|
||||
<a href="#Predeclared_identifiers"><code>nil</code></a>
|
||||
may be assigned to it.
|
||||
</p></li>
|
||||
</ol>
|
||||
|
||||
<h3 id="If_statements">If statements</h3>
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ proceeding. If your OS or architecture is not on the list, it's possible that
|
||||
<tr><td colspan="3"><hr></td></tr>
|
||||
<tr><td>FreeBSD 7 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr>
|
||||
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; no binary distribution for ARM yet</td></tr>
|
||||
<tr><td>Mac OS X 10.6/10.7</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
|
||||
<tr><td>Mac OS X 10.6 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
|
||||
<tr><td>Windows 2000 or later</td> <td>amd64, 386</td> <td>use mingw gcc<sup>†</sup>; cygwin or msys is not needed</td></tr>
|
||||
<tr><td>NetBSD 6 or later</td> <td>amd64, 386</td> <td></td></tr>
|
||||
</table>
|
||||
|
||||
@@ -47,7 +47,7 @@ Hello, 世界
|
||||
<div class="right">
|
||||
|
||||
<div id="about">
|
||||
Go is an open source programming environment that makes it easy to build
|
||||
Go is an open source programming language that makes it easy to build
|
||||
simple, reliable, and efficient software.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ from mercurial import util as hg_util
|
||||
if os.sys.platform == 'plan9':
|
||||
try:
|
||||
import plan9
|
||||
n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE)
|
||||
n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -c
|
||||
|
||||
void test() {
|
||||
xxx; // This is line 7.
|
||||
xxx; // ERROR HERE
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
13
misc/cgo/errors/err2.go
Normal file
13
misc/cgo/errors/err2.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
s := ""
|
||||
_ = s
|
||||
C.malloc(s) // ERROR HERE
|
||||
}
|
||||
@@ -2,18 +2,30 @@
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
if go tool cgo err1.go >errs 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
|
||||
exit 1
|
||||
fi
|
||||
if ! test -s errs; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
|
||||
exit 1
|
||||
fi
|
||||
if ! fgrep err1.go:7 errs >/dev/null 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error on line 7 but saw:
|
||||
cat 1>&2 errs
|
||||
exit 1
|
||||
fi
|
||||
check() {
|
||||
file=$1
|
||||
line=$(grep -n 'ERROR HERE' $file | sed 's/:.*//')
|
||||
if [ "$line" = "" ]; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file
|
||||
exit 1
|
||||
fi
|
||||
if go build $file >errs 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
|
||||
exit 1
|
||||
fi
|
||||
if ! test -s errs; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
|
||||
exit 1
|
||||
fi
|
||||
if ! fgrep $file:$line: errs >/dev/null 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error on line $line but saw:
|
||||
cat 1>&2 errs
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check err1.go
|
||||
check err2.go
|
||||
|
||||
rm -rf errs _obj
|
||||
exit 0
|
||||
|
||||
@@ -49,5 +49,6 @@ func TestFpVar(t *testing.T) { testFpVar(t) }
|
||||
func Test4339(t *testing.T) { test4339(t) }
|
||||
func Test6390(t *testing.T) { test6390(t) }
|
||||
func Test5986(t *testing.T) { test5986(t) }
|
||||
func TestNaming(t *testing.T) { testNaming(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
|
||||
93
misc/cgo/test/issue6612.go
Normal file
93
misc/cgo/test/issue6612.go
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// golang.org/issue/6612
|
||||
// Test new scheme for deciding whether C.name is an expression, type, constant.
|
||||
// Clang silences some warnings when the name is a #defined macro, so test those too
|
||||
// (even though we now use errors exclusively, not warnings).
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
void myfunc(void) {}
|
||||
int myvar = 5;
|
||||
const char *mytext = "abcdef";
|
||||
typedef int mytype;
|
||||
enum {
|
||||
myenum = 1234,
|
||||
};
|
||||
|
||||
#define myfunc_def myfunc
|
||||
#define myvar_def myvar
|
||||
#define mytext_def mytext
|
||||
#define mytype_def mytype
|
||||
#define myenum_def myenum
|
||||
#define myint_def 12345
|
||||
#define myfloat_def 1.5
|
||||
#define mystring_def "hello"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "testing"
|
||||
|
||||
func testNaming(t *testing.T) {
|
||||
C.myfunc()
|
||||
C.myfunc_def()
|
||||
if v := C.myvar; v != 5 {
|
||||
t.Errorf("C.myvar = %d, want 5", v)
|
||||
}
|
||||
if v := C.myvar_def; v != 5 {
|
||||
t.Errorf("C.myvar_def = %d, want 5", v)
|
||||
}
|
||||
if s := C.GoString(C.mytext); s != "abcdef" {
|
||||
t.Errorf("C.mytext = %q, want %q", s, "abcdef")
|
||||
}
|
||||
if s := C.GoString(C.mytext_def); s != "abcdef" {
|
||||
t.Errorf("C.mytext_def = %q, want %q", s, "abcdef")
|
||||
}
|
||||
if c := C.myenum; c != 1234 {
|
||||
t.Errorf("C.myenum = %v, want 1234", c)
|
||||
}
|
||||
if c := C.myenum_def; c != 1234 {
|
||||
t.Errorf("C.myenum_def = %v, want 1234", c)
|
||||
}
|
||||
{
|
||||
const c = C.myenum
|
||||
if c != 1234 {
|
||||
t.Errorf("C.myenum as const = %v, want 1234", c)
|
||||
}
|
||||
}
|
||||
{
|
||||
const c = C.myenum_def
|
||||
if c != 1234 {
|
||||
t.Errorf("C.myenum as const = %v, want 1234", c)
|
||||
}
|
||||
}
|
||||
if c := C.myint_def; c != 12345 {
|
||||
t.Errorf("C.myint_def = %v, want 12345", c)
|
||||
}
|
||||
{
|
||||
const c = C.myint_def
|
||||
if c != 12345 {
|
||||
t.Errorf("C.myint as const = %v, want 12345", c)
|
||||
}
|
||||
}
|
||||
|
||||
// This would be nice, but it has never worked.
|
||||
/*
|
||||
if c := C.myfloat_def; c != 1.5 {
|
||||
t.Errorf("C.myint_def = %v, want 1.5", c)
|
||||
}
|
||||
{
|
||||
const c = C.myfloat_def
|
||||
if c != 1.5 {
|
||||
t.Errorf("C.myint as const = %v, want 1.5", c)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if s := C.mystring_def; s != "hello" {
|
||||
t.Errorf("C.mystring_def = %q, want %q", s, "hello")
|
||||
}
|
||||
}
|
||||
48
misc/cgo/testcdefs/main.c
Normal file
48
misc/cgo/testcdefs/main.c
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "cdefstest.h"
|
||||
|
||||
void runtime·printf(int8*, ...);
|
||||
|
||||
// From cdefstest.go.
|
||||
typedef struct CdefsOrig CdefsOrig;
|
||||
struct CdefsOrig {
|
||||
int8 array1[20];
|
||||
int8 array2[20][20];
|
||||
int8 *array3[20];
|
||||
int8 *array4[20][20];
|
||||
int8 **array5[20][20];
|
||||
};
|
||||
|
||||
void
|
||||
main·test(int32 ret)
|
||||
{
|
||||
CdefsOrig o;
|
||||
CdefsTest t;
|
||||
|
||||
ret = 0;
|
||||
if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
|
||||
runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
|
||||
runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
|
||||
runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
|
||||
runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
|
||||
runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
FLUSH(&ret); // flush return value
|
||||
}
|
||||
@@ -2,7 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cgotest
|
||||
package main
|
||||
|
||||
// This file only exists so we can run 'go build' and build our .c files
|
||||
func test() {}
|
||||
import "os"
|
||||
|
||||
func test() int32 // in main.c
|
||||
|
||||
func main() {
|
||||
os.Exit(int(test()))
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ do
|
||||
go tool cgo -cdefs ${FP}.go > ${FP}.h
|
||||
done
|
||||
|
||||
go build .
|
||||
go build . && ./testcdefs
|
||||
EXIT=$?
|
||||
rm -rf _obj main *.h
|
||||
exit $EXIT
|
||||
|
||||
4
misc/dist/bindist.go
vendored
4
misc/dist/bindist.go
vendored
@@ -49,7 +49,7 @@ const (
|
||||
blogPath = "code.google.com/p/go.blog"
|
||||
toolPath = "code.google.com/p/go.tools"
|
||||
tourPath = "code.google.com/p/go-tour"
|
||||
defaultToolTag = "9e246fa49449" // go.tools as of 2013-10-18, for go1.2
|
||||
defaultToolTag = "release-branch.go1.2"
|
||||
)
|
||||
|
||||
// Import paths for tool commands.
|
||||
@@ -175,7 +175,7 @@ func main() {
|
||||
}
|
||||
if *includeRace {
|
||||
for _, t := range raceAvailable {
|
||||
if t == targ {
|
||||
if t == targ || strings.HasPrefix(targ, t+"-") {
|
||||
b.Race = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
|
||||
(defalias 'go--kill-whole-line
|
||||
(if (fboundp 'kill-whole-line)
|
||||
'kill-whole-line
|
||||
'kill-entire-line))
|
||||
#'kill-whole-line
|
||||
#'kill-entire-line))
|
||||
|
||||
;; Delete the current line without putting it in the kill-ring.
|
||||
(defun go--delete-whole-line (&optional arg)
|
||||
@@ -56,12 +56,16 @@
|
||||
(kill-new (s) ()))
|
||||
(go--kill-whole-line arg)))
|
||||
|
||||
|
||||
;; declare-function is an empty macro that only byte-compile cares
|
||||
;; about. Wrap in always false if to satisfy Emacsen without that
|
||||
;; macro.
|
||||
(if nil
|
||||
(declare-function go--position-bytes "go-mode" (point)))
|
||||
;; XEmacs unfortunately does not offer position-bytes. We can fall
|
||||
;; back to just using (point), but it will be incorrect as soon as
|
||||
;; multibyte characters are being used.
|
||||
(if (fboundp 'position-bytes)
|
||||
(defalias 'go--position-bytes 'position-bytes)
|
||||
(defalias 'go--position-bytes #'position-bytes)
|
||||
(defun go--position-bytes (point) point))
|
||||
|
||||
(defun go--old-completion-list-style (list)
|
||||
@@ -157,6 +161,12 @@ customize this variable to point to the wrapper script."
|
||||
:type 'string
|
||||
:group 'go)
|
||||
|
||||
(defcustom gofmt-command "gofmt"
|
||||
"The 'gofmt' command. Some users may replace this with 'goimports'
|
||||
from https://github.com/bradfitz/goimports."
|
||||
:type 'string
|
||||
:group 'go)
|
||||
|
||||
(defface go-coverage-untracked
|
||||
'((t (:foreground "#505050")))
|
||||
"Coverage color of untracked code."
|
||||
@@ -273,15 +283,15 @@ For mode=set, all covered lines will have this weight."
|
||||
|
||||
(defvar go-mode-map
|
||||
(let ((m (make-sparse-keymap)))
|
||||
(define-key m "}" 'go-mode-insert-and-indent)
|
||||
(define-key m ")" 'go-mode-insert-and-indent)
|
||||
(define-key m "," 'go-mode-insert-and-indent)
|
||||
(define-key m ":" 'go-mode-insert-and-indent)
|
||||
(define-key m "=" 'go-mode-insert-and-indent)
|
||||
(define-key m (kbd "C-c C-a") 'go-import-add)
|
||||
(define-key m (kbd "C-c C-j") 'godef-jump)
|
||||
(define-key m (kbd "C-x 4 C-c C-j") 'godef-jump-other-window)
|
||||
(define-key m (kbd "C-c C-d") 'godef-describe)
|
||||
(define-key m "}" #'go-mode-insert-and-indent)
|
||||
(define-key m ")" #'go-mode-insert-and-indent)
|
||||
(define-key m "," #'go-mode-insert-and-indent)
|
||||
(define-key m ":" #'go-mode-insert-and-indent)
|
||||
(define-key m "=" #'go-mode-insert-and-indent)
|
||||
(define-key m (kbd "C-c C-a") #'go-import-add)
|
||||
(define-key m (kbd "C-c C-j") #'godef-jump)
|
||||
(define-key m (kbd "C-x 4 C-c C-j") #'godef-jump-other-window)
|
||||
(define-key m (kbd "C-c C-d") #'godef-describe)
|
||||
m)
|
||||
"Keymap used by Go mode to implement electric keys.")
|
||||
|
||||
@@ -390,7 +400,7 @@ current line will be returned."
|
||||
|
||||
(defun go-indentation-at-point ()
|
||||
(save-excursion
|
||||
(let (start-nesting (outindent 0))
|
||||
(let (start-nesting)
|
||||
(back-to-indentation)
|
||||
(setq start-nesting (go-paren-level))
|
||||
|
||||
@@ -420,7 +430,6 @@ current line will be returned."
|
||||
(interactive)
|
||||
(let (indent
|
||||
shift-amt
|
||||
end
|
||||
(pos (- (point-max) (point)))
|
||||
(point (point))
|
||||
(beg (line-beginning-position)))
|
||||
@@ -511,7 +520,7 @@ consider binding godef-jump to `M-.', which is the default key
|
||||
for `find-tag':
|
||||
|
||||
\(add-hook 'go-mode-hook (lambda ()
|
||||
(local-set-key (kbd \"M-.\") 'godef-jump)))
|
||||
(local-set-key (kbd \"M-.\") #'godef-jump)))
|
||||
|
||||
Please note that godef is an external dependency. You can install
|
||||
it with
|
||||
@@ -531,7 +540,7 @@ recommended that you look at goflymake
|
||||
'(go--build-font-lock-keywords))
|
||||
|
||||
;; Indentation
|
||||
(set (make-local-variable 'indent-line-function) 'go-mode-indent-line)
|
||||
(set (make-local-variable 'indent-line-function) #'go-mode-indent-line)
|
||||
|
||||
;; Comments
|
||||
(set (make-local-variable 'comment-start) "// ")
|
||||
@@ -539,12 +548,12 @@ recommended that you look at goflymake
|
||||
(set (make-local-variable 'comment-use-syntax) t)
|
||||
(set (make-local-variable 'comment-start-skip) "\\(//+\\|/\\*+\\)\\s *")
|
||||
|
||||
(set (make-local-variable 'beginning-of-defun-function) 'go-beginning-of-defun)
|
||||
(set (make-local-variable 'end-of-defun-function) 'go-end-of-defun)
|
||||
(set (make-local-variable 'beginning-of-defun-function) #'go-beginning-of-defun)
|
||||
(set (make-local-variable 'end-of-defun-function) #'go-end-of-defun)
|
||||
|
||||
(set (make-local-variable 'parse-sexp-lookup-properties) t)
|
||||
(if (boundp 'syntax-propertize-function)
|
||||
(set (make-local-variable 'syntax-propertize-function) 'go-propertize-syntax))
|
||||
(set (make-local-variable 'syntax-propertize-function) #'go-propertize-syntax))
|
||||
|
||||
(set (make-local-variable 'go-dangling-cache) (make-hash-table :test 'eql))
|
||||
(add-hook 'before-change-functions (lambda (x y) (setq go-dangling-cache (make-hash-table :test 'eql))) t t)
|
||||
@@ -638,7 +647,7 @@ buffer."
|
||||
;; We're using errbuf for the mixed stdout and stderr output. This
|
||||
;; is not an issue because gofmt -w does not produce any stdout
|
||||
;; output in case of success.
|
||||
(if (zerop (call-process "gofmt" nil errbuf nil "-w" tmpfile))
|
||||
(if (zerop (call-process gofmt-command nil errbuf nil "-w" tmpfile))
|
||||
(if (zerop (call-process-region (point-min) (point-max) "diff" nil patchbuf nil "-n" "-" tmpfile))
|
||||
(progn
|
||||
(kill-buffer errbuf)
|
||||
@@ -749,6 +758,9 @@ declaration."
|
||||
(let ((old-point (point)))
|
||||
(goto-char (point-min))
|
||||
(cond
|
||||
((re-search-forward "^import ()" nil t)
|
||||
(backward-char 1)
|
||||
'block-empty)
|
||||
((re-search-forward "^import ([^)]+)" nil t)
|
||||
(backward-char 2)
|
||||
'block)
|
||||
@@ -843,6 +855,8 @@ uncommented, otherwise a new import will be added."
|
||||
(uncomment-region (line-beginning-position) (line-end-position))
|
||||
(case (go-goto-imports)
|
||||
('fail (message "Could not find a place to add import."))
|
||||
('block-empty
|
||||
(insert "\n\t" line "\n"))
|
||||
('block
|
||||
(save-excursion
|
||||
(re-search-backward "^import (")
|
||||
@@ -893,13 +907,13 @@ If IGNORE-CASE is non-nil, the comparison is case-insensitive."
|
||||
(mapcar (lambda (file)
|
||||
(let ((sub (substring file (length pkgdir) -2)))
|
||||
(unless (or (go--string-prefix-p "obj/" sub) (go--string-prefix-p "tool/" sub))
|
||||
(mapconcat 'identity (cdr (split-string sub "/")) "/"))))
|
||||
(mapconcat #'identity (cdr (split-string sub "/")) "/"))))
|
||||
(if (file-directory-p dir)
|
||||
(directory-files dir t "\\.a$"))))
|
||||
(if (file-directory-p pkgdir)
|
||||
(go--directory-dirs pkgdir)))))
|
||||
(go-root-and-paths)))
|
||||
'string<))
|
||||
#'string<))
|
||||
|
||||
(defun go-unused-imports-lines ()
|
||||
;; FIXME Technically, -o /dev/null fails in quite some cases (on
|
||||
@@ -945,11 +959,12 @@ will be commented, otherwise they will be removed completely."
|
||||
"Given a file name in the format of `filename:line:column',
|
||||
visit FILENAME and go to line LINE and column COLUMN."
|
||||
(if (not (string-match "\\(.+\\):\\([0-9]+\\):\\([0-9]+\\)" specifier))
|
||||
(error "Unexpected godef output: %s" specifier)
|
||||
;; We've only been given a directory name
|
||||
(funcall (if other-window #'find-file-other-window #'find-file) specifier)
|
||||
(let ((filename (match-string 1 specifier))
|
||||
(line (string-to-number (match-string 2 specifier)))
|
||||
(column (string-to-number (match-string 3 specifier))))
|
||||
(with-current-buffer (funcall (if other-window 'find-file-other-window 'find-file) filename)
|
||||
(with-current-buffer (funcall (if other-window #'find-file-other-window #'find-file) filename)
|
||||
(go--goto-line line)
|
||||
(beginning-of-line)
|
||||
(forward-char (1- column))
|
||||
@@ -988,7 +1003,7 @@ description at POINT."
|
||||
(let ((description (cdr (butlast (godef--call point) 1))))
|
||||
(if (not description)
|
||||
(message "No description found for expression at point")
|
||||
(message "%s" (mapconcat 'identity description "\n"))))
|
||||
(message "%s" (mapconcat #'identity description "\n"))))
|
||||
(file-error (message "Could not run godef binary"))))
|
||||
|
||||
(defun godef-jump (point &optional other-window)
|
||||
@@ -1003,6 +1018,8 @@ description at POINT."
|
||||
(message "%s" file))
|
||||
((go--string-prefix-p "godef: no declaration found for " file)
|
||||
(message "%s" file))
|
||||
((go--string-prefix-p "error finding import path for " file)
|
||||
(message "%s" file))
|
||||
(t
|
||||
(push-mark)
|
||||
(ring-insert find-tag-marker-ring (point-marker))
|
||||
@@ -1137,6 +1154,6 @@ for."
|
||||
(go--coverage-make-overlay range (cadr ranges-and-divisor))))
|
||||
|
||||
(if (not (eq cur-buffer (current-buffer)))
|
||||
(display-buffer (current-buffer) 'display-buffer-reuse-window)))))
|
||||
(display-buffer (current-buffer) #'display-buffer-reuse-window)))))
|
||||
|
||||
(provide 'go-mode)
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -101,57 +103,78 @@ func crawl(url string, sourceURL string) {
|
||||
|
||||
func addProblem(url, errmsg string) {
|
||||
msg := fmt.Sprintf("Error on %s: %s (from %s)", url, errmsg, linkSources[url])
|
||||
log.Print(msg)
|
||||
if *verbose {
|
||||
log.Print(msg)
|
||||
}
|
||||
problems = append(problems, msg)
|
||||
}
|
||||
|
||||
func crawlLoop() {
|
||||
for url := range urlq {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
addProblem(url, fmt.Sprintf("Error fetching: %v", err))
|
||||
wg.Done()
|
||||
continue
|
||||
if err := doCrawl(url); err != nil {
|
||||
addProblem(url, err.Error())
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
addProblem(url, fmt.Sprintf("Status code = %d", res.StatusCode))
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
slurp, err := ioutil.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading %s body: %v", url, err)
|
||||
}
|
||||
if *verbose {
|
||||
log.Printf("Len of %s: %d", url, len(slurp))
|
||||
}
|
||||
body := string(slurp)
|
||||
for _, ref := range localLinks(body) {
|
||||
if *verbose {
|
||||
log.Printf(" links to %s", ref)
|
||||
}
|
||||
dest := *root + ref
|
||||
linkSources[dest] = append(linkSources[dest], url)
|
||||
crawl(dest, url)
|
||||
}
|
||||
for _, id := range pageIDs(body) {
|
||||
if *verbose {
|
||||
log.Printf(" url %s has #%s", url, id)
|
||||
}
|
||||
fragExists[urlFrag{url, id}] = true
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}
|
||||
}
|
||||
|
||||
func doCrawl(url string) error {
|
||||
defer wg.Done()
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := http.DefaultTransport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Handle redirects.
|
||||
if res.StatusCode/100 == 3 {
|
||||
newURL, err := res.Location()
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolving redirect: %v", err)
|
||||
}
|
||||
if !strings.HasPrefix(newURL.String(), *root) {
|
||||
// Skip off-site redirects.
|
||||
return nil
|
||||
}
|
||||
crawl(newURL.String(), url)
|
||||
return nil
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return errors.New(res.Status)
|
||||
}
|
||||
slurp, err := ioutil.ReadAll(res.Body)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading %s body: %v", url, err)
|
||||
}
|
||||
if *verbose {
|
||||
log.Printf("Len of %s: %d", url, len(slurp))
|
||||
}
|
||||
body := string(slurp)
|
||||
for _, ref := range localLinks(body) {
|
||||
if *verbose {
|
||||
log.Printf(" links to %s", ref)
|
||||
}
|
||||
dest := *root + ref
|
||||
linkSources[dest] = append(linkSources[dest], url)
|
||||
crawl(dest, url)
|
||||
}
|
||||
for _, id := range pageIDs(body) {
|
||||
if *verbose {
|
||||
log.Printf(" url %s has #%s", url, id)
|
||||
}
|
||||
fragExists[urlFrag{url, id}] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
go crawlLoop()
|
||||
crawl(*root, "")
|
||||
crawl(*root+"/doc/go1.1.html", "")
|
||||
|
||||
wg.Wait()
|
||||
close(urlq)
|
||||
@@ -164,4 +187,7 @@ func main() {
|
||||
for _, s := range problems {
|
||||
fmt.Println(s)
|
||||
}
|
||||
if len(problems) > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,21 @@
|
||||
"
|
||||
" Flag to indicate whether to enable the commands listed above.
|
||||
"
|
||||
" g:gofmt_command [default="gofmt"]
|
||||
"
|
||||
" Flag naming the gofmt executable to use.
|
||||
"
|
||||
if exists("b:did_ftplugin_go_fmt")
|
||||
finish
|
||||
endif
|
||||
|
||||
|
||||
if !exists("g:go_fmt_commands")
|
||||
let g:go_fmt_commands = 1
|
||||
endif
|
||||
|
||||
if !exists("g:gofmt_command")
|
||||
let g:gofmt_command = "gofmt"
|
||||
endif
|
||||
|
||||
if g:go_fmt_commands
|
||||
command! -buffer Fmt call s:GoFormat()
|
||||
@@ -34,7 +40,7 @@ endif
|
||||
|
||||
function! s:GoFormat()
|
||||
let view = winsaveview()
|
||||
silent %!gofmt
|
||||
silent execute "%!" . g:gofmt_command
|
||||
if v:shell_error
|
||||
let errors = []
|
||||
for line in getline(1, line('$'))
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
http://plan9.bell-labs.com/magic/man2html/1/8a
|
||||
|
||||
Go-specific considerations are documented at
|
||||
|
||||
http://golang.org/doc/asm
|
||||
|
||||
Its target architecture is the ARM, referred to by these tools as arm.
|
||||
|
||||
*/
|
||||
|
||||
@@ -472,14 +472,27 @@ noops(void)
|
||||
p->to.reg = REGSP;
|
||||
p->spadj = -8;
|
||||
|
||||
/* SUB $8,SP */
|
||||
q1->as = ASUB;
|
||||
q1->from.type = D_CONST;
|
||||
q1->from.offset = 8;
|
||||
q1->from.reg = NREG;
|
||||
/* Keep saved LR at 0(SP) after SP change. */
|
||||
/* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
|
||||
/* TODO: Remove SP adjustments; see issue 6699. */
|
||||
q1->as = AMOVW;
|
||||
q1->from.type = D_OREG;
|
||||
q1->from.reg = REGSP;
|
||||
q1->from.offset = 0;
|
||||
q1->reg = NREG;
|
||||
q1->to.type = D_REG;
|
||||
q1->to.reg = REGTMP;
|
||||
|
||||
/* SUB $8,SP */
|
||||
q1 = appendp(q1);
|
||||
q1->as = AMOVW;
|
||||
q1->from.type = D_REG;
|
||||
q1->from.reg = REGTMP;
|
||||
q1->reg = NREG;
|
||||
q1->to.type = D_OREG;
|
||||
q1->to.reg = REGSP;
|
||||
q1->to.offset = -8;
|
||||
q1->scond |= C_WBIT;
|
||||
q1->spadj = 8;
|
||||
|
||||
break;
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
|
||||
http://plan9.bell-labs.com/magic/man2html/1/8a
|
||||
|
||||
Go-specific considerations are documented at
|
||||
|
||||
http://golang.org/doc/asm
|
||||
|
||||
Its target architecture is the x86-64, referred to by these tools as amd64.
|
||||
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
http://plan9.bell-labs.com/magic/man2html/1/8a
|
||||
|
||||
Go-specific considerations are documented at
|
||||
|
||||
http://golang.org/doc/asm
|
||||
|
||||
I
|
||||
Its target architecture is the x86, referred to by these tools for historical reasons as 386.
|
||||
|
||||
*/
|
||||
|
||||
@@ -269,29 +269,30 @@ Next, cgo needs to identify the kinds for each identifier. For the
|
||||
identifiers C.foo and C.bar, cgo generates this C program:
|
||||
|
||||
<preamble>
|
||||
void __cgo__f__(void) {
|
||||
#line 1 "cgo-test"
|
||||
foo;
|
||||
enum { _cgo_enum_0 = foo };
|
||||
bar;
|
||||
enum { _cgo_enum_1 = bar };
|
||||
}
|
||||
#line 1 "not-declared"
|
||||
void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }
|
||||
#line 1 "not-type"
|
||||
void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; }
|
||||
#line 1 "not-const"
|
||||
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; }
|
||||
#line 2 "not-declared"
|
||||
void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; }
|
||||
#line 2 "not-type"
|
||||
void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; }
|
||||
#line 2 "not-const"
|
||||
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; }
|
||||
|
||||
This program will not compile, but cgo can look at the error messages
|
||||
to infer the kind of each identifier. The line number given in the
|
||||
error tells cgo which identifier is involved.
|
||||
This program will not compile, but cgo can use the presence or absence
|
||||
of an error message on a given line to deduce the information it
|
||||
needs. The program is syntactically valid regardless of whether each
|
||||
name is a type or an ordinary identifier, so there will be no syntax
|
||||
errors that might stop parsing early.
|
||||
|
||||
An error like "unexpected type name" or "useless type name in empty
|
||||
declaration" or "declaration does not declare anything" tells cgo that
|
||||
the identifier is a type.
|
||||
An error on not-declared:1 indicates that foo is undeclared.
|
||||
An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier).
|
||||
An error on not-const:1 indicates that foo is not an integer constant.
|
||||
|
||||
An error like "statement with no effect" or "expression result unused"
|
||||
tells cgo that the identifier is not a type, but not whether it is a
|
||||
constant, function, or global variable.
|
||||
|
||||
An error like "not an integer constant" tells cgo that the identifier
|
||||
is not a constant. If it is also not a type, it must be a function or
|
||||
global variable. For now, those can be treated the same.
|
||||
The line number specifies the name involved. In the example, 1 is foo and 2 is bar.
|
||||
|
||||
Next, cgo must learn the details of each type, variable, function, or
|
||||
constant. It can do this by reading object files. If cgo has decided
|
||||
@@ -299,14 +300,14 @@ that t1 is a type, v2 and v3 are variables or functions, and c4, c5,
|
||||
and c6 are constants, it generates:
|
||||
|
||||
<preamble>
|
||||
typeof(t1) *__cgo__1;
|
||||
typeof(v2) *__cgo__2;
|
||||
typeof(v3) *__cgo__3;
|
||||
typeof(c4) *__cgo__4;
|
||||
__typeof__(t1) *__cgo__1;
|
||||
__typeof__(v2) *__cgo__2;
|
||||
__typeof__(v3) *__cgo__3;
|
||||
__typeof__(c4) *__cgo__4;
|
||||
enum { __cgo_enum__4 = c4 };
|
||||
typeof(c5) *__cgo__5;
|
||||
__typeof__(c5) *__cgo__5;
|
||||
enum { __cgo_enum__5 = c5 };
|
||||
typeof(c6) *__cgo__6;
|
||||
__typeof__(c6) *__cgo__6;
|
||||
enum { __cgo_enum__6 = c6 };
|
||||
|
||||
long long __cgo_debug_data[] = {
|
||||
|
||||
@@ -226,42 +226,22 @@ func (p *Package) loadDefines(f *File) {
|
||||
// name xxx for the references C.xxx in the Go input.
|
||||
// The kind is either a constant, type, or variable.
|
||||
func (p *Package) guessKinds(f *File) []*Name {
|
||||
// Coerce gcc into telling us whether each name is
|
||||
// a type, a value, or undeclared. We compile a function
|
||||
// containing the line:
|
||||
// name;
|
||||
// If name is a type, gcc will print:
|
||||
// cgo-test:2: warning: useless type name in empty declaration
|
||||
// If name is a value, gcc will print
|
||||
// cgo-test:2: warning: statement with no effect
|
||||
// If name is undeclared, gcc will print
|
||||
// cgo-test:2: error: 'name' undeclared (first use in this function)
|
||||
// A line number directive causes the line number to
|
||||
// correspond to the index in the names array.
|
||||
//
|
||||
// The line also has an enum declaration:
|
||||
// name; enum { _cgo_enum_1 = name };
|
||||
// If name is not a constant, gcc will print:
|
||||
// cgo-test:4: error: enumerator value for '_cgo_enum_4' is not an integer constant
|
||||
// we assume lines without that error are constants.
|
||||
|
||||
// Make list of names that need sniffing, type lookup.
|
||||
toSniff := make([]*Name, 0, len(f.Name))
|
||||
needType := make([]*Name, 0, len(f.Name))
|
||||
|
||||
// Determine kinds for names we already know about,
|
||||
// like #defines or 'struct foo', before bothering with gcc.
|
||||
var names, needType []*Name
|
||||
for _, n := range f.Name {
|
||||
// If we've already found this name as a #define
|
||||
// and we can translate it as a constant value, do so.
|
||||
if n.Define != "" {
|
||||
ok := false
|
||||
isConst := false
|
||||
if _, err := strconv.Atoi(n.Define); err == nil {
|
||||
ok = true
|
||||
isConst = true
|
||||
} else if n.Define[0] == '"' || n.Define[0] == '\'' {
|
||||
if _, err := parser.ParseExpr(n.Define); err == nil {
|
||||
ok = true
|
||||
isConst = true
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
if isConst {
|
||||
n.Kind = "const"
|
||||
// Turn decimal into hex, just for consistency
|
||||
// with enum-derived constants. Otherwise
|
||||
@@ -281,126 +261,139 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a struct, union, or enum type name,
|
||||
// record the kind but also that we need type information.
|
||||
needType = append(needType, n)
|
||||
|
||||
// If this is a struct, union, or enum type name, no need to guess the kind.
|
||||
if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
|
||||
n.Kind = "type"
|
||||
i := len(needType)
|
||||
needType = needType[0 : i+1]
|
||||
needType[i] = n
|
||||
continue
|
||||
}
|
||||
|
||||
i := len(toSniff)
|
||||
toSniff = toSniff[0 : i+1]
|
||||
toSniff[i] = n
|
||||
// Otherwise, we'll need to find out from gcc.
|
||||
names = append(names, n)
|
||||
}
|
||||
|
||||
if len(toSniff) == 0 {
|
||||
// Bypass gcc if there's nothing left to find out.
|
||||
if len(names) == 0 {
|
||||
return needType
|
||||
}
|
||||
|
||||
// Coerce gcc into telling us whether each name is a type, a value, or undeclared.
|
||||
// For names, find out whether they are integer constants.
|
||||
// We used to look at specific warning or error messages here, but that tied the
|
||||
// behavior too closely to specific versions of the compilers.
|
||||
// Instead, arrange that we can infer what we need from only the presence or absence
|
||||
// of an error on a specific line.
|
||||
//
|
||||
// For each name, we generate these lines, where xxx is the index in toSniff plus one.
|
||||
//
|
||||
// #line xxx "not-declared"
|
||||
// void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
|
||||
// #line xxx "not-type"
|
||||
// void __cgo_f_xxx_2(void) { name *__cgo_undefined__; }
|
||||
// #line xxx "not-const"
|
||||
// void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; }
|
||||
//
|
||||
// If we see an error at not-declared:xxx, the corresponding name is not declared.
|
||||
// If we see an error at not-type:xxx, the corresponding name is a type.
|
||||
// If we see an error at not-const:xxx, the corresponding name is not an integer constant.
|
||||
// If we see no errors, we assume the name is an expression but not a constant
|
||||
// (so a variable or a function).
|
||||
//
|
||||
// The specific input forms are chosen so that they are valid C syntax regardless of
|
||||
// whether name denotes a type or an expression.
|
||||
|
||||
var b bytes.Buffer
|
||||
b.WriteString(f.Preamble)
|
||||
b.WriteString(builtinProlog)
|
||||
b.WriteString("void __cgo__f__(void) {\n")
|
||||
|
||||
// For a #defined expression, clang silences the warning about "unused expression".
|
||||
// http://llvm.org/viewvc/llvm-project?view=revision&revision=172696
|
||||
// Silencing the warning is not a big deal, because our default assumption is that
|
||||
// (in the absence of other evidence) names are expressions.
|
||||
// However, if all the C names we are investigating are #defined expressions,
|
||||
// clang will print no warnings at all and then exit successfully.
|
||||
// We want clang to print warnings, so seed the code with a function
|
||||
// that is guaranteed to provoke a warning (that we will ignore).
|
||||
// This way, if clang becomes even more broken, we'll find out.
|
||||
// See golang.org/issue/6128.
|
||||
fmt.Fprintf(&b, "1;\n")
|
||||
|
||||
b.WriteString("#line 1 \"cgo-test\"\n")
|
||||
for i, n := range toSniff {
|
||||
fmt.Fprintf(&b, "%s; /* #%d */\nenum { _cgo_enum_%d = %s }; /* #%d */\n", n.C, i, i, n.C, i)
|
||||
for i, n := range names {
|
||||
fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
|
||||
"void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+
|
||||
"#line %d \"not-type\"\n"+
|
||||
"void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+
|
||||
"#line %d \"not-const\"\n"+
|
||||
"void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n",
|
||||
i+1, i+1, n.C,
|
||||
i+1, i+1, n.C,
|
||||
i+1, i+1, n.C)
|
||||
}
|
||||
b.WriteString("}\n")
|
||||
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
||||
"int __cgo__1 = __cgo__2;\n")
|
||||
|
||||
stderr := p.gccErrors(b.Bytes())
|
||||
if stderr == "" {
|
||||
fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
||||
}
|
||||
|
||||
names := make([]*Name, len(toSniff))
|
||||
copy(names, toSniff)
|
||||
|
||||
isConst := make([]bool, len(toSniff))
|
||||
for i := range isConst {
|
||||
isConst[i] = true // until proven otherwise
|
||||
}
|
||||
|
||||
completed := false
|
||||
sniff := make([]int, len(names))
|
||||
const (
|
||||
notType = 1 << iota
|
||||
notConst
|
||||
)
|
||||
for _, line := range strings.Split(stderr, "\n") {
|
||||
if len(line) < 9 || line[0:9] != "cgo-test:" {
|
||||
// the user will see any compiler errors when the code is compiled later.
|
||||
if !strings.Contains(line, ": error:") {
|
||||
// we only care about errors.
|
||||
// we tried to turn off warnings on the command line, but one never knows.
|
||||
continue
|
||||
}
|
||||
line = line[9:]
|
||||
colon := strings.Index(line, ":")
|
||||
if colon < 0 {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(line[0:colon])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
i = (i - 1) / 2
|
||||
what := ""
|
||||
switch {
|
||||
default:
|
||||
continue
|
||||
case strings.Contains(line, ": useless type name in empty declaration"),
|
||||
strings.Contains(line, ": declaration does not declare anything"),
|
||||
strings.Contains(line, ": unexpected type name"):
|
||||
what = "type"
|
||||
isConst[i] = false
|
||||
case strings.Contains(line, ": statement with no effect"),
|
||||
strings.Contains(line, ": expression result unused"):
|
||||
what = "not-type" // const or func or var
|
||||
case strings.Contains(line, "undeclared"):
|
||||
error_(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
|
||||
case strings.Contains(line, "is not an integer constant"):
|
||||
isConst[i] = false
|
||||
continue
|
||||
}
|
||||
n := toSniff[i]
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
toSniff[i] = nil
|
||||
n.Kind = what
|
||||
|
||||
j := len(needType)
|
||||
needType = needType[0 : j+1]
|
||||
needType[j] = n
|
||||
}
|
||||
for i, b := range isConst {
|
||||
if b {
|
||||
names[i].Kind = "const"
|
||||
if toSniff[i] != nil && names[i].Const == "" {
|
||||
j := len(needType)
|
||||
needType = needType[0 : j+1]
|
||||
needType[j] = names[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, n := range toSniff {
|
||||
if n == nil {
|
||||
c1 := strings.Index(line, ":")
|
||||
if c1 < 0 {
|
||||
continue
|
||||
}
|
||||
if n.Kind != "" {
|
||||
c2 := strings.Index(line[c1+1:], ":")
|
||||
if c2 < 0 {
|
||||
continue
|
||||
}
|
||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
c2 += c1 + 1
|
||||
|
||||
filename := line[:c1]
|
||||
i, _ := strconv.Atoi(line[c1+1 : c2])
|
||||
i--
|
||||
if i < 0 || i >= len(names) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch filename {
|
||||
case "completed":
|
||||
// Strictly speaking, there is no guarantee that seeing the error at completed:1
|
||||
// (at the end of the file) means we've seen all the errors from earlier in the file,
|
||||
// but usually it does. Certainly if we don't see the completed:1 error, we did
|
||||
// not get all the errors we expected.
|
||||
completed = true
|
||||
|
||||
case "not-declared":
|
||||
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
|
||||
case "not-type":
|
||||
sniff[i] |= notType
|
||||
case "not-const":
|
||||
sniff[i] |= notConst
|
||||
}
|
||||
}
|
||||
|
||||
if !completed {
|
||||
fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
switch sniff[i] {
|
||||
case 0:
|
||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notType:
|
||||
n.Kind = "const"
|
||||
case notConst:
|
||||
n.Kind = "type"
|
||||
case notConst | notType:
|
||||
n.Kind = "not-type"
|
||||
}
|
||||
}
|
||||
if nerrors > 0 {
|
||||
fatalf("unresolved names")
|
||||
}
|
||||
|
||||
needType = append(needType, names...)
|
||||
return needType
|
||||
}
|
||||
|
||||
@@ -413,14 +406,14 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||
// for symbols in the object file, so it is not enough to print the
|
||||
// preamble and hope the symbols we care about will be there.
|
||||
// Instead, emit
|
||||
// typeof(names[i]) *__cgo__i;
|
||||
// __typeof__(names[i]) *__cgo__i;
|
||||
// for each entry in names and then dereference the type we
|
||||
// learn for __cgo__i.
|
||||
var b bytes.Buffer
|
||||
b.WriteString(f.Preamble)
|
||||
b.WriteString(builtinProlog)
|
||||
for i, n := range names {
|
||||
fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i)
|
||||
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
|
||||
if n.Kind == "const" {
|
||||
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
||||
}
|
||||
@@ -661,7 +654,7 @@ func (p *Package) rewriteRef(f *File) {
|
||||
// Okay - might be new(T)
|
||||
expr = r.Name.Type.Go
|
||||
} else if r.Name.Kind == "var" {
|
||||
expr = &ast.StarExpr{X: expr}
|
||||
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
|
||||
}
|
||||
|
||||
case "type":
|
||||
@@ -690,6 +683,16 @@ func (p *Package) rewriteRef(f *File) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy position information from old expr into new expr,
|
||||
// in case expression being replaced is first on line.
|
||||
// See golang.org/issue/6563.
|
||||
pos := (*r.Expr).Pos()
|
||||
switch x := expr.(type) {
|
||||
case *ast.Ident:
|
||||
expr = &ast.Ident{NamePos: pos, Name: x.Name}
|
||||
}
|
||||
|
||||
*r.Expr = expr
|
||||
}
|
||||
|
||||
@@ -739,13 +742,12 @@ func gccTmp() string {
|
||||
// the input.
|
||||
func (p *Package) gccCmd() []string {
|
||||
c := append(p.gccBaseCmd(),
|
||||
"-Wall", // many warnings
|
||||
"-Werror", // warnings are errors
|
||||
"-o"+gccTmp(), // write object to tmp
|
||||
"-gdwarf-2", // generate DWARF v2 debugging symbols
|
||||
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
|
||||
"-c", // do not link
|
||||
"-xc", // input language is C
|
||||
"-w", // no warnings
|
||||
"-Wno-error", // warnings are not errors
|
||||
"-o"+gccTmp(), // write object to tmp
|
||||
"-gdwarf-2", // generate DWARF v2 debugging symbols
|
||||
"-c", // do not link
|
||||
"-xc", // input language is C
|
||||
)
|
||||
if strings.Contains(c[0], "clang") {
|
||||
c = append(c,
|
||||
@@ -778,6 +780,11 @@ func (p *Package) gccCmd() []string {
|
||||
func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
|
||||
runGcc(stdin, p.gccCmd())
|
||||
|
||||
isDebugData := func(s string) bool {
|
||||
// Some systems use leading _ to denote non-assembly symbols.
|
||||
return s == "__cgodebug_data" || s == "___cgodebug_data"
|
||||
}
|
||||
|
||||
if f, err := macho.Open(gccTmp()); err == nil {
|
||||
defer f.Close()
|
||||
d, err := f.DWARF()
|
||||
@@ -788,8 +795,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
|
||||
if f.Symtab != nil {
|
||||
for i := range f.Symtab.Syms {
|
||||
s := &f.Symtab.Syms[i]
|
||||
// Mach-O still uses a leading _ to denote non-assembly symbols.
|
||||
if s.Name == "_"+"__cgodebug_data" {
|
||||
if isDebugData(s.Name) {
|
||||
// Found it. Now find data section.
|
||||
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
|
||||
sect := f.Sections[i]
|
||||
@@ -816,7 +822,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
|
||||
if err == nil {
|
||||
for i := range symtab {
|
||||
s := &symtab[i]
|
||||
if s.Name == "__cgodebug_data" {
|
||||
if isDebugData(s.Name) {
|
||||
// Found it. Now find data section.
|
||||
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
|
||||
sect := f.Sections[i]
|
||||
@@ -840,7 +846,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
|
||||
}
|
||||
var data []byte
|
||||
for _, s := range f.Symbols {
|
||||
if s.Name == "_"+"__cgodebug_data" {
|
||||
if isDebugData(s.Name) {
|
||||
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
|
||||
sect := f.Sections[i]
|
||||
if s.Value < sect.Size {
|
||||
@@ -876,14 +882,6 @@ func (p *Package) gccErrors(stdin []byte) string {
|
||||
// TODO(rsc): require failure
|
||||
args := p.gccCmd()
|
||||
|
||||
// GCC 4.8.0 has a bug: it sometimes does not apply
|
||||
// -Wunused-value to values that are macros defined in system
|
||||
// headers. See issue 5118. Adding -Wsystem-headers avoids
|
||||
// that problem. This will produce additional errors, but it
|
||||
// doesn't matter because we will ignore all errors that are
|
||||
// not marked for the cgo-test file.
|
||||
args = append(args, "-Wsystem-headers")
|
||||
|
||||
if *debugGcc {
|
||||
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
|
||||
os.Stderr.Write(stdin)
|
||||
@@ -1048,21 +1046,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
}
|
||||
|
||||
t := new(Type)
|
||||
t.Size = dtype.Size()
|
||||
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
||||
t.Align = -1
|
||||
t.C = &TypeRepr{Repr: dtype.Common().Name}
|
||||
c.m[dtype] = t
|
||||
|
||||
if t.Size < 0 {
|
||||
// Unsized types are [0]byte
|
||||
t.Size = 0
|
||||
t.Go = c.Opaque(0)
|
||||
if t.C.Empty() {
|
||||
t.C.Set("void")
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
switch dt := dtype.(type) {
|
||||
default:
|
||||
fatalf("%s: unexpected type: %s", lineno(pos), dtype)
|
||||
@@ -1087,7 +1075,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
sub := c.Type(dt.Type, pos)
|
||||
t.Align = sub.Align
|
||||
gt.Elt = sub.Go
|
||||
t.C.Set("typeof(%s[%d])", sub.C, dt.Count)
|
||||
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
|
||||
|
||||
case *dwarf.BoolType:
|
||||
t.Go = c.bool
|
||||
@@ -1209,6 +1197,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
return t
|
||||
|
||||
case *dwarf.StructType:
|
||||
if dt.ByteSize < 0 { // opaque struct
|
||||
break
|
||||
}
|
||||
// Convert to Go struct, being careful about alignment.
|
||||
// Have to give it a name to simulate C "struct foo" references.
|
||||
tag := dt.StructName
|
||||
@@ -1225,7 +1216,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
case "class", "union":
|
||||
t.Go = c.Opaque(t.Size)
|
||||
if t.C.Empty() {
|
||||
t.C.Set("typeof(unsigned char[%d])", t.Size)
|
||||
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
|
||||
}
|
||||
t.Align = 1 // TODO: should probably base this on field alignment.
|
||||
typedef[name.Name] = t
|
||||
@@ -1327,6 +1318,25 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
||||
}
|
||||
}
|
||||
|
||||
if t.Size <= 0 {
|
||||
// Clang does not record the size of a pointer in its DWARF entry,
|
||||
// so if dtype is an array, the call to dtype.Size at the top of the function
|
||||
// computed the size as the array length * 0 = 0.
|
||||
// The type switch called Type (this function) recursively on the pointer
|
||||
// entry, and the code near the top of the function updated the size to
|
||||
// be correct, so calling dtype.Size again will produce the correct value.
|
||||
t.Size = dtype.Size()
|
||||
if t.Size < 0 {
|
||||
// Unsized types are [0]byte
|
||||
t.Size = 0
|
||||
t.Go = c.Opaque(0)
|
||||
if t.C.Empty() {
|
||||
t.C.Set("void")
|
||||
}
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
if t.C.Empty() {
|
||||
fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
|
||||
}
|
||||
|
||||
@@ -700,6 +700,13 @@ typefmt(Fmt *fp, Type *t)
|
||||
return 0;
|
||||
|
||||
case TSTRUCT:
|
||||
// Format the bucket struct for map[x]y as map.bucket[x]y.
|
||||
// This avoids a recursive print that generates very long names.
|
||||
if(t->hmap != T) {
|
||||
t = t->hmap;
|
||||
return fmtprint(fp, "map.bucket[%T]%T", t->down, t->type);
|
||||
}
|
||||
|
||||
if(t->funarg) {
|
||||
fmtstrcpy(fp, "(");
|
||||
if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape" tags
|
||||
|
||||
@@ -62,7 +62,7 @@ begin:
|
||||
// sys.go claims to be in package PACKAGE to avoid
|
||||
// conflicts during "6g sys.go". rename PACKAGE to $2.
|
||||
printf("\t\"");
|
||||
while(q = strstr(p, "PACKAGE")) {
|
||||
while((q = strstr(p, "PACKAGE")) != NULL) {
|
||||
*q = 0;
|
||||
esc(p); // up to the substitution
|
||||
printf("%s", name); // the sub name
|
||||
|
||||
@@ -229,6 +229,7 @@ hmap(Type *t)
|
||||
h->width = offset;
|
||||
h->local = t->local;
|
||||
t->hmap = h;
|
||||
h->hmap = t;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# Copyright 2012 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
include ../../Make.dist
|
||||
@@ -1,49 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build ignore
|
||||
|
||||
/*
|
||||
|
||||
Prof is a rudimentary real-time profiler.
|
||||
|
||||
Given a command to run or the process id (pid) of a command already
|
||||
running, it samples the program's state at regular intervals and reports
|
||||
on its behavior. With no options, it prints a histogram of the locations
|
||||
in the code that were sampled during execution.
|
||||
|
||||
Since it is a real-time profiler, unlike a traditional profiler it samples
|
||||
the program's state even when it is not running, such as when it is
|
||||
asleep or waiting for I/O. Each thread contributes equally to the
|
||||
statistics.
|
||||
|
||||
Usage:
|
||||
go tool prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
|
||||
|
||||
The output modes (default -h) are:
|
||||
|
||||
-P file.prof:
|
||||
Write the profile information to file.prof, in the format used by pprof.
|
||||
At the moment, this only works on Linux amd64 binaries and requires that the
|
||||
binary be written using 6l -e to produce ELF debug info.
|
||||
See http://code.google.com/p/google-perftools for details.
|
||||
-h: histograms
|
||||
How many times a sample occurred at each location.
|
||||
-f: dynamic functions
|
||||
At each sample period, print the name of the executing function.
|
||||
-l: dynamic file and line numbers
|
||||
At each sample period, print the file and line number of the executing instruction.
|
||||
-r: dynamic registers
|
||||
At each sample period, print the register contents.
|
||||
-s: dynamic function stack traces
|
||||
At each sample period, print the symbolic stack trace.
|
||||
|
||||
Flag -t sets the maximum real time to sample, in seconds, and -d
|
||||
sets the sampling interval in milliseconds. The default is to sample
|
||||
every 100ms until the program completes.
|
||||
|
||||
It is installed as go tool prof and is architecture-independent.
|
||||
|
||||
*/
|
||||
package main
|
||||
@@ -1,910 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// +build !plan9
|
||||
|
||||
#include <u.h>
|
||||
#include <time.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define Ureg Ureg_amd64
|
||||
#include <ureg_amd64.h>
|
||||
#undef Ureg
|
||||
#define Ureg Ureg_x86
|
||||
#include <ureg_x86.h>
|
||||
#undef Ureg
|
||||
#include <mach.h>
|
||||
|
||||
char* file = "6.out";
|
||||
static Fhdr fhdr;
|
||||
int have_syms;
|
||||
int fd;
|
||||
struct Ureg_amd64 ureg_amd64;
|
||||
struct Ureg_x86 ureg_x86;
|
||||
int total_sec = 0;
|
||||
int delta_msec = 100;
|
||||
int nsample;
|
||||
int nsamplethread;
|
||||
|
||||
// pprof data, stored as sequences of N followed by N PC values.
|
||||
// See http://code.google.com/p/google-perftools .
|
||||
uvlong *ppdata; // traces
|
||||
Biobuf* pproffd; // file descriptor to write trace info
|
||||
long ppstart; // start position of current trace
|
||||
long nppdata; // length of data
|
||||
long ppalloc; // size of allocated data
|
||||
char ppmapdata[10*1024]; // the map information for the output file
|
||||
|
||||
// output formats
|
||||
int pprof; // print pprof output to named file
|
||||
int functions; // print functions
|
||||
int histograms; // print histograms
|
||||
int linenums; // print file and line numbers rather than function names
|
||||
int registers; // print registers
|
||||
int stacks; // print stack traces
|
||||
|
||||
int pid; // main process pid
|
||||
|
||||
int nthread; // number of threads
|
||||
int thread[32]; // thread pids
|
||||
Map *map[32]; // thread maps
|
||||
|
||||
void
|
||||
Usage(void)
|
||||
{
|
||||
fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
|
||||
fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
|
||||
fprint(2, "\tformats (default -h):\n");
|
||||
fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
|
||||
fprint(2, "\t\t-h: histograms\n");
|
||||
fprint(2, "\t\t-f: dynamic functions\n");
|
||||
fprint(2, "\t\t-l: dynamic file and line numbers\n");
|
||||
fprint(2, "\t\t-r: dynamic registers\n");
|
||||
fprint(2, "\t\t-s: dynamic function stack traces\n");
|
||||
fprint(2, "\t\t-hs: include stack info in histograms\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
typedef struct PC PC;
|
||||
struct PC {
|
||||
uvlong pc;
|
||||
uvlong callerpc;
|
||||
unsigned int count;
|
||||
PC* next;
|
||||
};
|
||||
|
||||
enum {
|
||||
Ncounters = 256
|
||||
};
|
||||
|
||||
PC *counters[Ncounters];
|
||||
|
||||
// Set up by setarch() to make most of the code architecture-independent.
|
||||
typedef struct Arch Arch;
|
||||
struct Arch {
|
||||
char* name;
|
||||
void (*regprint)(void);
|
||||
int (*getregs)(Map*);
|
||||
int (*getPC)(Map*);
|
||||
int (*getSP)(Map*);
|
||||
uvlong (*uregPC)(void);
|
||||
uvlong (*uregSP)(void);
|
||||
void (*ppword)(uvlong w);
|
||||
};
|
||||
|
||||
void
|
||||
amd64_regprint(void)
|
||||
{
|
||||
fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
|
||||
fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
|
||||
fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
|
||||
fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
|
||||
fprint(2, "si\t0x%llux\n", ureg_amd64.si);
|
||||
fprint(2, "di\t0x%llux\n", ureg_amd64.di);
|
||||
fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
|
||||
fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
|
||||
fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
|
||||
fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
|
||||
fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
|
||||
fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
|
||||
fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
|
||||
fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
|
||||
fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
|
||||
fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
|
||||
fprint(2, "es\t0x%llux\n", ureg_amd64.es);
|
||||
fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
|
||||
fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
|
||||
fprint(2, "type\t0x%llux\n", ureg_amd64.type);
|
||||
fprint(2, "error\t0x%llux\n", ureg_amd64.error);
|
||||
fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
|
||||
fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
|
||||
fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
|
||||
fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
|
||||
fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
|
||||
}
|
||||
|
||||
int
|
||||
amd64_getregs(Map *map)
|
||||
{
|
||||
int i;
|
||||
union {
|
||||
uvlong regs[1];
|
||||
struct Ureg_amd64 ureg;
|
||||
} u;
|
||||
|
||||
for(i = 0; i < sizeof ureg_amd64; i+=8) {
|
||||
if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
|
||||
return -1;
|
||||
}
|
||||
ureg_amd64 = u.ureg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
amd64_getPC(Map *map)
|
||||
{
|
||||
uvlong x;
|
||||
int r;
|
||||
|
||||
r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
|
||||
ureg_amd64.ip = x;
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
amd64_getSP(Map *map)
|
||||
{
|
||||
uvlong x;
|
||||
int r;
|
||||
|
||||
r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
|
||||
ureg_amd64.sp = x;
|
||||
return r;
|
||||
}
|
||||
|
||||
uvlong
|
||||
amd64_uregPC(void)
|
||||
{
|
||||
return ureg_amd64.ip;
|
||||
}
|
||||
|
||||
uvlong
|
||||
amd64_uregSP(void)
|
||||
{
|
||||
return ureg_amd64.sp;
|
||||
}
|
||||
|
||||
void
|
||||
amd64_ppword(uvlong w)
|
||||
{
|
||||
uchar buf[8];
|
||||
|
||||
buf[0] = w;
|
||||
buf[1] = w >> 8;
|
||||
buf[2] = w >> 16;
|
||||
buf[3] = w >> 24;
|
||||
buf[4] = w >> 32;
|
||||
buf[5] = w >> 40;
|
||||
buf[6] = w >> 48;
|
||||
buf[7] = w >> 56;
|
||||
Bwrite(pproffd, buf, 8);
|
||||
}
|
||||
|
||||
void
|
||||
x86_regprint(void)
|
||||
{
|
||||
fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
|
||||
fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
|
||||
fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
|
||||
fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
|
||||
fprint(2, "si\t0x%ux\n", ureg_x86.si);
|
||||
fprint(2, "di\t0x%ux\n", ureg_x86.di);
|
||||
fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
|
||||
fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
|
||||
fprint(2, "es\t0x%ux\n", ureg_x86.es);
|
||||
fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
|
||||
fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
|
||||
fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
|
||||
fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
|
||||
fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
|
||||
fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
|
||||
fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
|
||||
}
|
||||
|
||||
int
|
||||
x86_getregs(Map *map)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof ureg_x86; i+=4) {
|
||||
if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
x86_getPC(Map* map)
|
||||
{
|
||||
return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
|
||||
}
|
||||
|
||||
int
|
||||
x86_getSP(Map* map)
|
||||
{
|
||||
return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
|
||||
}
|
||||
|
||||
uvlong
|
||||
x86_uregPC(void)
|
||||
{
|
||||
return (uvlong)ureg_x86.pc;
|
||||
}
|
||||
|
||||
uvlong
|
||||
x86_uregSP(void)
|
||||
{
|
||||
return (uvlong)ureg_x86.sp;
|
||||
}
|
||||
|
||||
void
|
||||
x86_ppword(uvlong w)
|
||||
{
|
||||
uchar buf[4];
|
||||
|
||||
buf[0] = w;
|
||||
buf[1] = w >> 8;
|
||||
buf[2] = w >> 16;
|
||||
buf[3] = w >> 24;
|
||||
Bwrite(pproffd, buf, 4);
|
||||
}
|
||||
|
||||
Arch archtab[] = {
|
||||
{
|
||||
"amd64",
|
||||
amd64_regprint,
|
||||
amd64_getregs,
|
||||
amd64_getPC,
|
||||
amd64_getSP,
|
||||
amd64_uregPC,
|
||||
amd64_uregSP,
|
||||
amd64_ppword,
|
||||
},
|
||||
{
|
||||
"386",
|
||||
x86_regprint,
|
||||
x86_getregs,
|
||||
x86_getPC,
|
||||
x86_getSP,
|
||||
x86_uregPC,
|
||||
x86_uregSP,
|
||||
x86_ppword,
|
||||
},
|
||||
{
|
||||
nil
|
||||
}
|
||||
};
|
||||
|
||||
Arch *arch;
|
||||
|
||||
int
|
||||
setarch(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(mach != nil) {
|
||||
for(i = 0; archtab[i].name != nil; i++) {
|
||||
if (strcmp(mach->name, archtab[i].name) == 0) {
|
||||
arch = &archtab[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
getthreads(void)
|
||||
{
|
||||
int i, j, curn, found;
|
||||
Map *curmap[nelem(map)];
|
||||
int curthread[nelem(map)];
|
||||
static int complained = 0;
|
||||
|
||||
curn = procthreadpids(pid, curthread, nelem(curthread));
|
||||
if(curn <= 0)
|
||||
return curn;
|
||||
|
||||
if(curn > nelem(map)) {
|
||||
if(complained == 0) {
|
||||
fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
|
||||
complained = 1;
|
||||
}
|
||||
curn = nelem(map);
|
||||
}
|
||||
if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
|
||||
return curn; // no changes
|
||||
|
||||
// Number of threads has changed (might be the init case).
|
||||
// A bit expensive but rare enough not to bother being clever.
|
||||
for(i = 0; i < curn; i++) {
|
||||
found = 0;
|
||||
for(j = 0; j < nthread; j++) {
|
||||
if(curthread[i] == thread[j]) {
|
||||
found = 1;
|
||||
curmap[i] = map[j];
|
||||
map[j] = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found)
|
||||
continue;
|
||||
|
||||
// map new thread
|
||||
curmap[i] = attachproc(curthread[i], &fhdr);
|
||||
if(curmap[i] == nil) {
|
||||
fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < nthread; j++)
|
||||
if(map[j] != nil)
|
||||
detachproc(map[j]);
|
||||
|
||||
nthread = curn;
|
||||
memmove(thread, curthread, nthread*sizeof thread[0]);
|
||||
memmove(map, curmap, sizeof map);
|
||||
return nthread;
|
||||
}
|
||||
|
||||
int
|
||||
sample(Map *map)
|
||||
{
|
||||
static int n;
|
||||
|
||||
n++;
|
||||
if(registers) {
|
||||
if(arch->getregs(map) < 0)
|
||||
goto bad;
|
||||
} else {
|
||||
// we need only two registers
|
||||
if(arch->getPC(map) < 0)
|
||||
goto bad;
|
||||
if(arch->getSP(map) < 0)
|
||||
goto bad;
|
||||
}
|
||||
return 1;
|
||||
bad:
|
||||
if(n == 1)
|
||||
fprint(2, "prof: can't read registers: %r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
|
||||
{
|
||||
int h;
|
||||
PC *x;
|
||||
|
||||
USED(sp);
|
||||
|
||||
h = (pc + callerpc*101) % Ncounters;
|
||||
for(x = counters[h]; x != NULL; x = x->next) {
|
||||
if(x->pc == pc && x->callerpc == callerpc) {
|
||||
x->count++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
x = malloc(sizeof(PC));
|
||||
if(x == nil)
|
||||
sysfatal("out of memory");
|
||||
x->pc = pc;
|
||||
x->callerpc = callerpc;
|
||||
x->count = 1;
|
||||
x->next = counters[h];
|
||||
counters[h] = x;
|
||||
}
|
||||
|
||||
void
|
||||
addppword(uvlong pc)
|
||||
{
|
||||
if(pc == 0) {
|
||||
return;
|
||||
}
|
||||
if(nppdata == ppalloc) {
|
||||
ppalloc = (1000+nppdata)*2;
|
||||
ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
|
||||
if(ppdata == nil) {
|
||||
fprint(2, "prof: realloc failed: %r\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
ppdata[nppdata++] = pc;
|
||||
}
|
||||
|
||||
void
|
||||
startpptrace(void)
|
||||
{
|
||||
ppstart = nppdata;
|
||||
addppword(~0);
|
||||
}
|
||||
|
||||
void
|
||||
endpptrace(void)
|
||||
{
|
||||
ppdata[ppstart] = nppdata-ppstart-1;
|
||||
}
|
||||
|
||||
uvlong nextpc;
|
||||
|
||||
void
|
||||
xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
|
||||
{
|
||||
USED(map);
|
||||
|
||||
char buf[1024];
|
||||
if(sym == nil){
|
||||
fprint(2, "syms\n");
|
||||
return;
|
||||
}
|
||||
if(histograms)
|
||||
addtohistogram(nextpc, pc, sp);
|
||||
if(!histograms || stacks > 1 || pprof) {
|
||||
if(nextpc == 0)
|
||||
nextpc = sym->value;
|
||||
if(stacks){
|
||||
fprint(2, "%s(", sym->name);
|
||||
fprint(2, ")");
|
||||
if(nextpc != sym->value)
|
||||
fprint(2, "+%#llux ", nextpc - sym->value);
|
||||
if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
|
||||
fprint(2, " %s", buf);
|
||||
}
|
||||
fprint(2, "\n");
|
||||
}
|
||||
if (pprof) {
|
||||
addppword(nextpc);
|
||||
}
|
||||
}
|
||||
nextpc = pc;
|
||||
}
|
||||
|
||||
void
|
||||
stacktracepcsp(Map *map, uvlong pc, uvlong sp)
|
||||
{
|
||||
nextpc = pc;
|
||||
if(pprof){
|
||||
startpptrace();
|
||||
}
|
||||
if(machdata->ctrace==nil)
|
||||
fprint(2, "no machdata->ctrace\n");
|
||||
else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
|
||||
fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
|
||||
else {
|
||||
addtohistogram(nextpc, 0, sp);
|
||||
if(stacks)
|
||||
fprint(2, "\n");
|
||||
}
|
||||
if(pprof){
|
||||
endpptrace();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
printpc(Map *map, uvlong pc, uvlong sp)
|
||||
{
|
||||
char buf[1024];
|
||||
if(registers)
|
||||
arch->regprint();
|
||||
if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
|
||||
fprint(2, "%s\n", buf);
|
||||
if(have_syms > 0 && functions) {
|
||||
symoff(buf, sizeof(buf), pc, CANY);
|
||||
fprint(2, "%s\n", buf);
|
||||
}
|
||||
if(stacks || pprof){
|
||||
stacktracepcsp(map, pc, sp);
|
||||
}
|
||||
else if(histograms){
|
||||
addtohistogram(pc, 0, sp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ppmaps(void)
|
||||
{
|
||||
int fd, n;
|
||||
char tmp[100];
|
||||
Seg *seg;
|
||||
|
||||
// If it's Linux, the info is in /proc/$pid/maps
|
||||
snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
|
||||
fd = open(tmp, 0);
|
||||
if(fd >= 0) {
|
||||
n = read(fd, ppmapdata, sizeof ppmapdata - 1);
|
||||
close(fd);
|
||||
if(n < 0) {
|
||||
fprint(2, "prof: can't read %s: %r\n", tmp);
|
||||
exit(2);
|
||||
}
|
||||
ppmapdata[n] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// It's probably a mac. Synthesize an entry for the text file.
|
||||
// The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
|
||||
for(n = 0; n < 3; n++){
|
||||
seg = &map[0]->seg[n];
|
||||
if(seg->b == 0) {
|
||||
continue;
|
||||
}
|
||||
snprint(ppmapdata, sizeof ppmapdata,
|
||||
"%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
|
||||
seg->b, seg->e, seg->f, "/home/r/6.out"
|
||||
);
|
||||
return;
|
||||
}
|
||||
fprint(2, "prof: no text segment in maps for %s\n", file);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void
|
||||
samples(void)
|
||||
{
|
||||
int i, pid, msec;
|
||||
struct timespec req;
|
||||
int getmaps;
|
||||
|
||||
req.tv_sec = delta_msec/1000;
|
||||
req.tv_nsec = 1000000*(delta_msec % 1000);
|
||||
getmaps = 0;
|
||||
if(pprof)
|
||||
getmaps= 1;
|
||||
for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
|
||||
nsample++;
|
||||
nsamplethread += nthread;
|
||||
for(i = 0; i < nthread; i++) {
|
||||
pid = thread[i];
|
||||
if(ctlproc(pid, "stop") < 0)
|
||||
return;
|
||||
if(!sample(map[i])) {
|
||||
ctlproc(pid, "start");
|
||||
return;
|
||||
}
|
||||
printpc(map[i], arch->uregPC(), arch->uregSP());
|
||||
ctlproc(pid, "start");
|
||||
}
|
||||
nanosleep(&req, NULL);
|
||||
getthreads();
|
||||
if(nthread == 0)
|
||||
break;
|
||||
if(getmaps) {
|
||||
getmaps = 0;
|
||||
ppmaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Func Func;
|
||||
struct Func
|
||||
{
|
||||
Func *next;
|
||||
Symbol s;
|
||||
uint onstack;
|
||||
uint leaf;
|
||||
};
|
||||
|
||||
Func *func[257];
|
||||
int nfunc;
|
||||
|
||||
Func*
|
||||
findfunc(uvlong pc)
|
||||
{
|
||||
Func *f;
|
||||
uint h;
|
||||
Symbol s;
|
||||
|
||||
if(pc == 0)
|
||||
return nil;
|
||||
|
||||
if(!findsym(pc, CTEXT, &s))
|
||||
return nil;
|
||||
|
||||
h = s.value % nelem(func);
|
||||
for(f = func[h]; f != NULL; f = f->next)
|
||||
if(f->s.value == s.value)
|
||||
return f;
|
||||
|
||||
f = malloc(sizeof *f);
|
||||
if(f == nil)
|
||||
sysfatal("out of memory");
|
||||
memset(f, 0, sizeof *f);
|
||||
f->s = s;
|
||||
f->next = func[h];
|
||||
func[h] = f;
|
||||
nfunc++;
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
compareleaf(const void *va, const void *vb)
|
||||
{
|
||||
Func *a, *b;
|
||||
|
||||
a = *(Func**)va;
|
||||
b = *(Func**)vb;
|
||||
if(a->leaf != b->leaf)
|
||||
return b->leaf - a->leaf;
|
||||
if(a->onstack != b->onstack)
|
||||
return b->onstack - a->onstack;
|
||||
return strcmp(a->s.name, b->s.name);
|
||||
}
|
||||
|
||||
void
|
||||
dumphistogram(void)
|
||||
{
|
||||
int i, h, n;
|
||||
PC *x;
|
||||
Func *f, **ff;
|
||||
|
||||
if(!histograms)
|
||||
return;
|
||||
|
||||
// assign counts to functions.
|
||||
for(h = 0; h < Ncounters; h++) {
|
||||
for(x = counters[h]; x != NULL; x = x->next) {
|
||||
f = findfunc(x->pc);
|
||||
if(f) {
|
||||
f->onstack += x->count;
|
||||
f->leaf += x->count;
|
||||
}
|
||||
f = findfunc(x->callerpc);
|
||||
if(f)
|
||||
f->leaf -= x->count;
|
||||
}
|
||||
}
|
||||
|
||||
// build array
|
||||
ff = malloc(nfunc*sizeof ff[0]);
|
||||
if(ff == nil)
|
||||
sysfatal("out of memory");
|
||||
n = 0;
|
||||
for(h = 0; h < nelem(func); h++)
|
||||
for(f = func[h]; f != NULL; f = f->next)
|
||||
ff[n++] = f;
|
||||
|
||||
// sort by leaf counts
|
||||
qsort(ff, nfunc, sizeof ff[0], compareleaf);
|
||||
|
||||
// print.
|
||||
fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
|
||||
for(i = 0; i < nfunc; i++) {
|
||||
f = ff[i];
|
||||
fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
|
||||
if(stacks)
|
||||
fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
|
||||
fprint(2, "%s\n", f->s.name);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct Trace Trace;
|
||||
struct Trace {
|
||||
int count;
|
||||
int npc;
|
||||
uvlong *pc;
|
||||
Trace *next;
|
||||
};
|
||||
|
||||
void
|
||||
dumppprof(void)
|
||||
{
|
||||
uvlong i, n, *p, *e;
|
||||
int ntrace;
|
||||
Trace *trace, *tp, *up, *prev;
|
||||
|
||||
if(!pprof)
|
||||
return;
|
||||
e = ppdata + nppdata;
|
||||
// Create list of traces. First, count the traces
|
||||
ntrace = 0;
|
||||
for(p = ppdata; p < e;) {
|
||||
n = *p++;
|
||||
p += n;
|
||||
if(n == 0)
|
||||
continue;
|
||||
ntrace++;
|
||||
}
|
||||
if(ntrace <= 0)
|
||||
return;
|
||||
// Allocate and link the traces together.
|
||||
trace = malloc(ntrace * sizeof(Trace));
|
||||
if(trace == nil)
|
||||
sysfatal("out of memory");
|
||||
tp = trace;
|
||||
for(p = ppdata; p < e;) {
|
||||
n = *p++;
|
||||
if(n == 0)
|
||||
continue;
|
||||
tp->count = 1;
|
||||
tp->npc = n;
|
||||
tp->pc = p;
|
||||
tp->next = tp+1;
|
||||
tp++;
|
||||
p += n;
|
||||
}
|
||||
trace[ntrace-1].next = nil;
|
||||
// Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
|
||||
// the list collapses fast.
|
||||
for(tp = trace; tp != nil; tp = tp->next) {
|
||||
prev = tp;
|
||||
for(up = tp->next; up != nil; up = up->next) {
|
||||
if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
|
||||
tp->count++;
|
||||
prev->next = up->next;
|
||||
} else {
|
||||
prev = up;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write file.
|
||||
// See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
|
||||
// 1) Header
|
||||
arch->ppword(0); // must be zero
|
||||
arch->ppword(3); // 3 words follow in header
|
||||
arch->ppword(0); // must be zero
|
||||
arch->ppword(delta_msec * 1000); // sampling period in microseconds
|
||||
arch->ppword(0); // must be zero (padding)
|
||||
// 2) One record for each trace.
|
||||
for(tp = trace; tp != nil; tp = tp->next) {
|
||||
arch->ppword(tp->count);
|
||||
arch->ppword(tp->npc);
|
||||
for(i = 0; i < tp->npc; i++) {
|
||||
arch->ppword(tp->pc[i]);
|
||||
}
|
||||
}
|
||||
// 3) Binary trailer
|
||||
arch->ppword(0); // must be zero
|
||||
arch->ppword(1); // must be one
|
||||
arch->ppword(0); // must be zero
|
||||
// 4) Mapped objects.
|
||||
Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
|
||||
// 5) That's it.
|
||||
Bterm(pproffd);
|
||||
}
|
||||
|
||||
int
|
||||
startprocess(char **argv)
|
||||
{
|
||||
int pid;
|
||||
|
||||
if((pid = fork()) == 0) {
|
||||
pid = getpid();
|
||||
if(ctlproc(pid, "hang") < 0){
|
||||
fprint(2, "prof: child process could not hang\n");
|
||||
exits(0);
|
||||
}
|
||||
execv(argv[0], argv);
|
||||
fprint(2, "prof: could not exec %s: %r\n", argv[0]);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
if(pid == -1) {
|
||||
fprint(2, "prof: could not fork\n");
|
||||
exit(1);
|
||||
}
|
||||
if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
|
||||
fprint(2, "prof: could not attach to child process: %r\n");
|
||||
exit(1);
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
void
|
||||
detach(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nthread; i++)
|
||||
detachproc(map[i]);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *ppfile;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'P':
|
||||
pprof =1;
|
||||
ppfile = EARGF(Usage());
|
||||
pproffd = Bopen(ppfile, OWRITE);
|
||||
if(pproffd == nil) {
|
||||
fprint(2, "prof: cannot open %s: %r\n", ppfile);
|
||||
exit(2);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
delta_msec = atoi(EARGF(Usage()));
|
||||
break;
|
||||
case 't':
|
||||
total_sec = atoi(EARGF(Usage()));
|
||||
break;
|
||||
case 'p':
|
||||
pid = atoi(EARGF(Usage()));
|
||||
break;
|
||||
case 'f':
|
||||
functions = 1;
|
||||
break;
|
||||
case 'h':
|
||||
histograms = 1;
|
||||
break;
|
||||
case 'l':
|
||||
linenums = 1;
|
||||
break;
|
||||
case 'r':
|
||||
registers = 1;
|
||||
break;
|
||||
case 's':
|
||||
stacks++;
|
||||
break;
|
||||
default:
|
||||
Usage();
|
||||
}ARGEND
|
||||
if(pid <= 0 && argc == 0)
|
||||
Usage();
|
||||
if(functions+linenums+registers+stacks+pprof == 0)
|
||||
histograms = 1;
|
||||
if(!machbyname("amd64")) {
|
||||
fprint(2, "prof: no amd64 support\n", pid);
|
||||
exit(1);
|
||||
}
|
||||
if(argc > 0)
|
||||
file = argv[0];
|
||||
else if(pid) {
|
||||
file = proctextfile(pid);
|
||||
if (file == NULL) {
|
||||
fprint(2, "prof: can't find file for pid %d: %r\n", pid);
|
||||
fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
fd = open(file, 0);
|
||||
if(fd < 0) {
|
||||
fprint(2, "prof: can't open %s: %r\n", file);
|
||||
exit(1);
|
||||
}
|
||||
if(crackhdr(fd, &fhdr)) {
|
||||
have_syms = syminit(fd, &fhdr);
|
||||
if(!have_syms) {
|
||||
fprint(2, "prof: no symbols for %s: %r\n", file);
|
||||
}
|
||||
} else {
|
||||
fprint(2, "prof: crack header for %s: %r\n", file);
|
||||
exit(1);
|
||||
}
|
||||
if(pid <= 0)
|
||||
pid = startprocess(argv);
|
||||
attachproc(pid, &fhdr); // initializes thread list
|
||||
if(setarch() < 0) {
|
||||
detach();
|
||||
fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
|
||||
exit(1);
|
||||
}
|
||||
if(getthreads() <= 0) {
|
||||
detach();
|
||||
fprint(2, "prof: can't find threads for pid %d\n", pid);
|
||||
exit(1);
|
||||
}
|
||||
for(i = 0; i < nthread; i++)
|
||||
ctlproc(thread[i], "start");
|
||||
samples();
|
||||
detach();
|
||||
dumphistogram();
|
||||
dumppprof();
|
||||
exit(0);
|
||||
}
|
||||
@@ -357,7 +357,7 @@ func main() {
|
||||
func setup() {
|
||||
var j, ty int
|
||||
|
||||
stderr = bufio.NewWriter(os.NewFile(2, "stderr"))
|
||||
stderr = bufio.NewWriter(os.Stderr)
|
||||
foutput = nil
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@@ -126,10 +126,19 @@ type signatureAndHash struct {
|
||||
hash, signature uint8
|
||||
}
|
||||
|
||||
// supportedSignatureAlgorithms contains the signature and hash algorithms that
|
||||
// the code can advertise as supported both in a TLS 1.2 ClientHello and
|
||||
// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
|
||||
// that the code advertises as supported in a TLS 1.2 ClientHello.
|
||||
var supportedSKXSignatureAlgorithms = []signatureAndHash{
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA256, signatureECDSA},
|
||||
{hashSHA1, signatureRSA},
|
||||
{hashSHA1, signatureECDSA},
|
||||
}
|
||||
|
||||
// supportedClientCertSignatureAlgorithms contains the signature and hash
|
||||
// algorithms that the code advertises as supported in a TLS 1.2
|
||||
// CertificateRequest.
|
||||
var supportedSignatureAlgorithms = []signatureAndHash{
|
||||
var supportedClientCertSignatureAlgorithms = []signatureAndHash{
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA256, signatureECDSA},
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ NextCipherSuite:
|
||||
}
|
||||
|
||||
if hello.vers >= VersionTLS12 {
|
||||
hello.signatureAndHashes = supportedSignatureAlgorithms
|
||||
hello.signatureAndHashes = supportedSKXSignatureAlgorithms
|
||||
}
|
||||
|
||||
c.writeRecord(recordTypeHandshake, hello.marshal())
|
||||
|
||||
@@ -1834,30 +1834,30 @@ var clientChainCertificateScript = [][]byte{
|
||||
// -minversion=0x0303 -maxversion=0x0303
|
||||
var clientTLS12Script = [][]byte{
|
||||
{
|
||||
0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
|
||||
0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
|
||||
0x01, 0x00, 0x00, 0x25, 0x00, 0x05, 0x00, 0x05,
|
||||
0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
||||
0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
|
||||
0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x04,
|
||||
0x03,
|
||||
0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
|
||||
0x03, 0x02, 0x01, 0x02, 0x03,
|
||||
},
|
||||
{
|
||||
0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x51, 0xe5, 0x78, 0x4c, 0x64,
|
||||
0x66, 0xd0, 0xee, 0x0b, 0x8b, 0xfd, 0x9b, 0xe0,
|
||||
0x54, 0x3c, 0x6e, 0x05, 0x04, 0x2f, 0x77, 0x07,
|
||||
0x8c, 0x04, 0xb9, 0xf6, 0xdd, 0xea, 0x1a, 0x7c,
|
||||
0xdf, 0x65, 0x39, 0x20, 0xea, 0xa2, 0xef, 0x53,
|
||||
0x96, 0xf5, 0x0b, 0x8a, 0x47, 0xa0, 0x7c, 0x20,
|
||||
0x53, 0x75, 0xee, 0x87, 0xb9, 0xd3, 0xe2, 0xa6,
|
||||
0x97, 0x64, 0xb9, 0xa6, 0xcc, 0xc0, 0xe5, 0xbf,
|
||||
0x92, 0x1d, 0xee, 0x4d, 0xc0, 0x13, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xbd, 0xe8,
|
||||
0x72, 0x03, 0x6a, 0x52, 0x8d, 0x28, 0x2c, 0x9a,
|
||||
0x53, 0xff, 0xc2, 0xa1, 0x62, 0x5f, 0x54, 0xfb,
|
||||
0x73, 0x00, 0xcf, 0x4d, 0x28, 0x36, 0xc2, 0xee,
|
||||
0xfd, 0x78, 0xf0, 0x20, 0x6f, 0xbe, 0x49, 0xec,
|
||||
0x5b, 0x6f, 0xf9, 0x53, 0x42, 0x69, 0x0d, 0x6d,
|
||||
0x8b, 0x68, 0x2e, 0xca, 0x3c, 0x3c, 0x88, 0x9e,
|
||||
0x8b, 0xf9, 0x32, 0x65, 0x09, 0xd6, 0xa0, 0x7d,
|
||||
0xea, 0xc6, 0xd5, 0xc4, 0xc0, 0x13, 0x00, 0x00,
|
||||
0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
|
||||
0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
|
||||
0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
|
||||
@@ -1932,24 +1932,24 @@ var clientTLS12Script = [][]byte{
|
||||
0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
|
||||
0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
|
||||
0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
|
||||
0x03, 0x00, 0x17, 0x41, 0x04, 0x39, 0xe9, 0x59,
|
||||
0x24, 0x76, 0xf0, 0x1a, 0xd6, 0x21, 0xa5, 0xbc,
|
||||
0x28, 0xb9, 0xd5, 0x3d, 0xf7, 0xf3, 0xbe, 0x09,
|
||||
0xff, 0xc1, 0x79, 0x33, 0x82, 0xf8, 0xe1, 0x5f,
|
||||
0x1c, 0x34, 0x96, 0x3a, 0x10, 0xf2, 0x2c, 0x69,
|
||||
0xab, 0x57, 0xf6, 0x20, 0xb6, 0x59, 0x1f, 0x8c,
|
||||
0x3e, 0xa2, 0xac, 0x4d, 0xf2, 0x10, 0x58, 0x0b,
|
||||
0x61, 0x27, 0x6c, 0x47, 0xa0, 0x52, 0xc7, 0xe6,
|
||||
0x36, 0xfd, 0xb1, 0xa2, 0x49, 0x04, 0x01, 0x00,
|
||||
0x40, 0x99, 0x7e, 0xf9, 0xed, 0x8b, 0x62, 0x82,
|
||||
0x00, 0xde, 0x5f, 0x2f, 0xb9, 0xf9, 0x9d, 0xa1,
|
||||
0xb0, 0x14, 0x05, 0xc1, 0xdd, 0xa3, 0xb9, 0x08,
|
||||
0xa5, 0x36, 0xb6, 0xfe, 0x8a, 0x5b, 0x2d, 0x6e,
|
||||
0xd8, 0x5a, 0x5c, 0x89, 0x84, 0x85, 0x56, 0x01,
|
||||
0xaf, 0x43, 0xd3, 0x0f, 0x85, 0xd0, 0xb2, 0x35,
|
||||
0x3d, 0x1d, 0xd6, 0x67, 0x52, 0x48, 0xe8, 0x82,
|
||||
0x47, 0xbb, 0x2a, 0x54, 0x4a, 0x55, 0xcd, 0x10,
|
||||
0x54, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00,
|
||||
0x03, 0x00, 0x17, 0x41, 0x04, 0x48, 0x93, 0x62,
|
||||
0x6a, 0xf8, 0x7c, 0x94, 0xcc, 0xcc, 0x0a, 0x9b,
|
||||
0x5e, 0x11, 0xad, 0x0b, 0x30, 0xc4, 0x5d, 0xf7,
|
||||
0x63, 0x24, 0xc1, 0xb0, 0x40, 0x5f, 0xff, 0x9f,
|
||||
0x0d, 0x7e, 0xd5, 0xa5, 0xd0, 0x4f, 0x80, 0x16,
|
||||
0xa8, 0x66, 0x18, 0x31, 0x1f, 0x81, 0xb2, 0x9a,
|
||||
0x41, 0x62, 0x5b, 0xcf, 0x73, 0xac, 0x4a, 0x64,
|
||||
0xb5, 0xc1, 0x46, 0x4d, 0x8a, 0xac, 0x25, 0xba,
|
||||
0x81, 0x7f, 0xbe, 0x64, 0x68, 0x04, 0x01, 0x00,
|
||||
0x40, 0x4e, 0x3f, 0x1e, 0x04, 0x4c, 0xef, 0xd2,
|
||||
0xa6, 0x82, 0xe6, 0x7c, 0x76, 0x23, 0x17, 0xb9,
|
||||
0xe7, 0x52, 0x15, 0x6b, 0x3d, 0xb2, 0xb1, 0x17,
|
||||
0x7d, 0xe6, 0xde, 0x06, 0x87, 0x30, 0xb0, 0xb5,
|
||||
0x57, 0xae, 0xdf, 0xb2, 0xdc, 0x8d, 0xab, 0x76,
|
||||
0x9c, 0xaa, 0x45, 0x6d, 0x23, 0x5d, 0xc1, 0xa8,
|
||||
0x7b, 0x79, 0x79, 0xb1, 0x3c, 0xdc, 0xf5, 0x33,
|
||||
0x2c, 0xa1, 0x62, 0x3e, 0xbd, 0xf5, 0x5d, 0x6c,
|
||||
0x87, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00,
|
||||
0x00, 0x00,
|
||||
},
|
||||
{
|
||||
@@ -1965,74 +1965,74 @@ var clientTLS12Script = [][]byte{
|
||||
0xdc, 0x5a, 0x89, 0x14, 0x03, 0x03, 0x00, 0x01,
|
||||
0x01, 0x16, 0x03, 0x03, 0x00, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xcb,
|
||||
0x97, 0x41, 0x63, 0x39, 0xeb, 0xda, 0x04, 0x39,
|
||||
0xfb, 0x67, 0x1d, 0x6d, 0xf8, 0x58, 0xd1, 0x22,
|
||||
0x35, 0xe3, 0xc3, 0x9d, 0xfc, 0x4e, 0xcc, 0x71,
|
||||
0x93, 0x78, 0x64, 0x39, 0x04, 0xa0, 0xa9, 0x41,
|
||||
0xcf, 0x4c, 0xd6, 0x34, 0xad, 0x5c, 0xc9, 0x7a,
|
||||
0x44, 0xb1, 0x1d, 0x77, 0x52, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x17,
|
||||
0x54, 0x51, 0xb6, 0x1d, 0x8e, 0xe4, 0x6b, 0xed,
|
||||
0x5b, 0xa1, 0x27, 0x7f, 0xdc, 0xa9, 0xa5, 0xcf,
|
||||
0x38, 0xe6, 0x5d, 0x17, 0x34, 0xf9, 0xc0, 0x07,
|
||||
0xb8, 0xbe, 0x56, 0xe6, 0xd6, 0x6a, 0xb6, 0x26,
|
||||
0x4e, 0x45, 0x8d, 0x48, 0xe9, 0xc6, 0xb1, 0xa1,
|
||||
0xea, 0xdc, 0xb1, 0x37, 0xd9, 0xf6,
|
||||
},
|
||||
{
|
||||
0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
|
||||
0x03, 0x00, 0x40, 0x55, 0x75, 0x8a, 0x57, 0xb4,
|
||||
0x53, 0xa2, 0x8f, 0xbf, 0xd3, 0x79, 0x72, 0x1e,
|
||||
0x94, 0x53, 0xb3, 0x03, 0x9d, 0x4d, 0x8a, 0x1f,
|
||||
0xbd, 0x25, 0x79, 0x69, 0x61, 0x65, 0xd7, 0x26,
|
||||
0xad, 0xa6, 0x0e, 0x89, 0x83, 0xc0, 0xbe, 0x46,
|
||||
0x51, 0xe4, 0x38, 0x7b, 0x65, 0x74, 0x6d, 0x24,
|
||||
0xff, 0xd4, 0x9f, 0xcb, 0xfc, 0xd7, 0x03, 0xaa,
|
||||
0x7b, 0x8e, 0x30, 0x09, 0xdb, 0xaa, 0x9d, 0xad,
|
||||
0xcd, 0x56, 0xcf,
|
||||
0x03, 0x00, 0x40, 0x00, 0x68, 0xc5, 0x27, 0xd5,
|
||||
0x3d, 0xba, 0x04, 0xde, 0x63, 0xf1, 0x5b, 0xc3,
|
||||
0x86, 0xb9, 0x82, 0xc7, 0xb3, 0x90, 0x31, 0xea,
|
||||
0x15, 0xe1, 0x42, 0x76, 0x7d, 0x90, 0xcb, 0xc9,
|
||||
0xd1, 0x05, 0xe6, 0x8c, 0x76, 0xc7, 0x9a, 0x35,
|
||||
0x67, 0xa2, 0x70, 0x9a, 0x8a, 0x6c, 0xb5, 0x6b,
|
||||
0xc7, 0x87, 0xf3, 0x65, 0x0a, 0xa0, 0x98, 0xba,
|
||||
0x57, 0xbb, 0x31, 0x7b, 0x1f, 0x1a, 0xf7, 0x2a,
|
||||
0xf3, 0x12, 0xf6,
|
||||
},
|
||||
{
|
||||
0x17, 0x03, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x01, 0x46,
|
||||
0xa8, 0xdd, 0x62, 0x73, 0x67, 0x99, 0x01, 0x42,
|
||||
0xb2, 0x9e, 0x22, 0x18, 0xf5, 0x8f, 0x10, 0x97,
|
||||
0xde, 0x58, 0x24, 0x34, 0x36, 0xa2, 0x5d, 0xf4,
|
||||
0x96, 0x2a, 0xed, 0x6c, 0x06, 0x15, 0x03, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x80,
|
||||
0x54, 0x1e, 0x72, 0xd3, 0x1a, 0x86, 0x1c, 0xc4,
|
||||
0x4a, 0x9b, 0xd4, 0x80, 0xd2, 0x03, 0x35, 0x0d,
|
||||
0xe4, 0x12, 0xc2, 0x3d, 0x79, 0x4a, 0x2c, 0xba,
|
||||
0xc2, 0xad, 0xf3, 0xd2, 0x16, 0x15, 0x03, 0x03,
|
||||
0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x9f, 0x7a, 0x9f, 0xab, 0xf5, 0x4e,
|
||||
0x1c, 0x4e, 0xf4, 0xcb, 0x1a, 0x39, 0xae, 0x21,
|
||||
0x85, 0x39, 0xc4, 0x51, 0xac, 0x14, 0xde, 0xa0,
|
||||
0xe7, 0x70, 0x7c, 0x6a, 0x53, 0x54, 0x19, 0xbc,
|
||||
0x2f, 0x32,
|
||||
0x00, 0x00, 0x04, 0x9b, 0x68, 0x78, 0x92, 0x28,
|
||||
0x62, 0x02, 0x65, 0x87, 0x90, 0xe4, 0x32, 0xd7,
|
||||
0x72, 0x08, 0x70, 0xb8, 0x52, 0x32, 0x1f, 0x97,
|
||||
0xd4, 0x6a, 0xc6, 0x28, 0x83, 0xb0, 0x1d, 0x6e,
|
||||
0x16, 0xd5,
|
||||
},
|
||||
}
|
||||
|
||||
// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
|
||||
// -port 10443
|
||||
// -port 10443 -verify 0
|
||||
// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc02f \
|
||||
// -maxversion=0x0303
|
||||
var clientTLS12ClientCertScript = [][]byte{
|
||||
{
|
||||
0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
|
||||
0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x2f,
|
||||
0x01, 0x00, 0x00, 0x25, 0x00, 0x05, 0x00, 0x05,
|
||||
0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
||||
0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
|
||||
0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x06, 0x00, 0x04, 0x04, 0x01, 0x04,
|
||||
0x03,
|
||||
0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
|
||||
0x03, 0x02, 0x01, 0x02, 0x03,
|
||||
},
|
||||
{
|
||||
0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x52, 0x37, 0x21, 0x96, 0x1c,
|
||||
0x0a, 0x59, 0xc7, 0x16, 0x6d, 0x44, 0x76, 0xda,
|
||||
0x3f, 0x36, 0x12, 0x0c, 0x9d, 0xe1, 0xf7, 0xeb,
|
||||
0x45, 0x53, 0x89, 0xd6, 0x88, 0xc0, 0xe9, 0xce,
|
||||
0x8b, 0x40, 0xf5, 0x20, 0x13, 0x61, 0xd9, 0x3b,
|
||||
0x29, 0x74, 0x3c, 0x4b, 0x9c, 0x7b, 0x3d, 0xfa,
|
||||
0x7a, 0x8e, 0x5b, 0xf2, 0x27, 0x62, 0xc5, 0xdf,
|
||||
0xe4, 0x61, 0x7d, 0xe3, 0x8f, 0x03, 0x0c, 0x2b,
|
||||
0x38, 0x6c, 0xfe, 0x31, 0xc0, 0x2f, 0x00, 0x00,
|
||||
0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xe0, 0xe8,
|
||||
0xf1, 0x13, 0x2a, 0x83, 0x28, 0xa8, 0x2e, 0x76,
|
||||
0x69, 0xe6, 0x89, 0x55, 0x6c, 0x48, 0x49, 0x2e,
|
||||
0x00, 0xf6, 0x87, 0x6c, 0x13, 0xa1, 0xd4, 0xaa,
|
||||
0xd0, 0x76, 0x3b, 0x20, 0xe4, 0xd6, 0x5b, 0x1d,
|
||||
0x11, 0xf2, 0x42, 0xf2, 0x82, 0x0c, 0x0d, 0x66,
|
||||
0x6d, 0xec, 0x52, 0xf8, 0x4a, 0xd9, 0x45, 0xcf,
|
||||
0xe4, 0x4a, 0xba, 0x8b, 0xf1, 0xab, 0x55, 0xe4,
|
||||
0x57, 0x18, 0xa9, 0x36, 0xc0, 0x2f, 0x00, 0x00,
|
||||
0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
|
||||
0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
|
||||
0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
|
||||
@@ -2107,24 +2107,24 @@ var clientTLS12ClientCertScript = [][]byte{
|
||||
0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
|
||||
0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
|
||||
0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
|
||||
0x03, 0x00, 0x17, 0x41, 0x04, 0xdf, 0xc4, 0x75,
|
||||
0x20, 0x7f, 0xc1, 0x8f, 0x92, 0x2d, 0xab, 0x2d,
|
||||
0x65, 0x19, 0x40, 0xf6, 0x26, 0x19, 0x90, 0x84,
|
||||
0x40, 0x55, 0xd3, 0x50, 0xe5, 0x63, 0x9e, 0x4b,
|
||||
0x7a, 0x95, 0xdc, 0xb7, 0x2b, 0xa7, 0xa3, 0x5a,
|
||||
0x5e, 0x01, 0xa0, 0x3e, 0xc2, 0x3c, 0x5d, 0xf6,
|
||||
0x9a, 0xc8, 0xbe, 0x22, 0x23, 0x38, 0x31, 0x7c,
|
||||
0x51, 0x83, 0x5d, 0x4f, 0xfb, 0x08, 0x66, 0x5f,
|
||||
0xfe, 0xf5, 0x97, 0x9a, 0x93, 0x04, 0x01, 0x00,
|
||||
0x40, 0x81, 0x52, 0x86, 0xe6, 0x20, 0x49, 0x65,
|
||||
0x1b, 0x27, 0x46, 0x88, 0xd8, 0x0c, 0x44, 0x47,
|
||||
0xae, 0xbd, 0xc6, 0xe4, 0x4a, 0x2c, 0x10, 0xf4,
|
||||
0x3a, 0xd5, 0xbe, 0x5c, 0xfb, 0x5a, 0xe9, 0x85,
|
||||
0x57, 0xda, 0xf9, 0xb1, 0x8e, 0xce, 0x01, 0x43,
|
||||
0x84, 0x91, 0x68, 0x58, 0xa0, 0xbf, 0xd0, 0x24,
|
||||
0xaa, 0x86, 0xfa, 0x19, 0x59, 0x06, 0x16, 0xe8,
|
||||
0x82, 0x99, 0x90, 0x60, 0x02, 0x82, 0xaf, 0x7e,
|
||||
0x0e, 0x16, 0x03, 0x03, 0x00, 0x30, 0x0d, 0x00,
|
||||
0x03, 0x00, 0x17, 0x41, 0x04, 0xaa, 0xf0, 0x0c,
|
||||
0xa3, 0x60, 0xcf, 0x69, 0x1e, 0xad, 0x16, 0x9a,
|
||||
0x01, 0x40, 0xc6, 0x22, 0xc4, 0xbb, 0x06, 0x3b,
|
||||
0x84, 0x65, 0xea, 0xc7, 0xa2, 0x96, 0x79, 0x17,
|
||||
0x2f, 0xc7, 0xbe, 0x56, 0x39, 0xe4, 0x79, 0xf3,
|
||||
0xad, 0x17, 0xf3, 0x7e, 0xe2, 0x7b, 0xa2, 0x6f,
|
||||
0x3f, 0x96, 0xea, 0xe5, 0x0e, 0xea, 0x39, 0x79,
|
||||
0x77, 0xeb, 0x14, 0x18, 0xbb, 0x7c, 0x95, 0xda,
|
||||
0xa7, 0x51, 0x09, 0xba, 0xd7, 0x04, 0x01, 0x00,
|
||||
0x40, 0x82, 0x3e, 0xce, 0xee, 0x7e, 0xba, 0x3b,
|
||||
0x51, 0xb1, 0xba, 0x71, 0x2e, 0x54, 0xa9, 0xb9,
|
||||
0xe2, 0xb1, 0x59, 0x17, 0xa1, 0xac, 0x76, 0xb4,
|
||||
0x4e, 0xf1, 0xae, 0x65, 0x17, 0x2b, 0x43, 0x06,
|
||||
0x31, 0x29, 0x0b, 0xa0, 0x1e, 0xb6, 0xfa, 0x35,
|
||||
0xe8, 0x63, 0x06, 0xde, 0x13, 0x89, 0x83, 0x69,
|
||||
0x3b, 0xc2, 0x15, 0x73, 0x1c, 0xc5, 0x07, 0xe9,
|
||||
0x38, 0x9b, 0x06, 0x81, 0x1b, 0x97, 0x7c, 0xa6,
|
||||
0x89, 0x16, 0x03, 0x03, 0x00, 0x30, 0x0d, 0x00,
|
||||
0x00, 0x28, 0x03, 0x01, 0x02, 0x40, 0x00, 0x20,
|
||||
0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
|
||||
0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
|
||||
@@ -2496,65 +2496,65 @@ var clientTLS12ClientCertScript = [][]byte{
|
||||
0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
|
||||
0xdc, 0x5a, 0x89, 0x16, 0x03, 0x03, 0x01, 0x08,
|
||||
0x0f, 0x00, 0x01, 0x04, 0x04, 0x01, 0x01, 0x00,
|
||||
0x78, 0x13, 0xba, 0x6a, 0xc6, 0xec, 0xd8, 0x03,
|
||||
0x7f, 0x66, 0x83, 0xbd, 0xa6, 0xd0, 0x60, 0x05,
|
||||
0x20, 0xf7, 0x2b, 0xa3, 0xe3, 0x8c, 0xbf, 0xab,
|
||||
0x40, 0x95, 0x47, 0x31, 0xd0, 0xb6, 0x9e, 0x3c,
|
||||
0x82, 0xf1, 0xd9, 0x25, 0x89, 0x6b, 0x12, 0xf4,
|
||||
0xb4, 0xf4, 0x50, 0x44, 0xad, 0xa1, 0x96, 0x5a,
|
||||
0x2e, 0x2a, 0x75, 0xb5, 0x61, 0x71, 0x08, 0xa0,
|
||||
0x73, 0xc0, 0xdf, 0xa6, 0xd6, 0x34, 0x0f, 0xc8,
|
||||
0x3d, 0x8e, 0x67, 0x73, 0x15, 0x7d, 0x6e, 0xe7,
|
||||
0xe8, 0xf9, 0x79, 0xd2, 0x26, 0x28, 0xef, 0x94,
|
||||
0x06, 0x68, 0xf4, 0x41, 0xc9, 0x06, 0x3c, 0x38,
|
||||
0x27, 0xb9, 0xbe, 0xf3, 0x03, 0x9f, 0x3f, 0x17,
|
||||
0xa9, 0xf8, 0x3f, 0x2b, 0x98, 0x09, 0x69, 0xd2,
|
||||
0x98, 0x71, 0xa8, 0xec, 0xe6, 0xdc, 0xf3, 0x38,
|
||||
0xbc, 0x2f, 0x4a, 0x91, 0xe5, 0x4e, 0x1d, 0x83,
|
||||
0x49, 0xb4, 0xdb, 0x1c, 0x88, 0x6f, 0x0c, 0x5d,
|
||||
0xbd, 0xf4, 0x9a, 0xd3, 0xd1, 0x32, 0xd0, 0xa6,
|
||||
0xf1, 0xe9, 0xb8, 0xf6, 0xfe, 0x3c, 0x09, 0x67,
|
||||
0x40, 0xb5, 0x13, 0xe6, 0xd4, 0x82, 0xda, 0x67,
|
||||
0x27, 0x31, 0xc6, 0xac, 0xc8, 0xf4, 0x17, 0x99,
|
||||
0x2c, 0x1d, 0xf1, 0x6f, 0x1d, 0x25, 0x5f, 0x83,
|
||||
0x60, 0xa9, 0xaf, 0xf1, 0x24, 0x85, 0xd8, 0x01,
|
||||
0x2f, 0x61, 0x21, 0x64, 0xeb, 0xa3, 0x43, 0xb7,
|
||||
0x8f, 0x55, 0x1e, 0xb6, 0xda, 0x47, 0x30, 0xb2,
|
||||
0x30, 0x40, 0xd9, 0x35, 0xb7, 0x6f, 0x5e, 0x7b,
|
||||
0x6f, 0x00, 0x5a, 0x08, 0xa9, 0x67, 0xa4, 0xe5,
|
||||
0xe7, 0xe9, 0xe1, 0xa7, 0x5b, 0x9e, 0xbd, 0xdb,
|
||||
0xd1, 0x2a, 0x48, 0xb2, 0x4f, 0xf6, 0xd5, 0xe4,
|
||||
0x44, 0x4a, 0xb8, 0xd3, 0x68, 0x25, 0xf9, 0xe9,
|
||||
0xb2, 0xf5, 0xcc, 0xcd, 0x81, 0xe0, 0x01, 0x0e,
|
||||
0xb6, 0x1a, 0xe4, 0x23, 0xe9, 0xee, 0xb1, 0x7b,
|
||||
0xca, 0xa8, 0xaa, 0x45, 0xf4, 0x14, 0xeb, 0x2d,
|
||||
0x7e, 0xe4, 0x65, 0x02, 0x8e, 0xb3, 0x34, 0x6a,
|
||||
0x47, 0x71, 0xd1, 0xb0, 0x8d, 0x3c, 0x0c, 0xe1,
|
||||
0xde, 0x7e, 0x5f, 0xb4, 0x15, 0x2d, 0x32, 0x0a,
|
||||
0x2a, 0xdb, 0x9b, 0x40, 0xba, 0xce, 0x8b, 0xf5,
|
||||
0x74, 0xc1, 0x68, 0x20, 0x7c, 0x87, 0x23, 0x13,
|
||||
0xc3, 0x13, 0xa7, 0xdb, 0xec, 0x59, 0xa0, 0x40,
|
||||
0x9e, 0x64, 0x03, 0x60, 0xac, 0x76, 0xff, 0x01,
|
||||
0x34, 0x7b, 0x32, 0x26, 0xd9, 0x41, 0x31, 0x93,
|
||||
0xaa, 0x30, 0x51, 0x83, 0x85, 0x40, 0xeb, 0x4e,
|
||||
0x66, 0x39, 0x83, 0xb1, 0x30, 0x0d, 0x96, 0x01,
|
||||
0xee, 0x81, 0x53, 0x5e, 0xec, 0xa9, 0xc9, 0xdf,
|
||||
0x7e, 0xc1, 0x09, 0x47, 0x8b, 0x35, 0xdb, 0x10,
|
||||
0x15, 0xd4, 0xc7, 0x5a, 0x39, 0xe3, 0xc0, 0xf3,
|
||||
0x93, 0x38, 0x11, 0xdc, 0x71, 0xbb, 0xc7, 0x62,
|
||||
0x2b, 0x85, 0xad, 0x6b, 0x4f, 0x09, 0xb3, 0x31,
|
||||
0xa8, 0xe5, 0xd1, 0xb3, 0xa9, 0x21, 0x37, 0x50,
|
||||
0xc8, 0x7d, 0xc3, 0xd2, 0xf7, 0x00, 0xd3, 0xdb,
|
||||
0x0f, 0x82, 0xf2, 0x43, 0xcf, 0x36, 0x6c, 0x98,
|
||||
0x63, 0xd8, 0x1d, 0xb3, 0xf3, 0xde, 0x63, 0x79,
|
||||
0x64, 0xf0, 0xdb, 0x46, 0x04, 0xe1, 0x1c, 0x57,
|
||||
0x0f, 0x9e, 0x96, 0xb9, 0x93, 0x45, 0x71, 0x1c,
|
||||
0x8b, 0x65, 0x7d, 0x1e, 0xad, 0xbd, 0x03, 0x51,
|
||||
0xae, 0x44, 0xef, 0x97, 0x45, 0x0d, 0x8d, 0x41,
|
||||
0x5c, 0x80, 0x7b, 0xe6, 0xe0, 0xbc, 0xa6, 0x72,
|
||||
0x95, 0xa0, 0x97, 0xe1, 0xbb, 0xc0, 0xcc, 0xe5,
|
||||
0x1e, 0xc3, 0xbe, 0xd7, 0x42, 0x2a, 0xf3, 0x75,
|
||||
0x8a, 0x44, 0x67, 0x3c, 0xe5, 0x68, 0x78, 0xe5,
|
||||
0x40, 0x1f, 0xf0, 0x89, 0x57, 0xda, 0xee, 0x45,
|
||||
0xf4, 0x44, 0x81, 0x01, 0x77, 0xf0, 0x4a, 0x14,
|
||||
0xb1, 0x3f, 0x60, 0x2b, 0xeb, 0x42, 0x38, 0xa6,
|
||||
0xfb, 0xe5, 0x4d, 0x71, 0xdc, 0x7d, 0x0a, 0x72,
|
||||
0x56, 0x28, 0x9d, 0xa6, 0x8e, 0x74, 0x2d, 0xbd,
|
||||
0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
|
||||
0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x56, 0x37, 0x62, 0x42, 0xb3,
|
||||
0xdc, 0xa4, 0x01, 0x64, 0x7f, 0xa7, 0xcf, 0xb1,
|
||||
0xa4, 0x03, 0x4c, 0xf2, 0x4c, 0xe1, 0xee, 0xd6,
|
||||
0x29, 0x45, 0x71, 0x67, 0xeb, 0x3f, 0x82, 0x77,
|
||||
0x65, 0x0c, 0x13,
|
||||
0x00, 0x00, 0x00, 0x31, 0x4d, 0x58, 0x94, 0x0b,
|
||||
0x0b, 0x06, 0x5f, 0xae, 0x57, 0x17, 0x98, 0x86,
|
||||
0xaa, 0x49, 0x17, 0x7f, 0xbd, 0x41, 0x05, 0xa5,
|
||||
0x74, 0x1c, 0x58, 0xc8, 0x38, 0x2d, 0x99, 0x5d,
|
||||
0xe5, 0x12, 0x43,
|
||||
},
|
||||
{
|
||||
0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
|
||||
0x03, 0x00, 0x28, 0xd3, 0x6b, 0x15, 0x0f, 0x23,
|
||||
0xd3, 0x5b, 0x93, 0x1d, 0x39, 0x6a, 0x74, 0xd9,
|
||||
0x78, 0x39, 0xf6, 0x76, 0x6d, 0x5d, 0x21, 0x98,
|
||||
0x7e, 0x10, 0xa4, 0x12, 0x11, 0x55, 0x25, 0xf7,
|
||||
0x6f, 0x12, 0xf1, 0x9b, 0x9f, 0xe1, 0xc0, 0xe6,
|
||||
0xbd, 0x93, 0xde,
|
||||
0x03, 0x00, 0x28, 0xf2, 0x60, 0xc2, 0x75, 0x27,
|
||||
0x64, 0xf4, 0x05, 0x98, 0xc9, 0xd3, 0xa8, 0x00,
|
||||
0x4c, 0xa0, 0x49, 0x82, 0x68, 0xf1, 0x21, 0x05,
|
||||
0x7b, 0x4b, 0x25, 0x3e, 0xe1, 0x5f, 0x0f, 0x84,
|
||||
0x26, 0x2d, 0x16, 0x2e, 0xc0, 0xfd, 0xdf, 0x0a,
|
||||
0xf4, 0xba, 0x19,
|
||||
},
|
||||
{
|
||||
0x17, 0x03, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0xc8, 0x95, 0x86,
|
||||
0xc0, 0xd0, 0xc2, 0x24, 0x1d, 0xf4, 0x20, 0xca,
|
||||
0x2b, 0x30, 0x08, 0xf1, 0xb7, 0xe3, 0x5d, 0xcf,
|
||||
0x86, 0xc3, 0xc5, 0x15, 0x03, 0x03, 0x00, 0x1a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x35, 0xef, 0x9d,
|
||||
0x6a, 0x86, 0x98, 0xc5, 0xca, 0x55, 0xca, 0x89,
|
||||
0x29, 0xb4, 0x55, 0xd4, 0x41, 0x08, 0x96, 0xe0,
|
||||
0xf3, 0x39, 0xfc, 0x15, 0x03, 0x03, 0x00, 0x1a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x20, 0x13, 0xac, 0xc4, 0x6a, 0x48, 0x36, 0x04,
|
||||
0xdb, 0xae, 0x52, 0xc5, 0xc1, 0x6f, 0x4c, 0xc4,
|
||||
0x0a, 0x77,
|
||||
0x02, 0x63, 0x1b, 0xaa, 0xc6, 0xc9, 0x6d, 0x72,
|
||||
0x24, 0x10, 0x55, 0xa9, 0x8c, 0x3b, 0x23, 0xce,
|
||||
0xd8, 0x4a,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
}
|
||||
}
|
||||
if rand.Intn(10) > 5 {
|
||||
m.signatureAndHashes = supportedSignatureAlgorithms
|
||||
m.signatureAndHashes = supportedSKXSignatureAlgorithms
|
||||
}
|
||||
|
||||
return reflect.ValueOf(m)
|
||||
|
||||
@@ -318,7 +318,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
}
|
||||
if c.vers >= VersionTLS12 {
|
||||
certReq.hasSignatureAndHash = true
|
||||
certReq.signatureAndHashes = supportedSignatureAlgorithms
|
||||
certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
|
||||
}
|
||||
|
||||
// An empty list of certificateAuthorities signals to
|
||||
|
||||
@@ -117,15 +117,47 @@ func sha256Hash(slices [][]byte) []byte {
|
||||
}
|
||||
|
||||
// hashForServerKeyExchange hashes the given slices and returns their digest
|
||||
// and the identifier of the hash function used.
|
||||
func hashForServerKeyExchange(sigType uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash) {
|
||||
// and the identifier of the hash function used. The hashFunc argument is only
|
||||
// used for >= TLS 1.2 and precisely identifies the hash function to use.
|
||||
func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
|
||||
if version >= VersionTLS12 {
|
||||
return sha256Hash(slices), crypto.SHA256
|
||||
switch hashFunc {
|
||||
case hashSHA256:
|
||||
return sha256Hash(slices), crypto.SHA256, nil
|
||||
case hashSHA1:
|
||||
return sha1Hash(slices), crypto.SHA1, nil
|
||||
default:
|
||||
return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer")
|
||||
}
|
||||
}
|
||||
if sigType == signatureECDSA {
|
||||
return sha1Hash(slices), crypto.SHA1
|
||||
return sha1Hash(slices), crypto.SHA1, nil
|
||||
}
|
||||
return md5SHA1Hash(slices), crypto.MD5SHA1
|
||||
return md5SHA1Hash(slices), crypto.MD5SHA1, nil
|
||||
}
|
||||
|
||||
// pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
|
||||
// ServerKeyExchange given the signature type being used and the client's
|
||||
// advertized list of supported signature and hash combinations.
|
||||
func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
|
||||
if len(clientSignatureAndHashes) == 0 {
|
||||
// If the client didn't specify any signature_algorithms
|
||||
// extension then we can assume that it supports SHA1. See
|
||||
// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
||||
return hashSHA1, nil
|
||||
}
|
||||
|
||||
for _, sigAndHash := range clientSignatureAndHashes {
|
||||
if sigAndHash.signature != sigType {
|
||||
continue
|
||||
}
|
||||
switch sigAndHash.hash {
|
||||
case hashSHA1, hashSHA256:
|
||||
return sigAndHash.hash, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("tls: client doesn't support any common hash functions")
|
||||
}
|
||||
|
||||
// ecdheRSAKeyAgreement implements a TLS key agreement where the server
|
||||
@@ -181,7 +213,17 @@ Curve:
|
||||
serverECDHParams[3] = byte(len(ecdhePublic))
|
||||
copy(serverECDHParams[4:], ecdhePublic)
|
||||
|
||||
digest, hashFunc := hashForServerKeyExchange(ka.sigType, ka.version, clientHello.random, hello.random, serverECDHParams)
|
||||
var tls12HashId uint8
|
||||
if ka.version >= VersionTLS12 {
|
||||
if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var sig []byte
|
||||
switch ka.sigType {
|
||||
case signatureECDSA:
|
||||
@@ -216,7 +258,7 @@ Curve:
|
||||
copy(skx.key, serverECDHParams)
|
||||
k := skx.key[len(serverECDHParams):]
|
||||
if ka.version >= VersionTLS12 {
|
||||
k[0] = hashSHA256
|
||||
k[0] = tls12HashId
|
||||
k[1] = ka.sigType
|
||||
k = k[2:]
|
||||
}
|
||||
@@ -279,9 +321,16 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
|
||||
if len(sig) < 2 {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
|
||||
var tls12HashId uint8
|
||||
if ka.version >= VersionTLS12 {
|
||||
// ignore SignatureAndHashAlgorithm
|
||||
sig = sig[2:]
|
||||
// handle SignatureAndHashAlgorithm
|
||||
var sigAndHash []uint8
|
||||
sigAndHash, sig = sig[:2], sig[2:]
|
||||
if sigAndHash[1] != ka.sigType {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
tls12HashId = sigAndHash[0]
|
||||
if len(sig) < 2 {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
@@ -292,7 +341,10 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
|
||||
}
|
||||
sig = sig[2:]
|
||||
|
||||
digest, hashFunc := hashForServerKeyExchange(ka.sigType, ka.version, clientHello.random, serverHello.random, serverECDHParams)
|
||||
digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch ka.sigType {
|
||||
case signatureECDSA:
|
||||
pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
|
||||
|
||||
@@ -154,14 +154,18 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
|
||||
}
|
||||
|
||||
if len(c.PermittedDNSDomains) > 0 {
|
||||
ok := false
|
||||
for _, domain := range c.PermittedDNSDomains {
|
||||
if opts.DNSName == domain ||
|
||||
(strings.HasSuffix(opts.DNSName, domain) &&
|
||||
len(opts.DNSName) >= 1+len(domain) &&
|
||||
opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
|
||||
continue
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return CertificateInvalidError{c, CANotAuthorizedForThisName}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,24 @@ var verifyTests = []verifyTest{
|
||||
{"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Check that a name constrained intermediate works even when
|
||||
// it lists multiple constraints.
|
||||
leaf: nameConstraintsLeaf,
|
||||
intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
|
||||
roots: []string{globalSignRoot},
|
||||
currentTime: 1382387896,
|
||||
dnsName: "secure.iddl.vt.edu",
|
||||
|
||||
expectedChains: [][]string{
|
||||
{
|
||||
"Technology-enhanced Learning and Online Strategies",
|
||||
"Virginia Tech Global Qualified Server CA",
|
||||
"Trusted Root CA G2",
|
||||
"GlobalSign Root CA",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
|
||||
@@ -753,3 +771,168 @@ zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
|
||||
BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
|
||||
ZQ==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var nameConstraintsLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIHMTCCBRmgAwIBAgIIIZaV/3ezOJkwDQYJKoZIhvcNAQEFBQAwgcsxCzAJBgNV
|
||||
BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEj
|
||||
MCEGA1UECxMaR2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1Zp
|
||||
cmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0
|
||||
eTExMC8GA1UEAxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZl
|
||||
ciBDQTAeFw0xMzA5MTkxNDM2NTVaFw0xNTA5MTkxNDM2NTVaMIHNMQswCQYDVQQG
|
||||
EwJVUzERMA8GA1UECAwIVmlyZ2luaWExEzARBgNVBAcMCkJsYWNrc2J1cmcxPDA6
|
||||
BgNVBAoMM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUg
|
||||
VW5pdmVyc2l0eTE7MDkGA1UECwwyVGVjaG5vbG9neS1lbmhhbmNlZCBMZWFybmlu
|
||||
ZyBhbmQgT25saW5lIFN0cmF0ZWdpZXMxGzAZBgNVBAMMEnNlY3VyZS5pZGRsLnZ0
|
||||
LmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkOyPpsOK/6IuPG
|
||||
WnIBlVwlHzeYf+cUlggqkLq0b0+vZbiTXgio9/VCuNQ8opSoss7J7o3ygV9to+9Y
|
||||
YwJKVC5WDT/y5JWpQey0CWILymViJnpNSwnxBc8A+Q8w5NUGDd/UhtPx/U8/hqbd
|
||||
WPDYj2hbOqyq8UlRhfS5pwtnv6BbCTaY11I6FhCLK7zttISyTuWCf9p9o/ggiipP
|
||||
ii/5oh4dkl+r5SfuSp5GPNHlYO8lWqys5NAPoDD4fc/kuflcK7Exx7XJ+Oqu0W0/
|
||||
psjEY/tES1ZgDWU/ParcxxFpFmKHbD5DXsfPOObzkVWXIY6tGMutSlE1Froy/Nn0
|
||||
OZsAOrcCAwEAAaOCAhMwggIPMIG4BggrBgEFBQcBAQSBqzCBqDBYBggrBgEFBQcw
|
||||
AoZMaHR0cDovL3d3dy5wa2kudnQuZWR1L2dsb2JhbHF1YWxpZmllZHNlcnZlci9j
|
||||
YWNlcnQvZ2xvYmFscXVhbGlmaWVkc2VydmVyLmNydDBMBggrBgEFBQcwAYZAaHR0
|
||||
cDovL3Z0Y2EtcC5lcHJvdi5zZXRpLnZ0LmVkdTo4MDgwL2VqYmNhL3B1YmxpY3dl
|
||||
Yi9zdGF0dXMvb2NzcDAdBgNVHQ4EFgQUp7xbO6iHkvtZbPE4jmndmnAbSEcwDAYD
|
||||
VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS8YmAn1eM1SBfpS6tFatDIqHdxjDBqBgNV
|
||||
HSAEYzBhMA4GDCsGAQQBtGgFAgICATAOBgwrBgEEAbRoBQICAQEwPwYMKwYBBAG0
|
||||
aAUCAgMBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9i
|
||||
YWwvY3BzLzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vd3d3LnBraS52dC5lZHUv
|
||||
Z2xvYmFscXVhbGlmaWVkc2VydmVyL2NybC9jYWNybC5jcmwwDgYDVR0PAQH/BAQD
|
||||
AgTwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHREEFjAUghJz
|
||||
ZWN1cmUuaWRkbC52dC5lZHUwDQYJKoZIhvcNAQEFBQADggIBAEgoYo4aUtatY3gI
|
||||
OyyKp7QlIOaLbTJZywESHqy+L5EGDdJW2DJV+mcE0LDGvqa2/1Lo+AR1ntsZwfOi
|
||||
Y718JwgVVaX/RCd5+QKP25c5/x72xI8hb/L1bgS0ED9b0YAhd7Qm1K1ot82+6mqX
|
||||
DW6WiGeDr8Z07MQ3143qQe2rBlq+QI69DYzm2GOqAIAnUIWv7tCyLUm31b4DwmrJ
|
||||
TeudVreTKUbBNB1TWRFHEPkWhjjXKZnNGRO11wHXcyBu6YekIvVZ+vmx8ePee4jJ
|
||||
3GFOi7lMuWOeq57jTVL7KOKaKLVXBb6gqo5aq+Wwt8RUD5MakrCAEeQZj7DKaFmZ
|
||||
oQCO0Pxrsl3InCGvxnGzT+bFVO9nJ/BAMj7hknFdm9Jr6Bg5q33Z+gnf909AD9QF
|
||||
ESqUSykaHu2LVdJx2MaCH1CyKnRgMw5tEwE15EXpUjCm24m8FMOYC+rNtf18pgrz
|
||||
5D8Jhh+oxK9PjcBYqXNtnioIxiMCYcV0q5d4w4BYFEh71tk7/bYB0R55CsBUVPmp
|
||||
timWNOdRd57Tfpk3USaVsumWZAf9MP3wPiC7gb4d5tYEEAG5BuDT8ruFw838wU8G
|
||||
1VvAVutSiYBg7k3NYO7AUqZ+Ax4klQX3aM9lgonmJ78Qt94UPtbptrfZ4/lSqEf8
|
||||
GBUwDrQNTb+gsXsDkjd5lcYxNx6l
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var nameConstraintsIntermediate1 = `-----BEGIN CERTIFICATE-----
|
||||
MIINLjCCDBagAwIBAgIRIqpyf/YoGgvHc8HiDAxAI8owDQYJKoZIhvcNAQEFBQAw
|
||||
XDELMAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQ
|
||||
R2xvYmFsU2lnbiBudi1zYTEbMBkGA1UEAxMSVHJ1c3RlZCBSb290IENBIEcyMB4X
|
||||
DTEyMTIxMzAwMDAwMFoXDTE3MTIxMzAwMDAwMFowgcsxCzAJBgNVBAYTAlVTMREw
|
||||
DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEjMCEGA1UECxMa
|
||||
R2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1ZpcmdpbmlhIFBv
|
||||
bHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTExMC8GA1UE
|
||||
AxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTCCAiIw
|
||||
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALgIZhEaptBWADBqdJ45ueFGzMXa
|
||||
GHnzNxoxR1fQIaaRQNdCg4cw3A4dWKMeEgYLtsp65ai3Xfw62Qaus0+KJ3RhgV+r
|
||||
ihqK81NUzkls78fJlADVDI4fCTlothsrE1CTOMiy97jKHai5mVTiWxmcxpmjv7fm
|
||||
5Nhc+uHgh2hIz6npryq495mD51ZrUTIaqAQN6Pw/VHfAmR524vgriTOjtp1t4lA9
|
||||
pXGWjF/vkhAKFFheOQSQ00rngo2wHgCqMla64UTN0oz70AsCYNZ3jDLx0kOP0YmM
|
||||
R3Ih91VA63kLqPXA0R6yxmmhhxLZ5bcyAy1SLjr1N302MIxLM/pSy6aquEnbELhz
|
||||
qyp9yGgRyGJay96QH7c4RJY6gtcoPDbldDcHI9nXngdAL4DrZkJ9OkDkJLyqG66W
|
||||
ZTF5q4EIs6yMdrywz0x7QP+OXPJrjYpbeFs6tGZCFnWPFfmHCRJF8/unofYrheq+
|
||||
9J7Jx3U55S/k57NXbAM1RAJOuMTlfn9Etf9Dpoac9poI4Liav6rBoUQk3N3JWqnV
|
||||
HNx/NdCyJ1/6UbKMJUZsStAVglsi6lVPo289HHOE4f7iwl3SyekizVOp01wUin3y
|
||||
cnbZB/rXmZbwapSxTTSBf0EIOr9i4EGfnnhCAVA9U5uLrI5OEB69IY8PNX0071s3
|
||||
Z2a2fio5c8m3JkdrAgMBAAGjggh5MIIIdTAOBgNVHQ8BAf8EBAMCAQYwTAYDVR0g
|
||||
BEUwQzBBBgkrBgEEAaAyATwwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
|
||||
YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wEgYDVR0TAQH/BAgwBgEB/wIBADCCBtAG
|
||||
A1UdHgSCBscwggbDoIIGvzASghAzZGJsYWNrc2J1cmcub3JnMBiCFmFjY2VsZXJh
|
||||
dGV2aXJnaW5pYS5jb20wGIIWYWNjZWxlcmF0ZXZpcmdpbmlhLm9yZzALgglhY3Zj
|
||||
cC5vcmcwCYIHYmV2Lm5ldDAJggdiZXYub3JnMAuCCWNsaWdzLm9yZzAMggpjbWl3
|
||||
ZWIub3JnMBeCFWVhc3Rlcm5icm9va3Ryb3V0Lm5ldDAXghVlYXN0ZXJuYnJvb2t0
|
||||
cm91dC5vcmcwEYIPZWNvcnJpZG9ycy5pbmZvMBOCEWVkZ2FycmVzZWFyY2gub3Jn
|
||||
MBKCEGdldC1lZHVjYXRlZC5jb20wE4IRZ2V0LWVkdWNhdGVkLmluZm8wEYIPZ2V0
|
||||
ZWR1Y2F0ZWQubmV0MBKCEGdldC1lZHVjYXRlZC5uZXQwEYIPZ2V0ZWR1Y2F0ZWQu
|
||||
b3JnMBKCEGdldC1lZHVjYXRlZC5vcmcwD4INaG9raWVjbHViLmNvbTAQgg5ob2tp
|
||||
ZXBob3RvLmNvbTAPgg1ob2tpZXNob3AuY29tMBGCD2hva2llc3BvcnRzLmNvbTAS
|
||||
ghBob2tpZXRpY2tldHMuY29tMBKCEGhvdGVscm9hbm9rZS5jb20wE4IRaHVtYW53
|
||||
aWxkbGlmZS5vcmcwF4IVaW5uYXR2aXJnaW5pYXRlY2guY29tMA+CDWlzY2hwMjAx
|
||||
MS5vcmcwD4INbGFuZHJlaGFiLm9yZzAggh5uYXRpb25hbHRpcmVyZXNlYXJjaGNl
|
||||
bnRlci5jb20wFYITbmV0d29ya3ZpcmdpbmlhLm5ldDAMggpwZHJjdnQuY29tMBiC
|
||||
FnBldGVkeWVyaXZlcmNvdXJzZS5jb20wDYILcmFkaW9pcS5vcmcwFYITcml2ZXJj
|
||||
b3Vyc2Vnb2xmLmNvbTALgglzZGltaS5vcmcwEIIOc292YW1vdGlvbi5jb20wHoIc
|
||||
c3VzdGFpbmFibGUtYmlvbWF0ZXJpYWxzLmNvbTAeghxzdXN0YWluYWJsZS1iaW9t
|
||||
YXRlcmlhbHMub3JnMBWCE3RoaXNpc3RoZWZ1dHVyZS5jb20wGIIWdGhpcy1pcy10
|
||||
aGUtZnV0dXJlLmNvbTAVghN0aGlzaXN0aGVmdXR1cmUubmV0MBiCFnRoaXMtaXMt
|
||||
dGhlLWZ1dHVyZS5uZXQwCoIIdmFkcy5vcmcwDIIKdmFsZWFmLm9yZzANggt2YXRl
|
||||
Y2guaW5mbzANggt2YXRlY2gubW9iaTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5n
|
||||
LmNvbTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5nLm5ldDAcghp2YXRlY2hsaWZl
|
||||
bG9uZ2xlYXJuaW5nLm9yZzAKggh2Y29tLmVkdTASghB2aXJnaW5pYXZpZXcubmV0
|
||||
MDSCMnZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVuaXZlcnNp
|
||||
dHkuY29tMDWCM3ZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVu
|
||||
aXZlcnNpdHkuaW5mbzA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0dXRlYW5k
|
||||
c3RhdGV1bml2ZXJzaXR5Lm5ldDA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0
|
||||
dXRlYW5kc3RhdGV1bml2ZXJzaXR5Lm9yZzAZghd2aXJnaW5pYXB1YmxpY3JhZGlv
|
||||
Lm9yZzASghB2aXJnaW5pYXRlY2guZWR1MBOCEXZpcmdpbmlhdGVjaC5tb2JpMByC
|
||||
GnZpcmdpbmlhdGVjaGZvdW5kYXRpb24ub3JnMAiCBnZ0LmVkdTALggl2dGFyYy5v
|
||||
cmcwDIIKdnQtYXJjLm9yZzALggl2dGNyYy5jb20wCoIIdnRpcC5vcmcwDIIKdnRs
|
||||
ZWFuLm9yZzAWghR2dGtub3dsZWRnZXdvcmtzLmNvbTAYghZ2dGxpZmVsb25nbGVh
|
||||
cm5pbmcuY29tMBiCFnZ0bGlmZWxvbmdsZWFybmluZy5uZXQwGIIWdnRsaWZlbG9u
|
||||
Z2xlYXJuaW5nLm9yZzATghF2dHNwb3J0c21lZGlhLmNvbTALggl2dHdlaS5jb20w
|
||||
D4INd2l3YXR3ZXJjLmNvbTAKggh3dnRmLm9yZzAIgQZ2dC5lZHUwd6R1MHMxCzAJ
|
||||
BgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVy
|
||||
ZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBT
|
||||
dGF0ZSBVbml2ZXJzaXR5MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYI
|
||||
KwYBBQUHAwkwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5nbG9iYWxzaWdu
|
||||
LmNvbS9ncy90cnVzdHJvb3RnMi5jcmwwgYQGCCsGAQUFBwEBBHgwdjAzBggrBgEF
|
||||
BQcwAYYnaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3RydXN0cm9vdGcyMD8G
|
||||
CCsGAQUFBzAChjNodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90
|
||||
cnVzdHJvb3RnMi5jcnQwHQYDVR0OBBYEFLxiYCfV4zVIF+lLq0Vq0Miod3GMMB8G
|
||||
A1UdIwQYMBaAFBT25YsxtkWASkxt/MKHico2w5BiMA0GCSqGSIb3DQEBBQUAA4IB
|
||||
AQAyJm/lOB2Er4tHXhc/+fSufSzgjohJgYfMkvG4LknkvnZ1BjliefR8tTXX49d2
|
||||
SCDFWfGjqyJZwavavkl/4p3oXPG/nAMDMvxh4YAT+CfEK9HH+6ICV087kD4BLegi
|
||||
+aFJMj8MMdReWCzn5sLnSR1rdse2mo2arX3Uod14SW+PGrbUmTuWNyvRbz3fVmxp
|
||||
UdbGmj3laknO9YPsBGgHfv73pVVsTJkW4ZfY/7KdD/yaVv6ophpOB3coXfjl2+kd
|
||||
Z4ypn2zK+cx9IL/LSewqd/7W9cD55PCUy4X9OTbEmAccwiz3LB66mQoUGfdHdkoB
|
||||
jUY+v9vLQXmaVwI0AYL7g9LN
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var nameConstraintsIntermediate2 = `-----BEGIN CERTIFICATE-----
|
||||
MIIEXTCCA0WgAwIBAgILBAAAAAABNuk6OrMwDQYJKoZIhvcNAQEFBQAwVzELMAkG
|
||||
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
|
||||
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMjA0MjUxMTAw
|
||||
MDBaFw0yNzA0MjUxMTAwMDBaMFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVz
|
||||
dGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRy
|
||||
dXN0ZWQgUm9vdCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AKyuvqrtcMr7g7EuNbu4sKwxM127UsCmx1RxbxxgcArGS7rjiefpBH/w4LYrymjf
|
||||
vcw1ueyMNoqLo9nJMz/ORXupb35NNfE667prQYHa+tTjl1IiKpB7QUwt3wXPuTMF
|
||||
Ja1tXtjKzkqJyuJlNuPKT76HcjgNqgV1s9qG44MD5I2JvI12du8zI1bgdQ+l/KsX
|
||||
kTfbGjUvhOLOlVNWVQDpL+YMIrGqgBYxy5TUNgrAcRtwpNdS2KkF5otSmMweVb5k
|
||||
hoUVv3u8UxQH/WWbNhHq1RrIlg/0rBUfi/ziShYFSB7U+aLx5DxPphTFBiDquQGp
|
||||
tB+FC4JvnukDStFihZCZ1R8CAwEAAaOCASMwggEfMA4GA1UdDwEB/wQEAwIBBjAP
|
||||
BgNVHRMBAf8EBTADAQH/MEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB
|
||||
FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAdBgNVHQ4E
|
||||
FgQUFPblizG2RYBKTG38woeJyjbDkGIwMwYDVR0fBCwwKjAooCagJIYiaHR0cDov
|
||||
L2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNybDA+BggrBgEFBQcBAQQyMDAwLgYI
|
||||
KwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjEwHwYD
|
||||
VR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEFBQADggEB
|
||||
AL7IG0l+k4LkcpI+a/kvZsSRwSM4uA6zGX34e78A2oytr8RG8bJwVb8+AHMUD+Xe
|
||||
2kYdh/Uj/waQXfqR0OgxQXL9Ct4ZM+JlR1avsNKXWL5AwYXAXCOB3J5PW2XOck7H
|
||||
Zw0vRbGQhjWjQx+B4KOUFg1b3ov/z6Xkr3yaCfRQhXh7KC0Bc0RXPPG5Nv5lCW+z
|
||||
tbbg0zMm3kyfQITRusMSg6IBsDJqOnjaiaKQRcXiD0Sk43ZXb2bUKMxC7+Td3QL4
|
||||
RyHcWJbQ7YylLTS/x+jxWIcOQ0oO5/54t5PTQ14neYhOz9x4gUk2AYAW6d1vePwb
|
||||
hcC8roQwkHT7HvfYBoc74FM=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
var globalSignRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
|
||||
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
|
||||
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
|
||||
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
|
||||
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
|
||||
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
|
||||
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
|
||||
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
|
||||
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
|
||||
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
|
||||
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
|
||||
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
|
||||
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
|
||||
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
|
||||
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
|
||||
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
|
||||
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
|
||||
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
|
||||
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
@@ -140,8 +140,8 @@ type Stmt interface {
|
||||
}
|
||||
|
||||
// ColumnConverter may be optionally implemented by Stmt if the
|
||||
// the statement is aware of its own columns' types and can
|
||||
// convert from any type to a driver Value.
|
||||
// statement is aware of its own columns' types and can convert from
|
||||
// any type to a driver Value.
|
||||
type ColumnConverter interface {
|
||||
// ColumnConverter returns a ValueConverter for the provided
|
||||
// column index. If the type of a specific column isn't known
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
//
|
||||
// The sql package must be used in conjunction with a database driver.
|
||||
// See http://golang.org/s/sqldrivers for a list of drivers.
|
||||
//
|
||||
// For more usage examples, see the wiki page at
|
||||
// http://golang.org/s/sqlwiki.
|
||||
package sql
|
||||
|
||||
import (
|
||||
@@ -198,7 +201,7 @@ type DB struct {
|
||||
connRequests *list.List // of connRequest
|
||||
numOpen int
|
||||
pendingOpens int
|
||||
// Used to sygnal the need for new connections
|
||||
// Used to signal the need for new connections
|
||||
// a goroutine running connectionOpener() reads on this chan and
|
||||
// maybeOpenNewConnections sends on the chan (one send per needed connection)
|
||||
// It is closed during db.Close(). The close tells the connectionOpener
|
||||
@@ -1634,7 +1637,16 @@ func (r *Row) Scan(dest ...interface{}) error {
|
||||
|
||||
// A Result summarizes an executed SQL command.
|
||||
type Result interface {
|
||||
// LastInsertId returns the integer generated by the database
|
||||
// in response to a command. Typically this will be from an
|
||||
// "auto increment" column when inserting a new row. Not all
|
||||
// databases support this feature, and the syntax of such
|
||||
// statements varies.
|
||||
LastInsertId() (int64, error)
|
||||
|
||||
// RowsAffected returns the number of rows affected by an
|
||||
// update, insert, or delete. Not every database or database
|
||||
// driver may support this.
|
||||
RowsAffected() (int64, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,10 @@ const (
|
||||
formRef8 format = 0x14
|
||||
formRefUdata format = 0x15
|
||||
formIndirect format = 0x16
|
||||
formSecOffset format = 0x17
|
||||
formExprloc format = 0x18
|
||||
formFlagPresent format = 0x19
|
||||
formRefSig8 format = 0x20
|
||||
)
|
||||
|
||||
// A Tag is the classification (the type) of an Entry.
|
||||
|
||||
@@ -188,6 +188,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
|
||||
// flag
|
||||
case formFlag:
|
||||
val = b.uint8() == 1
|
||||
// New in DWARF 4.
|
||||
case formFlagPresent:
|
||||
// The attribute is implicitly indicated as present, and no value is
|
||||
// encoded in the debugging information entry itself.
|
||||
@@ -236,6 +237,30 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
|
||||
b.err = b1.err
|
||||
return nil
|
||||
}
|
||||
|
||||
// lineptr, loclistptr, macptr, rangelistptr
|
||||
// New in DWARF 4, but clang can generate them with -gdwarf-2.
|
||||
// Section reference, replacing use of formData4 and formData8.
|
||||
case formSecOffset:
|
||||
is64, known := b.format.dwarf64()
|
||||
if !known {
|
||||
b.error("unknown size for DW_FORM_sec_offset")
|
||||
} else if is64 {
|
||||
val = int64(b.uint64())
|
||||
} else {
|
||||
val = int64(b.uint32())
|
||||
}
|
||||
|
||||
// exprloc
|
||||
// New in DWARF 4.
|
||||
case formExprloc:
|
||||
val = b.bytes(int(b.uint()))
|
||||
|
||||
// reference
|
||||
// New in DWARF 4.
|
||||
case formRefSig8:
|
||||
// 64-bit type signature.
|
||||
val = b.uint64()
|
||||
}
|
||||
e.Field[i].Val = val
|
||||
}
|
||||
|
||||
@@ -86,13 +86,13 @@ Functions and channels will not be sent in a gob. Attempting to encode such a va
|
||||
at top the level will fail. A struct field of chan or func type is treated exactly
|
||||
like an unexported field and is ignored.
|
||||
|
||||
Gob can encode a value of any type implementing the GobEncoder,
|
||||
encoding.BinaryMarshaler, or encoding.TextMarshaler interfaces by calling the
|
||||
corresponding method, in that order of preference.
|
||||
Gob can encode a value of any type implementing the GobEncoder or
|
||||
encoding.BinaryMarshaler interfaces by calling the corresponding method,
|
||||
in that order of preference.
|
||||
|
||||
Gob can decode a value of any type implementing the GobDecoder,
|
||||
encoding.BinaryUnmarshaler, or encoding.TextUnmarshaler interfaces by calling
|
||||
the corresponding method, again in that order of preference.
|
||||
Gob can decode a value of any type implementing the GobDecoder or
|
||||
encoding.BinaryUnmarshaler interfaces by calling the corresponding method,
|
||||
again in that order of preference.
|
||||
|
||||
Encoding Details
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ func (v *Vector) UnmarshalBinary(data []byte) error {
|
||||
}
|
||||
|
||||
// This example transmits a value that implements the custom encoding and decoding methods.
|
||||
func Example_gob_encode_decode() {
|
||||
func Example_encodeDecode() {
|
||||
var network bytes.Buffer // Stand-in for the network.
|
||||
|
||||
// Create an encoder and send a value.
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -767,3 +768,17 @@ func TestGobEncodePtrError(t *testing.T) {
|
||||
t.Fatalf("expected nil, got %v", err2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetIP(t *testing.T) {
|
||||
// Encoding of net.IP{1,2,3,4} in Go 1.1.
|
||||
enc := []byte{0x07, 0x0a, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04}
|
||||
|
||||
var ip net.IP
|
||||
err := NewDecoder(bytes.NewReader(enc)).Decode(&ip)
|
||||
if err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if ip.String() != "1.2.3.4" {
|
||||
t.Errorf("decoded to %v, want 1.2.3.4", ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,18 +88,25 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
|
||||
ut.externalEnc, ut.encIndir = xGob, indir
|
||||
} else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok {
|
||||
ut.externalEnc, ut.encIndir = xBinary, indir
|
||||
} else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {
|
||||
ut.externalEnc, ut.encIndir = xText, indir
|
||||
}
|
||||
|
||||
// NOTE(rsc): Would like to allow MarshalText here, but results in incompatibility
|
||||
// with older encodings for net.IP. See golang.org/issue/6760.
|
||||
// } else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {
|
||||
// ut.externalEnc, ut.encIndir = xText, indir
|
||||
// }
|
||||
|
||||
if ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok {
|
||||
ut.externalDec, ut.decIndir = xGob, indir
|
||||
} else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok {
|
||||
ut.externalDec, ut.decIndir = xBinary, indir
|
||||
} else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {
|
||||
ut.externalDec, ut.decIndir = xText, indir
|
||||
}
|
||||
|
||||
// See note above.
|
||||
// } else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {
|
||||
// ut.externalDec, ut.decIndir = xText, indir
|
||||
// }
|
||||
|
||||
userTypeCache[rt] = ut
|
||||
return
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ import (
|
||||
// Unmarshal records the attribute value in that field.
|
||||
//
|
||||
// * If the XML element contains character data, that data is
|
||||
// accumulated in the first struct field that has tag "chardata".
|
||||
// accumulated in the first struct field that has tag ",chardata".
|
||||
// The struct field may have type []byte or string.
|
||||
// If there is no such field, the character data is discarded.
|
||||
//
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
// - the compiler being used, either "gc" or "gccgo"
|
||||
// - "cgo", if ctxt.CgoEnabled is true
|
||||
// - "go1.1", from Go version 1.1 onward
|
||||
// - "go1.2", from Go version 1.2 onward
|
||||
// - any additional words listed in ctxt.BuildTags
|
||||
//
|
||||
// If a file's name, after stripping the extension and a possible _test suffix,
|
||||
|
||||
@@ -22,6 +22,9 @@ func firstSentenceLen(s string) int {
|
||||
if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) {
|
||||
return i
|
||||
}
|
||||
if p == '。' || p == '.' {
|
||||
return i
|
||||
}
|
||||
ppp, pp, p = pp, p, q
|
||||
}
|
||||
return len(s)
|
||||
|
||||
@@ -28,6 +28,8 @@ var tests = []struct {
|
||||
{"P. Q. ", 8, "P. Q."},
|
||||
{"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},
|
||||
{"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},
|
||||
{"Package こんにちは。世界", 26, "Package こんにちは。"},
|
||||
{"Package 안녕.世界", 17, "Package 안녕."},
|
||||
{"Package foo does bar.", 21, "Package foo does bar."},
|
||||
{"Copyright 2012 Google, Inc. Package foo does bar.", 27, ""},
|
||||
{"All Rights reserved. Package foo does bar.", 20, ""},
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// Derived from Inferno's libkern/getfcr-amd64.s
|
||||
// http://code.google.com/p/inferno-os/source/browse/libkern/getfcr-amd64.s
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
|
||||
// Portions Copyright 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "../../cmd/ld/textflag.h"
|
||||
|
||||
TEXT ·SetFPControl(SB), NOSPLIT, $8
|
||||
// Set new
|
||||
MOVL p+0(FP), DI
|
||||
XORL $(0x3F<<7), DI
|
||||
ANDL $0xFFC0, DI
|
||||
WAIT
|
||||
STMXCSR 0(SP)
|
||||
MOVL 0(SP), AX
|
||||
ANDL $~0x3F, AX
|
||||
ORL DI, AX
|
||||
MOVL AX, 0(SP)
|
||||
LDMXCSR 0(SP)
|
||||
RET
|
||||
|
||||
TEXT ·GetFPControl(SB), NOSPLIT, $0
|
||||
WAIT
|
||||
STMXCSR 0(SP)
|
||||
MOVWLZX 0(SP), AX
|
||||
ANDL $0xFFC0, AX
|
||||
XORL $(0x3F<<7), AX
|
||||
MOVL AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ·SetFPStatus(SB), $0
|
||||
MOVL p+0(FP), DI
|
||||
ANDL $0x3F, DI
|
||||
WAIT
|
||||
STMXCSR 0(SP)
|
||||
MOVL 0(SP), AX
|
||||
ANDL $~0x3F, AX
|
||||
ORL DI, AX
|
||||
MOVL AX, 0(SP)
|
||||
LDMXCSR 0(SP)
|
||||
RET
|
||||
|
||||
TEXT ·GetFPStatus(SB), $0
|
||||
WAIT
|
||||
STMXCSR 0(SP)
|
||||
MOVL 0(SP), AX
|
||||
ANDL $0x3F, AX
|
||||
MOVL AX, ret+0(FP)
|
||||
RET
|
||||
@@ -215,26 +215,30 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
|
||||
|
||||
// dialSingle attempts to establish and returns a single connection to
|
||||
// the destination address.
|
||||
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (Conn, error) {
|
||||
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
|
||||
if la != nil && la.Network() != ra.Network() {
|
||||
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
|
||||
}
|
||||
switch ra := ra.(type) {
|
||||
case *TCPAddr:
|
||||
la, _ := la.(*TCPAddr)
|
||||
return dialTCP(net, la, ra, deadline)
|
||||
c, err = dialTCP(net, la, ra, deadline)
|
||||
case *UDPAddr:
|
||||
la, _ := la.(*UDPAddr)
|
||||
return dialUDP(net, la, ra, deadline)
|
||||
c, err = dialUDP(net, la, ra, deadline)
|
||||
case *IPAddr:
|
||||
la, _ := la.(*IPAddr)
|
||||
return dialIP(net, la, ra, deadline)
|
||||
c, err = dialIP(net, la, ra, deadline)
|
||||
case *UnixAddr:
|
||||
la, _ := la.(*UnixAddr)
|
||||
return dialUnix(net, la, ra, deadline)
|
||||
c, err = dialUnix(net, la, ra, deadline)
|
||||
default:
|
||||
return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err // c is non-nil interface containing nil pointer
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Listen announces on the local network address laddr.
|
||||
@@ -246,14 +250,19 @@ func Listen(net, laddr string) (Listener, error) {
|
||||
if err != nil {
|
||||
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
|
||||
}
|
||||
var l Listener
|
||||
switch la := la.toAddr().(type) {
|
||||
case *TCPAddr:
|
||||
return ListenTCP(net, la)
|
||||
l, err = ListenTCP(net, la)
|
||||
case *UnixAddr:
|
||||
return ListenUnix(net, la)
|
||||
l, err = ListenUnix(net, la)
|
||||
default:
|
||||
return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err // l is non-nil interface containing nil pointer
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// ListenPacket announces on the local network address laddr.
|
||||
@@ -265,14 +274,19 @@ func ListenPacket(net, laddr string) (PacketConn, error) {
|
||||
if err != nil {
|
||||
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
|
||||
}
|
||||
var l PacketConn
|
||||
switch la := la.toAddr().(type) {
|
||||
case *UDPAddr:
|
||||
return ListenUDP(net, la)
|
||||
l, err = ListenUDP(net, la)
|
||||
case *IPAddr:
|
||||
return ListenIP(net, la)
|
||||
l, err = ListenIP(net, la)
|
||||
case *UnixAddr:
|
||||
return ListenUnixgram(net, la)
|
||||
l, err = ListenUnixgram(net, la)
|
||||
default:
|
||||
return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err // l is non-nil interface containing nil pointer
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
@@ -53,6 +53,19 @@ func TestLookupStaticHost(t *testing.T) {
|
||||
hostsPath = p
|
||||
}
|
||||
|
||||
// https://code.google.com/p/go/issues/detail?id=6646
|
||||
func TestSingleLineHostsFile(t *testing.T) {
|
||||
p := hostsPath
|
||||
hostsPath = "testdata/hosts_singleline"
|
||||
|
||||
ips := lookupStaticHost("odin")
|
||||
if len(ips) != 1 || ips[0] != "127.0.0.2" {
|
||||
t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
|
||||
}
|
||||
|
||||
hostsPath = p
|
||||
}
|
||||
|
||||
func TestLookupHost(t *testing.T) {
|
||||
// Can't depend on this to return anything in particular,
|
||||
// but if it does return something, make sure it doesn't
|
||||
|
||||
@@ -45,13 +45,27 @@ func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
type neverEnding byte
|
||||
|
||||
func (b neverEnding) Read(p []byte) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = byte(b)
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// DumpRequestOut is like DumpRequest but includes
|
||||
// headers that the standard http.Transport adds,
|
||||
// such as User-Agent.
|
||||
func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
|
||||
save := req.Body
|
||||
dummyBody := false
|
||||
if !body || req.Body == nil {
|
||||
req.Body = nil
|
||||
if req.ContentLength != 0 {
|
||||
req.Body = ioutil.NopCloser(io.LimitReader(neverEnding('x'), req.ContentLength))
|
||||
dummyBody = true
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
save, req.Body, err = drainBody(req.Body)
|
||||
@@ -99,7 +113,19 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
dump := buf.Bytes()
|
||||
|
||||
// If we used a dummy body above, remove it now.
|
||||
// TODO: if the req.ContentLength is large, we allocate memory
|
||||
// unnecessarily just to slice it off here. But this is just
|
||||
// a debug function, so this is acceptable for now. We could
|
||||
// discard the body earlier if this matters.
|
||||
if dummyBody {
|
||||
if i := bytes.Index(dump, []byte("\r\n\r\n")); i >= 0 {
|
||||
dump = dump[:i+4]
|
||||
}
|
||||
}
|
||||
return dump, nil
|
||||
}
|
||||
|
||||
// delegateReader is a reader that delegates to another reader,
|
||||
|
||||
@@ -20,6 +20,7 @@ type dumpTest struct {
|
||||
|
||||
WantDump string
|
||||
WantDumpOut string
|
||||
NoBody bool // if true, set DumpRequest{,Out} body to false
|
||||
}
|
||||
|
||||
var dumpTests = []dumpTest{
|
||||
@@ -83,6 +84,31 @@ var dumpTests = []dumpTest{
|
||||
"User-Agent: Go 1.1 package http\r\n" +
|
||||
"Accept-Encoding: gzip\r\n\r\n",
|
||||
},
|
||||
|
||||
// Request with Body, but Dump requested without it.
|
||||
{
|
||||
Req: http.Request{
|
||||
Method: "POST",
|
||||
URL: &url.URL{
|
||||
Scheme: "http",
|
||||
Host: "post.tld",
|
||||
Path: "/",
|
||||
},
|
||||
ContentLength: 6,
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
},
|
||||
|
||||
Body: []byte("abcdef"),
|
||||
|
||||
WantDumpOut: "POST / HTTP/1.1\r\n" +
|
||||
"Host: post.tld\r\n" +
|
||||
"User-Agent: Go 1.1 package http\r\n" +
|
||||
"Content-Length: 6\r\n" +
|
||||
"Accept-Encoding: gzip\r\n\r\n",
|
||||
|
||||
NoBody: true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestDumpRequest(t *testing.T) {
|
||||
@@ -105,7 +131,7 @@ func TestDumpRequest(t *testing.T) {
|
||||
|
||||
if tt.WantDump != "" {
|
||||
setBody()
|
||||
dump, err := DumpRequest(&tt.Req, true)
|
||||
dump, err := DumpRequest(&tt.Req, !tt.NoBody)
|
||||
if err != nil {
|
||||
t.Errorf("DumpRequest #%d: %s", i, err)
|
||||
continue
|
||||
@@ -118,7 +144,7 @@ func TestDumpRequest(t *testing.T) {
|
||||
|
||||
if tt.WantDumpOut != "" {
|
||||
setBody()
|
||||
dump, err := DumpRequestOut(&tt.Req, true)
|
||||
dump, err := DumpRequestOut(&tt.Req, !tt.NoBody)
|
||||
if err != nil {
|
||||
t.Errorf("DumpRequestOut #%d: %s", i, err)
|
||||
continue
|
||||
|
||||
@@ -521,7 +521,7 @@ func isAtext(c byte, dot bool) bool {
|
||||
return bytes.IndexByte(atextChars, c) >= 0
|
||||
}
|
||||
|
||||
// isQtext returns true if c is an RFC 5322 qtest character.
|
||||
// isQtext returns true if c is an RFC 5322 qtext character.
|
||||
func isQtext(c byte) bool {
|
||||
// Printable US-ASCII, excluding backslash or quote.
|
||||
if c == '\\' || c == '"' {
|
||||
|
||||
@@ -218,3 +218,41 @@ func TestTCPClose(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorNil(t *testing.T) {
|
||||
c, err := Dial("tcp", "127.0.0.1:65535")
|
||||
if err == nil {
|
||||
t.Fatal("Dial 127.0.0.1:65535 succeeded")
|
||||
}
|
||||
if c != nil {
|
||||
t.Fatalf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
|
||||
}
|
||||
|
||||
// Make Listen fail by relistening on the same address.
|
||||
l, err := Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal("Listen 127.0.0.1:0: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
l1, err := Listen("tcp", l.Addr().String())
|
||||
if err == nil {
|
||||
t.Fatal("second Listen %v: %v", l.Addr(), err)
|
||||
}
|
||||
if l1 != nil {
|
||||
t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1)
|
||||
}
|
||||
|
||||
// Make ListenPacket fail by relistening on the same address.
|
||||
lp, err := ListenPacket("udp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal("Listen 127.0.0.1:0: %v", err)
|
||||
}
|
||||
defer lp.Close()
|
||||
lp1, err := ListenPacket("udp", lp.LocalAddr().String())
|
||||
if err == nil {
|
||||
t.Fatal("second Listen %v: %v", lp.LocalAddr(), err)
|
||||
}
|
||||
if lp1 != nil {
|
||||
t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func (f *file) readLine() (s string, ok bool) {
|
||||
if n >= 0 {
|
||||
f.data = f.data[0 : ln+n]
|
||||
}
|
||||
if err == io.EOF {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
f.atEOF = true
|
||||
}
|
||||
}
|
||||
|
||||
1
src/pkg/net/testdata/hosts_singleline
vendored
Normal file
1
src/pkg/net/testdata/hosts_singleline
vendored
Normal file
@@ -0,0 +1 @@
|
||||
127.0.0.2 odin
|
||||
@@ -574,13 +574,10 @@ func canonicalMIMEHeaderKey(a []byte) string {
|
||||
// and upper case after each dash.
|
||||
// (Host, User-Agent, If-Modified-Since).
|
||||
// MIME headers are ASCII only, so no Unicode issues.
|
||||
if a[i] == ' ' {
|
||||
a[i] = '-'
|
||||
upper = true
|
||||
continue
|
||||
}
|
||||
c := a[i]
|
||||
if upper && 'a' <= c && c <= 'z' {
|
||||
if c == ' ' {
|
||||
c = '-'
|
||||
} else if upper && 'a' <= c && c <= 'z' {
|
||||
c -= toLower
|
||||
} else if !upper && 'A' <= c && c <= 'Z' {
|
||||
c += toLower
|
||||
|
||||
@@ -25,6 +25,10 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
|
||||
{"user-agent", "User-Agent"},
|
||||
{"USER-AGENT", "User-Agent"},
|
||||
{"üser-agenT", "üser-Agent"}, // non-ASCII unchanged
|
||||
|
||||
// This caused a panic due to mishandling of a space:
|
||||
{"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"},
|
||||
{"foo bar", "Foo-Bar"},
|
||||
}
|
||||
|
||||
func TestCanonicalMIMEHeaderKey(t *testing.T) {
|
||||
|
||||
@@ -558,8 +558,8 @@ func parseQuery(m Values, query string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Encode encodes the values into ``URL encoded'' form.
|
||||
// e.g. "foo=bar&bar=baz"
|
||||
// Encode encodes the values into ``URL encoded'' form
|
||||
// ("bar=baz&foo=quux") sorted by key.
|
||||
func (v Values) Encode() string {
|
||||
if v == nil {
|
||||
return ""
|
||||
|
||||
@@ -165,14 +165,11 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
|
||||
fi = make([]FileInfo, len(names))
|
||||
for i, filename := range names {
|
||||
fip, lerr := lstat(dirname + filename)
|
||||
if lerr == nil {
|
||||
fi[i] = fip
|
||||
} else {
|
||||
if lerr != nil {
|
||||
fi[i] = &fileStat{name: filename}
|
||||
if err == nil {
|
||||
err = lerr
|
||||
}
|
||||
continue
|
||||
}
|
||||
fi[i] = fip
|
||||
}
|
||||
return fi, err
|
||||
}
|
||||
|
||||
@@ -92,8 +92,8 @@ func TestReaddirWithBadLstat(t *testing.T) {
|
||||
defer func() { *LstatP = Lstat }()
|
||||
|
||||
dirs, err := handle.Readdir(-1)
|
||||
if err != ErrInvalid {
|
||||
t.Fatalf("Expected Readdir to return ErrInvalid, got %v", err)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected Readdir to return no error, got %v", err)
|
||||
}
|
||||
foundfail := false
|
||||
for _, dir := range dirs {
|
||||
|
||||
@@ -255,10 +255,6 @@ runtime·MProf_Malloc(void *p, uintptr size)
|
||||
uintptr stk[32];
|
||||
Bucket *b;
|
||||
|
||||
if(m->nomemprof > 0)
|
||||
return;
|
||||
|
||||
m->nomemprof++;
|
||||
nstk = runtime·callers(1, stk, 32);
|
||||
runtime·lock(&proflock);
|
||||
b = stkbucket(MProf, stk, nstk, true);
|
||||
@@ -266,7 +262,6 @@ runtime·MProf_Malloc(void *p, uintptr size)
|
||||
b->recent_alloc_bytes += size;
|
||||
setaddrbucket((uintptr)p, b);
|
||||
runtime·unlock(&proflock);
|
||||
m->nomemprof--;
|
||||
}
|
||||
|
||||
// Called when freeing a profiled block.
|
||||
@@ -275,10 +270,6 @@ runtime·MProf_Free(void *p, uintptr size)
|
||||
{
|
||||
Bucket *b;
|
||||
|
||||
if(m->nomemprof > 0)
|
||||
return;
|
||||
|
||||
m->nomemprof++;
|
||||
runtime·lock(&proflock);
|
||||
b = getaddrbucket((uintptr)p);
|
||||
if(b != nil) {
|
||||
@@ -286,7 +277,6 @@ runtime·MProf_Free(void *p, uintptr size)
|
||||
b->recent_free_bytes += size;
|
||||
}
|
||||
runtime·unlock(&proflock);
|
||||
m->nomemprof--;
|
||||
}
|
||||
|
||||
int64 runtime·blockprofilerate; // in CPU ticks
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/big"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
@@ -123,6 +124,10 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
|
||||
}
|
||||
})
|
||||
|
||||
if len(need) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var total uintptr
|
||||
for i, name := range need {
|
||||
total += have[i]
|
||||
@@ -237,6 +242,26 @@ func TestGoroutineSwitch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test that profiling of division operations is okay, especially on ARM. See issue 6681.
|
||||
func TestMathBigDivide(t *testing.T) {
|
||||
testCPUProfile(t, nil, func() {
|
||||
t := time.After(5 * time.Second)
|
||||
pi := new(big.Int)
|
||||
for {
|
||||
for i := 0; i < 100; i++ {
|
||||
n := big.NewInt(2646693125139304345)
|
||||
d := big.NewInt(842468587426513207)
|
||||
pi.Div(n, d)
|
||||
}
|
||||
select {
|
||||
case <-t:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Operating systems that are expected to fail the tests. See issue 6047.
|
||||
var badOS = map[string]bool{
|
||||
"darwin": true,
|
||||
|
||||
@@ -133,7 +133,6 @@ runtime·schedinit(void)
|
||||
runtime·sched.maxmcount = 10000;
|
||||
runtime·precisestack = haveexperiment("precisestack");
|
||||
|
||||
m->nomemprof++;
|
||||
runtime·mprofinit();
|
||||
runtime·mallocinit();
|
||||
mcommoninit(m);
|
||||
@@ -163,7 +162,6 @@ runtime·schedinit(void)
|
||||
procresize(procs);
|
||||
|
||||
mstats.enablegc = 1;
|
||||
m->nomemprof--;
|
||||
|
||||
if(raceenabled)
|
||||
g->racectx = runtime·raceinit();
|
||||
|
||||
@@ -310,7 +310,6 @@ struct M
|
||||
int32 throwing;
|
||||
int32 gcing;
|
||||
int32 locks;
|
||||
int32 nomemprof;
|
||||
int32 dying;
|
||||
int32 profilehz;
|
||||
int32 helpgc;
|
||||
|
||||
@@ -255,7 +255,7 @@ runtime·newstack(void)
|
||||
if(gp->stackguard0 == (uintptr)StackPreempt) {
|
||||
if(gp == m->g0)
|
||||
runtime·throw("runtime: preempt g0");
|
||||
if(oldstatus == Grunning && m->p == nil)
|
||||
if(oldstatus == Grunning && m->p == nil && m->locks == 0)
|
||||
runtime·throw("runtime: g is running but p is not");
|
||||
if(oldstatus == Gsyscall && m->locks == 0)
|
||||
runtime·throw("runtime: stack split during syscall");
|
||||
|
||||
@@ -84,7 +84,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
|
||||
frame.lr = 0;
|
||||
flr = nil;
|
||||
} else {
|
||||
if(frame.lr == 0)
|
||||
if((n == 0 && frame.sp < frame.fp) || frame.lr == 0)
|
||||
frame.lr = *(uintptr*)frame.sp;
|
||||
flr = runtime·findfunc(frame.lr);
|
||||
if(flr == nil) {
|
||||
|
||||
@@ -364,17 +364,18 @@ func makeSingleStringReplacer(pattern string, value string) *singleStringReplace
|
||||
|
||||
func (r *singleStringReplacer) Replace(s string) string {
|
||||
var buf []byte
|
||||
i := 0
|
||||
i, matched := 0, false
|
||||
for {
|
||||
match := r.finder.next(s[i:])
|
||||
if match == -1 {
|
||||
break
|
||||
}
|
||||
matched = true
|
||||
buf = append(buf, s[i:i+match]...)
|
||||
buf = append(buf, r.value...)
|
||||
i += match + len(r.finder.pattern)
|
||||
}
|
||||
if buf == nil {
|
||||
if !matched {
|
||||
return s
|
||||
}
|
||||
buf = append(buf, s[i:]...)
|
||||
|
||||
@@ -261,10 +261,21 @@ func TestReplacer(t *testing.T) {
|
||||
testCases = append(testCases,
|
||||
testCase{abcMatcher, "", ""},
|
||||
testCase{abcMatcher, "ab", "ab"},
|
||||
testCase{abcMatcher, "abc", "[match]"},
|
||||
testCase{abcMatcher, "abcd", "[match]d"},
|
||||
testCase{abcMatcher, "cabcabcdabca", "c[match][match]d[match]a"},
|
||||
)
|
||||
|
||||
// Issue 6659 cases (more single string replacer)
|
||||
|
||||
noHello := NewReplacer("Hello", "")
|
||||
testCases = append(testCases,
|
||||
testCase{noHello, "Hello", ""},
|
||||
testCase{noHello, "Hellox", "x"},
|
||||
testCase{noHello, "xHello", "x"},
|
||||
testCase{noHello, "xHellox", "xx"},
|
||||
)
|
||||
|
||||
// No-arg test cases.
|
||||
|
||||
nop := NewReplacer()
|
||||
|
||||
@@ -73,17 +73,19 @@
|
||||
//
|
||||
// Example functions without output comments are compiled but not executed.
|
||||
//
|
||||
// The naming convention to declare examples for a function F, a type T and
|
||||
// The naming convention to declare examples for the package, a function F, a type T and
|
||||
// method M on type T are:
|
||||
//
|
||||
// func Example() { ... }
|
||||
// func ExampleF() { ... }
|
||||
// func ExampleT() { ... }
|
||||
// func ExampleT_M() { ... }
|
||||
//
|
||||
// Multiple example functions for a type/function/method may be provided by
|
||||
// Multiple example functions for a package/type/function/method may be provided by
|
||||
// appending a distinct suffix to the name. The suffix must start with a
|
||||
// lower-case letter.
|
||||
//
|
||||
// func Example_suffix() { ... }
|
||||
// func ExampleF_suffix() { ... }
|
||||
// func ExampleT_suffix() { ... }
|
||||
// func ExampleT_M_suffix() { ... }
|
||||
|
||||
@@ -18,4 +18,7 @@ func ForceUSPacificForTesting() {
|
||||
localOnce.Do(initTestingZone)
|
||||
}
|
||||
|
||||
var ParseTimeZone = parseTimeZone
|
||||
var (
|
||||
ForceZipFileForTesting = forceZipFileForTesting
|
||||
ParseTimeZone = parseTimeZone
|
||||
)
|
||||
|
||||
@@ -1204,11 +1204,11 @@ func ParseDuration(s string) (Duration, error) {
|
||||
if err != nil {
|
||||
return 0, errors.New("time: invalid duration " + orig)
|
||||
}
|
||||
scale := 1
|
||||
scale := 1.0
|
||||
for n := pl - len(s); n > 0; n-- {
|
||||
scale *= 10
|
||||
}
|
||||
g += float64(x) / float64(scale)
|
||||
g += float64(x) / scale
|
||||
post = pl != len(s)
|
||||
}
|
||||
if !pre && !post {
|
||||
|
||||
@@ -578,6 +578,16 @@ func TestParseInSydney(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadLocationZipFile(t *testing.T) {
|
||||
ForceZipFileForTesting(true)
|
||||
defer ForceZipFileForTesting(false)
|
||||
|
||||
_, err := LoadLocation("Australia/Sydney")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var rubyTests = []ParseTest{
|
||||
{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
|
||||
// Ignore the time zone in the test. If it parses, it'll be OK.
|
||||
@@ -1318,6 +1328,8 @@ var parseDurationTests = []struct {
|
||||
{"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond},
|
||||
// large value
|
||||
{"52763797000ns", true, 52763797000 * Nanosecond},
|
||||
// more than 9 digits after decimal point, see http://golang.org/issue/6617
|
||||
{"0.3333333333333333333h", true, 20 * Minute},
|
||||
|
||||
// errors
|
||||
{"", false, 0},
|
||||
|
||||
@@ -154,3 +154,7 @@ func loadLocation(name string) (*Location, error) {
|
||||
}
|
||||
return nil, errors.New("unknown time zone " + name)
|
||||
}
|
||||
|
||||
func forceZipFileForTesting(zipOnly bool) {
|
||||
// We only use the zip file anyway.
|
||||
}
|
||||
|
||||
@@ -32,7 +32,19 @@ var zoneDirs = []string{
|
||||
"/usr/share/zoneinfo/",
|
||||
"/usr/share/lib/zoneinfo/",
|
||||
"/usr/lib/locale/TZ/",
|
||||
runtime.GOROOT() + "/lib/time/zoneinfo/",
|
||||
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
|
||||
}
|
||||
|
||||
var origZoneDirs = zoneDirs
|
||||
|
||||
func forceZipFileForTesting(zipOnly bool) {
|
||||
zoneDirs = make([]string, len(origZoneDirs))
|
||||
copy(zoneDirs, origZoneDirs)
|
||||
if zipOnly {
|
||||
for i := 0; i < len(zoneDirs)-1; i++ {
|
||||
zoneDirs[i] = "/XXXNOEXIST"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initLocal() {
|
||||
|
||||
@@ -264,3 +264,7 @@ func loadLocation(name string) (*Location, error) {
|
||||
}
|
||||
return nil, errors.New("unknown time zone " + name)
|
||||
}
|
||||
|
||||
func forceZipFileForTesting(zipOnly bool) {
|
||||
// We only use the zip file anyway.
|
||||
}
|
||||
|
||||
@@ -13,17 +13,13 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Test that NaNs in maps don't go quadratic.
|
||||
t := func(n int) time.Duration {
|
||||
var u0 syscall.Rusage
|
||||
if err := syscall.Getrusage(0, &u0); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t1 := time.Now()
|
||||
m := map[float64]int{}
|
||||
nan := math.NaN()
|
||||
for i := 0; i < n; i++ {
|
||||
@@ -32,11 +28,7 @@ func main() {
|
||||
if len(m) != n {
|
||||
panic("wrong size map after nan insertion")
|
||||
}
|
||||
var u1 syscall.Rusage
|
||||
if err := syscall.Getrusage(0, &u1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return time.Duration(u1.Utime.Nano() - u0.Utime.Nano())
|
||||
return time.Since(t1)
|
||||
}
|
||||
|
||||
// Depending on the machine and OS, this test might be too fast
|
||||
|
||||
Reference in New Issue
Block a user